Skip to content

Masihtabaei/cheap-16

Repository files navigation

cheap-16

Note

This project was completed as part of the Secure Software Engineering course during the Summer Term 2025 of our undergraduate studies, offered by Prof. Dr. Henning Meier at Coburg University. It was originally developed on our university’s GitLab instance and later partially migrated here, so some elements like issues or CI/CD pipelines may be missing.

Important

This project is licensed under the MIT License.

Explainer Videos

Here you can find also two explainer videos:

Project Information

  • Group Number: 5
  • Project Name: cheap-16 | cheap-sixteen
  • Project Team Members:
  • Release Version: 1.0
  • Project Logo:

    drawing

Highlights

Feature Note
Graphical user interface (GUI) Created with egui.
Handcrafted parser Implemented our own parser with error checking and reporting.
Own instruction set architecture Defined our very own instruction set architecture (documented here) with all the trimmings.
Project size Wrote more than 6000 lines of codes.
Extensive Git (Lab) usage Extended the list of files to be ignored by Git and attributes related to the Git and used a pre-commit plugin.
Extensive testing Written more than 300 unit tests and tested our program manually.
Own Docker image Built our own Docker image for the sake of faster pipeline flow.
Logging and tracing Used various methods to log and trace our executions.
Easy-to-comprehend code and linear code execution Followed the principle of KISS, minimized branch divergence, avoided polymorphism as much as possible, and preferred linear code execution.
Extensive documentation Composed doc strings, normal comments, architecture documentations and created supporting diagrams.
Conflict-free collaboration Avoided merge conflicts by clearly separating responsibilities.
Structured work Used conventional commits and semantic versioning.

Important Notes

We implemented all instructions except CLEAR and SETPX since they needed a graphics library, and we decided to omit both for the sake of simplicity. We also omitted both undo/redo features because of missing capacities in our team.

In this report, you can also see a curated list of feedbacks that you gave us and their consideration states. Thank you so much for your support and valuable feedback.

Introduction

Rust as the Programming Language of Choice

The decision to implement an emulator in Rust is largely based on the advantages of the language in the area of memory security. Rust prevents typical errors such as use-after-free or invalid memory accesses at compile time. This ensures that emulator users cannot inadvertently or manipulative access critical memory areas and/or program data at runtime. At the same time, Rust's modern type system, modular structure and stable tool chain promote long-lasting, maintainable code - a decisive advantage for long-term projects that are intended to go beyond simple prototypes.

Target Group

The program is primarily intended to provide students and teachers in an academic environment with the opportunity to develop a basic understanding of the structure and behavior of simple processor architectures. The deliberately reduced instruction set with only elementary arithmetic and logical operations is very easy to learn. Our GUI is ideal for teaching central concepts such as memory access, register work and instruction execution without being overwhelmed by technical complexity. The emulator thus creates a controlled, transparent environment for didactically motivated experiments, tasks and teaching scenarios.

Similar Projects

Here you find a list of similar projects:

Roadmap

Use-Cases

Use Case : 1

key value
Name Assembly source code compilation.
ID 1
Description User should be able to compile an assembly source code.
Actor User
Pre-conditions Source code is present within the text editor.
Steps Click the 'Build' button.
Post-conditions Compilation status (aka. diagnostics) will be shown. User sees now a 'Flash' button. A *cheapx file will be saved.

Use Case : 2

key value
Name Assembly source file compilation.
ID 2
Description User should be able to compile an assembly source file. A *cheapx file will be saved.
Actor User
Pre-conditions Source file is selected.
Steps Click the 'Build' button.
Post-conditions Compilation status (aka. diagnostics) will be shown. User sees now a 'Flash' button.

Use case : 3

key value
Name Load compiled source code.
ID 3
Description User clicks on 'Flash' button. By clicking the 'Flash' button the emulator loads the compiled program.
Actor User
Pre-conditions A source code was compiled successfully.
Steps Click the 'Flash' button
Post-conditions The user sees a output about the flashing status and new buttons : 'Execute' and 'Execute Stepwise'

Use case : 4

key value
Name Execute
ID 4
Description User clicks on 'Execute' button. By clicking the button the emulator loads the flashed file.
Actor User
Pre-conditions A source code was flashed successfully.
Steps Click the 'Execute' button.
Post-conditions The User sees the result saved in a register / memory / as a flag, based on command.

Use case : 5

key value
Name Stepwise Execution.
ID 5
Description User clicks on 'Execute Stepwise' button.
Actor User
Pre-conditions A source code was flashed successfully.
Steps Click the 'Execute Stepwise' button.
Post-conditions User sees new buttons: 'Next Step' 'Stop' 'Reset' 'Undo'

Use case : 6

key value
Name Execute one line (= one instruction).
ID 6
Description User clicks on 'Next step' button to execute one line.
Actor User
Pre-conditions A source code was flashed successfully, and the stepwise execution was started.
Steps Click the 'Next step' button.
Post-conditions The User sees the result saved in a register / memory / as a flag, based on command.

Use case : 7

key value
Name Reset Emulator.
ID 7
Description User clicks on 'reset' button. By clicking the button the emulator resets all values in register / memory / flags to random values
Actor User
Pre-conditions A source code was flashed successfully, and the stepwise execution was started.
Steps Click the 'Reset' button.
Post-conditions The User sees the result saved in a register / memory / as a flag, based on command.

Use case : 8

key value
Name Undo line (=instruction).
ID 8
Description User clicks on 'Undo' button. By clicking the button the UI shows results of the last operation
Actor User
Pre-conditions A source code was flashed successfully, and the stepwise execution was started. Additionally, at least one operation was executed
Steps Click the 'Undo' button.
Post-conditions The User sees the previous result saved in a register / memory / as a flag, based on command.

Use case : 9

key value
Name Stop stepwise execution.
ID 9
Description User clicks on 'Stop' button. By clicking the button the UI exits the execution mode.
Actor User
Pre-conditions A source code was flashed successfully, and the stepwise execution was started.
Steps Click the 'Stop' button.
Post-conditions The User sees the UI in editor mode with the buttons: 'Save File' 'Load File' 'Build'

Use case : 10

key value
Name Load a file.
ID 10
Description User clicks on 'Load File' button. By clicking the button the UI opens a dialogue with the file organization program of the OS.
Actor User
Pre-conditions Program was started.
Steps Click the 'Load file' button.
Post-conditions The User sees the loaded file in the editor area of the window.

Use case : 11

key value
Name Save a file
ID 11
Description User clicks on 'Save file' button. By clicking the button the UI may open a dialogue with the file organization program of the os. this depends on the scenario: If the file was loaded earlier no dialogue will be opened.
Actor User
Pre-conditions Program was started
Steps Click the 'Save file' button.
Post-conditions The User finds the saved file with ending : cheaps int his file system.

Use case : 12

key value
Name Edit / create text
ID 12
Description User has an area to write text here code into.
Actor User
Pre-conditions Program was started
Steps Write into the text editor area.
Post-conditions The User sees his written text.

Software Architecture

User Interface Architecture

Image of class structur Seeing this diagram raises the question of why the action_panel was not included in the Panel trait. This is due to the fact that action_panel requires a reference to the MyApp object in order to invoke its public methods and trigger the associated logic behind the buttons.

One might argue that the draw function in the trait could have been adapted to pass a reference to MyApp, and that panels not requiring it could simply ignore the reference. However, in accordance with the principle of least privilege, we deliberately chose not to expose such access to all panels and instead implemented the current design.

Build Sequence Diagram

Image of sequence diagram: build process

Flash Sequence Diagram

Image of sequence diagram: build process


User documentation

Usage

git clone <repo-link>
cd SSE_Projekt05/cheap-sixteen
cargo build
cargo run

Supporting Videos

Here you can find also two supporting videos:

Application

Screens

user-interface-first-image user-interface-second-image user-interface-third-image

Grid:

... ...
Code editor Registers panel
Code editor Flags panel
Code editor Application logs panel

Action buttons :

it depends on the program state which buttons are accessible:

  • Load file: Loads a file of arbitrary format
  • Save file: Saves file of arbitrary format
  • Build and flash : Compiles a file with *.cheaps ending to *cheapx in the same folder and loads the resulting *.cheapx binary into the emulator
  • Execute: Runs all instructions on the emulator at once
  • Execute Stepwise: Enters debug mode (here called step by step mode)
  • Next Step: Execute next line
  • Stop: Exit debug mode
  • Reset: Reset debug mode (to start from the beginning)

Program states and possible user actions

  • View: Load File | Save file | Build and Flash
  • ViewAfterFlash: Execute | Execute stepwise |Back
  • StepByStep: Stop | Next Step | Reset

Loading / editing example *.cheaps

The project provides various pieces of code example that can be found in the directory test_data.
In order to compile and running this code just click:

  1. Load file -> A dialogue will open to choose a file. Select the file path/to/test_data.
  2. Build and Flash
  3. Execute | Execute Stepwise
  4. Optional: If Execute Stepwise was selected continue clicking Next Step.

Writing code by yourself

A summary of all instruction supported in the architecture can be found here.

Intermediate Feedback

Here you can see a curated list of points and feedbacks that we got either per e-mail or via direct communication and their consideration states:

Feedback Status Notes
Missing use-case identifiers Done Added successfully.
Useless benchmarking stage Done Removed successfully.
Dead and deprecated code Done Cleaned-up successfully.
Duplicated code (Partially) done Deduplicated successfully.
Missing report Done Created and linked.
Missing code documentation (Partially) done Added a huge number of doc strings.
Missing user documentation Done Added to the report.
Dummy project name Done Renamed the project.
Low coverage (partially) done Increased the coverage successfully.
Shallow use-cases (Partially) done Added more context.

Challenges, Solutions, Lessons-Learned

General Challenges

We encountered following challenges or problems during this project:

  • Huge project (notes from Masih: my bad)
  • Linter issues
  • Low code coverage
  • Partially unsuccessfull team communication (notes from Masih: my bad)

Lessons-Learned

If we had the chance to re-do the project, we would probably consider following points:

  1. More intensive team-internal communication
  2. Better management, project planning, and state documentation
  3. Earlier confrontation with and deeper comprehension of deployment server and pipeline because of their usefulness
  4. Smaller project scope
  5. Earlier integration of units
  6. As-you-go documentation

User Interface Challenges

While researching GUI libraries for Rust, a helpful discussion on Reddit revealed that egui, iced, Tauri, and Slint are among the most popular libraries. However, many contributors in that thread criticized iced for complexity and performance issues, while Tauri and Slint received only a few comments. In contrast, egui was repeatedly praised for its simplicity and ease of use, leaving a notably positive impression.

By learning egui, we found its core concept straightforward: to implement a GUI for an application, the app logic should be encapsulated in a struct that implements the eframe::App trait. This trait requires defining an update() function, which describes the GUI and is called multiple times per second to update the interface (typically around 60 times per second by default).

To start the GUI, eframe::run_native() is used. It takes configuration information such as window options and a boxed instance of the app struct implementing the App trait.

The official egui website presents egui as a tool for simple and effective information representation and modeling. However, we did not evaluate its performance in graphically demanding scenarios.

Throughout development, we experienced egui as a very well-documented framework. Still, there were occasional issues with deprecated functions that produced warnings. As a result, we had to refactor the code several times to maintain compatibility with the current version. This raises whether the program will still run as smoothly in two to three years, once the framework has evolved further. If not, this would undermine one of Rust’s key advantages for our project: its reputation as a long-lived and stable language.

User Interface Vulnerabilities

As no critical data or computing resources are accessed by the software, an attack would most likely aim to crash the application. Input validation, a widely known principle especially in web services, is only required in our case for the code editor. The content entered there is later parsed and translated by our parser, which throws errors if invalid input appears. One interesting test missing would check whether extremely long input in the text editor could eventually cause the application to crash.
In an article, we read about GUI Element Misuse, short "GEM". This technique considers UI elements that should only be usable under specific conditions, such as at certain times or by users with special roles. In our case, this applies to the available actions in the action panel: flashing a program should only be possible after building it, and executing it should only be possible after flashing. These state-based actions were tested here. Problematically the draw method in the action panel could not be tested itself as it needed an egui::UI object. But this object cannot be created in a test. Therefore, a method copying the draw methods logic was created.

User Interface Testing

Testing a UI might appear very easy at first glance—just try to use the program. However, this assumption often stems from a developer’s perspective and overlooks the complexity of real user behavior. Developers tend to understand how the program is supposed to work, which can lead to a lack of insight into how users actually interact with the interface.

As a result, functionality tests that were only performed by developers should have been extended to a group of people with no prior involvement in the project. Unfortunately, this was not the case. Consequently, usability was also not properly tested.

In addition to functional and usability testing, mockup testing and integration testing would have been necessary to ensure a more complete evaluation of the application.

In the file application logic, there are, to some extent, two tests for a logic method responsible for saving a file to the current path. To verify correct functionality and guard against potential misuse, the following positive test cases were written:

  1. If the current path is empty, an error should be thrown.
  2. If the current path is not empty, the content of the file should be saved as expected.

This should be done for all functions that are important for the application logic. Further tests that would complement the testing are single tests if the panels for the GUI are loaded properly in different scenarios. Additionally, their own logic should be tested.

About

An educational 16-bit custom instruction set architecture with emulator, assembler, linker, and integrated development environment, all implemented in Rust.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages