├── .dockerignore ├── .github ├── FUNDING.yml └── workflows │ ├── benchmark.yml │ ├── grader.yml │ └── selfie.yml ├── .gitignore ├── .replit ├── AUTHORS ├── CITATION.cff ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── assignments ├── README.md ├── ascii-table.md ├── compiler-assignments.md ├── introductory-assignments.md └── systems-assignments.md ├── benchmark ├── Dockerfile ├── README.md ├── assets │ └── logo-fit.svg ├── bt.py ├── config.yml ├── lib │ ├── __init__.py │ ├── argument_parser.py │ ├── bitwuzla_terminator.py │ ├── color_map.py │ ├── config.py │ ├── dict_mixin.py │ ├── exceptions.py │ ├── generate.py │ ├── log.py │ ├── model.py │ ├── model_config_parser.py │ ├── model_data.py │ ├── model_generation_config.py │ ├── model_grapher.py │ ├── model_parser.py │ ├── model_type.py │ ├── overview.py │ ├── paths.py │ ├── presenter.py │ ├── rotor_parser.py │ ├── solver.py │ ├── solver_profile.py │ └── utils.py ├── requirements-tests.txt ├── requirements.txt ├── run_tests.py ├── setup.sh └── tests │ ├── __init__.py │ ├── integration │ ├── __init__.py │ ├── conftest.py │ ├── helpers.py │ └── test_basic_workflows.py │ └── unit │ ├── __init__.py │ ├── test_model_config_parser.py │ ├── test_paths.py │ └── test_solver.py ├── docs ├── CNAME ├── _config.yml ├── _layouts │ └── redirect.html ├── _redirects │ └── slides.html ├── images │ ├── bkg.png │ └── blacktocat.png ├── index.md ├── javascripts │ ├── main.js │ └── scale.fix.js └── stylesheets │ ├── github-dark.css │ ├── github-light.css │ ├── normalize.css │ ├── styles.css │ └── stylesheet.css ├── examples ├── README.md ├── assembly │ └── read-and-exit.s ├── bitwise.c ├── bounds.c ├── cache │ ├── coherency-invalidation.c │ ├── dcache-access-0.c │ └── dcache-access-1.c ├── count.c ├── countdown.c ├── division-by-zero.c ├── double.c ├── encoding.c ├── escape.c ├── function.c ├── gc │ ├── boehm-gc-test.c │ └── gc-test.c ├── hello-world-minified.c ├── hello-world.c ├── iteration-high.c ├── iteration-low.c ├── iteration.c ├── local.c ├── negative.c ├── overflows.c ├── overhead.c ├── pointer.c ├── procedure.c ├── quine.c ├── recursion.c ├── sat │ └── rivest.cnf └── symbolic │ ├── README.md │ ├── division-by-zero-3-35.c │ ├── invalid-memory-access-fail-2-35.c │ ├── memory-access-fail-1-35.c │ ├── nested-if-else-1-35.c │ ├── nested-if-else-reverse-1-35.c │ ├── nested-recursion-fail-1-35.c │ ├── recursive-ackermann-1-35.c │ ├── recursive-factorial-fail-1-35.c │ ├── recursive-fibonacci-1-10.c │ ├── return-from-loop-1-35.c │ ├── simple-assignment-1-35.c │ ├── simple-decreasing-loop-1-35.c │ ├── simple-if-else-1-35.c │ ├── simple-if-else-reverse-1-35.c │ ├── simple-if-without-else-1-35.c │ ├── simple-increasing-loop-1-35.c │ ├── three-level-nested-loop-fail-1-35.c │ └── two-level-nested-loop-1-35.c ├── grader ├── Dockerexamr ├── README.md ├── assignments │ ├── array │ │ ├── access-order.c │ │ ├── assignment-variables.c │ │ ├── assignment.c │ │ ├── call-by-reference.c │ │ ├── global-declaration.c │ │ ├── invalid-assignment.c │ │ ├── local-declaration.c │ │ ├── multidimensional-variables.c │ │ └── multidimensional.c │ ├── assembler │ │ ├── invalid-argument-add.s │ │ ├── missing-instruction.s │ │ ├── missing-literal.s │ │ ├── valid-hex.s │ │ ├── valid-registers-add.s │ │ └── valid-registers-addi.s │ ├── bitwise-logical │ │ ├── and-with-literals.c │ │ ├── and-with-variables.c │ │ ├── invalid-and.c │ │ ├── invalid-not.c │ │ ├── invalid-or.c │ │ ├── not-with-literals.c │ │ ├── not-with-variables.c │ │ ├── or-with-literals.c │ │ ├── or-with-variables.c │ │ ├── precedence.c │ │ ├── precedence2.c │ │ └── precedence3.c │ ├── bitwise-shift │ │ ├── invalid-left-shift.c │ │ ├── invalid-right-shift.c │ │ ├── left-shift-with-literals.c │ │ ├── left-shift-with-variables.c │ │ ├── precedence.c │ │ ├── right-shift-with-literals.c │ │ └── right-shift-with-variables.c │ ├── for-loop │ │ ├── missing-assignment.c │ │ ├── multiple-statements.c │ │ ├── nested.c │ │ └── single-statement.c │ ├── hex-literal │ │ ├── all-digit-characters.c │ │ ├── max-value.c │ │ └── min-value.c │ ├── lock │ │ ├── print-with-lock.c │ │ ├── print-without-lock.c │ │ └── release-after-exit.c │ ├── logical │ │ ├── advanced-logical-expressions.c │ │ ├── lazy-eval-and.c │ │ ├── lazy-eval-or.c │ │ ├── logical-and.c │ │ ├── logical-not.c │ │ ├── logical-or.c │ │ ├── precedence.c │ │ └── precedence2.c │ ├── processes │ │ └── hello-world.c │ ├── struct │ │ ├── as-parameter.c │ │ ├── declaration.c │ │ ├── definition.c │ │ ├── initialization.c │ │ ├── member-declaration.c │ │ ├── member-initialization.c │ │ ├── nested-declaration.c │ │ └── nested-initialization.c │ ├── system-calls │ │ ├── invalid-address.c │ │ ├── null-ptr.c │ │ ├── parallel-print.c │ │ ├── sum-exit-code.c │ │ └── unmapped-page-wait.c │ ├── threads │ │ ├── shared-data.c │ │ ├── shared-heap.c │ │ ├── sum-integer-dekker.c │ │ └── syscalls.c │ ├── threadsafe-malloc │ │ ├── load-reserved.c │ │ ├── lr-sc-interleaved.c │ │ ├── no-switch-malloc.c │ │ ├── store-conditional.c │ │ └── threadsafe-malloc.c │ └── treiber-stack │ │ ├── stack-pop.c │ │ └── stack-push.c ├── examr.py ├── lib │ ├── __init__.py │ ├── checks.py │ ├── cli.py │ ├── functional.py │ ├── grade.py │ ├── model.py │ ├── output_processing.py │ ├── print.py │ ├── string.py │ └── system.py ├── self.py └── tests │ ├── __init__.py │ ├── assignment_stubs │ └── processes │ │ └── hello-world.c │ ├── elf-header.m │ ├── instructions │ ├── bitwise-and.s │ ├── bitwise-left-shift.s │ ├── bitwise-not.s │ ├── bitwise-or.s │ ├── bitwise-right-shift.s │ ├── load-reserved.s │ └── store-conditional.s │ ├── links.txt │ ├── sleep-forever.c │ ├── test_bulk_grader.py │ ├── test_cli.py │ ├── test_compilable.py │ ├── test_execution.py │ ├── test_execution_timeout.py │ ├── test_grading.py │ ├── test_output_processing.py │ ├── test_processes.py │ ├── test_riscv_instruction.py │ ├── test_robustness.py │ └── utils.py ├── grammar.md ├── machine ├── .editorconfig ├── .gitignore ├── Makefile ├── README.md ├── asm │ ├── crt.S │ ├── mem.S │ └── trap.S ├── bootstrap.c ├── bootstrap.h ├── bootstrap_kernel.c ├── bootstrap_library.c ├── console.c ├── context.c ├── defines.mk ├── diag.c ├── elf.c ├── filesystem.c ├── filesystem.mk ├── gdbinit_qemu ├── glue_libraryos.c ├── include │ ├── asm_context_switch_offsets.h │ ├── compiler-utils.h │ ├── config.h │ ├── console.h │ ├── context.h │ ├── diag.h │ ├── elf.h │ ├── filesystem.h │ ├── linker-syms.h │ ├── mmu.h │ ├── numeric-utils.h │ ├── sbi_ecall.h │ ├── sbi_ecall_ids.h │ ├── syscalls.h │ ├── tinycstd.h │ └── trap.h ├── mmu.c ├── payload_template.ld ├── sbi_ecall.c ├── syscalls.c ├── tinycstd.c ├── tools │ └── asm_struct_macro_generator.c └── trap.c ├── replit.nix ├── riscu.md ├── selfie.c ├── semantics.md ├── theses ├── README.md ├── bachelor_thesis_bachinger.pdf ├── bachelor_thesis_barthel.pdf ├── bachelor_thesis_bauer.pdf ├── bachelor_thesis_diller.pdf ├── bachelor_thesis_edelmayer.pdf ├── bachelor_thesis_fejzic.pdf ├── bachelor_thesis_fischer.pdf ├── bachelor_thesis_haritopoulos.pdf ├── bachelor_thesis_kollert.pdf ├── bachelor_thesis_landl.pdf ├── bachelor_thesis_oblasser.pdf ├── bachelor_thesis_pape.pdf ├── bachelor_thesis_seidl.pdf ├── bachelor_thesis_siller.pdf ├── bachelor_thesis_thiele.pdf ├── bachelor_thesis_widmoser.pdf └── bachelor_thesis_wulz.pdf └── tools ├── README.md ├── babysat.c ├── beator.c ├── bitme.py ├── boehm-gc.c ├── buzzr.c ├── gc-lib.c ├── monster.c ├── periscope ├── README.md ├── periscope-py │ ├── .gitignore │ ├── README.md │ ├── pyrightconfig.json │ ├── requirements.txt │ └── src │ │ ├── cmp_bars.py │ │ ├── histogram.py │ │ ├── periscope.py │ │ ├── periscope_result.py │ │ └── whiskers.py └── periscope-rs │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ └── src │ ├── bench │ ├── hyperfine.rs │ ├── mod.rs │ ├── rotor.rs │ └── wc.rs │ ├── btor │ ├── assignment.rs │ ├── btor2.rs │ ├── helpers.rs │ ├── mod.rs │ └── witness_format.rs │ ├── lib.rs │ └── main.rs ├── quarc ├── README.md ├── add.ipynb ├── btor2QC.py ├── check_inputs.py ├── experiments │ ├── nested-if-else-1-35.ipynb │ ├── nested-if-else-reverse-1-35.ipynb │ ├── return-from-loop-1-35.ipynb │ ├── simple-assignment-1-35.ipynb │ ├── simple-if-else-1-35.ipynb │ ├── simple-if-else-reverse-1-35.ipynb │ └── simple-if-without-else-1-35.ipynb ├── instructions.py ├── main.py ├── qasm_files │ ├── add.qasm │ ├── add2.qasm │ ├── and.qasm │ ├── div.qasm │ ├── eq.qasm │ ├── eq_grover.qasm │ ├── ite.qasm │ ├── mul.qasm │ ├── not.qasm │ ├── rem.qasm │ ├── sub.qasm │ ├── ult.qasm │ ├── ult_grover.qasm │ ├── ulte.qasm │ └── ulte_grover.qasm ├── qword.py ├── qword_tools.py ├── requirements.txt ├── scripts │ ├── example_script.py │ └── operators.bash ├── settings.py ├── ult_grover.ipynb ├── uncompute.py └── utils.py ├── qubot ├── 32_symbolic_experiment_statistics.csv ├── 64bit_btor2_files │ └── .DS_Store ├── 64bit_small_sample │ ├── adj.coo │ └── input_propagation.unicorn ├── README.md ├── asplos_main_example.py ├── bit_transformation │ ├── bit_penalty_models.py │ ├── configurations.py │ └── more_gates │ │ ├── classical_gates.py │ │ ├── xnor.py │ │ └── xor.py ├── bqm_input_checker.py ├── btor2bqm.py ├── dummy_btor2files │ └── .DS_Store ├── instructions.py ├── main_experiment_statistics.csv ├── qa_examples │ ├── chimera_embedding.png │ ├── d.ipynb │ ├── d_embedding.csv │ ├── pegasus_embedding.png │ ├── qubit_growth.csv │ ├── u.ipynb │ ├── u_embedding.csv │ └── visualizations.ipynb ├── quantum_computer_tests │ ├── .ipynb_checkpoints │ │ ├── 32_12bad_c_lin-checkpoint.ipynb │ │ ├── Untitled-checkpoint.ipynb │ │ └── Untitled1-checkpoint.ipynb │ ├── pure_qa.ipynb │ └── qubit_growth_graph.ipynb ├── qubit_growth_script.py ├── qword.py ├── qword_tools.py ├── requirements.txt ├── script.py ├── scripts │ ├── 32bit_paper_example.py │ ├── 32symbolic_nomem.py │ ├── 64bit_paper_example.py │ ├── 64symbolic_nomem.py │ ├── qubit_growth.py │ └── symbolic_nomem.py ├── settings.py ├── symbolic_examples.py ├── symbolic_experiment_statistics.csv └── tools.py ├── rotor.c ├── rotor_disassembly_compare.py └── validator.py /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | docs 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # repo: cksystemsteaching/selfie 2 | # filename: FUNDING.YML 3 | 4 | github: cksystemsteaching -------------------------------------------------------------------------------- /.github/workflows/benchmark.yml: -------------------------------------------------------------------------------- 1 | name: Rotor benchmarking tool 2 | 3 | on: 4 | push: 5 | paths: 6 | - 'benchmark/**' # Only trigger when files in this subproject change 7 | pull_request: 8 | paths: 9 | - 'benchmark/**' 10 | 11 | jobs: 12 | test: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | - name: Set up Python 18 | uses: actions/setup-python@v4 19 | with: 20 | python-version: '3.10' 21 | 22 | - name: Install dependencies 23 | run: | 24 | cd benchmark && ./setup.sh 25 | 26 | - name: Run integration tests 27 | run: | 28 | cd benchmark 29 | source venv/bin/activate 30 | pip install -r requirements-tests.txt 31 | ./run_tests.py -i 32 | 33 | - name: Run unit tests 34 | run: | 35 | cd benchmark 36 | source venv/bin/activate 37 | pip install -r requirements-tests.txt 38 | ./run_tests.py -u 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *__pycache__* 2 | *.m 3 | *.s 4 | *.smt2 5 | *.btor2 6 | /benchmark/bt.log 7 | venv 8 | selfie 9 | selfie-32 10 | selfie.h 11 | selfie.exe 12 | babysat 13 | monster 14 | beator 15 | beator-32 16 | rotor 17 | rotor-32 18 | -------------------------------------------------------------------------------- /.replit: -------------------------------------------------------------------------------- 1 | # The command that is executed when the run button is clicked. 2 | run = "./selfie" 3 | 4 | compile = "make" 5 | 6 | # The default file opened in the editor. 7 | entrypoint = "selfie.c" 8 | 9 | # Setting environment variables 10 | # [env] 11 | # FOO="foo" 12 | 13 | # Packager configuration for the Universal Package Manager 14 | # See https://github.com/replit/upm for supported languages. 15 | [packager] 16 | language = "c" 17 | 18 | [packager.features] 19 | # Enables the package search sidebar 20 | packageSearch = true 21 | # Enabled package guessing 22 | guessImports = false 23 | 24 | # Per language configuration: language. 25 | [languages.c] 26 | # The glob pattern to match files for this programming language 27 | pattern = "**/*.{c,h}" 28 | 29 | # LSP configuration for code intelligence 30 | [languages.c.languageServer] 31 | start = ["ccls"] 32 | 33 | [nix] 34 | channel = "stable-21_11" -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Alireza Abyaneh 2 | Martin Aigner 3 | Sebastian Arming 4 | Christian Barthel 5 | Simon Bauer 6 | Christoph Edelmayer 7 | Martin Fischer 8 | Marcel Haritopoulos 9 | Christoph Kirsch 10 | Sebastian Landl 11 | Michael Lippautz 12 | Philipp Mayer 13 | Christian Moesl 14 | Simone Oblasser 15 | Sara Seidl 16 | Manuel Widmoser -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | title: selfie 3 | message: >- 4 | An educational software system of a tiny self-compiling C 5 | compiler, a tiny self-executing RISC-V emulator, and a 6 | tiny self-hosting RISC-V hypervisor. 7 | type: software 8 | authors: 9 | - given-names: Christoph 10 | family-names: Kirsch 11 | email: ck@cs.uni-salzburg.at 12 | affiliation: 'University of Salzburg, Austria' 13 | orcid: 'https://orcid.org/0000-0002-0961-0564' 14 | repository-code: 'https://github.com/cksystemsteaching/selfie' 15 | url: 'http://selfie.cs.uni-salzburg.at/' 16 | abstract: >- 17 | Selfie is a project of the Computational Systems Group at 18 | the Department of Computer Sciences of the University of 19 | Salzburg in Austria. 20 | 21 | 22 | The Selfie Project provides an educational platform for 23 | teaching undergraduate and graduate students the design 24 | and implementation of programming languages and runtime 25 | systems. The focus is on the construction of compilers, 26 | libraries, operating systems, and even virtual machine 27 | monitors. The common theme is to identify and resolve 28 | self-reference in systems code which is seen as the key 29 | challenge when teaching systems engineering, hence the 30 | name. 31 | keywords: 32 | - emulator 33 | - computer-science 34 | - compiler 35 | - virtual-machine 36 | - 'teaching ' 37 | - 'symbolic-execution-engine ' 38 | license: BSD-2-Clause 39 | commit: eb71b1e97ec1510adbc799c434c18901e48a9829 40 | date-released: '2024-08-03' 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) the Selfie Project authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright notice, 9 | this list of conditions and the following disclaimer in the documentation 10 | and/or other materials provided with the distribution. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 16 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /assignments/README.md: -------------------------------------------------------------------------------- 1 | # Homework Assignments 2 | 3 | The markdown files in this directory feature [introductory](introductory-assignments.md) homework assignments as well as autograded [compiler](compiler-assignments.md) and [systems](systems-assignments.md) assignments. See the autograder's [README.md](../grader/README.md) for instructions on how to run the autograder. -------------------------------------------------------------------------------- /benchmark/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use Debian as the base image 2 | 3 | FROM debian:bullseye-slim 4 | 5 | # Install necessary packages for building RISC-V GCC toolchain 6 | RUN apt-get update && apt-get install -y \ 7 | autoconf automake autotools-dev curl python3 python3-pip libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev ninja-build git cmake libglib2.0-dev libslirp-dev meson z3 8 | 9 | # Set working directory 10 | WORKDIR /workspace 11 | COPY . . 12 | 13 | #Source venv 14 | RUN ./setup.sh 15 | RUN . venv/bin/activate 16 | 17 | #Install Bitwuzla 18 | WORKDIR /opt/bitwuzla 19 | RUN . /workspace/venv/bin/activate && \ 20 | git clone https://github.com/bitwuzla/bitwuzla /opt/bitwuzla && \ 21 | pip install /opt/bitwuzla 22 | 23 | # Clone the RISC-V GNU toolchain repository 24 | RUN git clone https://github.com/riscv/riscv-gnu-toolchain /opt/riscv-toolchain 25 | # Set working directory 26 | WORKDIR /opt/riscv-toolchain 27 | # Configure and build the toolchain (this may take a while) 28 | RUN ./configure --prefix=/opt/riscv --enable-multilib --disable-gdb && make -j4 29 | 30 | # Add the RISC-V toolchain to the PATH 31 | ENV PATH="/opt/riscv/bin:${PATH}" 32 | 33 | 34 | # Create a default entry point for the container 35 | ENTRYPOINT ["/bin/bash"] 36 | -------------------------------------------------------------------------------- /benchmark/lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/benchmark/lib/__init__.py -------------------------------------------------------------------------------- /benchmark/lib/bitwuzla_terminator.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from bitwuzla import * 4 | 5 | 6 | class TimeTerminator: 7 | """Callback handler for enforcing time limits in Bitwzla solver operations. 8 | 9 | This class implements a termination callback that can be used to enforce 10 | time limits when solving SMT problems with the Bitwzla library. The callback 11 | will signal termination when the specified time limit has been exceeded 12 | 13 | More here: https://bitwuzla.github.io/docs/cpp/classes/terminator.html 14 | """ 15 | 16 | def __init__(self, time_limit): 17 | self.start_time = time.time() 18 | self.time_limit = time_limit 19 | self.activated = False 20 | 21 | def __call__(self): 22 | # Terminate after self.time_limit ms passed 23 | should_terminate = (time.time() - self.start_time) > self.time_limit 24 | if should_terminate: 25 | self.activated = True 26 | return should_terminate 27 | -------------------------------------------------------------------------------- /benchmark/lib/color_map.py: -------------------------------------------------------------------------------- 1 | """ 2 | Predefined color palettes for consistent visualization across BT's graphing tools. 3 | All colors are optimized for readability and colorblind accessibility. 4 | 5 | Note: This is an internal utility class used exclusively by the grapher module. 6 | """ 7 | 8 | 9 | class ColorMap: 10 | # Primary colors 11 | PRIMARY = { 12 | "blue": "#3574C6", # Vibrant but not overwhelming 13 | "red": "#E64A3C", # For highlights/important data 14 | "green": "#4EAC5B", # Balanced mid-tone 15 | "purple": "#7E57C2", # Good contrast to blues 16 | "orange": "#FF8F3E", # For secondary elements 17 | } 18 | 19 | # Extended categorical palette (8 colors) 20 | QUALITATIVE = [ 21 | "#3574C6", # Blue 22 | "#E64A3C", # Red 23 | "#4EAC5B", # Green 24 | "#7E57C2", # Purple 25 | "#FF8F3E", # Orange 26 | "#5FB7D4", # Cyan 27 | "#F06292", # Pink 28 | "#8D6E63", # Brown 29 | ] 30 | 31 | # Sequential (for ordered data) 32 | SEQUENTIAL = [ 33 | "#F7FBFF", # Lightest 34 | "#D2E3F3", 35 | "#9ECAE1", 36 | "#6BAED6", 37 | "#3B8EC9", 38 | "#1E6DB7", # Darkest 39 | ] 40 | 41 | # Diverging (for variance from median) 42 | DIVERGING = [ 43 | "#D7191C", # Negative 44 | "#FDAE61", 45 | "#FFFFBF", # Neutral 46 | "#ABD9E9", 47 | "#2C7BB6", # Positive 48 | ] 49 | 50 | SOLVER = { 51 | "z3": "#F06292", # Pink 52 | "bitwuzla": "#5FB7D4", # Cyan 53 | } 54 | -------------------------------------------------------------------------------- /benchmark/lib/config.py: -------------------------------------------------------------------------------- 1 | """ 2 | Loads and resolves critical paths from BT's configuration file. 3 | Paths are relative to the project root (parent of benchmark/ directory). 4 | """ 5 | 6 | from pathlib import Path 7 | import yaml 8 | 9 | # Directory resolution 10 | script_dir = Path(__file__).resolve().parent.parent 11 | project_root = script_dir.parent 12 | 13 | # Load the configuration file 14 | config_file = script_dir / "config.yml" 15 | with open(config_file, "r") as file: 16 | config = yaml.safe_load(file) 17 | 18 | model_builder_path = Path(project_root / config["model_builder_path"]) 19 | verbose = False 20 | -------------------------------------------------------------------------------- /benchmark/lib/dict_mixin.py: -------------------------------------------------------------------------------- 1 | from dataclasses import asdict 2 | from typing import Any, Dict 3 | import json 4 | 5 | 6 | class DictMixin: 7 | """ 8 | Mixin class that provides dictionary-like access to dataclass attributes. 9 | Enables conversion to dict and pretty-printing while maintaining type safety. 10 | 11 | Typical usage: 12 | @dataclass 13 | class MyData(DictMixin): 14 | field: str 15 | 16 | data = MyData("value") 17 | data["field"] # Dictionary access 18 | data.to_dict() # Convert to plain dict 19 | """ 20 | 21 | def _ensure_initialized(self): 22 | pass 23 | 24 | def __getitem__(self, key): 25 | return getattr(self, key) 26 | 27 | def get(self, key, default=None): 28 | try: 29 | return self[key] 30 | except (KeyError, AttributeError): 31 | return default 32 | 33 | def to_dict(self) -> Dict[str, Any]: 34 | self._ensure_initialized() 35 | return asdict(self) 36 | 37 | def pretty_print(self) -> str: 38 | return json.dumps(self.to_dict(), indent=2, default=str) 39 | -------------------------------------------------------------------------------- /benchmark/lib/model_generation_config.py: -------------------------------------------------------------------------------- 1 | """ 2 | Model configuration containers that handle: 3 | - Path resolution for generated/loaded models 4 | - Format-specific command generation 5 | - Output naming conventions 6 | 7 | Key Classes: 8 | 1. ModelBaseConfig: Core path/format handling 9 | 2. ModelGenerationConfig: Build process setup 10 | 3. ModelLoadConfig: Existing model loader 11 | """ 12 | 13 | from lib.model_type import ModelType 14 | from lib.paths import SourcePath, OutputPath 15 | 16 | 17 | class ModelBaseConfig: 18 | def __init__(self, source_path: SourcePath, format: str): 19 | self.source_path = source_path 20 | self.format = format 21 | 22 | def get_model_path(self): 23 | pass 24 | 25 | 26 | class ModelGenerationConfig(ModelBaseConfig): 27 | """Complete model generation specification. 28 | 29 | Args: 30 | source_path: Source file to process 31 | model_type: ModelType defining build commands 32 | output_path: Base output directory 33 | 34 | Automatically: 35 | - Determines output filename (stem + model_type segments) 36 | - Resolves full output path with proper extension 37 | """ 38 | def __init__( 39 | self, source_path: SourcePath, model_type: ModelType, output_path: OutputPath 40 | ): 41 | self.model_type = model_type 42 | super().__init__(source_path, self._determine_format()) 43 | self.compilation_cmd = model_type.get_compile_cmd() 44 | self.model_generation_cmd = model_type.get_model_generation_cmd() 45 | self.output_path = output_path.as_file_for( 46 | self._generate_output_name(source_path, model_type), model_type.get_format() 47 | ) 48 | 49 | def get_model_path(self): 50 | return self.output_path 51 | 52 | def _determine_format(self): 53 | return self.model_type.get_format() 54 | 55 | @staticmethod 56 | def _generate_output_name(source_path: SourcePath, model_type: ModelType): 57 | filename = ( 58 | f"{source_path.path.stem}_{'_'.join(model_type.get_bases()[:-1])}" 59 | ) 60 | return filename 61 | 62 | 63 | class ModelLoadConfig(ModelBaseConfig): 64 | """Simplified config for loading existing models. 65 | 66 | Derives format directly from file extension. 67 | """ 68 | def __init__(self, source_path: SourcePath): 69 | super().__init__(source_path, source_path._path.suffix[1:]) 70 | 71 | def get_model_path(self): 72 | return self.source_path 73 | -------------------------------------------------------------------------------- /benchmark/lib/solver_profile.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass, field 2 | from typing import NewType, NamedTuple, Dict, List 3 | 4 | Timestamp = NewType("Timestamp", float) 5 | MegaBytes = NewType("MegaBytes", int) 6 | CPUPercent = NewType("CPUPercent", float) 7 | 8 | 9 | class ProfileSample(NamedTuple): 10 | """Timestamped measurement of all solver runtime metrics""" 11 | 12 | timestamp: Timestamp 13 | rss: MegaBytes 14 | cpu_percent: CPUPercent 15 | 16 | 17 | @dataclass 18 | class SolverProfiler: 19 | samples: Dict["Model", List[ProfileSample]] = field(default_factory=dict) 20 | 21 | def record_sample( 22 | self, model: "Model", timestamp: float, rss: int, cpu_percent: float 23 | ): 24 | """Record a new performance sample with current timestamp""" 25 | self.samples.setdefault(model, []).append( 26 | ProfileSample( 27 | timestamp=Timestamp(timestamp), 28 | rss=MegaBytes(rss), 29 | cpu_percent=CPUPercent(cpu_percent), 30 | ) 31 | ) 32 | 33 | # Analysis methods 34 | def peak_memory(self, model: "Model") -> MegaBytes | None: 35 | """Get maximum RSS observed""" 36 | if samples := self.samples.get(model): 37 | return max(s.rss for s in samples) 38 | return None 39 | -------------------------------------------------------------------------------- /benchmark/requirements-tests.txt: -------------------------------------------------------------------------------- 1 | pytest>=8.0.0 -------------------------------------------------------------------------------- /benchmark/requirements.txt: -------------------------------------------------------------------------------- 1 | PyYAML>=6.0.2 2 | scipy>=1.11.0 3 | seaborn>=0.13.2 4 | packaging>=24.2 5 | psutil>=6.1.0 6 | pyparsing>=3.2.3 7 | -------------------------------------------------------------------------------- /benchmark/run_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Unified test runner with execution modes: 4 | - Default: Run all tests 5 | - -u/--unit: Unit tests only 6 | - -i/--integration: Integration tests only 7 | 8 | Specific argument for pytest can also be passed. 9 | """ 10 | import argparse 11 | import subprocess 12 | import sys 13 | from pathlib import Path 14 | 15 | def run_tests(test_paths: list, extra_args: list = None): 16 | """Execute pytest with given paths and arguments.""" 17 | cmd = [ 18 | sys.executable, "-m", "pytest", 19 | "-v", 20 | "--durations=5", 21 | *test_paths, 22 | *(extra_args or []) 23 | ] 24 | result = subprocess.run(cmd, cwd=Path(__file__).parent) 25 | return result.returncode 26 | 27 | def main(): 28 | parser = argparse.ArgumentParser() 29 | group = parser.add_mutually_exclusive_group() 30 | group.add_argument("-u", "--unit", action="store_true", help="Run only unit tests") 31 | group.add_argument("-i", "--integration", action="store_true", help="Run only integration tests") 32 | args, pytest_args = parser.parse_known_args() 33 | 34 | test_paths = [] 35 | if args.unit: 36 | test_paths.append("tests/unit/") 37 | elif args.integration: 38 | test_paths.append("tests/integration/") 39 | else: # Default: run both 40 | test_paths.extend(["tests/unit/", "tests/integration/"]) 41 | 42 | sys.exit(run_tests(test_paths, pytest_args)) 43 | 44 | if __name__ == "__main__": 45 | main() -------------------------------------------------------------------------------- /benchmark/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/benchmark/tests/__init__.py -------------------------------------------------------------------------------- /benchmark/tests/integration/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/benchmark/tests/integration/__init__.py -------------------------------------------------------------------------------- /benchmark/tests/integration/helpers.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | def get_output_path( 4 | input_path: Path, 5 | model_type: str, 6 | output_path: Path, 7 | 8 | ): 9 | """Gets the path of the output""" 10 | from lib.model_generation_config import ModelGenerationConfig 11 | from lib.model_type import ModelType 12 | from lib.paths import OutputPath, SourcePath 13 | 14 | config = ModelGenerationConfig(SourcePath(input_path), ModelType(model_type), OutputPath(output_path)) 15 | return config.get_model_path() -------------------------------------------------------------------------------- /benchmark/tests/unit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/benchmark/tests/unit/__init__.py -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | selfie.cs.uni-salzburg.at 2 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | title: selfie 2 | description: An educational software system of a tiny self-compiling C compiler, a tiny self-executing RISC-V emulator, and a tiny self-hosting RISC-V hypervisor. 3 | google_analytics: UA-3827654-1 4 | show_downloads: true 5 | theme: jekyll-theme-minimal 6 | 7 | gems: 8 | - jekyll-mentions 9 | 10 | collections: 11 | redirects: 12 | output: true 13 | 14 | defaults: 15 | - 16 | scope: 17 | type: redirects 18 | values: 19 | layout: redirect -------------------------------------------------------------------------------- /docs/_layouts/redirect.html: -------------------------------------------------------------------------------- 1 | --- 2 | # Jekyll layout to create URL redirects 3 | # https://github.com/jekylltools/jekyll-redirect-layout 4 | # v1.7 5 | --- 6 | {%- assign destination = page.destination | absolute_url -%} 7 | 8 | 9 | 10 | 11 | {% if page.canonical == true -%} 12 | 13 | {% endif -%} 14 | 17 | 18 | 30 | Redirecting... 31 | 32 | 33 | Follow this link if you are not redirected automatically. 34 | 35 | -------------------------------------------------------------------------------- /docs/_redirects/slides.html: -------------------------------------------------------------------------------- 1 | --- 2 | permalink: /slides/ 3 | destination: https://www.icloud.com/keynote/0J_SKB-ofwiuxg-lCag-s-gOA#selfie 4 | canonical: false 5 | --- -------------------------------------------------------------------------------- /docs/images/bkg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/docs/images/bkg.png -------------------------------------------------------------------------------- /docs/images/blacktocat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/docs/images/blacktocat.png -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | Selfie is a project of the [Computational Systems Group](https://cs.uni-salzburg.at/~ck) at the Department of Computer Sciences of the University of Salzburg in Austria. 2 | 3 | The Selfie Project provides an educational platform for teaching undergraduate and graduate students the design and implementation of programming languages and runtime systems. The focus is on the construction of compilers, libraries, operating systems, and even virtual machine monitors. The common theme is to identify and resolve self-reference in systems code which is seen as the key challenge when teaching systems engineering, hence the name. 4 | 5 | [README](https://github.com/cksystemsteaching/selfie/blob/main/README.md) for an overview of the system and all available resources. -------------------------------------------------------------------------------- /docs/javascripts/main.js: -------------------------------------------------------------------------------- 1 | console.log('This would be the main JS file.'); 2 | -------------------------------------------------------------------------------- /docs/javascripts/scale.fix.js: -------------------------------------------------------------------------------- 1 | var metas = document.getElementsByTagName('meta'); 2 | var i; 3 | if (navigator.userAgent.match(/iPhone/i)) { 4 | for (i=0; i 0) { 12 | // ... subtract the decimal value 1 from bar and assign the result to bar 13 | bar = bar - 1; 14 | 15 | // go back to the while statement and check again 16 | } 17 | 18 | // return the value of bar as the result of the invocation of main 19 | return bar; 20 | } -------------------------------------------------------------------------------- /examples/division-by-zero.c: -------------------------------------------------------------------------------- 1 | uint64_t x; 2 | uint64_t y; 3 | 4 | uint64_t main() { 5 | x = 1; 6 | y = 0; 7 | 8 | x = x / y; 9 | } -------------------------------------------------------------------------------- /examples/double.c: -------------------------------------------------------------------------------- 1 | int double(int n) { 2 | return n + n; 3 | } 4 | 5 | int main() { 6 | return double(42); 7 | } -------------------------------------------------------------------------------- /examples/encoding.c: -------------------------------------------------------------------------------- 1 | // printing the decimal number 85 in C* 2 | 3 | // libcstar procedures for printing 4 | void init_library(); 5 | void print(uint64_t* s); 6 | void print_integer(uint64_t n); 7 | void print_character(uint64_t c); 8 | void print_hexadecimal(uint64_t n, uint64_t a); 9 | void print_octal(uint64_t n, uint64_t a); 10 | void print_binary(uint64_t n, uint64_t a); 11 | void println(); 12 | 13 | uint64_t main() { 14 | // initialize selfie's libcstar library 15 | init_library(); 16 | 17 | // print the integer literal 85 in decimal 18 | print("85 in decimal: "); 19 | print_integer(85); 20 | println(); 21 | 22 | // print the ASCII character 85 (which is U) 23 | print("85 in ASCII: "); 24 | print_character(85); 25 | println(); 26 | 27 | // print the integer literal 85 in hexadecimal 28 | print("85 in hexadecimal: "); 29 | print_hexadecimal(85, 0); 30 | println(); 31 | 32 | // print the integer literal 85 in octal 33 | print("85 in octal: "); 34 | print_octal(85, 0); 35 | println(); 36 | 37 | // print the integer literal 85 in binary 38 | print("85 in binary: "); 39 | print_binary(85, 0); 40 | println(); 41 | } -------------------------------------------------------------------------------- /examples/escape.c: -------------------------------------------------------------------------------- 1 | uint64_t main() { 2 | uint64_t* string; 3 | 4 | // the length of the string needs to be a multiple of 8 5 | string = "\nSelfie supports the escape sequences \\n \\t \\b \\\' \\\" \\\% \\\\ \n\n"; 6 | 7 | while (*string != 0) { 8 | // 1 means that we print to the console 9 | // foo points to a chunk of 8 characters 10 | // 8 means that we print 8 characters 11 | write(1, string, 8); 12 | 13 | // go to the next chunk of 8 characters 14 | string = string + 1; 15 | } 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /examples/function.c: -------------------------------------------------------------------------------- 1 | uint64_t x; 2 | 3 | uint64_t f(uint64_t x) { 4 | while (x > 0) 5 | x = x - 1; 6 | 7 | return x; 8 | } 9 | 10 | uint64_t main() { 11 | x = 0; 12 | 13 | x = x + 1; 14 | 15 | if (x == 1) 16 | x = x + 1; 17 | else 18 | x = x - 1; 19 | 20 | return f(x); 21 | } -------------------------------------------------------------------------------- /examples/gc/boehm-gc-test.c: -------------------------------------------------------------------------------- 1 | // simple test of selfie's boehm gc tool 2 | 3 | // needs to be compiled using selfie's gc library and boehm-gc tool: 4 | // e.g. ./selfie -gc selfie-gc.h tools/boehm-gc.c examples/gc/boehm-gc-test.c -m 1 5 | 6 | int main(int argc, char** argv) { 7 | uint64_t* x; 8 | uint64_t* y; 9 | 10 | init_library(); 11 | 12 | turn_on_gc_library(0, " boehm-gc-test"); 13 | 14 | if (USE_GC_LIBRARY != GC_ENABLED) 15 | exit(1); 16 | 17 | x = gc_malloc(8); 18 | 19 | if((uint64_t) x >= (uint64_t) gc_chunk_heap_bump) 20 | exit(1); 21 | 22 | if((uint64_t) x <= (uint64_t) gc_chunk_heap_start) 23 | exit(1); 24 | 25 | y = gc_malloc(4104); 26 | 27 | if((uint64_t) y >= (uint64_t) gc_heap_seg_end) 28 | exit(1); 29 | 30 | if((uint64_t) y <= (uint64_t) gc_heap_seg_start) 31 | exit(1); 32 | } -------------------------------------------------------------------------------- /examples/hello-world-minified.c: -------------------------------------------------------------------------------- 1 | uint64_t*foo;uint64_t*main(){foo="Hello World! ";while(*foo!=0){write(1,foo,8);foo=foo+1;}} -------------------------------------------------------------------------------- /examples/hello-world.c: -------------------------------------------------------------------------------- 1 | // global variable for pointing to the "Hello World! " string 2 | uint64_t* foo; 3 | 4 | // main procedure for printing "Hello World! " on the console 5 | uint64_t* main() { 6 | // point to the "Hello World! " string 7 | foo = "Hello World! "; 8 | 9 | /* strings are actually stored in chunks of 8 characters in memory, 10 | that is, here as "Hello Wo", and "rld! " which allows us to 11 | print them conveniently in chunks of 8 characters at a time */ 12 | 13 | // as long as there are characters print them 14 | while (*foo != 0) { 15 | // 1 means that we print to the console 16 | // foo points to a chunk of 8 characters 17 | // 8 means that we print 8 characters 18 | write(1, foo, 8); 19 | 20 | // go to the next chunk of 8 characters 21 | foo = foo + 1; 22 | } 23 | } -------------------------------------------------------------------------------- /examples/iteration-high.c: -------------------------------------------------------------------------------- 1 | uint64_t x; // this is a global variable declaration 2 | 3 | uint64_t main() { // this is a global procedure declaration 4 | x = 0; // this is an assignment statement 5 | 6 | x = x + 1; // this is an assignment statement 7 | 8 | if (x == 1) // this is an if statement with 9 | x = x + 1; // an assignment statement in the true case and 10 | else 11 | x = x - 1; // an assignment statement in the false case 12 | 13 | while (x > 0) // this is a while statement with 14 | x = x - 1; // an assignment statement in the true case 15 | 16 | return x; // this is a return statement 17 | } -------------------------------------------------------------------------------- /examples/iteration-low.c: -------------------------------------------------------------------------------- 1 | uint64_t x; // this declares a globally visible variable called x 2 | // that represents an unsigned 64-bit integer value 3 | 4 | uint64_t main() { // this declares a globally visible procedure called main that 5 | // has no inputs and returns an unsigned 64-bit integer value 6 | 7 | // here the value of x is undefined 8 | 9 | x = 0; // this assigns the value 0 to x 10 | 11 | // here the value of x is 0 12 | 13 | x = x + 1; // this reads the value of x, adds 1 to it, and then 14 | // assigns the result to x 15 | 16 | // here the value of x is 1 17 | 18 | if (x == 1) // this checks if the value of x is 1 and, if true, 19 | x = x + 1; // increases the value of x by 1, 20 | else // or else, if false, 21 | x = x - 1; // decreases the value of x by 1 22 | 23 | // here the value of x is 2 24 | 25 | while (x > 0) // this checks if the value of x is greater than 0, and, 26 | x = x - 1; // if true, decreases the value of x by 1, and then repeats 27 | // this until the value of x is not greater than 0 anymore 28 | 29 | // here the value of x is 0 30 | 31 | return x; // this returns the value of x 32 | } -------------------------------------------------------------------------------- /examples/iteration.c: -------------------------------------------------------------------------------- 1 | uint64_t x; 2 | 3 | uint64_t main() { 4 | x = 0; 5 | 6 | x = x + 1; 7 | 8 | if (x == 1) 9 | x = x + 1; 10 | else 11 | x = x - 1; 12 | 13 | while (x > 0) 14 | x = x - 1; 15 | 16 | return x; 17 | } -------------------------------------------------------------------------------- /examples/local.c: -------------------------------------------------------------------------------- 1 | uint64_t f(uint64_t x) { 2 | while (x > 0) 3 | x = x - 1; 4 | 5 | return x; 6 | } 7 | 8 | uint64_t main() { 9 | uint64_t x; 10 | 11 | x = 0; 12 | 13 | x = x + 1; 14 | 15 | if (x == 1) 16 | x = x + 1; 17 | else 18 | x = x - 1; 19 | 20 | return f(x); 21 | } -------------------------------------------------------------------------------- /examples/negative.c: -------------------------------------------------------------------------------- 1 | // printing the negative decimal number -7 in C* 2 | 3 | // libcstar procedures for printing 4 | void init_library(); 5 | void print(uint64_t* s); 6 | void print_integer(uint64_t n); 7 | void print_hexadecimal(uint64_t n, uint64_t a); 8 | void print_octal(uint64_t n, uint64_t a); 9 | void print_binary(uint64_t n, uint64_t a); 10 | void println(); 11 | 12 | uint64_t main() { 13 | // initialize selfie's libcstar library 14 | init_library(); 15 | 16 | // print the integer literal -7 in decimal 17 | print("-7 in decimal: "); 18 | print_integer(-7); 19 | print(" (as signed 64-bit integer)\n"); 20 | 21 | // print the integer literal -7 in decimal 22 | print("-7 in decimal: "); 23 | print_unsigned_integer(-7); 24 | print(" (as unsigned integer)\n"); 25 | 26 | // print the integer literal -7 in hexadecimal 27 | print("-7 in hexadecimal: "); 28 | print_hexadecimal(-7, 0); 29 | println(); 30 | 31 | // print the integer literal -7 in octal 32 | print("-7 in octal: "); 33 | print_octal(-7, 0); 34 | println(); 35 | 36 | // print the integer literal -7 in binary 37 | print("-7 in binary: "); 38 | print_binary(-7, 0); 39 | println(); 40 | } -------------------------------------------------------------------------------- /examples/overhead.c: -------------------------------------------------------------------------------- 1 | // looping for measuring overhead of timer interrupts 2 | // as upper bound on overhead of context switching 3 | uint64_t main() { 4 | uint64_t i; 5 | 6 | i = 0; 7 | 8 | while (i < 1000000000) 9 | i = i + 1; 10 | } -------------------------------------------------------------------------------- /examples/pointer.c: -------------------------------------------------------------------------------- 1 | uint64_t main() { 2 | uint64_t* x; 3 | 4 | x = malloc(2 * sizeof(uint64_t)); 5 | 6 | *x = 0; 7 | 8 | *x = *x + 1; 9 | 10 | *(x + 1) = 0; 11 | 12 | x = x + 1; 13 | 14 | return *x; 15 | } -------------------------------------------------------------------------------- /examples/procedure.c: -------------------------------------------------------------------------------- 1 | uint64_t x; 2 | 3 | void p() { 4 | while (x > 0) 5 | x = x - 1; 6 | } 7 | 8 | uint64_t main() { 9 | x = 0; 10 | 11 | x = x + 1; 12 | 13 | if (x == 1) 14 | x = x + 1; 15 | else 16 | x = x - 1; 17 | 18 | p(); 19 | 20 | return x; 21 | } -------------------------------------------------------------------------------- /examples/recursion.c: -------------------------------------------------------------------------------- 1 | uint64_t f(uint64_t x, uint64_t y) { 2 | while (y > 0) { 3 | x = x + 1; 4 | y = y - 1; 5 | } 6 | 7 | return x; 8 | } 9 | 10 | uint64_t g(uint64_t x, uint64_t y) { 11 | if (y > 0) 12 | return g(x, y - 1) + 1; 13 | else 14 | return x; 15 | } 16 | 17 | uint64_t main() { 18 | return f(1,2) - g(1,2); 19 | } -------------------------------------------------------------------------------- /examples/sat/rivest.cnf: -------------------------------------------------------------------------------- 1 | c Rivest's unsatisfiable four-variable eight-clause formula 2 | c omitting the last clause to make the instance satisfiable 3 | c with -1 -2 3 and either 4 or -4 4 | c 5 | p cnf 4 7 6 | 2 3 -4 0 7 | 1 3 4 0 8 | -1 2 4 0 9 | -1 -2 3 0 10 | -2 -3 4 0 11 | -1 -3 -4 0 12 | 1 -2 -4 0 13 | c1 2 -3 0 -------------------------------------------------------------------------------- /examples/symbolic/README.md: -------------------------------------------------------------------------------- 1 | # C\* Code Examples for Symbolic Execution 2 | 3 | The purpose of the code in this directory is to demonstrate the capabilities of monster, a symbolic execution engine, beator, a RISC-U symbolic model generator, and rotor, a RISC-V symbolic model generator, which are all part of selfie. Monster as well as beator and rotor translate selfie-compiled RISC-U code to an SMT-LIB or BTOR2 formula, respectively, that is satisfiable if there is input to the code such that it exits with a non-zero exit code, or performs division by zero or an invalid/unsafe memory access. See selfie's Makefile for more details on how to execute the examples symbolically. -------------------------------------------------------------------------------- /examples/symbolic/division-by-zero-3-35.c: -------------------------------------------------------------------------------- 1 | uint64_t main() { 2 | uint64_t a; 3 | uint64_t* x; 4 | 5 | x = malloc(sizeof(uint64_t)); 6 | 7 | *x = 0; // touch memory 8 | 9 | read(0, x, 1); 10 | 11 | *x = *x - 48; 12 | 13 | // division by zero if the input is '0' (== 48 == b00110000) 14 | a = 41 + (1 / *x); 15 | 16 | // division by zero if the input is '2' (== 50 == b00110010) 17 | if (*x == 2) 18 | a = 41 + (1 / 0); 19 | 20 | if (a == 42) 21 | // non-zero exit code if the input is '1' (== 49 == b00110001) 22 | return 1; 23 | else 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /examples/symbolic/invalid-memory-access-fail-2-35.c: -------------------------------------------------------------------------------- 1 | uint64_t main() { 2 | uint64_t a; 3 | uint64_t* x; 4 | 5 | x = malloc(sizeof(uint64_t)); 6 | 7 | *x = 0; // touch memory 8 | 9 | read(0, x, 1); 10 | 11 | if (*x == 48) 12 | // on 64-bit systems: address is outside of virtual address space -> invalid memory access 13 | // on 32-bit systems: address is zero -> segmentation fault 14 | // if the input is '0' (== 48 == b00110000) 15 | *(x + 4294967248) = 0; 16 | 17 | a = *x - 7; 18 | 19 | if (a == 42) 20 | // non-zero exit code if the input is '1' (== 49 == b00110001) 21 | return 1; 22 | else 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /examples/symbolic/memory-access-fail-1-35.c: -------------------------------------------------------------------------------- 1 | uint64_t main() { 2 | uint64_t* x; 3 | uint64_t* v; 4 | 5 | x = malloc(sizeof(uint64_t)); 6 | 7 | *x = 0; // touch memory 8 | 9 | // access code segment by reaching over data segment with _bump variable, no --check-block-access required 10 | 11 | v = x + -(4096 / 8) + -1; 12 | 13 | *v = *v; 14 | open(v, 32768, 0); 15 | read(0, v, 1); 16 | write(1, v, 1); 17 | 18 | // access memory right above 4GB, avoiding big integer in data segment, no --check-block-access required 19 | 20 | v = x + ((uint64_t*) (4 * 1024 * 1024 * 1024) - x); 21 | 22 | *v = *v; 23 | open(v, 32768, 0); 24 | read(0, v, 1); 25 | write(1, v, 1); 26 | 27 | // access word-unaligned address, no --check-block-access required 28 | 29 | v = (uint64_t*) ((uint64_t) x + 1); 30 | 31 | *v = *v; 32 | open(v, 32768, 0); 33 | read(0, v, 1); 34 | write(1, v, 1); 35 | 36 | // access memory right above memory block but well below 4GB, requires --check-block-access 37 | 38 | v = x + 1; 39 | 40 | *v = *v; 41 | open(v, 32768, 0); 42 | read(0, v, 1); 43 | write(1, v, 1); 44 | 45 | // unsafe access right above memory block even without pointer arithmetic 46 | read(0, x, 9); 47 | write(1, x, 9); 48 | 49 | // access memory right below memory block but still above code segment, due to _bump variable, requires --check-block-access 50 | 51 | v = x + -1; 52 | 53 | *v = *v; 54 | open(v, 32768, 0); 55 | read(0, v, 1); 56 | write(1, v, 1); 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /examples/symbolic/nested-if-else-1-35.c: -------------------------------------------------------------------------------- 1 | uint64_t main() { 2 | uint64_t a; 3 | uint64_t* x; 4 | 5 | a = 40; 6 | x = malloc(sizeof(uint64_t)); 7 | 8 | *x = 0; // touch memory 9 | 10 | read(0, x, 1); 11 | 12 | if (*x > 48) { 13 | *x = *x - 47; 14 | 15 | if (*x == 2) 16 | a = a + *x; 17 | else 18 | a = a + (*x * 0); 19 | } else 20 | a = a + (*x * 0); 21 | 22 | if (a == 42) 23 | // non-zero exit code if the input is '1' (== 49 == b00110001) 24 | return 1; 25 | else 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /examples/symbolic/nested-if-else-reverse-1-35.c: -------------------------------------------------------------------------------- 1 | uint64_t main() { 2 | uint64_t a; 3 | uint64_t* x; 4 | 5 | a = 40; 6 | x = malloc(sizeof(uint64_t)); 7 | 8 | *x = 0; // touch memory 9 | 10 | read(0, x, 1); 11 | 12 | if (*x <= 48) 13 | a = a + (*x * 0); 14 | else { 15 | *x = *x - 47; 16 | 17 | if (*x != 2) 18 | a = a + (*x * 0); 19 | else 20 | a = a + *x; 21 | } 22 | 23 | if (a == 42) 24 | // non-zero exit code if the input is '1' (== 49 == b00110001) 25 | return 1; 26 | else 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /examples/symbolic/nested-recursion-fail-1-35.c: -------------------------------------------------------------------------------- 1 | uint64_t factorial_upwards(uint64_t n) { 2 | if (n >= 10) 3 | return n; 4 | else 5 | return n * factorial_upwards(n + 1); 6 | } 7 | 8 | uint64_t modified_factorial(uint64_t n) { 9 | if (n > 1) 10 | return n * modified_factorial(n - 1); 11 | else 12 | return factorial_upwards(1); 13 | } 14 | 15 | uint64_t main() { 16 | uint64_t a; 17 | uint64_t* x; 18 | 19 | x = malloc(sizeof(uint64_t)); 20 | 21 | *x = 0; // touch memory 22 | 23 | read(0, x, 1); 24 | 25 | *x = *x - 35; 26 | 27 | // 3628800 == 10! == factorial_upwards(1) 28 | // factorial_upwards(1) * 87178291200 == factorial_upwards(1) * 14! == modified_factorial(14) 29 | a = modified_factorial(*x); 30 | 31 | // 10! * 14! 32 | if (a == 3628800 * (2724321600 * 32)) 33 | // non-zero exit code if the input is '1' (== 49 == b00110001) 34 | return 1; 35 | else 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /examples/symbolic/recursive-ackermann-1-35.c: -------------------------------------------------------------------------------- 1 | uint64_t ackermann(uint64_t m, uint64_t n) { 2 | if (m != 0) { 3 | if (n != 0) 4 | return ackermann(m - 1, ackermann(m, n - 1)); 5 | else 6 | return ackermann(m - 1, 1); 7 | } else 8 | return n + 1; 9 | } 10 | 11 | uint64_t main() { 12 | uint64_t a; 13 | uint64_t* x; 14 | 15 | x = malloc(sizeof(uint64_t)); 16 | 17 | *x = 0; // touch memory 18 | 19 | read(0, x, 1); 20 | 21 | *x = *x - 47; 22 | 23 | // 4 == ackermann(1, 2) 24 | a = ackermann(1, *x); 25 | 26 | if (a == 4) 27 | // non-zero exit code if the input is '1' (== 49 == b00110001) 28 | return 1; 29 | else 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /examples/symbolic/recursive-factorial-fail-1-35.c: -------------------------------------------------------------------------------- 1 | uint64_t factorial(uint64_t n) { 2 | if (n <= 1) 3 | return n; 4 | else 5 | return n * factorial(n - 1); 6 | } 7 | 8 | uint64_t main() { 9 | uint64_t a; 10 | uint64_t* x; 11 | 12 | x = malloc(sizeof(uint64_t)); 13 | 14 | *x = 0; // touch memory 15 | 16 | read(0, x, 1); 17 | 18 | *x = *x - 39; 19 | 20 | // 3628800 == factorial(10) 21 | a = factorial(*x); 22 | 23 | if (a == 3628800) 24 | // non-zero exit code if the input is '1' (== 49 == b00110001) 25 | return 1; 26 | else 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /examples/symbolic/recursive-fibonacci-1-10.c: -------------------------------------------------------------------------------- 1 | uint64_t fibonacci(uint64_t n) { 2 | if (n <= 1) 3 | return n; 4 | else 5 | return fibonacci(n - 1) + fibonacci(n - 2); 6 | } 7 | 8 | uint64_t main() { 9 | uint64_t a; 10 | uint64_t* x; 11 | 12 | x = malloc(sizeof(uint64_t)); 13 | 14 | *x = 0; // touch memory 15 | 16 | read(0, x, 1); 17 | 18 | *x = *x - 46; 19 | 20 | // 2 == fibonacci(3) 21 | a = fibonacci(*x); 22 | 23 | if (a == 2) 24 | // non-zero exit code if the input is '1' (== 49 == b00110001) 25 | return 1; 26 | else 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /examples/symbolic/return-from-loop-1-35.c: -------------------------------------------------------------------------------- 1 | uint64_t main() { 2 | uint64_t a; 3 | uint64_t* x; 4 | 5 | x = malloc(sizeof(uint64_t)); 6 | 7 | *x = 0; // touch memory 8 | 9 | read(0, x, 1); 10 | 11 | a = 0; 12 | 13 | while (a < 10) { 14 | 15 | // non-zero exit code if the input is a digit 16 | if (*x - 48 == a) 17 | return 1; 18 | 19 | a = a + 1; 20 | } 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /examples/symbolic/simple-assignment-1-35.c: -------------------------------------------------------------------------------- 1 | uint64_t main() { 2 | uint64_t* x; 3 | 4 | x = malloc(sizeof(uint64_t)); 5 | 6 | *x = 0; // touch memory 7 | 8 | read(0, x, 1); 9 | 10 | *x = *x - 6; 11 | 12 | if (*x > 42) 13 | // non-zero exit code if the input is > '0' (== 48 == b00110000) 14 | return 1; 15 | else if (*x < 42) 16 | // non-zero exit code if the input is < '0' (== 48 == b00110000) 17 | return 1; 18 | else 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /examples/symbolic/simple-decreasing-loop-1-35.c: -------------------------------------------------------------------------------- 1 | uint64_t main() { 2 | uint64_t a; 3 | uint64_t* x; 4 | 5 | a = 33; 6 | x = malloc(sizeof(uint64_t)); 7 | 8 | *x = 0; // touch memory 9 | 10 | read(0, x, 1); 11 | 12 | *x = *x - 40; 13 | 14 | while (*x > 0) { 15 | a = a + 1; 16 | *x = *x - 1; 17 | } 18 | 19 | if (a == 42) 20 | // non-zero exit code if the input is '1' (== 49 == b00110001) 21 | return 1; 22 | else 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /examples/symbolic/simple-if-else-1-35.c: -------------------------------------------------------------------------------- 1 | uint64_t main() { 2 | uint64_t a; 3 | uint64_t* x; 4 | 5 | a = 40; 6 | x = malloc(sizeof(uint64_t)); 7 | 8 | *x = 0; // touch memory 9 | 10 | read(0, x, 1); 11 | 12 | *x = *x - 47; 13 | 14 | if (*x == 2) 15 | a = a + *x; 16 | else 17 | a = a + (*x * 0); 18 | 19 | if (a == 42) 20 | // non-zero exit code if the input is '1' (== 49 == b00110001) 21 | return 1; 22 | else 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /examples/symbolic/simple-if-else-reverse-1-35.c: -------------------------------------------------------------------------------- 1 | uint64_t main() { 2 | uint64_t a; 3 | uint64_t* x; 4 | 5 | a = 40; 6 | x = malloc(sizeof(uint64_t)); 7 | 8 | *x = 0; // touch memory 9 | 10 | read(0, x, 1); 11 | 12 | *x = *x - 47; 13 | 14 | if (*x != 2) 15 | a = a + (*x * 0); 16 | else 17 | a = a + *x; 18 | 19 | if (a == 42) 20 | // non-zero exit code if the input is '1' (== 49 == b00110001) 21 | return 1; 22 | else 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /examples/symbolic/simple-if-without-else-1-35.c: -------------------------------------------------------------------------------- 1 | uint64_t main() { 2 | uint64_t a; 3 | uint64_t* x; 4 | 5 | a = 40; 6 | x = malloc(sizeof(uint64_t)); 7 | 8 | *x = 0; // touch memory 9 | 10 | read(0, x, 1); 11 | 12 | *x = *x - 47; 13 | 14 | if (*x == 2) 15 | a = a + *x; 16 | 17 | if (a == 42) 18 | // non-zero exit code if the input is '1' (== 49 == b00110001) 19 | return 1; 20 | else 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /examples/symbolic/simple-increasing-loop-1-35.c: -------------------------------------------------------------------------------- 1 | uint64_t main() { 2 | uint64_t a; 3 | uint64_t* x; 4 | 5 | a = 31; 6 | x = malloc(sizeof(uint64_t)); 7 | 8 | *x = 0; // touch memory 9 | 10 | read(0, x, 1); 11 | 12 | while (*x < 60) { 13 | a = a + 1; 14 | *x = *x + 1; 15 | } 16 | 17 | if (a == 42) 18 | // non-zero exit code if the input is '1' (== 49 == b00110001) 19 | return 1; 20 | else 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /examples/symbolic/three-level-nested-loop-fail-1-35.c: -------------------------------------------------------------------------------- 1 | uint64_t main() { 2 | uint64_t a; 3 | uint64_t* x; 4 | 5 | a = 0; 6 | x = malloc(sizeof(uint64_t)); 7 | 8 | *x = 0; // touch memory 9 | 10 | read(0, x, 1); 11 | 12 | *x = *x - 49; 13 | 14 | while (*x < 15) { 15 | while (*x < 10) { 16 | while (*x < 5) { 17 | a = a + 1; 18 | *x = *x + 1; 19 | } 20 | 21 | a = a + 1; 22 | *x = *x + 1; 23 | } 24 | 25 | a = a + 1; 26 | *x = *x + 1; 27 | } 28 | 29 | a = a + 27; 30 | 31 | if (a == 42) 32 | // non-zero exit code if the input is '1' (== 49 == b00110001) 33 | return 1; 34 | else 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /examples/symbolic/two-level-nested-loop-1-35.c: -------------------------------------------------------------------------------- 1 | uint64_t main() { 2 | uint64_t a; 3 | uint64_t* x; 4 | 5 | a = 37; 6 | x = malloc(sizeof(uint64_t)); 7 | 8 | *x = 0; // touch memory 9 | 10 | read(0, x, 1); 11 | 12 | *x = *x - 47; 13 | 14 | while (*x < 7) { 15 | while (*x < 5) { 16 | a = a + 1; 17 | *x = *x + 1; 18 | } 19 | 20 | a = a + 1; 21 | *x = *x + 1; 22 | } 23 | 24 | if (a == 42) 25 | // non-zero exit code if the input is '1' (== 49 == b00110001) 26 | return 1; 27 | else 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /grader/Dockerexamr: -------------------------------------------------------------------------------- 1 | # Dockerfile for examr.py 2 | # Installs pip, numpy, sklearn, torch and textdistance from the distro repository 3 | # plus langid and laserembeddings using pip 4 | 5 | # Build using: `sudo docker build -t examr -f Dockerexamr .` 6 | # Run using: `sudo docker -it --rm -v $PWD:/examr/host examr` 7 | # which mounts the current directory into the container as `/examr/host` 8 | # The shell starts at `/examr`, where `examr.py` is located in 9 | 10 | FROM archlinux:latest 11 | 12 | WORKDIR /examr 13 | 14 | RUN \ 15 | pacman -Syu --noconfirm \ 16 | python-pip \ 17 | python-numpy \ 18 | python-scikit-learn \ 19 | python-pytorch \ 20 | python-textdistance && \ 21 | pip install langid laserembeddings && \ 22 | python -m laserembeddings download-models && \ 23 | pacman -Scc --noconfirm && \ 24 | curl -L https://github.com/cksystemsteaching/selfie/raw/main/grader/examr.py -O && \ 25 | chmod +x examr.py 26 | 27 | CMD [ "/bin/bash" ] 28 | -------------------------------------------------------------------------------- /grader/assignments/array/access-order.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | uint64_t a[2][2]; 3 | uint64_t* p; 4 | 5 | // write consecutive numbers in row major order 6 | a[0][0] = 0; 7 | a[0][1] = 1; 8 | a[1][0] = 2; 9 | a[1][1] = 3; 10 | 11 | p = (uint64_t*) a; 12 | 13 | if (*p == 0) 14 | if (*(p + 1) == 1) 15 | if (*(p + 2) == 2) 16 | if (*(p + 3) == 3) 17 | // is row-major order 18 | return 0; 19 | 20 | // is column-major order 21 | return 1; 22 | } -------------------------------------------------------------------------------- /grader/assignments/array/assignment-variables.c: -------------------------------------------------------------------------------- 1 | uint64_t a[2]; 2 | 3 | int main(int argc, char** argv) { 4 | uint64_t b[2]; 5 | uint64_t i; 6 | 7 | i = 0; 8 | 9 | a[i] = 21; 10 | a[i+1] = 10; 11 | 12 | b[i] = 1; 13 | b[i+1] = 10; 14 | 15 | return a[i] + a[1] + b[0] + b[i+1]; 16 | } 17 | -------------------------------------------------------------------------------- /grader/assignments/array/assignment.c: -------------------------------------------------------------------------------- 1 | uint64_t a[2]; 2 | 3 | int main(int argc, char** argv) { 4 | uint64_t b[2]; 5 | 6 | a[0] = 21; 7 | a[1] = 10; 8 | 9 | b[0] = 1; 10 | b[1] = 10; 11 | 12 | return a[0] + a[1] + b[0] + b[1]; 13 | } -------------------------------------------------------------------------------- /grader/assignments/array/call-by-reference.c: -------------------------------------------------------------------------------- 1 | void change(uint64_t b[2]) { 2 | b[0] = 20; 3 | b[1] = 22; 4 | } 5 | 6 | int main(int argc, char** argv) { 7 | uint64_t a[2]; 8 | 9 | change(a); 10 | 11 | return a[0] + a[1]; 12 | } -------------------------------------------------------------------------------- /grader/assignments/array/global-declaration.c: -------------------------------------------------------------------------------- 1 | uint64_t a[2]; 2 | 3 | int main(int argc, char** argv) { } -------------------------------------------------------------------------------- /grader/assignments/array/invalid-assignment.c: -------------------------------------------------------------------------------- 1 | uint64_t a[2]; 2 | 3 | int main(int argc, char** argv) { 4 | a = 2; 5 | } -------------------------------------------------------------------------------- /grader/assignments/array/local-declaration.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | uint64_t a[2]; 3 | } -------------------------------------------------------------------------------- /grader/assignments/array/multidimensional-variables.c: -------------------------------------------------------------------------------- 1 | uint64_t a[2][3][4]; 2 | 3 | int main(int argc, char** argv) { 4 | uint64_t i; 5 | 6 | i = 2; 7 | 8 | a[0][1][i] = 20; // a[0][1][2] 9 | a[i-1][i][3] = 22; // a[1][2][3] 10 | 11 | // a[0][1][2] + a[1][2][3] 12 | return a[i-2][1][2] + a[1][(a[0][1][i] - 18)][3]; 13 | } 14 | -------------------------------------------------------------------------------- /grader/assignments/array/multidimensional.c: -------------------------------------------------------------------------------- 1 | uint64_t a[2][3][4]; 2 | 3 | int main(int argc, char** argv) { 4 | a[0][1][2] = 20; 5 | a[1][2][3] = 22; 6 | 7 | return a[0][1][2] + a[1][2][3]; 8 | } -------------------------------------------------------------------------------- /grader/assignments/assembler/invalid-argument-add.s: -------------------------------------------------------------------------------- 1 | lui t0,0x10 2 | addi t0,t0,t0 3 | .8byte 0x6F57206F6C6C6548 4 | -------------------------------------------------------------------------------- /grader/assignments/assembler/missing-instruction.s: -------------------------------------------------------------------------------- 1 | t0,0x10 2 | addi t0,t0,504 3 | .8byte 0x6F57206F6C6C6548 4 | -------------------------------------------------------------------------------- /grader/assignments/assembler/missing-literal.s: -------------------------------------------------------------------------------- 1 | lui t0,0x10 2 | addi t0,t0 3 | .8byte 0x6F57206F6C6C6548 4 | -------------------------------------------------------------------------------- /grader/assignments/assembler/valid-hex.s: -------------------------------------------------------------------------------- 1 | lui t0,0x10 2 | addi t0,t0,504 3 | .8byte 0x6F57206F6C6C6548 4 | -------------------------------------------------------------------------------- /grader/assignments/assembler/valid-registers-add.s: -------------------------------------------------------------------------------- 1 | add zero,zero,zero 2 | add t0,t0,zero 3 | add t1,t1,zero 4 | add t2,t2,zero 5 | add t3,t3,zero 6 | add t4,t4,zero 7 | add t5,t5,zero 8 | add t6,t6,zero 9 | add s0,s0,zero 10 | add s1,s1,zero 11 | add s2,s2,zero 12 | add s3,s3,zero 13 | add s4,s4,zero 14 | add s5,s5,zero 15 | add s6,s6,zero 16 | add s7,s7,zero 17 | add s8,s8,zero 18 | add s9,s9,zero 19 | add s10,s10,zero 20 | add s11,s11,zero 21 | add a0,a0,zero 22 | add a1,a1,zero 23 | add a2,a2,zero 24 | add a3,a3,zero 25 | add a4,a4,zero 26 | add a5,a5,zero 27 | add a6,a6,zero 28 | add ra,ra,zero 29 | add sp,sp,zero 30 | add gp,gp,zero 31 | add tp,tp,zero 32 | .8byte 0x6F57206F6C6C6548 33 | -------------------------------------------------------------------------------- /grader/assignments/assembler/valid-registers-addi.s: -------------------------------------------------------------------------------- 1 | addi zero,zero,0 2 | addi t0,t0,0 3 | addi t1,t1,0 4 | addi t2,t2,0 5 | addi t3,t3,0 6 | addi t4,t4,0 7 | addi t5,t5,0 8 | addi t6,t6,0 9 | addi s0,s0,0 10 | addi s1,s1,0 11 | addi s2,s2,0 12 | addi s3,s3,0 13 | addi s4,s4,0 14 | addi s5,s5,0 15 | addi s6,s6,0 16 | addi s7,s7,0 17 | addi s8,s8,0 18 | addi s9,s9,0 19 | addi s10,s10,0 20 | addi s11,s11,0 21 | addi a0,a0,0 22 | addi a1,a1,0 23 | addi a2,a2,0 24 | addi a3,a3,0 25 | addi a4,a4,0 26 | addi a5,a5,0 27 | addi a6,a6,0 28 | addi ra,ra,0 29 | addi sp,sp,0 30 | addi gp,gp,0 31 | addi tp,tp,0 32 | .8byte 0x6F57206F6C6C6548 33 | -------------------------------------------------------------------------------- /grader/assignments/bitwise-logical/and-with-literals.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | return 43 & 58; 3 | } -------------------------------------------------------------------------------- /grader/assignments/bitwise-logical/and-with-variables.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | uint64_t a; 3 | uint64_t b; 4 | 5 | a = 43; 6 | b = 58; 7 | 8 | return a & b; 9 | } -------------------------------------------------------------------------------- /grader/assignments/bitwise-logical/invalid-and.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | return 1 & ; 3 | } -------------------------------------------------------------------------------- /grader/assignments/bitwise-logical/invalid-not.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | return ~; 3 | } -------------------------------------------------------------------------------- /grader/assignments/bitwise-logical/invalid-or.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | return 1 | ; 3 | } -------------------------------------------------------------------------------- /grader/assignments/bitwise-logical/not-with-literals.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | return ~((uint64_t)18446744073709551573); 3 | } -------------------------------------------------------------------------------- /grader/assignments/bitwise-logical/not-with-variables.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | uint64_t a; 3 | 4 | a = ~((uint64_t)18446744073709551573); 5 | 6 | return a; 7 | } -------------------------------------------------------------------------------- /grader/assignments/bitwise-logical/or-with-literals.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | return 40 | 34; 3 | } -------------------------------------------------------------------------------- /grader/assignments/bitwise-logical/or-with-variables.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | uint64_t a; 3 | uint64_t b; 4 | 5 | a = 40; 6 | b = 34; 7 | 8 | return a | b; 9 | } -------------------------------------------------------------------------------- /grader/assignments/bitwise-logical/precedence.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | return 40 & ~((uint64_t)18446744073709551573) | 42; 3 | } -------------------------------------------------------------------------------- /grader/assignments/bitwise-logical/precedence2.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | return 42 - 0 & ~((uint64_t)18446744073709551573) + 1 | 42; 3 | } -------------------------------------------------------------------------------- /grader/assignments/bitwise-logical/precedence3.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | return 42 | 21 & ~(-1); 3 | } 4 | -------------------------------------------------------------------------------- /grader/assignments/bitwise-shift/invalid-left-shift.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | return 1 << ; 3 | } -------------------------------------------------------------------------------- /grader/assignments/bitwise-shift/invalid-right-shift.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | return 4 >> ; 3 | } -------------------------------------------------------------------------------- /grader/assignments/bitwise-shift/left-shift-with-literals.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | return 21 << 1; 3 | } -------------------------------------------------------------------------------- /grader/assignments/bitwise-shift/left-shift-with-variables.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | uint64_t a; 3 | uint64_t b; 4 | 5 | a = 21; 6 | b = 1; 7 | 8 | return a << b; 9 | } -------------------------------------------------------------------------------- /grader/assignments/bitwise-shift/precedence.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | return 42 << 0 + 2 >> 1 * 2; 3 | } -------------------------------------------------------------------------------- /grader/assignments/bitwise-shift/right-shift-with-literals.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | return 84 >> 1; 3 | } -------------------------------------------------------------------------------- /grader/assignments/bitwise-shift/right-shift-with-variables.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | uint64_t a; 3 | uint64_t b; 4 | 5 | a = 84; 6 | b = 1; 7 | 8 | return a >> b; 9 | } -------------------------------------------------------------------------------- /grader/assignments/for-loop/missing-assignment.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | uint64_t i; 3 | uint64_t sum; 4 | 5 | sum = 0; 6 | 7 | for (i = 0; i < 3) 8 | sum = sum + i; 9 | 10 | return sum + 39; 11 | } -------------------------------------------------------------------------------- /grader/assignments/for-loop/multiple-statements.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | uint64_t i; 3 | uint64_t j; 4 | uint64_t sum; 5 | 6 | sum = 0; 7 | j = 0; 8 | 9 | for (i = 0; i < 3; i = i + 1) { 10 | sum = sum + i; 11 | 12 | j = j + 1; 13 | } 14 | 15 | return sum + 39; 16 | } -------------------------------------------------------------------------------- /grader/assignments/for-loop/nested.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | uint64_t i; 3 | uint64_t j; 4 | uint64_t sum; 5 | 6 | sum = 0; 7 | 8 | for (i = 0; i < 3; i = i + 1) 9 | for (j = 0; j < 3; j = j + 1) 10 | sum = sum + 1; 11 | 12 | return sum + 33; 13 | } -------------------------------------------------------------------------------- /grader/assignments/for-loop/single-statement.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | uint64_t i; 3 | uint64_t sum; 4 | 5 | sum = 0; 6 | 7 | for (i = 0; i < 3; i = i + 1) 8 | sum = sum + i; 9 | 10 | return sum + 39; 11 | } -------------------------------------------------------------------------------- /grader/assignments/hex-literal/all-digit-characters.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | // test all characters of a hex integer literal 3 | if (0x123456789ABCDEF0 == 1311768467463790320) 4 | return 42; 5 | else 6 | return 0; 7 | } -------------------------------------------------------------------------------- /grader/assignments/hex-literal/max-value.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | if (0xFFFFFFFFFFFFFFFF == 18446744073709551615) 3 | return 42; 4 | else 5 | return 0; 6 | } -------------------------------------------------------------------------------- /grader/assignments/hex-literal/min-value.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | if (((uint64_t)-0x8000000000000000) == ((uint64_t)-9223372036854775808)) 3 | return 42; 4 | else 5 | return 0; 6 | } -------------------------------------------------------------------------------- /grader/assignments/lock/print-with-lock.c: -------------------------------------------------------------------------------- 1 | // global variable for pointing to the "Hello World! " string 2 | uint64_t* foo; 3 | 4 | // main procedure for printing "Hello World! " on the console 5 | int main(int argc, char** argv) { 6 | // create 2^3 processes 7 | fork(); 8 | fork(); 9 | fork(); 10 | 11 | // point to the "Hello World! " string 12 | foo = "Hello World! "; 13 | 14 | // strings are actually stored in chunks of 8 characters in memory, 15 | // that is, here as "Hello Wo", and "rld! " which allows us to 16 | // print them conveniently in chunks of 8 characters at a time 17 | 18 | lock(); 19 | 20 | // as long as there are characters print them 21 | while (*foo != 0) { 22 | // 1 means that we print to the console 23 | // foo points to a chunk of 8 characters 24 | // 8 means that we print 8 characters 25 | write(1, foo, 8); 26 | 27 | // go to the next chunk of 8 characters 28 | foo = foo + 1; 29 | } 30 | 31 | unlock(); 32 | } -------------------------------------------------------------------------------- /grader/assignments/lock/print-without-lock.c: -------------------------------------------------------------------------------- 1 | // global variable for pointing to the "Hello World! " string 2 | uint64_t* foo; 3 | 4 | // main procedure for printing "Hello World! " on the console 5 | int main(int argc, char** argv) { 6 | // create 2^3 processes 7 | fork(); 8 | fork(); 9 | fork(); 10 | 11 | // point to the "Hello World! " string 12 | foo = "Hello World! "; 13 | 14 | // strings are actually stored in chunks of 8 characters in memory, 15 | // that is, here as "Hello Wo", and "rld! " which allows us to 16 | // print them conveniently in chunks of 8 characters at a time 17 | 18 | // as long as there are characters print them 19 | while (*foo != 0) { 20 | // 1 means that we print to the console 21 | // foo points to a chunk of 8 characters 22 | // 8 means that we print 8 characters 23 | write(1, foo, 8); 24 | 25 | // go to the next chunk of 8 characters 26 | foo = foo + 1; 27 | } 28 | } -------------------------------------------------------------------------------- /grader/assignments/lock/release-after-exit.c: -------------------------------------------------------------------------------- 1 | uint64_t* foo_parent; 2 | uint64_t* foo_child; 3 | 4 | int main() { 5 | uint64_t pid; 6 | uint64_t* status; 7 | 8 | status = malloc(sizeof(uint64_t)); 9 | foo_parent = "Hello parent! "; 10 | foo_child = "Hello child! "; 11 | 12 | pid = fork(); 13 | if (pid == 0) { 14 | lock(); 15 | write(1, foo_child, 16); 16 | // The lock will not be released intentionally before the child process terminates 17 | exit(0); 18 | } else { 19 | pid = wait(status); 20 | 21 | // If the implementation does not free the lock after the child holding it terminated, 22 | // this call will block indefinitely 23 | lock(); 24 | write(1, foo_parent, 16); 25 | unlock(); 26 | exit(0); 27 | } 28 | } -------------------------------------------------------------------------------- /grader/assignments/logical/advanced-logical-expressions.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | uint64_t a; 3 | uint64_t b; 4 | uint64_t c; 5 | uint64_t d; 6 | 7 | a = 0; 8 | b = 0; 9 | c = 0; 10 | d = 1; 11 | 12 | a = b || d; 13 | c = b && d; 14 | 15 | a = !(!(d)); 16 | 17 | if (a || b) 18 | if (b || c) 19 | return 0; 20 | else if (c || d) 21 | if ((a && b) || (a && c) || (a && d)) 22 | return (b || c || d) * a * 42 * !b * !(c && d) * (d); 23 | else 24 | return 0; 25 | else 26 | return 0; 27 | else 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /grader/assignments/logical/lazy-eval-and.c: -------------------------------------------------------------------------------- 1 | uint64_t endless() { 2 | uint64_t x; 3 | 4 | while (1) { 5 | x = 1; 6 | } 7 | 8 | return x; 9 | } 10 | 11 | int main(int argc, char** argv) { 12 | uint64_t a; 13 | uint64_t b; 14 | uint64_t c; 15 | 16 | a = 1; 17 | b = 1; 18 | c = 0; 19 | 20 | if (a && b) 21 | if (a && c && endless()) 22 | return 0; 23 | else 24 | return 42; 25 | else 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /grader/assignments/logical/lazy-eval-or.c: -------------------------------------------------------------------------------- 1 | uint64_t endless() { 2 | uint64_t x; 3 | 4 | while (1) { 5 | x = 1; 6 | } 7 | 8 | return x; 9 | } 10 | 11 | int main(int argc, char** argv) { 12 | uint64_t a; 13 | uint64_t b; 14 | uint64_t c; 15 | 16 | a = 1; 17 | b = 0; 18 | c = 0; 19 | 20 | if (a || b) 21 | if (b || c) 22 | return 0; 23 | else if (a || endless()) 24 | return 42; 25 | else 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /grader/assignments/logical/logical-and.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | uint64_t a; 3 | uint64_t b; 4 | uint64_t c; 5 | 6 | a = 1; 7 | b = 1; 8 | c = 0; 9 | 10 | if ((a && c) != (c && a)) 11 | return 0; 12 | 13 | if (a && b) 14 | if (a && b && c) 15 | return 0; 16 | else 17 | return 42 * (a && b); 18 | else 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /grader/assignments/logical/logical-not.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | uint64_t integer; 3 | 4 | integer = 1; 5 | 6 | integer = !integer; 7 | 8 | if (!integer) 9 | if (!(!integer)) 10 | return 0; 11 | else 12 | return 42 * !integer; 13 | else 14 | return 0; 15 | } -------------------------------------------------------------------------------- /grader/assignments/logical/logical-or.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | uint64_t a; 3 | uint64_t b; 4 | uint64_t c; 5 | 6 | a = 1; 7 | b = 0; 8 | c = 0; 9 | 10 | if ((a || c) != (c || a)) 11 | return 0; 12 | 13 | if (a || b) 14 | if (b || c) 15 | return 0; 16 | else 17 | return 42 * (a || b); 18 | else 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /grader/assignments/logical/precedence.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | uint64_t a; 3 | uint64_t b; 4 | uint64_t c; 5 | uint64_t d; 6 | 7 | a = 1; 8 | b = 0; 9 | c = 0; 10 | 11 | if (a && b || c) 12 | return 0; 13 | else 14 | if (c || a && b) 15 | return 0; 16 | else 17 | return 42; 18 | } 19 | -------------------------------------------------------------------------------- /grader/assignments/logical/precedence2.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | return (1 || 42 && !1) + 41; 3 | } 4 | -------------------------------------------------------------------------------- /grader/assignments/processes/hello-world.c: -------------------------------------------------------------------------------- 1 | // global variable for pointing to the "Hello World! " string 2 | uint64_t* foo; 3 | 4 | // main procedure for printing "Hello World! " on the console 5 | int main(int argc, char** argv) { 6 | // point to the "Hello World! " string 7 | foo = "Hello World! "; 8 | 9 | // strings are actually stored in chunks of 8 characters in memory, 10 | // that is, here as "Hello Wo", and "rld! " which allows us to 11 | // print them conveniently in chunks of 8 characters at a time 12 | 13 | // as long as there are characters print them 14 | while (*foo != 0) { 15 | // 1 means that we print to the console 16 | // foo points to a chunk of 8 characters 17 | // 8 means that we print 8 characters 18 | write(1, foo, 8); 19 | 20 | // go to the next chunk of 8 characters 21 | foo = foo + 1; 22 | } 23 | } -------------------------------------------------------------------------------- /grader/assignments/struct/as-parameter.c: -------------------------------------------------------------------------------- 1 | struct nested_struct { 2 | uint64_t member; 3 | struct nested_struct* another_struct; 4 | }; 5 | 6 | struct nested_struct* my_struct; 7 | 8 | uint64_t modify_member(struct nested_struct* parameter) { 9 | uint64_t previous; 10 | 11 | previous = parameter->another_struct->member; 12 | 13 | parameter->another_struct->member = 321; 14 | 15 | return previous; 16 | } 17 | 18 | int main(int argc, char** argv) { 19 | my_struct = malloc(2 * sizeof(uint64_t)); 20 | 21 | my_struct->another_struct = malloc(2 * sizeof(uint64_t)); 22 | my_struct->another_struct->member = 123; 23 | 24 | if (modify_member(my_struct) == 123) 25 | if (my_struct->another_struct->member == 321) 26 | return 42; 27 | } 28 | -------------------------------------------------------------------------------- /grader/assignments/struct/declaration.c: -------------------------------------------------------------------------------- 1 | struct empty_struct { }; 2 | 3 | int main(int argc, char** argv) { } -------------------------------------------------------------------------------- /grader/assignments/struct/definition.c: -------------------------------------------------------------------------------- 1 | struct empty_struct { }; 2 | 3 | struct empty_struct* global_struct; 4 | 5 | int main(int argc, char** argv) { 6 | struct empty_struct* local_struct; 7 | } -------------------------------------------------------------------------------- /grader/assignments/struct/initialization.c: -------------------------------------------------------------------------------- 1 | struct empty_struct { }; 2 | 3 | struct empty_struct* my_struct; 4 | 5 | int main(int argc, char** argv) { 6 | my_struct = malloc(sizeof(uint64_t)); 7 | } -------------------------------------------------------------------------------- /grader/assignments/struct/member-declaration.c: -------------------------------------------------------------------------------- 1 | struct trivial_struct { 2 | uint64_t member; 3 | uint64_t* pointer; 4 | }; 5 | 6 | int main(int argc, char** argv) { } -------------------------------------------------------------------------------- /grader/assignments/struct/member-initialization.c: -------------------------------------------------------------------------------- 1 | struct trivial_struct { 2 | uint64_t member; 3 | }; 4 | 5 | struct trivial_struct* my_struct; 6 | 7 | int main(int argc, char** argv) { 8 | my_struct = malloc(sizeof(uint64_t)); 9 | 10 | my_struct->member = 42; 11 | 12 | return my_struct->member; 13 | } -------------------------------------------------------------------------------- /grader/assignments/struct/nested-declaration.c: -------------------------------------------------------------------------------- 1 | struct nested_struct { 2 | struct nested_struct* another_struct; 3 | uint64_t member; 4 | }; 5 | 6 | int main(int argc, char** argv) { } -------------------------------------------------------------------------------- /grader/assignments/struct/nested-initialization.c: -------------------------------------------------------------------------------- 1 | struct nested_struct { 2 | struct nested_struct* another_struct; 3 | uint64_t member; 4 | }; 5 | 6 | struct nested_struct* my_struct; 7 | 8 | int main(int argc, char** argv) { 9 | my_struct = malloc(2 * sizeof(uint64_t)); 10 | 11 | my_struct->another_struct = malloc(2 * sizeof(uint64_t)); 12 | my_struct->another_struct->member = 20; 13 | 14 | my_struct->another_struct->another_struct = malloc(2 * sizeof(uint64_t)); 15 | my_struct->another_struct->another_struct->member = 22; 16 | 17 | return my_struct->another_struct->member + my_struct->another_struct->another_struct->member; 18 | } 19 | -------------------------------------------------------------------------------- /grader/assignments/system-calls/invalid-address.c: -------------------------------------------------------------------------------- 1 | uint64_t* VIRTUALMEMORYSIZE = (uint64_t*) 4294967296; // 4GB of virtual memory 2 | uint64_t* ELF_ENTRY_POINT = (uint64_t*) 65536; // = 0x10000 (address of beginning of code) 3 | 4 | 5 | // computes the exit code from the status value 6 | // exit code is in the least significant bits from 8 to 16 7 | uint64_t wexitstatus(uint64_t status) { 8 | return status * 281474976710656 / 72057594037927936; 9 | } 10 | 11 | 12 | int main() { 13 | uint64_t sum; 14 | uint64_t wait_pid; 15 | uint64_t fork_pid; 16 | uint64_t* heap_top; 17 | 18 | heap_top = malloc(sizeof(uint64_t)); 19 | 20 | // touch to force mapping virtual memory 21 | *heap_top = 0; 22 | 23 | sum = 40; 24 | 25 | fork_pid = fork(); 26 | if (fork_pid == 0) 27 | exit(5); 28 | else { 29 | // First invalid access - code segment 30 | wait_pid = wait(ELF_ENTRY_POINT); 31 | sum = sum + wait_pid; 32 | 33 | // Second invalid access - free region between stack and heap 34 | // Bump pointer allocation -> we can derive the end of the heap 35 | // using the most recently allocated memory block, in this case `heap_top` 36 | wait_pid = wait(heap_top + 1); 37 | sum = sum + wait_pid; 38 | 39 | // Third invalid address - outside the 4GiB virtual addressing space 40 | wait_pid = wait(VIRTUALMEMORYSIZE); 41 | sum = sum + wait_pid; 42 | } 43 | 44 | // Actually query the PID/status 45 | // The previous calls should have failed before and mustn't have consumed the zombie 46 | wait_pid = wait(heap_top); 47 | 48 | // 40 (initial) + 5 (exit code) + 3 * (-1) (wait error on invalid vaddr) (+ child PID - child PID) 49 | return sum + fork_pid - wait_pid + wexitstatus(*heap_top); 50 | } -------------------------------------------------------------------------------- /grader/assignments/system-calls/null-ptr.c: -------------------------------------------------------------------------------- 1 | uint64_t* NULL = (uint64_t*) 0; 2 | 3 | int main() { 4 | uint64_t fork_pid; 5 | uint64_t wait_pid; 6 | uint64_t i; 7 | 8 | fork_pid = fork(); 9 | if (fork_pid == 0) 10 | exit(0); 11 | else 12 | wait_pid = wait(NULL); 13 | 14 | if (fork_pid == -1) 15 | return 1; 16 | if (wait_pid == -1) 17 | return 2; 18 | 19 | return 42 + (fork_pid - wait_pid); 20 | } -------------------------------------------------------------------------------- /grader/assignments/system-calls/unmapped-page-wait.c: -------------------------------------------------------------------------------- 1 | // computes the exit code from the status value 2 | // exit code is in the least significant bits from 8 to 16 3 | uint64_t wexitstatus(uint64_t status) { 4 | return status * 281474976710656 / 72057594037927936; 5 | } 6 | 7 | int main() { 8 | uint64_t pid; 9 | uint64_t* exit_code; 10 | 11 | // Enforce an unmapped virtual address by allocating a page-wide array 12 | // and not touching it 13 | // It must be page-wide to move the last element across potential already 14 | // mapped page boundaries 15 | // wait uses the last element, then 16 | exit_code = malloc(sizeof(uint64_t) * 4096); 17 | 18 | pid = fork(); 19 | if (pid == 0) 20 | // Child process - return 21 | exit(84); 22 | else 23 | // Parent process - wait for the child and calculate the exit code; 24 | wait(exit_code + 4095); 25 | 26 | return 21 + wexitstatus(*(exit_code + 4095)) / 4; 27 | } -------------------------------------------------------------------------------- /grader/assignments/threads/shared-data.c: -------------------------------------------------------------------------------- 1 | void* malloc(unsigned long); 2 | 3 | uint64_t pthread_create(); 4 | uint64_t pthread_join(uint64_t* status); 5 | void pthread_exit(uint64_t status); 6 | 7 | uint64_t global_variable = 0; 8 | 9 | int main(int argc, char** argv) { 10 | uint64_t tid; 11 | uint64_t* status; 12 | 13 | status = malloc(sizeof(uint64_t)); 14 | 15 | tid = pthread_create(); 16 | 17 | if (tid) 18 | pthread_join(status); 19 | else { 20 | global_variable = 32; 21 | 22 | pthread_exit(10); 23 | } 24 | 25 | return *status + global_variable; 26 | } -------------------------------------------------------------------------------- /grader/assignments/threads/shared-heap.c: -------------------------------------------------------------------------------- 1 | void* malloc(unsigned long); 2 | 3 | uint64_t pthread_create(); 4 | uint64_t pthread_join(uint64_t* status); 5 | void pthread_exit(uint64_t status); 6 | 7 | uint64_t* heap_variable; 8 | 9 | int main(int argc, char** argv) { 10 | uint64_t tid; 11 | uint64_t* status; 12 | 13 | status = malloc(sizeof(uint64_t)); 14 | 15 | tid = pthread_create(); 16 | 17 | if (tid) 18 | pthread_join(status); 19 | else { 20 | heap_variable = malloc(sizeof(uint64_t)); 21 | *heap_variable = 30; 22 | 23 | pthread_exit(12); 24 | } 25 | 26 | return *status + *heap_variable; 27 | } -------------------------------------------------------------------------------- /grader/assignments/threads/sum-integer-dekker.c: -------------------------------------------------------------------------------- 1 | void* malloc(unsigned long); 2 | 3 | uint64_t pthread_create(); 4 | uint64_t pthread_join(uint64_t* status); 5 | void pthread_exit(uint64_t status); 6 | 7 | uint64_t turn = 0; 8 | uint64_t* wants_to_enter; 9 | uint64_t sum = 0; 10 | 11 | void dekker_enter_critical_section(uint64_t my_turn_id) { 12 | uint64_t other_turn_id; 13 | 14 | if (my_turn_id == 0) 15 | other_turn_id = 1; 16 | else 17 | other_turn_id = 0; 18 | 19 | *(wants_to_enter + my_turn_id) = 1; 20 | while (*(wants_to_enter + other_turn_id) == 1) { 21 | if (turn != my_turn_id) { 22 | *(wants_to_enter + my_turn_id) = 0; 23 | while (turn != my_turn_id) { 24 | // We do not have a direct way to yield 25 | // Instead, perform a zero-sized read() to (hopefully) provoke a switch 26 | read(0, (uint64_t*) 0, 0); 27 | } 28 | *(wants_to_enter + my_turn_id) = 1; 29 | } 30 | } 31 | } 32 | void dekker_leave_critical_section(uint64_t my_turn_id) { 33 | uint64_t other_turn_id; 34 | 35 | if (my_turn_id == 0) 36 | other_turn_id = 1; 37 | else 38 | other_turn_id = 0; 39 | 40 | *(wants_to_enter + my_turn_id) = 0; 41 | turn = other_turn_id; 42 | } 43 | 44 | int main(int argc, char** argv) { 45 | uint64_t tid; 46 | uint64_t* status; 47 | uint64_t i; 48 | 49 | uint64_t my_turn_id; 50 | uint64_t other_turn_id; 51 | 52 | status = malloc(sizeof(uint64_t)); 53 | wants_to_enter = malloc(2 * sizeof(uint64_t)); 54 | 55 | tid = pthread_create(); 56 | 57 | if (tid) 58 | my_turn_id = 0; 59 | else 60 | my_turn_id = 1; 61 | 62 | dekker_enter_critical_section(my_turn_id); 63 | 64 | // The main thread will sum up all odd integers: 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 65 | // The second thread will sum up all even integers: 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 66 | while (i < 10) { 67 | sum = sum + (2*i + my_turn_id + 1); 68 | i = i + 1; 69 | } 70 | 71 | dekker_leave_critical_section(my_turn_id); 72 | 73 | 74 | if (tid) 75 | pthread_join(status); 76 | else 77 | pthread_exit(0); 78 | 79 | return sum; 80 | } -------------------------------------------------------------------------------- /grader/assignments/threads/syscalls.c: -------------------------------------------------------------------------------- 1 | void* malloc(unsigned long); 2 | uint64_t pthread_create(); 3 | uint64_t pthread_join(uint64_t* wstatus); 4 | 5 | uint64_t* status; 6 | 7 | uint64_t sumChilds(uint64_t offset, uint64_t pid, uint64_t acc) { 8 | if (pid) { 9 | // this is the parent process/thread 10 | // => accumulate pid from pthread_create call, pid from pthread_join call and exit status code 11 | acc = acc + pid + pthread_join(status + offset); 12 | acc = acc + *(status + offset); 13 | } 14 | 15 | return acc; 16 | } 17 | 18 | uint64_t get_unique_offset(uint64_t pid1, uint64_t pid2, uint64_t pid3) { 19 | uint64_t bit0; 20 | uint64_t bit1; 21 | uint64_t bit2; 22 | 23 | bit0 = pid3 != 0; 24 | bit1 = pid2 != 0; 25 | bit2 = pid1 != 0; 26 | 27 | return (bit2 * 2 + bit1) * 2 + bit0; 28 | } 29 | 30 | int main(int argc, char** argv) { 31 | uint64_t offset; 32 | uint64_t pid1; 33 | uint64_t pid2; 34 | uint64_t pid3; 35 | uint64_t result; 36 | 37 | status = malloc(8 * sizeof(uint64_t)); 38 | 39 | // 2^3 processes 40 | pid1 = pthread_create(); 41 | pid2 = pthread_create(); 42 | pid3 = pthread_create(); 43 | 44 | offset = get_unique_offset(pid1, pid2, pid3); 45 | 46 | // do not wait for child-threads of the parent-process 47 | if (pid3 == 0) 48 | pid2 = 0; 49 | if (pid2 == 0) 50 | pid1 = 0; 51 | 52 | result = sumChilds(offset, pid3, sumChilds(offset, pid2, sumChilds(offset, pid1, 0))); 53 | 54 | if (pid1 != 0) 55 | if (pid2 != 0) 56 | if (pid3 != 0) 57 | return result; 58 | 59 | pthread_exit(result); 60 | } -------------------------------------------------------------------------------- /grader/assignments/threadsafe-malloc/load-reserved.c: -------------------------------------------------------------------------------- 1 | uint64_t lr(uint64_t address); 2 | 3 | int main(int argc, char** argv) { 4 | return (int) lr(0); 5 | } -------------------------------------------------------------------------------- /grader/assignments/threadsafe-malloc/lr-sc-interleaved.c: -------------------------------------------------------------------------------- 1 | uint64_t lr(uint64_t address); 2 | uint64_t sc(uint64_t address, uint64_t value); 3 | 4 | uint64_t pthread_create(); 5 | uint64_t pthread_join(uint64_t* wstatus); 6 | 7 | // used to force context switches 8 | // there are no process children, so this does nothing 9 | uint64_t wait(uint64_t* wstatus); 10 | 11 | uint64_t child = 0; 12 | 13 | int main(int argc, char** argv) { 14 | uint64_t* address; 15 | uint64_t* status; 16 | uint64_t pid; 17 | uint64_t x; 18 | 19 | address = malloc(sizeof(uint64_t)); 20 | *address = 10; 21 | 22 | status = malloc(sizeof(uint64_t)); 23 | 24 | pid = pthread_create(); 25 | 26 | if (pid == 0) { 27 | // child 28 | child = 1; 29 | 30 | x = lr(address); 31 | 32 | wait((uint64_t*) 0); 33 | 34 | x = sc(address, x); 35 | 36 | return x; // must be 1 (failed) 37 | } else { 38 | // parent 39 | 40 | // make sure child is running first 41 | while (child == 0) 42 | wait((uint64_t*) 0); 43 | 44 | x = lr(address); 45 | 46 | if (x == 10) { 47 | if (sc(address, 42)) 48 | return 7; // parent sc may not fail but it did 49 | } else 50 | return 8; // wrong x value, something went entirely wrong 51 | 52 | // switch to child 53 | x = pthread_join(status); 54 | 55 | if (x == 0) 56 | return 9; // child sc must fail but it did not 57 | else if (*address == 10) 58 | return 6; // child sc stored a new value which it may not do 59 | 60 | // should be 1 * 42 = 42 61 | return *status * *address; 62 | } 63 | } -------------------------------------------------------------------------------- /grader/assignments/threadsafe-malloc/no-switch-malloc.c: -------------------------------------------------------------------------------- 1 | uint64_t write(uint64_t fd, uint64_t* buffer, uint64_t bytes_to_write); 2 | 3 | uint64_t pthread_create(); 4 | uint64_t pthread_join(uint64_t* wstatus); 5 | 6 | uint64_t* foo; 7 | uint64_t child; 8 | 9 | int main(int argc, char** argv) { 10 | uint64_t pid; 11 | 12 | foo = "Hello World! "; 13 | 14 | child = 0; 15 | 16 | pid = pthread_create(); 17 | 18 | if (pid) { 19 | // main thread 20 | 21 | // make sure child is executed first 22 | // variable is shared 23 | while (child == 0) {} 24 | 25 | write(1, foo + 1, 8); 26 | 27 | return 0; 28 | 29 | } else { 30 | // child thread 31 | child = 1; 32 | 33 | // see if we switch back to main (parent) 34 | malloc(sizeof(uint64_t)); 35 | 36 | write(1, foo, 8); 37 | 38 | return 0; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /grader/assignments/threadsafe-malloc/store-conditional.c: -------------------------------------------------------------------------------- 1 | uint64_t sc(uint64_t address, uint64_t value); 2 | 3 | int main(int argc, char** argv) { 4 | return (int) sc(0, 1); 5 | } -------------------------------------------------------------------------------- /grader/assignments/treiber-stack/stack-pop.c: -------------------------------------------------------------------------------- 1 | uint64_t write(uint64_t fd, uint64_t* buffer, uint64_t bytes_to_write); 2 | 3 | uint64_t pthread_create(); 4 | uint64_t pthread_join(uint64_t* wstatus); 5 | 6 | uint64_t lr(uint64_t address); 7 | uint64_t sc(uint64_t address, uint64_t value); 8 | 9 | uint64_t* id; 10 | uint64_t* c; 11 | 12 | uint64_t allocate_id() { 13 | uint64_t value; 14 | 15 | value = lr((uint64_t) id); 16 | 17 | while (sc((uint64_t) id, value + 1)) { 18 | value = lr((uint64_t) id); 19 | } 20 | 21 | return value; 22 | } 23 | 24 | void print_integer(uint64_t i) { 25 | // single character number 26 | *c = 32 * 256 + 48 + i; 27 | write(1, c, 2); 28 | } 29 | 30 | int main(int argc, char** argv) { 31 | uint64_t pid1; 32 | uint64_t pid2; 33 | uint64_t pid3; 34 | uint64_t* s; 35 | uint64_t* results; 36 | uint64_t i; 37 | 38 | id = malloc(sizeof(uint64_t)); 39 | 40 | *id = 0; 41 | 42 | s = malloc(sizeof(uint64_t)); 43 | 44 | c = malloc(sizeof(uint64_t)); 45 | 46 | init_stack(); 47 | 48 | push(allocate_id()); 49 | push(allocate_id()); 50 | push(allocate_id()); 51 | push(allocate_id()); 52 | push(allocate_id()); 53 | push(allocate_id()); 54 | push(allocate_id()); 55 | push(allocate_id()); 56 | 57 | // 2^3 processes 58 | pid1 = pthread_create(); 59 | pid2 = pthread_create(); 60 | pid3 = pthread_create(); 61 | 62 | print_integer(pop()); 63 | 64 | // do not wait for child-threads of the parent-process 65 | if (pid3 == 0) 66 | pid2 = 0; 67 | if (pid2 == 0) 68 | pid1 = 0; 69 | 70 | if (pid1) 71 | pthread_join(s); 72 | if (pid2) 73 | pthread_join(s); 74 | if (pid3) 75 | pthread_join(s); 76 | } -------------------------------------------------------------------------------- /grader/assignments/treiber-stack/stack-push.c: -------------------------------------------------------------------------------- 1 | uint64_t write(uint64_t fd, uint64_t* buffer, uint64_t bytes_to_write); 2 | 3 | uint64_t pthread_create(); 4 | uint64_t pthread_join(uint64_t* wstatus); 5 | 6 | uint64_t lr(uint64_t address); 7 | uint64_t sc(uint64_t address, uint64_t value); 8 | 9 | uint64_t* id; 10 | uint64_t* c; 11 | 12 | uint64_t allocate_id() { 13 | uint64_t value; 14 | 15 | value = lr((uint64_t) id); 16 | 17 | while (sc((uint64_t) id, value + 1)) { 18 | value = lr((uint64_t) id); 19 | } 20 | 21 | return value; 22 | } 23 | 24 | void print_integer(uint64_t i) { 25 | // single character number 26 | *c = 32 * 256 + 48 + i; 27 | write(1, c, 2); 28 | } 29 | 30 | int main(int argc, char** argv) { 31 | uint64_t pid1; 32 | uint64_t pid2; 33 | uint64_t pid3; 34 | uint64_t* s; 35 | uint64_t* results; 36 | uint64_t i; 37 | 38 | id = malloc(sizeof(uint64_t)); 39 | 40 | *id = 0; 41 | 42 | s = malloc(sizeof(uint64_t)); 43 | 44 | c = malloc(sizeof(uint64_t)); 45 | 46 | init_stack(); 47 | 48 | // 2^3 processes 49 | pid1 = pthread_create(); 50 | pid2 = pthread_create(); 51 | pid3 = pthread_create(); 52 | 53 | push(allocate_id()); 54 | 55 | // do not wait for child-threads of the parent-process 56 | if (pid3 == 0) 57 | pid2 = 0; 58 | if (pid2 == 0) 59 | pid1 = 0; 60 | 61 | if (pid1) 62 | pthread_join(s); 63 | if (pid2) 64 | pthread_join(s); 65 | if (pid3) 66 | pthread_join(s); 67 | 68 | if (pid1 != 0) 69 | if (pid2 != 0) 70 | if (pid3 != 0) { 71 | // main thread 72 | print_integer(pop()); 73 | print_integer(pop()); 74 | print_integer(pop()); 75 | print_integer(pop()); 76 | print_integer(pop()); 77 | print_integer(pop()); 78 | print_integer(pop()); 79 | print_integer(pop()); 80 | } 81 | } -------------------------------------------------------------------------------- /grader/lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/grader/lib/__init__.py -------------------------------------------------------------------------------- /grader/lib/functional.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | 3 | def flatmap(f, iterable): 4 | return itertools.chain.from_iterable(map(f, iterable)) 5 | -------------------------------------------------------------------------------- /grader/lib/grade.py: -------------------------------------------------------------------------------- 1 | from typing import List, Tuple 2 | from lib.model import CheckResult 3 | from lib.print import (print_failed, print_grade, print_loud, print_passed, 4 | print_warning, stop_processing_spinner) 5 | 6 | def grade(results: List[CheckResult]) -> Tuple[int, List[str]]: 7 | if len(results) == 0: 8 | return 9 | 10 | mandatory_tests = list(filter(lambda x: x.mandatory, results)) 11 | normal_tests = list(filter(lambda x: not x.mandatory, results)) 12 | 13 | number_of_tests = len(results) - len(mandatory_tests) 14 | number_of_tests_passed = len( 15 | list(filter(lambda x: x.result == x.should_succeed, normal_tests))) 16 | number_of_positive_tests_passed = len( 17 | list(filter(lambda x: x.result and x.should_succeed, normal_tests))) 18 | 19 | failed_mandatory_test = any( 20 | filter(lambda x: x.result != x.should_succeed, mandatory_tests)) 21 | 22 | if number_of_tests_passed == 0 and number_of_tests != 0: 23 | passed = 0.0 24 | elif number_of_tests_passed == 0 and number_of_tests == 0: # No tests or only mandatory tests 25 | passed = 1.0 26 | else: 27 | passed = number_of_tests_passed / float(number_of_tests) 28 | 29 | reasons = [ ] 30 | 31 | if failed_mandatory_test or (number_of_positive_tests_passed == 0 and number_of_tests != 0): 32 | if failed_mandatory_test: 33 | reasons.append('you have failed a mandatory test') 34 | if number_of_positive_tests_passed == 0 and number_of_tests != 0: 35 | reasons.append('you have not passed at least one positive test') 36 | 37 | grade = 5 38 | elif passed == 1.0: 39 | grade = 2 40 | elif passed >= 0.5: 41 | grade = 3 42 | elif passed > 0.0: 43 | grade = 4 44 | else: 45 | grade = 5 46 | 47 | return (grade, reasons) 48 | -------------------------------------------------------------------------------- /grader/lib/model.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | from dataclasses import dataclass, field 3 | from typing import Callable, Optional, List 4 | 5 | @dataclass(frozen=True) 6 | class CheckResult: 7 | result: bool 8 | msg: str 9 | output: str 10 | warning: str 11 | should_succeed: bool = True 12 | command: Optional[str] = None 13 | mandatory: bool = False 14 | 15 | @dataclass(frozen=True) 16 | class Check: 17 | msg: str 18 | command: str 19 | execute: Callable[[], CheckResult] 20 | 21 | @dataclass(frozen=True) 22 | class Assignment: 23 | name: str 24 | lecture: str 25 | category: str 26 | description: str 27 | create_checks: Callable[[], List[Check]] 28 | parent: Assignment = None 29 | children: List = field(default_factory=lambda: []) 30 | 31 | def __hash__(self): 32 | return hash(self.name) 33 | -------------------------------------------------------------------------------- /grader/lib/string.py: -------------------------------------------------------------------------------- 1 | def nfind(text: str, pattern: str, n: int): 2 | """ 3 | Finds the n-th occurrence of a pattern in a string. 4 | This is done by calling str.find n times and passing the 5 | previously found index + 1 as start. 6 | """ 7 | 8 | pos = -1 9 | for i in range(n): 10 | pos = text.find(pattern, pos + 1) 11 | if pos == -1: 12 | return -1 13 | 14 | return pos 15 | 16 | 17 | def nrfind(text: str, pattern: str, n: int): 18 | """ 19 | Finds the n-th occurrence of a pattern in a string in reverse. 20 | This is done by calling str.rfind n times and passing the 21 | previously found index - 1 as end. 22 | """ 23 | 24 | pos = len(text) + 1 25 | for i in range(n): 26 | pos = text.rfind(pattern, 0, pos - 1) 27 | if pos == -1: 28 | return -1 29 | 30 | return pos 31 | -------------------------------------------------------------------------------- /grader/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/grader/tests/__init__.py -------------------------------------------------------------------------------- /grader/tests/assignment_stubs/processes/hello-world.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char* argv) { 2 | write(1, "Hello World! ", 16); 3 | write(1, "Hello World! ", 16); 4 | write(1, "HelloHelloHello ", 16); 5 | write(1, " WorldWorldWorl", 16); 6 | write(1, "!!d! ", 16); 7 | write(1, "Hello World! ", 16); 8 | write(1, "Hello World! ", 16); 9 | write(1, "Hello World! ", 16); 10 | write(1, "Hello World! ", 16); 11 | write(1, "Hello World! ", 16); 12 | } 13 | -------------------------------------------------------------------------------- /grader/tests/elf-header.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/grader/tests/elf-header.m -------------------------------------------------------------------------------- /grader/tests/instructions/bitwise-and.s: -------------------------------------------------------------------------------- 1 | and t0,t1,t2 2 | -------------------------------------------------------------------------------- /grader/tests/instructions/bitwise-left-shift.s: -------------------------------------------------------------------------------- 1 | sll t0,t1,t2 2 | -------------------------------------------------------------------------------- /grader/tests/instructions/bitwise-not.s: -------------------------------------------------------------------------------- 1 | xori t0,t0,-1 2 | -------------------------------------------------------------------------------- /grader/tests/instructions/bitwise-or.s: -------------------------------------------------------------------------------- 1 | or t0,t0,t0 2 | -------------------------------------------------------------------------------- /grader/tests/instructions/bitwise-right-shift.s: -------------------------------------------------------------------------------- 1 | srl t0,t1,t2 2 | -------------------------------------------------------------------------------- /grader/tests/instructions/load-reserved.s: -------------------------------------------------------------------------------- 1 | lr.d t0,(t1) 2 | -------------------------------------------------------------------------------- /grader/tests/instructions/store-conditional.s: -------------------------------------------------------------------------------- 1 | sc.d t0,t1,(t2) 2 | -------------------------------------------------------------------------------- /grader/tests/links.txt: -------------------------------------------------------------------------------- 1 | https://github.com/cksystemsteaching/selfie/commit/b6d5393ba60940d2414af716f89481f0b283316d 2 | https://github.com/ChristianMoesl/selfie/commit/6c4eb46af6fc8be6777f2f865b2dd5478db17b78 3 | -------------------------------------------------------------------------------- /grader/tests/sleep-forever.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | while (1) { } 3 | } -------------------------------------------------------------------------------- /grader/tests/test_bulk_grader.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import sys 3 | import re 4 | import os 5 | import subprocess 6 | # from os import system 7 | from os.path import isfile 8 | import shlex 9 | from subprocess import Popen, PIPE, run 10 | from unittest.mock import patch 11 | 12 | from self import main as grader_main 13 | from lib.print import println 14 | from tests.utils import CaptureOutput, compile_with_gcc_and_run 15 | 16 | 17 | class ExitError(Exception): 18 | def __init__(self, code): 19 | self.message = str(code) 20 | 21 | 22 | class TestBulkGrader(unittest.TestCase): 23 | 24 | def commit_without_auth(self, command, **kwargs): 25 | return run([arg.replace('git@github.com:', 'https://github.com/') for arg in command], **kwargs) 26 | 27 | @patch('lib.cli.run') # imported from subprocess 28 | def test_bulk_grading_with_wrong_arguments(self, mock): 29 | mock.side_effect = self.commit_without_auth 30 | 31 | process = Popen(shlex.split('./self.py -b'), stdout=PIPE, 32 | stderr=PIPE) 33 | process.communicate() 34 | self.assertNotEqual(process.returncode, 0) 35 | 36 | process = Popen(shlex.split('./self.py -d'), stdout=PIPE, 37 | stderr=PIPE) 38 | process.communicate() 39 | self.assertNotEqual(process.returncode, 0) 40 | 41 | def exit_mock(self, code): 42 | if code != 0: 43 | raise ExitError(code) 44 | 45 | @patch('lib.cli.exit') 46 | @patch('lib.cli.run') # imported from subprocess 47 | def test_bulk_grading(self, mock, exit_mock): 48 | mock.side_effect = self.commit_without_auth 49 | 50 | exit_mock.side_effect = self.exit_mock 51 | 52 | with CaptureOutput() as capture: 53 | grader_main([sys.argv[0], '-b', 'tests/links.txt', 'self-compile']) 54 | 55 | output = capture.get_loud_output() 56 | 57 | for line in output.split('\n'): 58 | self.assertTrue(line == '' or re.match( 59 | '[^/]+/[^/:]+: [1-5]', line) != None) 60 | 61 | def test_cloning_without_permissions(self): 62 | with CaptureOutput() as capture: 63 | grader_main([sys.argv[0], '-b', 'tests/links.txt', 'self-compile']) 64 | 65 | output = capture.get_loud_output() 66 | 67 | # should not raise an exception and state errors for both repositories 68 | self.assertIn('cksystemsteaching/selfie: ', output) 69 | self.assertIn('ChristianMoesl/selfie: ', output) 70 | 71 | 72 | if __name__ == '__main__': 73 | unittest.main() 74 | -------------------------------------------------------------------------------- /grader/tests/test_cli.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import unittest 4 | from importlib import reload 5 | from shutil import copyfile 6 | from unittest.mock import patch 7 | from typing import Callable, Optional, List, Set, Tuple, Any 8 | 9 | from tests.utils import (CaptureOutput, assemble_for_selfie, 10 | for_all_test_results, list_files) 11 | 12 | import self as grader 13 | from lib.checks import execute 14 | from lib.model import Assignment, Check, CheckResult 15 | from self import baseline_assignments, main 16 | 17 | 18 | class TestCli(unittest.TestCase): 19 | 20 | def setUp(self): 21 | self.assignments = grader.assignments 22 | self.baseline_assignments = grader.baseline_assignments 23 | 24 | grader.baseline_assignments = [ 25 | # capture index in closure with python default value of lambda 26 | Assignment(a.name, a.lecture, a.category, a.description, lambda i=i: self.check_baseline_assignment_mock(i)) 27 | for i, a in enumerate(grader.baseline_assignments) 28 | ] 29 | 30 | grader.assignments = [ 31 | Assignment(a.name, a.lecture, a.category, a.description, self.check_assignment_mock) 32 | for a in grader.assignments 33 | ] 34 | 35 | self.count = 0 36 | 37 | def tearDown(self): 38 | grader.assignments = self.assignments 39 | grader.baseline_assignments = self.baseline_assignments 40 | 41 | def check_baseline_assignment_mock(self, n_th_baseline) -> List[Check]: 42 | def assert_order(i) -> CheckResult: 43 | self.assertEqual(self.count, i) 44 | self.count = self.count + 1 45 | 46 | return CheckResult(True, '', '', '') 47 | 48 | return [Check('', '', lambda: assert_order(n_th_baseline))] 49 | 50 | def check_assignment_mock(self) -> List[Check]: 51 | def assert_executed_after_baseline() -> CheckResult: 52 | self.assertEqual(self.count, len(self.baseline_assignments)) 53 | 54 | return CheckResult(True, '', '', '') 55 | 56 | return [Check('', '', assert_executed_after_baseline)] 57 | 58 | def test_baseline_execution_order(self): 59 | with CaptureOutput(): 60 | grader.main([sys.argv[0], list(self.assignments)[0].name]) 61 | 62 | 63 | if __name__ == '__main__': 64 | unittest.main() 65 | -------------------------------------------------------------------------------- /grader/tests/test_compilable.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from unittest.mock import patch 3 | import sys 4 | import os 5 | from typing import List 6 | 7 | from self import main, assignments 8 | from lib.checks import check_execution 9 | from lib.output_processing import has_no_compile_warnings 10 | from lib.model import Check, CheckResult 11 | from tests.utils import compile_with_gcc, run_compilable_assignments 12 | 13 | class TestCompilable(unittest.TestCase): 14 | 15 | def is_compilable(self, file): 16 | return not ('invalid' in file or 'missing' in file) 17 | 18 | def compilable_mock(self, file, msg, should_succeed=True) -> List[Check]: 19 | def execute() -> CheckResult: 20 | file_path = 'assignments/' + self.assignment + '/' + file 21 | 22 | is_compilable = self.is_compilable(file) 23 | 24 | self.assertEqual(is_compilable, should_succeed) 25 | 26 | if not is_compilable: 27 | self.assertNotEqual(compile_with_gcc( 28 | file_path), 0, 'compiling ' + file + ' with gcc leads to an error') 29 | else: 30 | self.assertEqual(compile_with_gcc(file_path), 0, 31 | 'compiling ' + file + ' with gcc leads to no error') 32 | return CheckResult(True, "unittest", "", "") 33 | 34 | return [Check("compilable_check_mock", "", execute)] 35 | 36 | def save_assignment(self, assignment): 37 | self.assignment = assignment.category 38 | 39 | @patch('self.check_compilable') 40 | def test_compilability_of_test_files(self, check_compilable_mock): 41 | check_compilable_mock.side_effect = self.compilable_mock 42 | 43 | run_compilable_assignments(self.save_assignment) 44 | 45 | def test_self_compilation_without_warnings(self): 46 | os.system("cd .. && make -s selfie") 47 | 48 | check_execution('../selfie -c ../selfie.c', '', success_criteria=lambda code, 49 | out: has_no_compile_warnings(code, out), should_succeed=True) 50 | 51 | 52 | if __name__ == '__main__': 53 | unittest.main() 54 | -------------------------------------------------------------------------------- /grader/tests/test_execution.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from unittest import TestCase, main 3 | from unittest.mock import patch 4 | from typing import List 5 | 6 | from lib.model import Check, CheckResult 7 | from lib.system import EXITCODE_ERROR_RANGE 8 | from lib.output_processing import filter_status_messages 9 | from tests.utils import (Console, compile_with_gcc_and_run, 10 | run_compilable_assignments) 11 | from self import main as grader_main 12 | 13 | class TestExecution(TestCase): 14 | 15 | def save_directory(self, assignment): 16 | self.assignment = assignment.category 17 | 18 | def execution_mock(self, file, success_criteria, msg) -> List[Check]: 19 | def execution() -> CheckResult: 20 | if 'invalid' not in file: 21 | return_value, out, err = compile_with_gcc_and_run( 22 | 'assignments/' + self.assignment + '/' + file) 23 | 24 | msg = 'compiling ' + file + ' with gcc and running the programming gives the expected result' 25 | 26 | if type(success_criteria) is int: 27 | self.assertNotIn(success_criteria, EXITCODE_ERROR_RANGE, 28 | 'The hypster execution result value can also be an Selfie error code') 29 | 30 | self.assertEqual(success_criteria, return_value, msg) 31 | 32 | elif type(success_criteria) is str: 33 | filtered = filter_status_messages(out) 34 | 35 | self.assertIs(filtered, success_criteria, msg) 36 | 37 | elif callable(success_criteria): 38 | self.assertTrue(success_criteria(return_value, out)[0], msg) 39 | else: 40 | self.assertTrue(False) 41 | 42 | return CheckResult(True, "", "", "") 43 | 44 | return [Check("execution_mock", "", execution)] 45 | 46 | 47 | @patch('self.check_mipster_execution') 48 | def test_mipster_execution_results(self, check_mipster_execution_mock): 49 | check_mipster_execution_mock.side_effect = self.execution_mock 50 | 51 | run_compilable_assignments(self.save_directory) 52 | 53 | 54 | @patch('self.check_hypster_execution') 55 | def test_hypster_execution_results(self, check_hypster_execution_mock): 56 | check_hypster_execution_mock.side_effect = self.execution_mock 57 | 58 | run_compilable_assignments(self.save_directory) 59 | 60 | 61 | if __name__ == '__main__': 62 | main() 63 | -------------------------------------------------------------------------------- /grader/tests/test_execution_timeout.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import sys 3 | import os 4 | from os import system 5 | from time import time 6 | from pathlib import Path 7 | from unittest.mock import patch 8 | 9 | from self import check_self_compilation 10 | from lib.checks import execute, TimeoutException, set_home_path 11 | from tests.utils import CaptureOutput, for_all_test_results 12 | 13 | class TestExecutionTimeout(unittest.TestCase): 14 | 15 | def setUp(self): 16 | os.chdir('..') 17 | 18 | def tearDown(self): 19 | os.chdir('grader') 20 | 21 | @classmethod 22 | def setUpClass(self): 23 | system('cd .. && make selfie >/dev/null 2>&1') 24 | 25 | def test_timeout(self): 26 | start = time() 27 | 28 | self.assertRaises(TimeoutException, execute, 29 | './selfie -c grader/tests/sleep-forever.c -m 10', 3) 30 | 31 | self.assertLess(time() - start, 4) 32 | 33 | def execute_mock(self, command, timeout=10): 34 | return execute(command, timeout=0) 35 | 36 | def check_output(self, result, msg): 37 | self.assertFalse(result) 38 | 39 | @patch('lib.checks.execute') 40 | def test_result_of_timed_out_test(self, mock): 41 | mock.side_effect = self.execute_mock 42 | 43 | set_home_path(Path('..')) 44 | 45 | with CaptureOutput() as capture: 46 | check_self_compilation() 47 | 48 | output = capture.get_output() 49 | 50 | for_all_test_results(output, self.check_output) 51 | 52 | 53 | if __name__ == '__main__': 54 | unittest.main() 55 | -------------------------------------------------------------------------------- /grader/tests/test_grading.py: -------------------------------------------------------------------------------- 1 | from unittest import main, TestCase 2 | from unittest.mock import patch 3 | from importlib import reload 4 | 5 | from tests.utils import Console 6 | from lib.print import enter_quiet_mode 7 | from lib.grade import grade 8 | from lib.model import CheckResult 9 | import self as grader 10 | 11 | 12 | class TestGrading(TestCase): 13 | 14 | def setUp(self): 15 | self.grade = '' 16 | 17 | def save_grade(self, grade): 18 | self.grade = grade 19 | 20 | def test_mandatory_property(self): 21 | (mark, reasons) = grade([ 22 | CheckResult(True, '', '', '') 23 | ]) 24 | 25 | self.assertEqual( 26 | mark, 2, 'if all tests are passed, the grade should be 2') 27 | 28 | (mark, reasons) = grade([ 29 | CheckResult(False, '', '', '', should_succeed=False) 30 | ]) 31 | 32 | self.assertEqual( 33 | mark, 5, 'no positive grade without passing one positive test') 34 | 35 | (mark, reasons) = grade([ 36 | CheckResult(False, '', '', '', should_succeed=False), 37 | CheckResult(True, '', '', '', should_succeed=True) 38 | ]) 39 | 40 | self.assertEqual( 41 | mark, 2, 'postive grade with at least one positive test') 42 | 43 | (mark, reasons) = grade([ 44 | CheckResult(True, '', '', '', should_succeed=True), 45 | CheckResult(True, '', '', '', should_succeed=True), 46 | CheckResult(True, '', '', '', should_succeed=True), 47 | CheckResult(True, '', '', '', should_succeed=True), 48 | CheckResult(False, '', '', '', should_succeed=True, mandatory=True) 49 | ]) 50 | 51 | self.assertEqual( 52 | mark, 5, 'can not pass when failing a mandatory test') 53 | 54 | def print_grade(self, grade): 55 | self.assertEqual(grade, 5, msg='{} has to fail for default Selfie'.format( 56 | self.current_assignment)) 57 | 58 | @patch('lib.cli.print_grade') 59 | def test_default_grade(self, mock): 60 | assignments = map(lambda a: a.name, grader.assignments) 61 | 62 | mock.side_effect = self.print_grade 63 | 64 | for assignment in assignments: 65 | self.current_assignment = assignment 66 | 67 | grader.main(['grader/self.py', '-q', assignment]) 68 | 69 | 70 | if __name__ == '__main__': 71 | main() 72 | -------------------------------------------------------------------------------- /grader/tests/test_processes.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from unittest.mock import patch 3 | import sys 4 | import os 5 | 6 | from self import main, assignments 7 | from lib.checks import insert_assignment_path 8 | from tests.utils import CaptureOutput, compile_with_gcc, run_compilable_assignments 9 | 10 | 11 | class TestProcesses(unittest.TestCase): 12 | 13 | def setUp(self): 14 | os.chdir("..") 15 | 16 | def tearDown(self): 17 | os.chdir("grader") 18 | 19 | def insert_assignment_stub(self, command): 20 | return insert_assignment_path(command) \ 21 | .replace(' -x ', ' -m ') \ 22 | .replace(' -z ', ' -m ') \ 23 | .replace('assignments/', 'grader/tests/assignment_stubs/') 24 | 25 | @patch('lib.checks.insert_assignment_path') 26 | def test_processes(self, mock): 27 | mock.side_effect = self.insert_assignment_stub 28 | 29 | with CaptureOutput() as capture: 30 | main([sys.argv[0], 'processes']) 31 | 32 | self.assertIs('2', capture.get_loud_output()) 33 | 34 | 35 | if __name__ == '__main__': 36 | unittest.main() 37 | -------------------------------------------------------------------------------- /grader/tests/test_riscv_instruction.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import unittest 4 | from importlib import reload 5 | from shutil import copyfile 6 | from unittest.mock import patch 7 | 8 | from tests.utils import (CaptureOutput, assemble_for_selfie, 9 | for_all_test_results, list_files) 10 | 11 | import self as grader 12 | from lib.checks import execute 13 | from self import assignments, main 14 | 15 | 16 | class TestRiscvInstruction(unittest.TestCase): 17 | 18 | @classmethod 19 | def setUpClass(self): 20 | self.instructions = list( 21 | map(lambda f: f[:-2], list_files('tests/instructions', extension='.s'))) 22 | 23 | def execute_mock(self, command, timeout=60): 24 | if '.tmp.bin' in command: 25 | for instruction in self.instructions: 26 | if instruction in command: 27 | assemble_for_selfie('instructions/' + instruction + '.s') 28 | 29 | if '.tmp.s' in command: 30 | for instruction in self.instructions: 31 | if instruction in command: 32 | copyfile('tests/instructions/' + 33 | instruction + '.s', '.tmp.s') 34 | 35 | return (0, '') 36 | 37 | def check_encoding_results(self, result, msg): 38 | if 'RISC-V encoding' in msg: 39 | self.assertTrue( 40 | result, 'following encoding test passed "' + msg + '"') 41 | if 'assembly instruction format' in msg: 42 | self.assertTrue( 43 | result, 'following format test passed "' + msg + '"') 44 | 45 | @patch('lib.checks.execute') 46 | def test_instruction(self, mock): 47 | mock.side_effect = self.execute_mock 48 | 49 | with CaptureOutput() as capture: 50 | for assignment in assignments: 51 | grader.main([sys.argv[0], assignment.name]) 52 | 53 | for_all_test_results(capture.get_output(), self.check_encoding_results) 54 | 55 | 56 | if __name__ == '__main__': 57 | unittest.main() 58 | -------------------------------------------------------------------------------- /grader/tests/test_robustness.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase, main 2 | from os import chdir, getcwd 3 | from shutil import copytree, rmtree 4 | from unittest.mock import patch 5 | 6 | from self import main as grader_main 7 | from lib.checks import execute 8 | from lib.system import EXITCODE_IOERROR 9 | from tests.utils import CaptureOutput 10 | 11 | dst = '/tmp/sel fie' 12 | 13 | 14 | class TestRobustness(TestCase): 15 | 16 | def setUp(self): 17 | rmtree(dst, ignore_errors=True) 18 | 19 | def execute_mock(self, command, timeout=60): 20 | ret_code, output = execute(command, timeout) 21 | 22 | self.assertNotEqual(ret_code, EXITCODE_IOERROR) 23 | 24 | return (ret_code, output) 25 | 26 | def insert_assignment_path(self, command): 27 | return command.replace("", "grader/assignments/hex-literal/") 28 | 29 | @patch('lib.checks.execute') 30 | def test_path_name_with_whitespaces(self, mock): 31 | mock.side_effect = self.execute_mock 32 | 33 | copytree('..', dst) 34 | 35 | cwd = getcwd() 36 | 37 | chdir(dst) 38 | 39 | with CaptureOutput(), patch('lib.checks.insert_assignment_path') as assignment_path_mock: 40 | assignment_path_mock.side_effect = self.insert_assignment_path 41 | 42 | grader_main([getcwd(), 'hex-literal']) 43 | 44 | chdir(cwd) 45 | 46 | rmtree(dst) 47 | 48 | def tearDown(self): 49 | rmtree(dst, ignore_errors=True) 50 | 51 | 52 | if __name__ == '__main__': 53 | main() 54 | -------------------------------------------------------------------------------- /machine/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | 6 | [*.{c,h,S}] 7 | indent_style = space 8 | indent_size = 2 9 | 10 | [{Makefile,*.mk}] 11 | indent_style = tab 12 | -------------------------------------------------------------------------------- /machine/.gitignore: -------------------------------------------------------------------------------- 1 | opensbi.tar.gz 2 | opensbi 3 | 4 | # Build artifacts 5 | *.o 6 | *.d 7 | *.bin 8 | *.elf 9 | files_package.c 10 | tools/asm_struct_macro_generator 11 | build 12 | 13 | # Generated linker scripts (except for template script) 14 | *.ld 15 | !payload_template.ld 16 | 17 | # Allow machine specific .h-files 18 | !*.h 19 | 20 | # Generated assembler struct offset header 21 | include/asm_offsets.h 22 | 23 | # LSP 24 | .clangd 25 | compile_commands.json 26 | -------------------------------------------------------------------------------- /machine/asm/crt.S: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-2-Clause 3 | * 4 | * Copyright (c) 2019 Western Digital Corporation or its affiliates. 5 | * 6 | * Authors: 7 | * Anup Patel 8 | */ 9 | 10 | #include "config.h" 11 | 12 | .text 13 | 14 | .section .entry, "ax", %progbits 15 | .p2align 2 16 | .global _start 17 | _start: 18 | /* Set up the Global Pointer */ 19 | .option push 20 | .option norelax 21 | 22 | la gp, __SDATA_BEGIN__ 23 | 24 | .option pop 25 | 26 | /* Zero-out BSS */ 27 | la a4, _bss_start 28 | la a5, _bss_end 29 | _bss_zero: 30 | sd zero, (a4) 31 | add a4, a4, __SIZEOF_POINTER__ 32 | blt a4, a5, _bss_zero 33 | 34 | _start_warm: 35 | /* Disable and clear all interrupts */ 36 | csrw sie, zero 37 | csrw sip, zero 38 | 39 | /* Setup exception vectors */ 40 | la a3, hang_machine 41 | csrw stvec, a3 42 | 43 | /* Setup stack */ 44 | jal initial_stack_start 45 | mv sp, a0 46 | 47 | /* Jump to C main */ 48 | call bootstrap 49 | 50 | /* We don't expect to reach here hence just hang */ 51 | j hang_machine 52 | 53 | .section .entry, "ax", %progbits 54 | .p2align 2 55 | .global hang_machine 56 | hang_machine: 57 | wfi 58 | j hang_machine 59 | 60 | .global initial_stack_start 61 | initial_stack_start: 62 | la t0, _payload_end 63 | li a0, NUM_STACK_PAGES 64 | slli a0, a0, 12 65 | 66 | add a0, a0, t0 67 | ret 68 | -------------------------------------------------------------------------------- /machine/asm/mem.S: -------------------------------------------------------------------------------- 1 | // a0: address 2 | // a1: size, in bytes 3 | .global zero_mem 4 | zero_mem: 5 | // Check whether we are 8 byte aligned 6 | addi t0, zero, 8 7 | remu t1, a0, t0 8 | beqz t1, after_align_addr 9 | 10 | // Align if we are not 11 | sub t1, t0, t1 12 | align_addr: 13 | beqz t1, after_align_addr 14 | sb zero, 0(a0) 15 | addi a0, a0, 1 16 | addi a1, a1, -1 17 | addi t1, t1, -1 18 | j align_addr 19 | 20 | 21 | after_align_addr: 22 | 23 | // Now that the address is 8 byte aligned, do the actual zeroing 24 | // using decreasing granularity: sd(8) -> sw(4) -> sh(2) -> sb(1) 25 | addi t0, zero, 8 26 | 27 | zero_sd_loop: 28 | beqz a1, zero_done 29 | blt a1, t0, zero_sw 30 | sd zero, 0(a0) 31 | add a0, a0, t0 32 | sub a1, a1, t0 33 | j zero_sd_loop 34 | 35 | zero_sw: 36 | addi t0, zero, 4 37 | zero_sw_loop: 38 | beqz a1, zero_done 39 | blt a1, t0, zero_sh 40 | sw zero, 0(a0) 41 | add a0, a0, t0 42 | sub a1, a1, t0 43 | j zero_sw_loop 44 | 45 | zero_sh: 46 | addi t0, zero, 2 47 | zero_sh_loop: 48 | beqz a1, zero_done 49 | blt a1, t0, zero_sb 50 | sh zero, 0(a0) 51 | add a0, a0, t0 52 | sub a1, a1, t0 53 | j zero_sh_loop 54 | 55 | zero_sb: 56 | addi t0, zero, 1 57 | zero_sb_loop: 58 | blt a1, t0, zero_done 59 | sb zero, 0(a0) 60 | add a0, a0, t0 61 | sub a1, a1, t0 62 | j zero_sb_loop 63 | 64 | zero_done: 65 | ret 66 | 67 | 68 | -------------------------------------------------------------------------------- /machine/bootstrap.c: -------------------------------------------------------------------------------- 1 | #include "bootstrap.h" 2 | #include "config.h" 3 | #include "console.h" 4 | #include "diag.h" 5 | #include "tinycstd.h" 6 | 7 | int main(int argc, char** argv); 8 | 9 | 10 | void bootstrap() { 11 | early_init(); 12 | console_init(); 13 | 14 | kernel_environ_init(); 15 | 16 | char* args[] = { 17 | "./" INIT_FILE_PATH, 18 | "-c", 19 | "selfie.c", 20 | "-m", 21 | "2", 22 | "-l", 23 | "selfie.m", 24 | "-y", 25 | "1", 26 | "-c", 27 | "hello-world.c", 28 | (char*) 0, 29 | }; 30 | int argc = 0; 31 | 32 | puts("Booting " INIT_FILE_PATH " with args: \n"); 33 | 34 | while (args[argc] != (char*) 0) { 35 | printf(" %s\n", args[argc]); 36 | argc++; 37 | } 38 | printf(" \n\n"); 39 | 40 | uint64_t result = start_init_process(argc, args); 41 | 42 | printf("\nInit process terminated with exit code %d\n", result); 43 | shutdown(); 44 | } 45 | -------------------------------------------------------------------------------- /machine/bootstrap.h: -------------------------------------------------------------------------------- 1 | #ifndef KERN_BOOTSTRAP 2 | #define KERN_BOOTSTRAP 3 | 4 | #include 5 | 6 | void early_init(); 7 | void kernel_environ_init(); 8 | int start_init_process(uint64_t argc, const char** argv); 9 | 10 | #endif /* KERN_BOOTSTRAP */ 11 | -------------------------------------------------------------------------------- /machine/bootstrap_library.c: -------------------------------------------------------------------------------- 1 | #include "bootstrap.h" 2 | #include 3 | 4 | void early_init() {} 5 | 6 | extern uint64_t heap_head; 7 | extern void* initial_stack_start(); 8 | void kernel_environ_init() { 9 | heap_head = (uint64_t) initial_stack_start(); 10 | } 11 | 12 | extern int main(uint64_t argc, const char** argv); 13 | int start_init_process (uint64_t argc, const char** argv) { 14 | return main(argc, argv); 15 | } 16 | -------------------------------------------------------------------------------- /machine/console.c: -------------------------------------------------------------------------------- 1 | #include "console.h" 2 | #include "sbi_ecall.h" 3 | #include 4 | 5 | int console_init() { 6 | return 0; 7 | } 8 | 9 | void console_putc(int chr) { 10 | sbi_ecall_sbi_putchar(chr); 11 | } 12 | 13 | intmax_t console_puts(const char* str, size_t len) { 14 | size_t i = 0; 15 | 16 | while (i < len) { 17 | console_putc(*str); 18 | str = str + 1; 19 | i++; 20 | } 21 | 22 | return i; 23 | } 24 | -------------------------------------------------------------------------------- /machine/diag.c: -------------------------------------------------------------------------------- 1 | #include "diag.h" 2 | #include "sbi_ecall.h" 3 | #include "tinycstd.h" 4 | 5 | void panic(const char* diagnostic_message, ...) { 6 | va_list args; 7 | va_start(args, diagnostic_message); 8 | 9 | printf("!!!!!!!!!!!!!!!!!!!!\n"); 10 | printf("!!! KERNEL PANIC !!!\n"); 11 | printf("!!!!!!!!!!!!!!!!!!!!\n\n"); 12 | printf("diagnostic message: "); 13 | 14 | va_printf(diagnostic_message, args); 15 | printf("\n\n"); 16 | printf("shutting down...\n"); 17 | 18 | va_end(args); 19 | shutdown(); 20 | } 21 | 22 | void shutdown() { 23 | sbi_ecall_sbi_shutdown(); 24 | 25 | printf("shutdown failed - hanging machine...\n"); 26 | hang_machine(); 27 | } 28 | -------------------------------------------------------------------------------- /machine/filesystem.c: -------------------------------------------------------------------------------- 1 | #include "filesystem.h" 2 | #include "tinycstd.h" 3 | 4 | const KFILE* find_file(const char* filename) { 5 | const KFILE* file = files; 6 | 7 | while (file->data != NULL) { 8 | if (strncmp(filename, file->name, 511) == 0) 9 | break; 10 | 11 | file++; 12 | } 13 | 14 | if (file->data != NULL) 15 | return file; 16 | else 17 | return NULL; 18 | } 19 | 20 | bool fd_is_stdio(int fd) { 21 | return (fd >= 0) && (fd <= 2); 22 | } 23 | 24 | bool fd_is_valid(int fd, size_t num_fds) { 25 | return (fd >= 0) && (((uint32_t) fd) < num_fds + OPEN_FILE_FD_OFFSET); 26 | } 27 | 28 | FILEDESC* get_fd_entry(int fd, FILEDESC* open_files, size_t num_fds) { 29 | if (!fd_is_valid(fd, num_fds)) 30 | return NULL; 31 | 32 | // There's no FILEDESC for stdin/stdout/stderr 33 | if (fd_is_stdio(fd)) 34 | return NULL; 35 | 36 | return open_files + (fd - OPEN_FILE_FD_OFFSET); 37 | } 38 | 39 | bool fd_entry_is_opened(FILEDESC* entry) { 40 | return (entry != NULL) && (entry->file != NULL); 41 | } 42 | 43 | bool fd_is_opened(int fd, FILEDESC* open_files, size_t num_fds) { 44 | FILEDESC* entry = get_fd_entry(fd, open_files, num_fds); 45 | // If an entry is NULL, fd is either invalid or an stdio special fd 46 | if (entry == NULL) 47 | return fd_is_stdio(fd); 48 | 49 | return fd_entry_is_opened(entry); 50 | } 51 | -------------------------------------------------------------------------------- /machine/filesystem.mk: -------------------------------------------------------------------------------- 1 | files_package.c: $(SBI_WRAPPER_FILES_PACKAGE) 2 | @printf "#include \"filesystem.h\"\n\n" >$@ 3 | 4 | @# Package all files as a byte array using xxd 5 | @for file in $^ ;\ 6 | do \ 7 | BASENAME=`basename $$file` ;\ 8 | VARIABLENAME=`echo $$BASENAME | sed 's/\W/_/g'`; \ 9 | echo "static const char $${VARIABLENAME}[] = {" >> $@; \ 10 | cat "$$file" | xxd -i >>$@; \ 11 | echo "};" >>$@; \ 12 | printf "\n\n" >>$@; \ 13 | done; 14 | 15 | @# Create a mapping to all packaged files 16 | @echo "const KFILE files[] = {" >>$@; 17 | @for file in $^;\ 18 | do \ 19 | BASENAME=`basename $$file` ;\ 20 | VARIABLENAME=`echo $$BASENAME | sed 's/\W/_/g'`; \ 21 | FILESIZE=`wc -c "$$file" | awk '{print $$1}'`; \ 22 | echo " {\"$$BASENAME\", $$VARIABLENAME, $$FILESIZE}," >>$@; \ 23 | done; 24 | @echo " {\"\", (const char*) NULL, 0}," >>$@; 25 | @echo "};" >>$@; 26 | 27 | .PHONY: clean-fs-package 28 | clean-fs-package: 29 | rm -f files_package.c 30 | -------------------------------------------------------------------------------- /machine/gdbinit_qemu: -------------------------------------------------------------------------------- 1 | echo "Connecting to QEMU on localhost:9000..." 2 | target remote :9000 3 | 4 | echo "Loading symbol files..." 5 | file selfie-qemu.elf 6 | add-symbol-file payload-qemu.elf 7 | 8 | echo "Enable TUI..." 9 | tui enable 10 | 11 | echo "Resetting emulation..." 12 | monitor system_reset 13 | 14 | echo "Setting output radix to hex..." 15 | set output-radix 16 16 | -------------------------------------------------------------------------------- /machine/glue_libraryos.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include "diag.h" 3 | #include "filesystem.h" 4 | #include "sbi_ecall.h" 5 | #include "syscalls.h" 6 | #include 7 | 8 | #include "compiler-utils.h" 9 | 10 | static FILEDESC open_files[NUM_FDS]; 11 | void* heap_head; 12 | 13 | ssize_t read(int fd, char* buf, size_t count) { 14 | return kread(fd, buf, count, open_files, NUM_FDS); 15 | } 16 | 17 | intmax_t write(int fd, const char* buf, size_t count) { 18 | return kwrite(fd, buf, count, open_files, NUM_FDS); 19 | } 20 | 21 | uint64_t open(char* filename, uint64_t flags, uint64_t mode) { 22 | UNUSED_VAR(mode); 23 | return kopen(filename, flags, open_files, NUM_FDS); 24 | } 25 | 26 | 27 | extern void zero_mem(uint64_t* addr, uint64_t size); 28 | void* malloc(unsigned long size) { 29 | void* return_ptr; 30 | 31 | return_ptr = heap_head; 32 | heap_head += size; 33 | 34 | #ifdef DEBUG 35 | printf("-- malloc: allocated 0x%x bytes at addr %p-%p\n", size, return_ptr, heap_head); 36 | #endif /* DEBUG */ 37 | 38 | zero_mem(return_ptr, size); 39 | 40 | return return_ptr; 41 | } 42 | 43 | void exit(int status) { 44 | printf(">EXIT called with exit code %x<\n", status); 45 | shutdown(); 46 | } 47 | -------------------------------------------------------------------------------- /machine/include/asm_context_switch_offsets.h: -------------------------------------------------------------------------------- 1 | #ifndef ASM_CONTEXT_SWITCH_OFFSETS 2 | #define ASM_CONTEXT_SWITCH_OFFSETS 3 | 4 | #define CONTEXT_SWITCH_STACK_SPACE_ALLOCATION (4 * 8) 5 | 6 | #define CONTEXT_SWITCH_STACK_TEMP_REGISTER_BUFFER_OFFSET 0 7 | #define CONTEXT_SWITCH_STACK_KERNEL_SATP_OFFSET 8 8 | #define CONTEXT_SWITCH_STACK_KERNEL_GP_OFFSET 16 9 | #define CONTEXT_SWITCH_STACK_TRAP_HANDLER_ADDRESS_OFFSET 24 10 | 11 | #endif /* ASM_CONTEXT_SWITCH_OFFSETS */ 12 | -------------------------------------------------------------------------------- /machine/include/compiler-utils.h: -------------------------------------------------------------------------------- 1 | #ifndef KERN_COMPILER_UTILS 2 | #define KERN_COMPILER_UTILS 3 | 4 | #define UNUSED_VAR(x) (void) (x) 5 | 6 | #define STRINGIFICATE(x) STRINGIFICATE_HELPER(x) 7 | #define STRINGIFICATE_HELPER(x) #x 8 | 9 | #endif /* KERN_COMPILER_UTILS */ 10 | -------------------------------------------------------------------------------- /machine/include/console.h: -------------------------------------------------------------------------------- 1 | #ifndef KERN_CONSOLE 2 | #define KERN_CONSOLE 3 | 4 | #include 5 | #include 6 | 7 | int console_init(); 8 | void console_putc(int chr); 9 | intmax_t console_puts(const char* str, size_t size); 10 | 11 | #endif /* KERN_CONSOLE */ 12 | -------------------------------------------------------------------------------- /machine/include/diag.h: -------------------------------------------------------------------------------- 1 | #ifndef KERN_DIAG 2 | #define KERN_DIAG 3 | 4 | #include 5 | 6 | void panic(const char* diagnostic_message, ...) __attribute__((noreturn)); 7 | void shutdown() __attribute__((noreturn)); 8 | 9 | extern void hang_machine() __attribute__((noreturn)); 10 | 11 | #ifdef DEBUG 12 | #define assert(x) if (!(x)) panic("Assertion failed: " __FILE__ ":%u: " #x, __LINE__) 13 | #else 14 | #define assert(x) (void) 0 15 | #endif 16 | 17 | #endif /* KERN_DIAG */ 18 | -------------------------------------------------------------------------------- /machine/include/elf.h: -------------------------------------------------------------------------------- 1 | #ifndef KERN_ELF 2 | #define KERN_ELF 3 | 4 | #include "context.h" 5 | 6 | #define ELF_MAGIC "\177ELF" 7 | 8 | #define ELF_CLASS_32 0x01 9 | #define ELF_CLASS_64 0x02 10 | 11 | #define ELF_ENDIANESS_LITTLE 0x01 12 | #define ELF_ENDIANESS_BIG 0x02 13 | 14 | #define ELF_TYPE_NONE 0x00 // No file type 15 | #define ELF_TYPE_REL 0x01 // Relocatable 16 | #define ELF_TYPE_EXEC 0x02 // Executable 17 | #define ELF_TYPE_DYN 0x03 // Shared objects 18 | #define ELF_TYPE_CORE 0x03 // Core dump 19 | 20 | #define ELF_MACHINE_RISCV 243 21 | 22 | #define ELF_VERSION_1 0x01 23 | 24 | #define ELF_PH_TYPE_NULL 0x00 // Unused 25 | #define ELF_PH_TYPE_LOAD 0x01 // Loadable segment 26 | 27 | #define ELF_PH_FLAG_EXECUTABLE 1 28 | #define ELF_PH_FLAG_WRITABLE 2 29 | #define ELF_PH_FLAG_READABLE 4 30 | 31 | #define ENOELF 1 // No valid ELF file 32 | #define EOOB 2 // Out of Bounds 33 | #define EINVMACHINE 3 // Executable is not RISC-V 34 | #define EINVCLASS 4 // Executable is not 64 bits 35 | #define EINVTYPE 5 // ELF file is not an executable 36 | #define EUNSUPPORTED 6 // ELF file contains unsupported features 37 | #define EOOM 7 // File couldn't be mapped entirely 38 | #define EINVVADDR 8 // Virtual address is invalid or in upper half 39 | 40 | int load_elf(struct context* context, const char* elf, uint64_t len); 41 | 42 | const char* elf_strerror(int errno); 43 | 44 | #endif /* KERN_ELF */ 45 | -------------------------------------------------------------------------------- /machine/include/filesystem.h: -------------------------------------------------------------------------------- 1 | #ifndef SBI_FILES_BASE 2 | #define SBI_FILES_BASE 3 | 4 | #include "config.h" 5 | 6 | #include 7 | #include 8 | 9 | typedef struct KFILE { 10 | const char name[PATH_MAX_LEN]; 11 | const char* data; 12 | size_t length; 13 | } KFILE; 14 | 15 | typedef struct FILEDESC { 16 | const KFILE* file; 17 | size_t pos; 18 | } FILEDESC; 19 | 20 | extern const KFILE files[]; 21 | 22 | const KFILE* find_file(const char* filename); 23 | 24 | // File descriptor util functions 25 | bool fd_is_stdio(int fd); 26 | bool fd_is_valid(int fd, size_t num_fds); 27 | FILEDESC* get_fd_entry(int fd, FILEDESC* open_files, size_t num_fds); 28 | bool fd_entry_is_opened(FILEDESC* entry); 29 | bool fd_is_opened(int fd, FILEDESC* open_files, size_t num_fds); 30 | 31 | #define OPEN_FILE_FD_OFFSET 3 32 | 33 | #endif /* SBI_FILES_BASE */ 34 | -------------------------------------------------------------------------------- /machine/include/linker-syms.h: -------------------------------------------------------------------------------- 1 | #ifndef KERN_LINKER_SYMS 2 | #define KERN_LINKER_SYMS 3 | 4 | extern const void* _payload_start; 5 | extern const void* _payload_end; 6 | 7 | extern const void* _text_start; 8 | extern const void* _text_end; 9 | 10 | extern const void* _rodata_start; 11 | extern const void* _rodata_end; 12 | 13 | extern const void* _data_start; 14 | extern const void* _data_end; 15 | 16 | extern const void* _bss_start; 17 | extern const void* _bss_end; 18 | 19 | extern const void* __SDATA_BEGIN__; 20 | 21 | 22 | #endif /* KERN_LINKER_SYMS */ 23 | -------------------------------------------------------------------------------- /machine/include/numeric-utils.h: -------------------------------------------------------------------------------- 1 | #ifndef KERN_NUMERIC_UTILS 2 | #define KERN_NUMERIC_UTILS 3 | 4 | // IS_ALIGNED works by setting up a bitmask 5 | // (e.g. three bits padding -> 2^3 - 1 = 8 - 1 = 7 = 0b111) 6 | // If (value AND bitmask) is zero, the value is aligned 7 | #define IS_ALIGNED(value, pad) ((value & ((1 << pad) - 1)) == 0) 8 | 9 | #define MIN(first, second) ((first) < (second) ? (first) : (second)) 10 | #define MAX(first, second) ((first) > (second) ? (first) : (second)) 11 | 12 | #define ROUND_UP(num, to) (((num) % (to)) > 0 ? (num) + ((to) - ((num) % (to))) : (num)) 13 | 14 | #endif /* KERN_NUMERIC_UTILS */ 15 | -------------------------------------------------------------------------------- /machine/include/sbi_ecall.h: -------------------------------------------------------------------------------- 1 | #ifndef KERN_SBI_ECALL 2 | #define KERN_SBI_ECALL 3 | 4 | #include 5 | #include 6 | 7 | // ==================== LEGACY EXTENSION ==================== 8 | 9 | void sbi_ecall_sbi_putchar(int chr); 10 | 11 | bool sbi_ecall_sbi_set_timer(uint64_t interrupt_at); 12 | 13 | // ==================== TIMER EXTENSION ==================== 14 | 15 | void sbi_ecall_sbi_shutdown(); 16 | 17 | #endif /* KERN_SBI_ECALL */ 18 | -------------------------------------------------------------------------------- /machine/include/sbi_ecall_ids.h: -------------------------------------------------------------------------------- 1 | #ifndef KERN_SBI_ECALL_IDS 2 | #define KERN_SBI_ECALL_IDS 3 | 4 | #define SBI_EXTENSION_ID_LEGACY_EXTENSION_SBI_CONSOLE_PUTCHAR 0x01 5 | #define SBI_EXTENSION_ID_LEGACY_EXTENSION_SBI_SHUTDOWN 0x08 6 | #define SBI_EXTENSION_ID_TIMER_EXTENSION 0x54494D45 7 | 8 | #define SBI_FUNCTION_ID_LEGACY_EXTENSION_SBI_CONSOLE_PUTCHAR 0 9 | #define SBI_FUNCTION_ID_LEGACY_EXTENSION_SBI_SHUTDOWN 0 10 | #define SBI_FUNCTION_ID_TIMER_EXTENSION_SBI_SET_TIMER 0 11 | 12 | #endif /* KERN_SBI_ECALL_IDS */ 13 | -------------------------------------------------------------------------------- /machine/include/syscalls.h: -------------------------------------------------------------------------------- 1 | #ifndef KERN_SYSCALL 2 | #define KERN_SYSCALL 3 | 4 | #include "filesystem.h" 5 | #include "tinycstd.h" 6 | 7 | ssize_t kread(int fd, char* buf, size_t count, FILEDESC* open_files, size_t num_fds); 8 | ssize_t kwrite(int fd, const char* buf, size_t count, FILEDESC* open_files, size_t num_fds); 9 | int kopen(const char* filename, int flags, FILEDESC* open_files, size_t num_fds); 10 | 11 | #endif /* KERN_SYSCALL */ 12 | -------------------------------------------------------------------------------- /machine/include/tinycstd.h: -------------------------------------------------------------------------------- 1 | #ifndef KERN_TINYCSTD 2 | #define KERN_TINYCSTD 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | typedef int64_t ssize_t; 10 | 11 | void* memmove(void* dest, const void* source, size_t num); 12 | void* memcpy (void* destination, const void* source, size_t num); 13 | int memcmp(const void* ptr1, const void* ptr2, size_t num); 14 | void* memset(void* ptr, int value, size_t num); 15 | 16 | // String functions 17 | uint64_t strlen(const char* str); 18 | ssize_t strncmp(const char* first, const char* second, size_t n); 19 | const char* strchr(const char* str, int c); 20 | size_t strlcpy(char* dest, const char* src, size_t n); 21 | 22 | // I/O functions 23 | int printf(const char* format, ...); 24 | int sprintf(char* str, const char* format, ...); 25 | void puts(const char* s); 26 | void putc(char c); 27 | 28 | // POSIX.1-2008 29 | int dprintf(int fd, const char* format, ...); 30 | 31 | int va_printf(const char* format, va_list args); 32 | 33 | #endif /* KERN_TINYCSTD */ 34 | -------------------------------------------------------------------------------- /machine/include/trap.h: -------------------------------------------------------------------------------- 1 | #ifndef KERN_TRAP 2 | #define KERN_TRAP 3 | 4 | #include "config.h" 5 | 6 | #include 7 | #include "context.h" 8 | #include "tinycstd.h" 9 | 10 | // 3.1.7 mstatus - Machine status register 11 | // MIE, SIE and UIE enable interrupts for M-Mode, S-Mode and U-Mode, respectively 12 | #define CSR_STATUS_SIE 1 13 | #define CSR_STATUS_SPIE 5 14 | 15 | #define CSR_SIE_TIMER_INTS 5 16 | 17 | typedef void (*trap_handler_t)(); 18 | 19 | void disable_smode_interrupts(); 20 | void enable_smode_interrupts(); 21 | 22 | void enable_smode_interrupt_types(uint64_t bitmask); 23 | void disable_smode_interrupt_types(uint64_t bitmask); 24 | 25 | extern void trap_handler_wrapper(); 26 | void store_saved_registers_from_buffer_into_context(struct context* context, struct registers* registers_buffer); 27 | void load_saved_registers_from_context_into_buffer(struct context* context, struct registers* registers_buffer); 28 | uint64_t get_current_cpu_time(); 29 | bool set_timer_interrupt_delta(uint64_t delta); 30 | bool set_timer_interrupt(uint64_t interrupt_at); 31 | uint64_t trap_handler(struct registers registers_buffer); 32 | 33 | void print_unhandled_trap(struct context* context, bool interrupt_bit, uint64_t exception_code, uint64_t stval, uint64_t sepc); 34 | 35 | void handle_ecall(struct context* context); 36 | void implement_syscall_exit(struct context* context); 37 | void implement_syscalls_read_and_write(struct context* context, ssize_t (*kernel_func)(int, char*, size_t, FILEDESC*, size_t)); 38 | void implement_syscall_read(struct context* context); 39 | void implement_syscall_write(struct context* context); 40 | void implement_syscall_openat(struct context* context); 41 | void implement_syscall_brk(struct context* context); 42 | 43 | enum memory_access_type { 44 | memory_access_type_unknown, 45 | memory_access_type_lo, 46 | memory_access_type_mid, 47 | memory_access_type_hi 48 | }; 49 | enum memory_access_type determine_memory_access_type(struct memory_boundaries* legal_memory_boundaries, uint64_t vaddr); 50 | 51 | void signal_oom(struct context* context); 52 | void handle_load_or_store_amo_page_fault(struct context* context, uint64_t stval); 53 | void handle_instruction_page_fault(struct context* context, uint64_t sepc, uint64_t stval); 54 | void handle_load_page_fault(struct context* context, uint64_t stval); 55 | void handle_store_amo_page_fault(struct context* context, uint64_t stval); 56 | 57 | void setup_smode_trap_handler(trap_handler_t handler); 58 | 59 | #endif /* KERN_TRAP */ 60 | -------------------------------------------------------------------------------- /machine/payload_template.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: BSD-2-Clause 3 | * 4 | * Copyright (c) 2019 Western Digital Corporation or its affiliates. 5 | * 6 | * Authors: 7 | * Anup Patel 8 | */ 9 | 10 | OUTPUT_ARCH(riscv) 11 | ENTRY(_start) 12 | 13 | SECTIONS 14 | { 15 | . = $SBI_START + $PAYLOAD_OFFSET; 16 | 17 | PROVIDE(_payload_start = .); 18 | 19 | . = ALIGN(0x1000); /* Need this to create proper sections */ 20 | 21 | /* Beginning of the code section */ 22 | 23 | .text : 24 | { 25 | PROVIDE(_text_start = .); 26 | *(.entry) 27 | *(.text) 28 | . = ALIGN(8); 29 | PROVIDE(_text_end = .); 30 | } 31 | 32 | . = ALIGN(0x1000); /* Ensure next section is page aligned */ 33 | 34 | /* End of the code sections */ 35 | 36 | /* Beginning of the read-only data sections */ 37 | 38 | . = ALIGN(0x1000); /* Ensure next section is page aligned */ 39 | 40 | .rodata : 41 | { 42 | PROVIDE(_rodata_start = .); 43 | *(.rodata .rodata.*) 44 | . = ALIGN(8); 45 | PROVIDE(_rodata_end = .); 46 | } 47 | 48 | /* End of the read-only data sections */ 49 | 50 | 51 | /* Beginning of the read-write data sections */ 52 | 53 | . = ALIGN(0x1000); /* Ensure next section is page aligned */ 54 | 55 | PROVIDE(_data_start = .); 56 | .data : 57 | { 58 | *(.data) 59 | *(.data.*) 60 | *(.readmostly.data) 61 | *(*.data) 62 | . = ALIGN(8); 63 | } 64 | 65 | /* We want the small data sections together, so single-instruction offsets 66 | can access them all, and initialized data all before uninitialized, so 67 | we can shorten the on-disk segment size. 68 | */ 69 | .sdata : 70 | { 71 | __global_pointer$ = . + 0x800; 72 | __SDATA_BEGIN__ = . + 0x800; 73 | *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*) 74 | *(.sdata .sdata.* .gnu.linkonce.s.*) 75 | } 76 | PROVIDE(_data_end = .); 77 | 78 | . = .; 79 | PROVIDE(_bss_start = .); 80 | .sbss : 81 | { 82 | *(.dynsbss) 83 | *(.sbss .sbss.* .gnu.linkonce.sb.*) 84 | *(.scommon) 85 | } 86 | 87 | . = ALIGN(0x1000); /* Ensure next section is page aligned */ 88 | 89 | .bss : 90 | { 91 | *(.bss) 92 | *(.bss.*) 93 | . = ALIGN(8); 94 | } 95 | PROVIDE(_bss_end = .); 96 | 97 | /* End of the read-write data sections */ 98 | 99 | . = ALIGN(0x1000); /* Need this to create proper sections */ 100 | 101 | PROVIDE(_payload_end = .); 102 | } 103 | -------------------------------------------------------------------------------- /machine/sbi_ecall.c: -------------------------------------------------------------------------------- 1 | #include "compiler-utils.h" 2 | #include "sbi_ecall.h" 3 | #include "sbi_ecall_ids.h" 4 | 5 | void sbi_ecall_sbi_putchar(int chr) { 6 | asm volatile ( 7 | "li a6, " STRINGIFICATE(SBI_FUNCTION_ID_LEGACY_EXTENSION_SBI_CONSOLE_PUTCHAR) ";" 8 | "li a7, " STRINGIFICATE(SBI_EXTENSION_ID_LEGACY_EXTENSION_SBI_CONSOLE_PUTCHAR) ";" 9 | "mv a0, %[chr];" 10 | "ecall;" 11 | : 12 | : [chr] "r" (chr) 13 | : "a0", "a6", "a7" 14 | ); 15 | } 16 | 17 | bool sbi_ecall_sbi_set_timer(uint64_t interrupt_at) { 18 | long error; 19 | 20 | asm volatile ( 21 | "li a6, " STRINGIFICATE(SBI_FUNCTION_ID_TIMER_EXTENSION_SBI_SET_TIMER) ";" 22 | "li a7, " STRINGIFICATE(SBI_EXTENSION_ID_TIMER_EXTENSION) ";" 23 | "mv a0, %[interrupt_at];" 24 | "ecall;" 25 | "mv %[error], a1" 26 | : [error] "=r" (error) 27 | : [interrupt_at] "r" (interrupt_at) 28 | : "a7", "a6", "a1", "a0" // a1 because the SBI returns an error code in there 29 | ); 30 | 31 | return (error == 0); 32 | } 33 | 34 | void sbi_ecall_sbi_shutdown() { 35 | asm volatile ( 36 | "li a6, " STRINGIFICATE(SBI_FUNCTION_ID_LEGACY_EXTENSION_SBI_SHUTDOWN) ";" 37 | "li a7, " STRINGIFICATE(SBI_EXTENSION_ID_LEGACY_EXTENSION_SBI_SHUTDOWN) ";" 38 | "ecall" 39 | : 40 | : 41 | : "a6", "a7" 42 | ); 43 | } 44 | -------------------------------------------------------------------------------- /machine/syscalls.c: -------------------------------------------------------------------------------- 1 | #include "filesystem.h" 2 | #include "syscalls.h" 3 | #include "console.h" 4 | #include "tinycstd.h" 5 | 6 | #include "compiler-utils.h" 7 | 8 | ssize_t kread(int fd, char* buf, size_t nbytes, FILEDESC* open_files, size_t num_fds) { 9 | if (!fd_is_valid(fd, num_fds)) 10 | return -1; 11 | 12 | if (fd_is_stdio(fd)) { 13 | // TODO: No stdin yet 14 | return -1; 15 | } else { 16 | FILEDESC* desc = get_fd_entry(fd, open_files, num_fds); 17 | if (!fd_entry_is_opened(desc)) 18 | return -1; 19 | 20 | uint64_t num_read = nbytes; 21 | uint64_t max_readable = desc->file->length - desc->pos; 22 | if (num_read > max_readable) 23 | num_read = max_readable; 24 | 25 | const char* fileDataOffset = desc->file->data + desc->pos; 26 | 27 | memcpy(buf, fileDataOffset, num_read); 28 | desc->pos += num_read; 29 | 30 | return num_read; 31 | } 32 | } 33 | 34 | intmax_t kwrite(int fd, const char* buf, size_t count, FILEDESC* open_files, size_t num_fds) { 35 | UNUSED_VAR(open_files); 36 | UNUSED_VAR(num_fds); 37 | // No file descriptor support yet for write - write to console instead 38 | 39 | // only allow writes to stdin (0), stdout (1) or stderr (2) 40 | if (!fd_is_stdio(fd)) 41 | return -1; 42 | 43 | return console_puts(buf, count); 44 | } 45 | 46 | int last_allocated_fd = OPEN_FILE_FD_OFFSET - 1; 47 | int kopen(const char* filename, int flags, FILEDESC* open_files, size_t num_fds) { 48 | const int O_RDONLY = 0x0; 49 | const int _O_BINARY = 0x8000; 50 | const KFILE* file = files; 51 | 52 | if (flags != O_RDONLY && flags != (_O_BINARY | O_RDONLY)) 53 | return -1; 54 | 55 | while (file->data != NULL) { 56 | if (strncmp(filename, file->name, 511) == 0) 57 | break; 58 | 59 | file++; 60 | } 61 | if (file->data == NULL) 62 | return -1; 63 | 64 | // Check if we are able to use the fd slot one above the last allocated FD 65 | int fd = last_allocated_fd + 1; 66 | if (fd_is_opened(fd, open_files, num_fds)) { 67 | // No, so fall back to linear iteration over all slots 68 | fd = OPEN_FILE_FD_OFFSET; 69 | while (fd_is_valid(fd, num_fds)) { 70 | if (!fd_is_opened(fd, open_files, num_fds)) 71 | break; 72 | fd++; 73 | } 74 | } 75 | 76 | if (!fd_is_valid(fd, num_fds)) 77 | return -1; 78 | 79 | FILEDESC* fd_slot = get_fd_entry(fd, open_files, num_fds); 80 | 81 | fd_slot->pos = 0; 82 | fd_slot->file = file; 83 | 84 | return fd; 85 | } 86 | -------------------------------------------------------------------------------- /machine/tools/asm_struct_macro_generator.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "context.h" 4 | 5 | #define PRINT_SIZE_DEF(prefix, name, stru) printf("#define %s%s %lu\n", #prefix, #name, sizeof(stru)) 6 | #define PRINT_OFFSET_DEF(prefix, name, stru, memb) printf("#define %s%s %lu\n", #prefix, #name, offsetof(stru, memb)) 7 | 8 | int main() { 9 | PRINT_SIZE_DEF(SIZEOF_, REGISTERS_STRUCT, struct registers); 10 | 11 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, RA, struct registers, ra); 12 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, SP, struct registers, sp); 13 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, GP, struct registers, gp); 14 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, TP, struct registers, tp); 15 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, T0, struct registers, t0); 16 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, T1, struct registers, t1); 17 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, T2, struct registers, t2); 18 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, S0, struct registers, s0); 19 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, S1, struct registers, s1); 20 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, A0, struct registers, a0); 21 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, A1, struct registers, a1); 22 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, A2, struct registers, a2); 23 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, A3, struct registers, a3); 24 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, A4, struct registers, a4); 25 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, A5, struct registers, a5); 26 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, A6, struct registers, a6); 27 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, A7, struct registers, a7); 28 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, S2, struct registers, s2); 29 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, S3, struct registers, s3); 30 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, S4, struct registers, s4); 31 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, S5, struct registers, s5); 32 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, S6, struct registers, s6); 33 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, S7, struct registers, s7); 34 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, S8, struct registers, s8); 35 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, S9, struct registers, s9); 36 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, S10, struct registers, s10); 37 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, S11, struct registers, s11); 38 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, T3, struct registers, t3); 39 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, T4, struct registers, t4); 40 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, T5, struct registers, t5); 41 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, T6, struct registers, t6); 42 | 43 | PRINT_OFFSET_DEF(REGISTERS_OFFSET_, PC, struct registers, pc); 44 | } 45 | -------------------------------------------------------------------------------- /replit.nix: -------------------------------------------------------------------------------- 1 | { pkgs }: { 2 | deps = [ 3 | pkgs.cowsay 4 | ]; 5 | } -------------------------------------------------------------------------------- /theses/bachelor_thesis_bachinger.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/theses/bachelor_thesis_bachinger.pdf -------------------------------------------------------------------------------- /theses/bachelor_thesis_barthel.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/theses/bachelor_thesis_barthel.pdf -------------------------------------------------------------------------------- /theses/bachelor_thesis_bauer.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/theses/bachelor_thesis_bauer.pdf -------------------------------------------------------------------------------- /theses/bachelor_thesis_diller.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/theses/bachelor_thesis_diller.pdf -------------------------------------------------------------------------------- /theses/bachelor_thesis_edelmayer.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/theses/bachelor_thesis_edelmayer.pdf -------------------------------------------------------------------------------- /theses/bachelor_thesis_fejzic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/theses/bachelor_thesis_fejzic.pdf -------------------------------------------------------------------------------- /theses/bachelor_thesis_fischer.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/theses/bachelor_thesis_fischer.pdf -------------------------------------------------------------------------------- /theses/bachelor_thesis_haritopoulos.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/theses/bachelor_thesis_haritopoulos.pdf -------------------------------------------------------------------------------- /theses/bachelor_thesis_kollert.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/theses/bachelor_thesis_kollert.pdf -------------------------------------------------------------------------------- /theses/bachelor_thesis_landl.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/theses/bachelor_thesis_landl.pdf -------------------------------------------------------------------------------- /theses/bachelor_thesis_oblasser.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/theses/bachelor_thesis_oblasser.pdf -------------------------------------------------------------------------------- /theses/bachelor_thesis_pape.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/theses/bachelor_thesis_pape.pdf -------------------------------------------------------------------------------- /theses/bachelor_thesis_seidl.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/theses/bachelor_thesis_seidl.pdf -------------------------------------------------------------------------------- /theses/bachelor_thesis_siller.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/theses/bachelor_thesis_siller.pdf -------------------------------------------------------------------------------- /theses/bachelor_thesis_thiele.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/theses/bachelor_thesis_thiele.pdf -------------------------------------------------------------------------------- /theses/bachelor_thesis_widmoser.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/theses/bachelor_thesis_widmoser.pdf -------------------------------------------------------------------------------- /theses/bachelor_thesis_wulz.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/theses/bachelor_thesis_wulz.pdf -------------------------------------------------------------------------------- /tools/README.md: -------------------------------------------------------------------------------- 1 | # Tools based on Selfie 2 | 3 | The code in this directory showcases how to extend selfie. See selfie's Makefile for more details on how to build and use the tools. -------------------------------------------------------------------------------- /tools/gc-lib.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char** argv) { 2 | uint64_t exit_code; 3 | 4 | init_library(); 5 | 6 | turn_on_gc_library(12000, ""); // use library variant of gc 7 | 8 | exit_code = selfie_main(argc, argv); 9 | 10 | print_gc_profile(0); 11 | 12 | return exit_code; 13 | } -------------------------------------------------------------------------------- /tools/periscope/README.md: -------------------------------------------------------------------------------- 1 | # peRISCope 2 | 3 | This is a project for exploring the reasoning performance of RISC-V software 4 | models in BTOR2. The name `periscope` is derived from the idea of exploring 5 | PErformance of RISC models, and the idea of a periscope that can be used to 6 | explore the unknown surroundings. 7 | 8 | ## Structure 9 | 10 | The project consists of two sub-projects: 11 | 12 | - [`periscope-rs`](./periscope-rs) - A binary written in Rust that can be used 13 | to parse witness format producec by `btormc`, and for benchmarking of model 14 | checking. Check the [README](./periscope-rs/README.md) for more information. 15 | - [`periscope-py`](./periscope-py) - A Python package that can be used to read 16 | output of `periscope-rs` and produce plots. Check the 17 | [README](./periscope-py/README.md) for more information. 18 | -------------------------------------------------------------------------------- /tools/periscope/periscope-py/.gitignore: -------------------------------------------------------------------------------- 1 | .venv/ 2 | 3 | src/__pycache__/ 4 | -------------------------------------------------------------------------------- /tools/periscope/periscope-py/README.md: -------------------------------------------------------------------------------- 1 | # PeRISCope - Python script for results visualisation 2 | 3 | This is a simple Python script for generating plots of benchmarking results 4 | produced by [`periscope-rs`](../periscope-rs). 5 | 6 | ## Usage 7 | 8 | Make sure you installed all required dependencies: 9 | 10 | ```sh 11 | pip install -r requirements.txt 12 | ``` 13 | 14 | After that, run the main script file with `--help` flag to get more information: 15 | 16 | ```sh 17 | python src/periscope.py --help 18 | ``` 19 | 20 | ## Example usage: 21 | 22 | ```sh 23 | # Generate a plot with bars for each configuration, overall sort-by median time, 24 | # and scale the y-axis logarithmically. Plot results contained in `results_dir` 25 | # and save the plot to test.png file. 26 | python src/periscope.py --sort-by median --scale log --type cmp-bars -o test.png results_dir 27 | ``` 28 | -------------------------------------------------------------------------------- /tools/periscope/periscope-py/pyrightconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "src", 4 | ], 5 | 6 | "exclude": [ 7 | "**/node_modules", 8 | "**/__pycache__", 9 | ".venv", 10 | ], 11 | 12 | "venvPath": ".", 13 | "venv": ".venv", 14 | 15 | "ignore": [ 16 | "src/oldstuff" 17 | ], 18 | 19 | "reportMissingImports": true, 20 | "reportMissingTypeStubs": false, 21 | 22 | "executionEnvironments": [ 23 | { 24 | "root": "src" 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /tools/periscope/periscope-py/requirements.txt: -------------------------------------------------------------------------------- 1 | jsonpickle==3.0.4 2 | matplotlib==3.8.4 3 | -------------------------------------------------------------------------------- /tools/periscope/periscope-py/src/histogram.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | from matplotlib import figure, pyplot as plt 4 | import numpy as np 5 | 6 | from periscope_result import BenchResult 7 | 8 | 9 | def cmp_wc(labels: list[str], periscope_results: list[BenchResult]): 10 | def compare(i, j): 11 | wc_i = periscope_results[i].wc 12 | wc_j = periscope_results[j].wc 13 | if wc_i == wc_j: 14 | return labels[i] < labels[j] 15 | else: 16 | return wc_i - wc_j 17 | 18 | return compare 19 | 20 | 21 | def plot_histogram( 22 | args: argparse.Namespace, 23 | periscope_results: list[BenchResult], 24 | figure: figure.Figure, 25 | of_dump: bool, 26 | ): 27 | labels = [b.name for b in periscope_results] 28 | all_times = [b.times for pr in periscope_results for b in pr.hyperfine_results()] 29 | 30 | t_min = np.min(list(map(np.min, all_times))) 31 | t_max = np.max(list(map(np.max, all_times))) 32 | 33 | if of_dump: 34 | wcs = [pr.results.wc_btormc_dump for pr in periscope_results] 35 | else: 36 | wcs = [pr.results.wc_raw for pr in periscope_results] 37 | 38 | times = list(map(np.min, all_times)) 39 | 40 | _ = figure.subplots(1, 1) 41 | cmap = plt.get_cmap("rainbow") 42 | colors = [cmap(val / len(times)) for val in range(len(times))] 43 | plt.bar(x=times, height=wcs, label=labels, color=colors, width=5) 44 | 45 | plt.title("Solving time and model size") 46 | plt.xlabel("Time [s]") 47 | 48 | if of_dump: 49 | plt.ylabel("Model Size after btormc dump [#chars]") 50 | else: 51 | plt.ylabel("Model Size [#chars]") 52 | 53 | plt.xticks(np.arange(np.floor(t_min), np.floor(t_max), step=10)) 54 | plt.xticks( 55 | list(map(np.min, all_times)), 56 | labels, 57 | rotation=65, 58 | minor=True, 59 | ) 60 | 61 | for xtick, color in zip(plt.gca().get_xticklabels(which="minor"), colors): 62 | xtick.set_color(color) 63 | -------------------------------------------------------------------------------- /tools/periscope/periscope-py/src/whiskers.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import functools 3 | import pathlib 4 | 5 | from matplotlib import figure 6 | import matplotlib.pyplot as plt 7 | 8 | from periscope_result import BenchResult 9 | 10 | 11 | def cmp_median(medians: list[float], labels: list[str]): 12 | def compare(i, j): 13 | med_cmp = medians[i] - medians[j] 14 | if med_cmp == 0: 15 | return labels[i] < labels[j] 16 | else: 17 | return med_cmp 18 | 19 | return compare 20 | 21 | 22 | def plot_whiskers( 23 | args: argparse.Namespace, 24 | periscope_results: list[BenchResult], 25 | figure: figure.Figure, 26 | ): 27 | labels = [b.name for b in periscope_results] 28 | times = [b.times for pr in periscope_results for b in pr.hyperfine_results()] 29 | 30 | if args.sort_by == "median": 31 | medians = [b.median for pr in periscope_results for b in pr.hyperfine_results()] 32 | indices = sorted( 33 | range(len(labels)), 34 | key=functools.cmp_to_key(cmp_median(medians, labels)), 35 | ) 36 | labels = [labels[i] for i in indices] 37 | times = [times[i] for i in indices] 38 | 39 | _ = figure.subplots(1, 1) 40 | plt.subplots(figsize=(20, 12), constrained_layout=True) 41 | boxplot = plt.boxplot(times, vert=True, patch_artist=True) 42 | cmap = plt.get_cmap("rainbow") 43 | colors = [cmap(val / len(times)) for val in range(len(times))] 44 | 45 | for patch, color in zip(boxplot["boxes"], colors): 46 | patch.set_facecolor(color) 47 | 48 | if args.title: 49 | plt.title(args.title) 50 | # plt.legend(handles=boxplot["boxes"], labels=labels, loc="best", fontsize="medium") 51 | plt.title("Solving time and model size") 52 | plt.ylabel("Time [s]") 53 | plt.ylim(0, None) 54 | plt.xticks(list(range(1, len(labels) + 1)), labels, rotation=65) 55 | -------------------------------------------------------------------------------- /tools/periscope/periscope-rs/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /.periscope 3 | -------------------------------------------------------------------------------- /tools/periscope/periscope-rs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "periscope" 3 | description = "To be added" 4 | version = "0.1.0" 5 | edition = "2021" 6 | authors = [ "Nadir Fejzic " ] 7 | license = "MIT" 8 | 9 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 10 | 11 | [dependencies] 12 | anyhow = "1.0.83" 13 | clap = { version = "4.5.4", features = ["derive"] } 14 | nom = "7.1.3" 15 | serde = { version = "1.0.201", features = ["serde_derive"] } 16 | serde_json = "1.0.117" 17 | serde_yaml = "0.9.34" 18 | -------------------------------------------------------------------------------- /tools/periscope/periscope-rs/src/bench/hyperfine.rs: -------------------------------------------------------------------------------- 1 | use std::{fs::OpenOptions, io::Read, path::Path, process::Command}; 2 | 3 | use anyhow::Context; 4 | use serde::{Deserialize, Serialize}; 5 | 6 | #[derive(Debug, Clone, Serialize, Deserialize)] 7 | pub struct Hyperfine { 8 | pub results: Vec, 9 | } 10 | 11 | /// Results from a single run of `hyperfine`. 12 | #[derive(Debug, Clone, Serialize, Deserialize)] 13 | pub struct HyperfineResult { 14 | pub command: String, 15 | pub mean: f64, 16 | pub stddev: f64, 17 | pub median: f64, 18 | pub user: f64, 19 | pub system: f64, 20 | pub min: f64, 21 | pub max: f64, 22 | pub times: Vec, 23 | pub exit_codes: Vec, 24 | } 25 | 26 | /// Run `hyperfine` on a `btormc` and return the parsed results. 27 | pub fn run( 28 | path: impl AsRef, 29 | hyperfine_output: impl AsRef, 30 | hyperfine_json_path: impl AsRef, 31 | btormc_flags: &Option, 32 | timeout: Option, 33 | ) -> anyhow::Result { 34 | let json_path = hyperfine_json_path.as_ref(); 35 | let mut json_out = OpenOptions::new() 36 | .create(true) 37 | .write(true) 38 | .truncate(true) 39 | .read(true) 40 | .open(json_path)?; 41 | 42 | let btormc_flags = btormc_flags.as_deref().unwrap_or("-kmax 200"); 43 | let mut btormc_cmd = format!("btormc {} {}", path.as_ref().display(), btormc_flags); 44 | 45 | if let Some(timeout) = timeout { 46 | btormc_cmd = format!("timeout --foreground {}s {}", timeout, btormc_cmd); 47 | } 48 | 49 | let _ = Command::new("hyperfine") 50 | .args(["--warmup", "3"]) 51 | .args(["--runs", "5"]) 52 | .arg("--ignore-failure") 53 | .arg("--export-json") 54 | .arg(json_path) 55 | .args([ 56 | "--output", 57 | hyperfine_output 58 | .as_ref() 59 | .to_str() 60 | .context("Invalid path for output from 'btormc'")?, 61 | ]) 62 | .arg(&btormc_cmd) 63 | .spawn()? 64 | .wait()?; 65 | 66 | let hyperfine: Hyperfine = serde_json::from_reader(&json_out).map_err(|_| { 67 | let mut output = String::new(); 68 | json_out.read_to_string(&mut output).unwrap_or_default(); 69 | anyhow::format_err!("Failed reading json_output: \n{}\n", output) 70 | })?; 71 | 72 | Ok(hyperfine) 73 | } 74 | -------------------------------------------------------------------------------- /tools/periscope/periscope-rs/src/bench/rotor.rs: -------------------------------------------------------------------------------- 1 | use std::{path::Path, process::Command}; 2 | 3 | /// Run rotor in the provided selfie directory. Make sure that the following make targets exist: 4 | /// * `clean` 5 | /// * `rotor-symbolic` 6 | /// 7 | /// Other make targets can be run by providing the corresponding CLI flag. [Commands::Bench] for more 8 | /// information. 9 | /// 10 | /// [Commands::Bench]: crate::Commands::Bench 11 | pub fn run_rotor( 12 | selfie_dir: &Path, 13 | rotor_args: &str, 14 | make_target: &Option, 15 | ) -> anyhow::Result<()> { 16 | // make sure we start fresh 17 | Command::new("make") 18 | .arg("clean") 19 | .current_dir(selfie_dir) 20 | .spawn()? 21 | .wait()?; 22 | 23 | let make_target = make_target.as_deref().unwrap_or("rotor-symbolic"); 24 | 25 | Command::new("make") 26 | .arg(make_target) 27 | .arg(format!("rotor={}", rotor_args)) 28 | .current_dir(selfie_dir) 29 | .spawn()? 30 | .wait()?; 31 | 32 | Ok(()) 33 | } 34 | -------------------------------------------------------------------------------- /tools/periscope/periscope-rs/src/bench/wc.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | io::Write, 3 | path::Path, 4 | process::{Command, Stdio}, 5 | }; 6 | 7 | use anyhow::Context; 8 | 9 | /// Count number of characters in the BTOR2 file generated by `rotor`. 10 | pub fn char_count_in_file(file: impl AsRef) -> anyhow::Result { 11 | let wc = Command::new("wc") 12 | .arg("-c") 13 | .arg(file.as_ref()) 14 | .output()? 15 | .stdout; 16 | 17 | parse_wc_output(&wc) 18 | } 19 | 20 | /// Count the number of characters in dump generated by `btormc` from BTOR2 file generated by 21 | /// `rotor`. 22 | pub fn char_count_in_dump(path: impl AsRef) -> anyhow::Result { 23 | let s = Command::new("btormc") 24 | .arg("-d") 25 | .arg(path.as_ref()) 26 | .output()? 27 | .stdout; 28 | 29 | let mut wc_child = Command::new("wc") 30 | .arg("-c") 31 | .arg("-") 32 | .stdin(Stdio::piped()) 33 | .stdout(Stdio::piped()) 34 | .spawn()?; 35 | 36 | if let Some(stdin) = wc_child.stdin.as_mut() { 37 | stdin.write_all(&s)?; 38 | } 39 | 40 | let wc = wc_child.wait_with_output()?.stdout; 41 | 42 | parse_wc_output(&wc) 43 | } 44 | 45 | /// Parse the output of the `wc` command into `usize`. 46 | fn parse_wc_output(output: &[u8]) -> anyhow::Result { 47 | let idx = output 48 | .iter() 49 | .position(|c| c == &b' ') 50 | .context("Bad output from 'wc' command.")?; 51 | 52 | let wc = std::str::from_utf8(output[..idx].as_ref())?; 53 | 54 | wc.parse() 55 | .context("Could not parse output of 'wc' command.") 56 | } 57 | -------------------------------------------------------------------------------- /tools/periscope/periscope-rs/src/btor/btor2.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | collections::HashMap, 3 | io::{BufRead, BufReader, Read}, 4 | }; 5 | 6 | use serde::{Deserialize, Serialize}; 7 | 8 | use crate::btor::witness_format::PropKind; 9 | 10 | #[derive(Debug, Clone, Serialize, Deserialize)] 11 | pub struct Property { 12 | pub node: usize, 13 | pub _kind: PropKind, 14 | pub name: Option, 15 | } 16 | 17 | pub(super) fn get_property_names(input: R) -> HashMap { 18 | let input = BufReader::new(input); 19 | input 20 | .lines() 21 | .filter(|line| match line { 22 | Ok(line) => line 23 | .split(' ') 24 | .nth(1) 25 | .is_some_and(|kind| kind == "bad" || kind == "justice"), 26 | Err(_) => false, 27 | }) 28 | .enumerate() 29 | .filter_map(|(idx, line)| { 30 | let line = line.ok()?; 31 | let mut iter = line.split(' '); 32 | let node = iter.next()?.parse().ok()?; 33 | let kind: PropKind = iter.next()?.parse().ok()?; 34 | let name = iter.nth(1).map(String::from); 35 | let idx = idx.try_into().ok()?; 36 | 37 | Some(( 38 | idx, 39 | Property { 40 | node, 41 | _kind: kind, 42 | name, 43 | }, 44 | )) 45 | }) 46 | .collect() 47 | } 48 | -------------------------------------------------------------------------------- /tools/periscope/periscope-rs/src/btor/helpers.rs: -------------------------------------------------------------------------------- 1 | use nom::{bytes::complete, character, combinator, sequence}; 2 | 3 | pub fn uint(input: &str) -> nom::IResult<&str, u64> { 4 | combinator::map_res(character::complete::digit1, |s: &str| s.parse())(input) 5 | } 6 | 7 | pub fn newline(input: &str) -> nom::IResult<&str, &str> { 8 | complete::tag("\n")(input) 9 | } 10 | 11 | pub fn comment(input: &str) -> nom::IResult<&str, ()> { 12 | let first = sequence::preceded(complete::tag(";"), complete::take_until("\\n")); 13 | combinator::map(sequence::terminated(first, newline), |_| ())(input) 14 | } 15 | -------------------------------------------------------------------------------- /tools/quarc/README.md: -------------------------------------------------------------------------------- 1 | # QUARC 2 | 3 | QUBOT is a bounded model checker and a symbolic execution engine. It generates a Quantum Circuit in polynomic time from a given BTOR2 file and a given number of timesteps *n*. 4 | 5 | The purpose of QUARC is to build an oracle than can be used in Grover's Algorithm to search for inputs that cause bad states. 6 | 7 | ## Usage 8 | ```` Python 9 | from btor2QC import BTor2QC 10 | from check_inputs import check_input # used only for debugging purposes 11 | 12 | n = 21 13 | parser = BTor2QC(n) # creates a btor2 file parser of 21 timesteps 14 | quantum_circuit, result_bad_states = parser.parse_file(a_btor2_file, "output.qasm", is_selfie_file=True, generate_with_grover=False) 15 | 16 | assert (len(result_bad_states) == 1) # this is a quantum register that represents the output of the circuit. 17 | # debug generated circuit 18 | circuit_queue = get_circuit_queue(Instruction.global_stack) 19 | for i in range(0, 256): # test ascii decimal values that fit in 1 byte 20 | circuit_output, bad_states = check_input(n, circuit_queue, i, result_bad_states) 21 | print(f"input {i} makes the circuit output {circuit_output}. {bad_states} happen") 22 | 23 | ```` 24 | 25 | ## Prerequisites 26 | python >= 3.6 27 | 28 | 29 | ## Installation 30 | Install required libraries (a virtual environment is recommended): 31 | 32 | ```bash 33 | pip install -r requirements.txt 34 | ``` -------------------------------------------------------------------------------- /tools/quarc/qasm_files/add.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg q2[2]; 4 | qreg q3[2]; 5 | qreg q4[2]; 6 | h q4[0]; 7 | h q4[1]; 8 | ccx q3[0],q4[0],q3[1]; 9 | cx q4[0],q3[0]; 10 | cx q4[1],q3[1]; 11 | ccx q3[0],q2[0],q3[1]; 12 | cx q2[0],q3[0]; 13 | cx q2[1],q3[1]; 14 | -------------------------------------------------------------------------------- /tools/quarc/qasm_files/add2.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg q2[2]; 4 | qreg q3[2]; 5 | qreg q4[2]; 6 | h q4[0]; 7 | h q4[1]; 8 | ccx q3[0],q4[0],q3[1]; 9 | cx q4[0],q3[0]; 10 | cx q4[1],q3[1]; 11 | ccx q3[0],q2[0],q3[1]; 12 | cx q2[0],q3[0]; 13 | cx q2[1],q3[1]; 14 | -------------------------------------------------------------------------------- /tools/quarc/qasm_files/and.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg q2[2]; 4 | qreg q3[2]; 5 | qreg q4[2]; 6 | h q2[0]; 7 | h q2[1]; 8 | h q3[0]; 9 | h q3[1]; 10 | ccx q3[0],q2[0],q4[0]; 11 | ccx q3[1],q2[1],q4[1]; 12 | -------------------------------------------------------------------------------- /tools/quarc/qasm_files/div.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg q2[2]; 4 | qreg q3[2]; 5 | qreg udiv[2]; 6 | x q2[1]; 7 | x q3[1]; 8 | x udiv[0]; 9 | -------------------------------------------------------------------------------- /tools/quarc/qasm_files/eq.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg q2[1]; 4 | qreg q3[1]; 5 | qreg eq[1]; 6 | qreg an[2]; 7 | qreg q4[1]; 8 | h q2[0]; 9 | h q3[0]; 10 | x an[1]; 11 | cx an[1],an[0]; 12 | cx q2[0],an[0]; 13 | cx q3[0],an[0]; 14 | cx an[0],eq[0]; 15 | x eq[0]; 16 | cx eq[0],q4[0]; 17 | x eq[0]; 18 | -------------------------------------------------------------------------------- /tools/quarc/qasm_files/eq_grover.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg in2[1]; 4 | qreg in3[1]; 5 | qreg eq[1]; 6 | qreg an[2]; 7 | qreg q2[1]; 8 | qreg q4[1]; 9 | qreg gout[1]; 10 | creg c0[2]; 11 | h in2[0]; 12 | h in3[0]; 13 | x an[1]; 14 | cx an[1],an[0]; 15 | cx in2[0],an[0]; 16 | cx in3[0],an[0]; 17 | cx an[0],eq[0]; 18 | cx eq[0],q2[0]; 19 | h q4[0]; 20 | x gout[0]; 21 | h gout[0]; 22 | barrier in2[0],in3[0],eq[0],an[0],an[1],q2[0],q4[0],gout[0]; 23 | ccx q2[0],q4[0],gout[0]; 24 | barrier in2[0],in3[0],eq[0],an[0],an[1],q2[0],q4[0],gout[0]; 25 | cx eq[0],q2[0]; 26 | cx an[0],eq[0]; 27 | cx in3[0],an[0]; 28 | cx in2[0],an[0]; 29 | cx an[1],an[0]; 30 | x an[1]; 31 | barrier in2[0],in3[0],eq[0],an[0],an[1],q2[0],q4[0],gout[0]; 32 | h in2[0]; 33 | h in3[0]; 34 | h q4[0]; 35 | x in2[0]; 36 | x in3[0]; 37 | x q4[0]; 38 | h in2[0]; 39 | ccx in3[0],q4[0],in2[0]; 40 | h in2[0]; 41 | x in2[0]; 42 | x in3[0]; 43 | x q4[0]; 44 | h in2[0]; 45 | h in3[0]; 46 | h q4[0]; 47 | barrier in2[0],in3[0],eq[0],an[0],an[1],q2[0],q4[0],gout[0]; 48 | x an[1]; 49 | cx an[1],an[0]; 50 | cx in2[0],an[0]; 51 | cx in3[0],an[0]; 52 | cx an[0],eq[0]; 53 | cx eq[0],q2[0]; 54 | barrier in2[0],in3[0],eq[0],an[0],an[1],q2[0],q4[0],gout[0]; 55 | ccx q2[0],q4[0],gout[0]; 56 | barrier in2[0],in3[0],eq[0],an[0],an[1],q2[0],q4[0],gout[0]; 57 | cx eq[0],q2[0]; 58 | cx an[0],eq[0]; 59 | cx in3[0],an[0]; 60 | cx in2[0],an[0]; 61 | cx an[1],an[0]; 62 | x an[1]; 63 | h in2[0]; 64 | h in3[0]; 65 | h q4[0]; 66 | x in2[0]; 67 | x in3[0]; 68 | x q4[0]; 69 | h in2[0]; 70 | ccx in3[0],q4[0],in2[0]; 71 | h in2[0]; 72 | x in2[0]; 73 | x in3[0]; 74 | x q4[0]; 75 | h in2[0]; 76 | h in3[0]; 77 | h q4[0]; 78 | barrier in2[0],in3[0],eq[0],an[0],an[1],q2[0],q4[0],gout[0]; 79 | x an[1]; 80 | cx an[1],an[0]; 81 | cx in2[0],an[0]; 82 | cx in3[0],an[0]; 83 | cx an[0],eq[0]; 84 | cx eq[0],q2[0]; 85 | barrier in2[0],in3[0],eq[0],an[0],an[1],q2[0],q4[0],gout[0]; 86 | ccx q2[0],q4[0],gout[0]; 87 | barrier in2[0],in3[0],eq[0],an[0],an[1],q2[0],q4[0],gout[0]; 88 | cx eq[0],q2[0]; 89 | cx an[0],eq[0]; 90 | cx in3[0],an[0]; 91 | cx in2[0],an[0]; 92 | cx an[1],an[0]; 93 | x an[1]; 94 | h in2[0]; 95 | h in3[0]; 96 | h q4[0]; 97 | x in2[0]; 98 | x in3[0]; 99 | x q4[0]; 100 | h in2[0]; 101 | ccx in3[0],q4[0],in2[0]; 102 | h in2[0]; 103 | x in2[0]; 104 | x in3[0]; 105 | x q4[0]; 106 | h in2[0]; 107 | h in3[0]; 108 | h q4[0]; 109 | barrier in2[0],in3[0],eq[0],an[0],an[1],q2[0],q4[0],gout[0]; 110 | measure in2[0] -> c0[0]; 111 | measure in3[0] -> c0[1]; 112 | -------------------------------------------------------------------------------- /tools/quarc/qasm_files/ite.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg q2[1]; 4 | qreg q3[1]; 5 | qreg q4[1]; 6 | qreg q5[1]; 7 | qreg q6[1]; 8 | h q2[0]; 9 | h q3[0]; 10 | h q4[0]; 11 | ccx q2[0],q3[0],q5[0]; 12 | x q2[0]; 13 | ccx q2[0],q4[0],q5[0]; 14 | x q2[0]; 15 | x q5[0]; 16 | cx q5[0],q6[0]; 17 | x q5[0]; 18 | x q6[0]; 19 | -------------------------------------------------------------------------------- /tools/quarc/qasm_files/mul.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg q2[2]; 4 | qreg q3[2]; 5 | qreg mul[2]; 6 | qreg an[2]; 7 | x q2[1]; 8 | x q3[0]; 9 | ccx q3[0],q2[0],an[0]; 10 | ccx q3[1],q2[0],an[0]; 11 | ccx mul[0],an[0],mul[1]; 12 | cx an[0],mul[0]; 13 | cx an[1],mul[1]; 14 | ccx q3[1],q2[0],an[0]; 15 | ccx q3[0],q2[0],an[0]; 16 | ccx q3[0],q2[1],an[1]; 17 | ccx mul[0],an[0],mul[1]; 18 | cx an[0],mul[0]; 19 | cx an[1],mul[1]; 20 | ccx q3[0],q2[1],an[1]; 21 | -------------------------------------------------------------------------------- /tools/quarc/qasm_files/not.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg q2[2]; 4 | qreg q3[2]; 5 | qreg q4[2]; 6 | qreg q5[2]; 7 | qreg q6[2]; 8 | h q3[0]; 9 | h q3[1]; 10 | cx q3[0],q4[0]; 11 | x q4[0]; 12 | cx q3[1],q4[1]; 13 | x q4[1]; 14 | h q5[0]; 15 | h q5[1]; 16 | cx q5[0],q6[0]; 17 | x q6[0]; 18 | cx q5[1],q6[1]; 19 | x q6[1]; 20 | -------------------------------------------------------------------------------- /tools/quarc/qasm_files/rem.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg q2[2]; 4 | qreg q3[2]; 5 | qreg urem[2]; 6 | x q2[1]; 7 | x q3[0]; 8 | x urem[0]; 9 | -------------------------------------------------------------------------------- /tools/quarc/qasm_files/sub.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg q2[2]; 4 | qreg q3[2]; 5 | qreg q4[2]; 6 | h q4[0]; 7 | h q4[1]; 8 | x q2[0]; 9 | x q2[1]; 10 | cx q2[0],q2[1]; 11 | x q2[0]; 12 | ccx q3[0],q4[0],q3[1]; 13 | cx q4[0],q3[0]; 14 | cx q4[1],q3[1]; 15 | ccx q3[0],q2[0],q3[1]; 16 | cx q2[0],q3[0]; 17 | cx q2[1],q3[1]; 18 | x q2[0]; 19 | cx q2[0],q2[1]; 20 | x q2[1]; 21 | x q2[0]; 22 | -------------------------------------------------------------------------------- /tools/quarc/qasm_files/ult.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg q2[1]; 4 | qreg q3[1]; 5 | qreg q4[1]; 6 | qreg an[3]; 7 | h q2[0]; 8 | h q3[0]; 9 | x q3[0]; 10 | x an[1]; 11 | cx q3[0],an[1]; 12 | x q3[0]; 13 | ccx an[2],q2[0],q4[0]; 14 | cx q2[0],an[2]; 15 | cx an[0],q4[0]; 16 | ccx an[2],q3[0],q4[0]; 17 | cx q3[0],an[2]; 18 | cx an[1],q4[0]; 19 | x q3[0]; 20 | cx q3[0],an[1]; 21 | x an[1]; 22 | x q3[0]; 23 | -------------------------------------------------------------------------------- /tools/quarc/qasm_files/ult_grover.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg in2[1]; 4 | qreg in3[1]; 5 | qreg q2[1]; 6 | qreg an[3]; 7 | qreg q4[1]; 8 | qreg gout[1]; 9 | creg c0[2]; 10 | h in2[0]; 11 | h in3[0]; 12 | x in3[0]; 13 | x an[1]; 14 | cx in3[0],an[1]; 15 | x in3[0]; 16 | ccx an[2],in2[0],q2[0]; 17 | cx in2[0],an[2]; 18 | cx an[0],q2[0]; 19 | ccx an[2],in3[0],q2[0]; 20 | cx in3[0],an[2]; 21 | cx an[1],q2[0]; 22 | x in3[0]; 23 | cx in3[0],an[1]; 24 | x an[1]; 25 | x in3[0]; 26 | cx q2[0],q4[0]; 27 | x gout[0]; 28 | barrier in2[0],in3[0],q2[0],an[0],an[1],an[2],q4[0],gout[0]; 29 | cz q4[0],gout[0]; 30 | barrier in2[0],in3[0],q2[0],an[0],an[1],an[2],q4[0],gout[0]; 31 | cx q2[0],q4[0]; 32 | x in3[0]; 33 | x an[1]; 34 | cx in3[0],an[1]; 35 | x in3[0]; 36 | cx an[1],q2[0]; 37 | cx in3[0],an[2]; 38 | ccx an[2],in3[0],q2[0]; 39 | cx an[0],q2[0]; 40 | cx in2[0],an[2]; 41 | ccx an[2],in2[0],q2[0]; 42 | x in3[0]; 43 | cx in3[0],an[1]; 44 | x an[1]; 45 | x in3[0]; 46 | barrier in2[0],in3[0],q2[0],an[0],an[1],an[2],q4[0],gout[0]; 47 | h in2[0]; 48 | h in3[0]; 49 | x in2[0]; 50 | x in3[0]; 51 | h in2[0]; 52 | cx in3[0],in2[0]; 53 | h in2[0]; 54 | x in2[0]; 55 | x in3[0]; 56 | h in2[0]; 57 | h in3[0]; 58 | barrier in2[0],in3[0],q2[0],an[0],an[1],an[2],q4[0],gout[0]; 59 | measure in2[0] -> c0[0]; 60 | measure in3[0] -> c0[1]; 61 | -------------------------------------------------------------------------------- /tools/quarc/qasm_files/ulte.qasm: -------------------------------------------------------------------------------- 1 | OPENQASM 2.0; 2 | include "qelib1.inc"; 3 | qreg q2[1]; 4 | qreg q3[1]; 5 | qreg q4[1]; 6 | qreg an[7]; 7 | h q2[0]; 8 | h q3[0]; 9 | x q3[0]; 10 | x an[1]; 11 | cx q3[0],an[1]; 12 | x q3[0]; 13 | ccx an[2],q2[0],an[6]; 14 | cx q2[0],an[2]; 15 | cx an[0],an[6]; 16 | ccx an[2],q3[0],an[6]; 17 | cx q3[0],an[2]; 18 | cx an[1],an[6]; 19 | x q3[0]; 20 | cx q3[0],an[1]; 21 | x an[1]; 22 | x q3[0]; 23 | x an[4]; 24 | cx an[4],an[3]; 25 | cx q2[0],an[3]; 26 | cx q3[0],an[3]; 27 | cx an[3],an[5]; 28 | x an[6]; 29 | x an[5]; 30 | ccx an[6],an[5],q4[0]; 31 | x an[6]; 32 | x an[5]; 33 | -------------------------------------------------------------------------------- /tools/quarc/requirements.txt: -------------------------------------------------------------------------------- 1 | certifi==2024.7.4 2 | cffi==1.15.0 3 | charset-normalizer==2.0.12 4 | cryptography==44.0.1 5 | dill==0.3.5.1 6 | idna==3.7 7 | mpmath==1.3.0 8 | ntlm-auth==1.5.0 9 | numpy==1.22.4 10 | pbr==5.9.0 11 | ply==3.11 12 | psutil==5.9.1 13 | pycparser==2.21 14 | python-constraint==1.4.0 15 | python-dateutil==2.8.2 16 | qiskit==1.4.2 17 | qiskit-aer==0.10.4 18 | qiskit-ibmq-provider==0.19.1 19 | qiskit-ignis==0.7.1 20 | qiskit-terra==0.20.2 21 | requests==2.32.2 22 | requests-ntlm==1.1.0 23 | retworkx==0.11.0 24 | scipy==1.10.0 25 | six==1.16.0 26 | stevedore==3.5.0 27 | symengine==0.9.2 28 | sympy==1.10.1 29 | tweedledum==1.1.1 30 | urllib3==1.26.19 31 | websocket-client==1.3.3 32 | websockets==10.3 33 | -------------------------------------------------------------------------------- /tools/quarc/scripts/example_script.py: -------------------------------------------------------------------------------- 1 | from os import listdir 2 | from os.path import isfile, join 3 | path = "./test_files/" 4 | for f in listdir(path): 5 | if isfile(join(path, f)): 6 | file_name = f.split(".")[0] 7 | print(f"python main.py 1 {join(path, f)} ./qasm_files/{file_name}.qasm") -------------------------------------------------------------------------------- /tools/quarc/scripts/operators.bash: -------------------------------------------------------------------------------- 1 | python main.py 1 ./test_files/ite.btor2 ./qasm_files/ite.qasm 2 | python main.py 1 ./test_files/add.btor2 ./qasm_files/add.qasm 3 | python main.py 1 ./test_files/and.btor2 ./qasm_files/and.qasm 4 | python main.py 1 ./test_files/sub.btor2 ./qasm_files/sub.qasm 5 | python main.py 1 ./test_files/ulte.btor2 ./qasm_files/ulte.qasm 6 | python main.py 1 ./test_files/eq.btor2 ./qasm_files/eq.qasm 7 | python main.py 1 ./test_files/rem.btor2 ./qasm_files/rem.qasm 8 | python main.py 1 ./test_files/ult.btor2 ./qasm_files/ult.qasm 9 | python main.py 1 ./test_files/mul.btor2 ./qasm_files/mul.qasm 10 | python main.py 1 ./test_files/not.btor2 ./qasm_files/not.qasm 11 | python main.py 1 ./test_files/div.btor2 ./qasm_files/div.qasm 12 | -------------------------------------------------------------------------------- /tools/quarc/settings.py: -------------------------------------------------------------------------------- 1 | CONSTD = "constd" 2 | SORT = "sort" 3 | STATE = "state" 4 | INPUT = "input" 5 | NEXT = "next" 6 | ADD = "add" 7 | SUB = "sub" 8 | ITE = "ite" 9 | MUL = "mul" 10 | UEXT = "uext" 11 | ZERO = "zero" 12 | ONE = "one" 13 | DEC = "dec" 14 | INC = "inc" 15 | AND = "and" 16 | NOT = "not" 17 | EQ = "eq" 18 | ULT = "ult" 19 | ULTE = "ulte" 20 | UGT = "ugt" 21 | UGTE = "ugte" 22 | UDIV = "udiv" 23 | UREM = "urem" 24 | WRITE = "write" 25 | READ = "read" 26 | BAD = "bad" 27 | NEQ = "neq" 28 | INIT = "init" 29 | SLICE = "slice" -------------------------------------------------------------------------------- /tools/qubot/32_symbolic_experiment_statistics.csv: -------------------------------------------------------------------------------- 1 | architecture,file,logic_variables,time 2 | 32symbolic,memory-access-fail-1-35,0,0.08 3 | 32symbolic,nested-if-else-1-35,247258,6.52 4 | 32symbolic,nested-if-else-reverse-1-35,232693,6.43 5 | 32symbolic,recursive-ackermann-1-35,12748,1.8 6 | 32symbolic,recursive-factorial-fail-1-35,133282,4.4 7 | 32symbolic,recursive-fibonacci-1-10,196354,6.63 8 | 32symbolic,return-from-loop-1-35,37206,2.03 9 | 32symbolic,simple-assignment-1-35,44021,1.85 10 | 32symbolic,simple-if-else-1-35,65430,3.16 11 | 32symbolic,simple-if-else-reverse-1-35,70842,2.87 12 | 32symbolic,simple-if-without-else-1-35,116626,4.91 13 | 32symbolic,u,620,0.5 14 | 64symbolic,memory-access-fail-1-35,0,0.13 15 | 64symbolic,nested-if-else-1-35,365548,9.94 16 | 64symbolic,nested-if-else-reverse-1-35,350618,9.85 17 | 64symbolic,recursive-ackermann-1-35,11290,2.98 18 | 64symbolic,recursive-factorial-fail-1-35,33780,2.81 19 | 64symbolic,recursive-fibonacci-1-10,35411,3.14 20 | 64symbolic,return-from-loop-1-35,61740,3.03 21 | 64symbolic,simple-assignment-1-35,70369,3.07 22 | 64symbolic,simple-if-else-1-35,103691,4.76 23 | 64symbolic,simple-if-else-reverse-1-35,112047,4.77 24 | 64symbolic,simple-if-without-else-1-35,184418,6.07 25 | 64symbolic,u,718,0.92 26 | 64symbolic,invalid-memory-access-fail-2-35,14853,1.47 27 | 64symbolic,nested-recursion-fail-1-35,16366,2.54 28 | -------------------------------------------------------------------------------- /tools/qubot/64bit_btor2_files/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/tools/qubot/64bit_btor2_files/.DS_Store -------------------------------------------------------------------------------- /tools/qubot/README.md: -------------------------------------------------------------------------------- 1 | # QUBOT 2 | 3 | QUBOT is a bounded model checker and a symbolic execution engine. It generates a Binary Quadratic Model (BQM) in polynomic time, specifically a Quadratic Unconstrained Binary Optimization (QUBO) model, from a given BTOR2 file and a given number of timesteps *n*. QUBOs are special functions that quantum annealers can optimize. 4 | 5 | The purpose of QUBOT is to build a function whose ground state (global minimum value) equals 0 for all inputs that cause any bad state of a given BTOR2 file (e.g bad memory accesses, division by 0, etc.) in *n* or less arbitrarly executed instructions. 6 | 7 | 8 | ## Usage 9 | ```` Python 10 | from btor2bqm import BTor2BQM 11 | from bqm_input_checker import InputChecker # used only for debugging purposes 12 | 13 | parser = BTor2BQM(21) # creates a btor2 file parser of 21 timesteps 14 | bqm = parser.parse_file(f"./btor2files/a_btor2_file.btor2",f"./output_dir_path/", input_nid=81) 15 | 16 | # run an exact solver (with more than 21 variables it is really slow) 17 | result_sampleset = parser.run_exact_solver(f"./btor2files/a_btor2_file.btor2",f"./output_dir_path/", input_nid=81) 18 | 19 | # run DWave's quantum annealer 20 | result_sampleset = parser.run_quantum_solver(f"./btor2files/a_btor2_file.btor2",f"./output_dir_path/", input_nid=81) 21 | 22 | # debug generated function 23 | for i in range(0, 256): # test ascii decimal values that fit in 1 byte 24 | energy, error_states = InputChecker.run_checker(f"./output_dir_path/", i) 25 | print(f"{i}: ",energy, error_states) 26 | 27 | ```` 28 | 29 | If the model built by calling one of the three methods of `parser` is still in memory, 30 | you can use the method `BTor2BQM.get_variable_value(some_nid, timestep_t, result_sampleset)` to get any **nid** 31 | value at any timestep. 32 | 33 | Instead, `InputChecker` class loads everything from disk, the model that is saved at `./output_dir_path/` 34 | 35 | 36 | ## Prerequisites 37 | python >= 3.6 38 | 39 | 40 | ## Installation 41 | Install required libraries (a virtual environment is recommended): 42 | 43 | ```bash 44 | pip install -r requirements.txt 45 | ``` 46 | 47 | If you want to submit problems to DWave's quantum computer you should setup your configurations files after installing the libraries. 48 | Follow the [setup guide of Dwave](https://docs.ocean.dwavesys.com/en/latest/overview/install.html#set-up-your-environment). 49 | 50 | The file `quantum_computer_tests/pure_qa` contains further examples of how to use run a BQM in DWave's annealer. 51 | 52 | 53 | -------------------------------------------------------------------------------- /tools/qubot/asplos_main_example.py: -------------------------------------------------------------------------------- 1 | from bqm_input_checker import InputChecker 2 | from btor2bqm import BTor2BQM 3 | import os 4 | 5 | directories = ['../../32fsm', '../../64fsm'] 6 | files_106_steps = ['base_ram', 'baseline', 'base_lin', 'base_mmu', 'base_mr', '12bad', '12bad_lin', '12bad_mmu', '12bad_ram', '12bad_mr'] 7 | assert(len(files_106_steps) == 10) 8 | 9 | statistics_file = open(f"./main_experiment_statistics.csv", "w") 10 | statistics_file.write("architecture,file,logic_variables,time") 11 | 12 | for directory in directories: 13 | assert(len(os.listdir(directory)) == 20) 14 | directory_name = directory.split("/")[-1] 15 | c = 0 16 | for file in os.listdir(directory): 17 | print(f"{directory_name} - {file.split('.')[0]} ({c+1}/{len(os.listdir(directory))})") 18 | c+=1 19 | os.mkdir(f"./main_experiment_outputs/{directory_name}_{file.split('.')[0]}") 20 | 21 | log_file = open(f"./main_experiment_outputs/{directory_name}_{file.split('.')[0]}/log.txt", "w") 22 | log_file.write("architecture,file,logic_variables,time\n") 23 | 24 | if file.split('.')[0] in files_106_steps: 25 | print("building model for 106 state transitions") 26 | parser = BTor2BQM(106) 27 | else: 28 | print("building model for 37 state transitions") 29 | parser = BTor2BQM(37) 30 | _, total_time, num_variables = parser.parse_file(f"{directory}/{file}", 31 | f"./main_experiment_outputs/{directory_name}_{file.split('.')[0]}/", 32 | with_init=True, modify_memory_sort=True, log_file=log_file) 33 | statistics_file.write(f"{directory_name},{file.split('.')[0]},{num_variables},{total_time}\n") 34 | log_file.write("\n") 35 | for i in range(256): 36 | energy, bad_states = InputChecker.run_checker(f'./main_experiment_outputs/{directory_name}_{file.split(".")[0]}/', i) 37 | if i == 49: 38 | assert (energy == 0 and len(bad_states) == 1) 39 | else: 40 | assert (energy == 2 and len(bad_states) == 0) 41 | log_file.write(f"test for input {i}: {energy},{bad_states}\n") 42 | log_file.close() 43 | print() 44 | statistics_file.close() 45 | -------------------------------------------------------------------------------- /tools/qubot/bit_transformation/more_gates/classical_gates.py: -------------------------------------------------------------------------------- 1 | def l_NOT(x1): 2 | return not x1 3 | 4 | def l_NAND(x1, x2): 5 | return not (x1 and x2) 6 | 7 | def l_AND(x1, x2): 8 | return x1 and x2 9 | 10 | def l_XOR(x1, x2): 11 | return x1 != x2 12 | 13 | def l_XNOR(x1, x2): 14 | return x1 == x2 -------------------------------------------------------------------------------- /tools/qubot/bit_transformation/more_gates/xor.py: -------------------------------------------------------------------------------- 1 | from bit_transformation.more_gates.classical_gates import * 2 | import itertools 3 | from dimod import ExactSolver 4 | from bit_transformation.bit_penalty_models import get_model 5 | from bit_transformation.configurations import Config 6 | 7 | def test_circuit(): 8 | for (x1, x2) in list(itertools.product([0, 1], repeat=2)): 9 | n_x1 = l_NOT(x1) 10 | n_x2 = l_NOT(x2) 11 | result = l_AND(l_NAND(x1, x2), l_NAND(n_x1,n_x2)) 12 | assert(result == l_XOR(x1, x2)) 13 | 14 | 15 | def get_XOR(var_names=None): 16 | if var_names is None: 17 | var_names = { 18 | 'x1': 0, 19 | 'x2': 1, 20 | 'nx1': 2, 21 | 'nx2': 3, 22 | 'nand1': 4, 23 | 'nand2': 5, 24 | 'z': 6 25 | } 26 | model, _ = get_model(Config.NOT, [var_names['x1'], var_names['nx1']]) 27 | model.update(get_model(Config.NOT, [var_names['x2'], var_names['nx2']])[0]) 28 | model.update(get_model(Config.NAND, [var_names['x1'], var_names['x2'], var_names['nand1']])[0]) 29 | model.update(get_model(Config.NAND, [var_names['nx1'], var_names['nx2'], var_names['nand2']])[0]) 30 | model.update(get_model(Config.AND, [var_names['nand1'], var_names['nand2'], var_names['z']])[0]) 31 | return model 32 | 33 | def test_quantum_circuit(): 34 | f = open("./results/XOR.csv", "w") 35 | f.write(f'x1,x2,~x1,~x2,NAND(x1-x2),NAND(~x1-~x2),z,E\n') 36 | 37 | for (x1, x2) in list(itertools.product([0, 1], repeat=2)): 38 | model = get_XOR() 39 | model.fix_variable('x1', x1) 40 | model.fix_variable('x2', x2) 41 | sampler = ExactSolver() 42 | result = sampler.sample(model).first 43 | vars = result[0] 44 | energy = result.energy 45 | f.write(f"{x1},{x2},{vars['nx1']},{vars['nx2']},{vars['nand1']}, {vars['nand2']},{vars['z']},{round(energy,2)}\n") 46 | assert(l_NOT(x1) == vars['nx1']) 47 | assert(l_NOT(x2) == vars['nx2']) 48 | assert(l_NAND(x1,x2) == vars['nand1']) 49 | assert(l_NAND(l_NOT(x1),l_NOT(x2)) == vars['nand2']) 50 | assert(l_XOR(x1,x2) == vars['z']) 51 | 52 | 53 | if __name__ == '__main__': 54 | test_circuit() 55 | test_quantum_circuit() -------------------------------------------------------------------------------- /tools/qubot/dummy_btor2files/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/tools/qubot/dummy_btor2files/.DS_Store -------------------------------------------------------------------------------- /tools/qubot/main_experiment_statistics.csv: -------------------------------------------------------------------------------- 1 | architecture,file,logic_variables,time 2 | 32fsm,12bad_const,69699,2.14 3 | 32fsm,baseline,91691,5.19 4 | 32fsm,base_mr,99899,5.93 5 | 32fsm,const_mr,88686,3.57 6 | 32fsm,base_lin,90775,5.5 7 | 32fsm,12bad_c_lin,68966,2.41 8 | 32fsm,12bad_lin,90346,5.31 9 | 32fsm,const_prop,70128,2.55 10 | 32fsm,const_lin,69395,2.28 11 | 32fsm,base_mmu,106134,6.51 12 | 32fsm,base_ram,114855,6.6 13 | 32fsm,const_mmu,97558,3.3 14 | 32fsm,12bad_c_mr,88257,2.81 15 | 32fsm,const_ram,104637,3.55 16 | 32fsm,12bad,91262,5.3 17 | 32fsm,12bad_mmu,105705,7.74 18 | 32fsm,12bad_c_ram,104208,3.43 19 | 32fsm,12bad_ram,114426,7.23 20 | 32fsm,12bad_mr,99470,5.72 21 | 32fsm,12bad_c_mmu,97129,3.25 22 | 64fsm,12bad_const,138267,4.45 23 | 64fsm,baseline,180447,10.06 24 | 64fsm,base_mr,196619,10.53 25 | 64fsm,const_mr,173139,5.47 26 | 64fsm,base_lin,163691,10.03 27 | 64fsm,12bad_c_lin,124862,4.59 28 | 64fsm,12bad_lin,162837,9.43 29 | 64fsm,const_prop,139121,4.53 30 | 64fsm,const_lin,125716,4.27 31 | 64fsm,base_mmu,204359,12.78 32 | 64fsm,base_ram,221044,12.76 33 | 64fsm,const_mmu,187644,6.59 34 | 64fsm,12bad_c_mr,172285,5.75 35 | 64fsm,const_ram,201631,7.21 36 | 64fsm,12bad,179593,10.55 37 | 64fsm,12bad_mmu,203505,11.18 38 | 64fsm,12bad_c_ram,200777,7.01 39 | 64fsm,12bad_ram,220190,12.42 40 | 64fsm,12bad_mr,195765,11.94 41 | 64fsm,12bad_c_mmu,186790,7.64 42 | -------------------------------------------------------------------------------- /tools/qubot/qa_examples/chimera_embedding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/tools/qubot/qa_examples/chimera_embedding.png -------------------------------------------------------------------------------- /tools/qubot/qa_examples/d_embedding.csv: -------------------------------------------------------------------------------- 1 | ,file_name,wordsize,logic_vars,emb_max_time,emb_min_time,emb_median_time,emb_avg_time,emb_max_chain,emb_min_chain,emb_median_chain,emb_avg_chain,emb_max_vars,emb_min_vars,emb_median_vars,emb_avg_vars,topology 2 | 0,d.btor2,32,1414,411.4,411.4,411.4,411.4,62,1,2.0,3.18,4498,4498,4498,4498.0,pegasus 3 | -------------------------------------------------------------------------------- /tools/qubot/qa_examples/pegasus_embedding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/tools/qubot/qa_examples/pegasus_embedding.png -------------------------------------------------------------------------------- /tools/qubot/qa_examples/u_embedding.csv: -------------------------------------------------------------------------------- 1 | ,file_name,wordsize,logic_vars,emb_max_time,emb_min_time,emb_median_time,emb_avg_time,emb_max_chain,emb_min_chain,emb_median_chain,emb_avg_chain,emb_max_vars,emb_min_vars,emb_median_vars,emb_avg_vars,topology 2 | 0,u.btor2,32,348,23.2,0.87,5.41,8.29,31,1,2.0,3.18,1201,998,1110.0,1106.0,chimera 3 | 1,u.btor2,64,398,26.77,2.43,9.45,12.16,29,1,2.0,2.83,1203,1052,1126.0,1124.9,chimera 4 | 2,u.btor2,32,348,4.44,1.87,3.08,3.12,11,1,1.0,1.69,628,555,584.5,588.6,pegasus 5 | 3,u.btor2,64,398,7.82,3.89,4.87,5.29,12,1,1.0,1.7,711,652,680.5,677.0,pegasus 6 | -------------------------------------------------------------------------------- /tools/qubot/quantum_computer_tests/.ipynb_checkpoints/Untitled-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [], 3 | "metadata": {}, 4 | "nbformat": 4, 5 | "nbformat_minor": 5 6 | } 7 | -------------------------------------------------------------------------------- /tools/qubot/quantum_computer_tests/.ipynb_checkpoints/Untitled1-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [], 3 | "metadata": {}, 4 | "nbformat": 4, 5 | "nbformat_minor": 5 6 | } 7 | -------------------------------------------------------------------------------- /tools/qubot/qubit_growth_script.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cksystemsteaching/selfie/51bd1d4fe222bc483f6fd483c64b0a91bbeecc52/tools/qubot/qubit_growth_script.py -------------------------------------------------------------------------------- /tools/qubot/qword.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional, Dict 2 | from settings import * 3 | from tools import * 4 | 5 | 6 | class QWord: 7 | """ 8 | This class is a general abstraction of a piece of memory. This class group qubits to represent 9 | a variable/constant and change its value as required. 10 | """ 11 | size_in_bits: int 12 | name: str 13 | states: Dict[int, List[int]] # we don't use a vector cause we will create qwords whose first record is 14 | # not necessarily a first step 15 | last_n: int 16 | 17 | def __init__(self, size_in_bits: int = 64, name: str = ""): 18 | """ 19 | @param size_in_bits: this is the number of bits that this 'piece of memory occupies'. Default is WORD_SIZE, a variable 20 | declared at settings.py 21 | :rtype: object 22 | """ 23 | 24 | self.states = {} # saves the transformations of qubits. Each element of this array is an array with 25 | # size_in_bits elements. These elements are the names of the qubits that represent 26 | # this variable in a given transformation. 27 | self.size_in_bits = size_in_bits 28 | self.name = name 29 | self.last_n = -1 30 | 31 | def __len__(self): 32 | return len(self.states) 33 | 34 | def __getitem__(self, i): 35 | return self.states[i] 36 | 37 | def __repr__(self): 38 | return self.states.__str__() 39 | 40 | def append_state(self, state: List[int], n: int) -> None: 41 | self.last_n = max(n, self.last_n) 42 | self.states[n] = state 43 | 44 | def create_state(self, bqm: dimod.BinaryQuadraticModel, n: int) -> List[int]: 45 | """ 46 | creates a state with qubits in perfect superposition. 47 | 48 | @param bqm: binary quadratic model to update. 49 | @return: the new state created 50 | """ 51 | self.last_n = max(n, self.last_n) 52 | 53 | state_index = len(self) # we need index of the timestep we are creating to name the newly 54 | # created qubits 55 | qubits = [GlobalIndexer.get_name_index() for _ in range(self.size_in_bits)] 56 | for qubit in qubits: 57 | bqm.add_variable(qubit) 58 | self.append_state(qubits, n) 59 | return qubits 60 | 61 | @property 62 | def top(self) -> Optional[List[int]]: 63 | if self.states[self.last_n]: 64 | if len(self.states[self.last_n]) > 0: 65 | return self.states[self.last_n] 66 | assert False 67 | -------------------------------------------------------------------------------- /tools/qubot/requirements.txt: -------------------------------------------------------------------------------- 1 | absl-py==0.14.0 2 | appnope==0.1.2 3 | argon2-cffi==21.1.0 4 | attrs==21.2.0 5 | backcall==0.2.0 6 | bleach==4.1.0 7 | certifi==2024.7.4 8 | cffi==1.15.0 9 | charset-normalizer==2.0.6 10 | click==8.0.1 11 | cycler==0.10.0 12 | debugpy==1.5.1 13 | decorator==4.4.2 14 | defusedxml==0.7.1 15 | Deprecated==1.2.13 16 | dimod==0.10.7 17 | diskcache==5.2.1 18 | dwave-cloud-client==0.9.2 19 | dwave-greedy==0.2.1 20 | dwave-hybrid==0.6.4 21 | dwave-inspector 22 | dwave-inspectorapp 23 | dwave-neal==0.5.8 24 | dwave-networkx==0.8.10 25 | dwave-ocean-sdk==4.2.0 26 | dwave-preprocessing==0.3.1.post0 27 | dwave-qbsolv==0.3.3 28 | dwave-system==1.10.0 29 | dwave-tabu==0.4.2 30 | dwavebinarycsp==0.1.3 31 | ipykernel==6.4.1 32 | ipython==8.10.0 33 | ipython-genutils==0.2.0 34 | ipywidgets==7.6.5 35 | jsonschema==4.1.0 36 | jupyter==1.0.0 37 | jupyter-client==7.0.6 38 | jupyter-console==6.4.0 39 | jupyter-core==4.11.2 40 | jupyterlab-pygments==0.1.2 41 | jupyterlab-widgets==1.0.2 42 | kiwisolver==1.3.2 43 | minorminer==0.2.6 44 | nbclient==0.5.4 45 | nbconvert==6.5.1 46 | nbformat==5.1.3 47 | nest-asyncio==1.5.1 48 | networkx==2.6.3 49 | notebook==6.4.12 50 | numpy==1.22.0 51 | ortools==8.2.8710 52 | packaging==21.0 53 | pandocfilters==1.5.0 54 | parso==0.8.2 55 | pexpect==4.8.0 56 | pickleshare==0.7.5 57 | plucky==0.4.3 58 | prometheus-client==0.11.0 59 | prompt-toolkit==3.0.20 60 | ptyprocess==0.7.0 61 | pycparser==2.20 62 | pydantic==1.10.13 63 | Pygments==2.15.0 64 | pyparsing==2.4.7 65 | pyqubo==1.0.13 66 | pyrsistent==0.18.0 67 | python-dateutil==2.8.2 68 | requests==2.32.0 69 | terminado==0.12.1 70 | typing-extensions==3.10.0.2 71 | wcwidth==0.2.5 72 | webencodings==0.5.1 73 | widgetsnbextension==3.5.1 74 | -------------------------------------------------------------------------------- /tools/qubot/script.py: -------------------------------------------------------------------------------- 1 | from bqm_input_checker import InputChecker 2 | from btor2bqm import BTor2BQM 3 | 4 | parser = BTor2BQM(15) 5 | print(parser.parse_file(f"../../64symbolic/u.btor2", 6 | f"./temp_result/", 7 | with_init=True, modify_memory_sort=True)) 8 | 9 | for i in range(256): 10 | print(f"{i}: ",InputChecker.run_checker("./temp_result/", i)) 11 | -------------------------------------------------------------------------------- /tools/qubot/scripts/32bit_paper_example.py: -------------------------------------------------------------------------------- 1 | from bqm_input_checker import InputChecker 2 | from btor2bqm import BTor2BQM 3 | 4 | def run_input_checker(path): 5 | print(f"running input checker ({path})") 6 | file = open(f"{path}result.csv", "w") 7 | file.write("input, bias, error_states\n") 8 | for i in range(0, 256): 9 | #print("running input:",i) 10 | bias, error_states = InputChecker.run_checker(path, i) 11 | if bias < 0: 12 | print(f"FAIL: test failed for ({path})") 13 | return False 14 | if i != 49: 15 | if bias == 0: 16 | print(f"FAIL: {path} non zero energy for input={i}") 17 | return False 18 | else: 19 | if bias != 0: 20 | print(f"FAIL: {path} gives non zero energy for correct input") 21 | return False 22 | string_errors = "" 23 | for error in error_states: 24 | if len(string_errors) == 0: 25 | string_errors = str(error) 26 | else: 27 | string_errors += f" {error}" 28 | file.write(f"{i},{bias},{string_errors}\n") 29 | file.close() 30 | return True 31 | 32 | btor2files = { 33 | '32base_mr': 107, 34 | '32const_mr': 37, 35 | '32_12bad_mr':107, 36 | '32_12bad_c_mr': 37, 37 | '32_12bad': 107, 38 | '32_12bad_c_lin': 37, 39 | '32_12bad_c_mmu': 37, 40 | '32_12bad_c_ram': 37, 41 | '32_12bad_const': 37, 42 | '32baseline': 107, 43 | '32const_lin': 37, 44 | '32const_mmu': 37, 45 | '32const_prop': 37, 46 | '32const_ram': 37, 47 | '32base_lin': 107, 48 | '32base_ram': 107, 49 | '32_12bad_lin':107, 50 | '32_12bad_mmu': 107, 51 | '32_12bad_ram': 107, 52 | '32base_mmu': 107 53 | } 54 | 55 | 56 | 57 | for btor2file in btor2files.keys(): 58 | parser = BTor2BQM(btor2files[btor2file]) 59 | parser.parse_file(f"./32bit_running_examples/{btor2file}.btor2", 60 | f"./32_bit_results/{btor2file}/", 61 | with_init=True, modify_memory_sort=True) 62 | run_input_checker(f"./32_bit_results/{btor2file}/") 63 | 64 | -------------------------------------------------------------------------------- /tools/qubot/scripts/32symbolic_nomem.py: -------------------------------------------------------------------------------- 1 | import os 2 | directory = "examples/symbolic" 3 | 4 | for file in os.listdir(directory): 5 | if file not in ["invalid-memory-access-fail-2-35.c","nested-recursion-fail-1-35.c"]: 6 | 7 | path = f"{directory}/{file}" 8 | file_name = file.split(".")[0] 9 | heap_allowance = 0 10 | stack_allowance = 0 11 | extra_flags = "--constant-propagation --linear-address-space --MMURAM" 12 | exit_code = os.system(f"./beator-32 -c {path} - 0 --heap-allowance {heap_allowance} --stack-allowance {stack_allowance} {extra_flags}\n") 13 | assert(exit_code == 0) 14 | exit_code = os.system(f"mv {directory}/{file_name}.btor2 32symbolic_nomem/{file_name}.btor2\n") 15 | assert(exit_code == 0) 16 | -------------------------------------------------------------------------------- /tools/qubot/scripts/64bit_paper_example.py: -------------------------------------------------------------------------------- 1 | from bqm_input_checker import InputChecker 2 | from btor2bqm import BTor2BQM 3 | 4 | def run_input_checker(path): 5 | print(f"running input checker ({path})") 6 | file = open(f"{path}result.csv", "w") 7 | file.write("input, bias, error_states\n") 8 | for i in range(0, 256): 9 | #print("running input:",i) 10 | bias, error_states = InputChecker.run_checker(path, i) 11 | if bias < 0: 12 | print(f"FAIL: test failed for ({path})") 13 | return False 14 | if i != 49: 15 | if bias == 0: 16 | print(f"FAIL: {path} non zero energy for input={i}") 17 | return False 18 | else: 19 | if bias != 0: 20 | print(f"FAIL: {path} gives non zero energy for correct input") 21 | return False 22 | #print(bias, error_states) 23 | string_errors = "" 24 | for error in error_states: 25 | if len(string_errors) == 0: 26 | string_errors = str(error) 27 | else: 28 | string_errors += f" {error}" 29 | file.write(f"{i},{bias},{string_errors}\n") 30 | file.close() 31 | return True 32 | 33 | btor2files = {'12bad': 107, 34 | '12bad_c_lin': 37, 35 | '12bad_c_mmu': 37, 36 | '12bad_c_ram': 37, 37 | '12bad_const': 37, 38 | 'baseline': 107, 39 | 'const_lin': 37, 40 | 'const_mmu': 37, 41 | 'const_prop': 37, 42 | 'const_ram': 37, 43 | 'base_lin': 107, 44 | 'base_ram': 107, 45 | '12bad_lin':107, 46 | '12bad_mmu': 107, 47 | '12bad_ram': 107, 48 | 'base_mmu': 107, 49 | 'base_mr': 107, 50 | 'const_mr': 37, 51 | '12bad_mr': 107, 52 | '12bad_c_mr': 37 53 | } 54 | 55 | 56 | 57 | for btor2file in btor2files.keys(): 58 | parser = BTor2BQM(btor2files[btor2file]) 59 | parser.parse_file(f"../b64bit_btor2_files/{btor2file}.btor2", 60 | f"../paper_results/{btor2file}/", 61 | with_init=True, modify_memory_sort=True) 62 | run_input_checker(f"./paper_results/{btor2file}/") 63 | 64 | -------------------------------------------------------------------------------- /tools/qubot/scripts/64symbolic_nomem.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | directory = "examples/symbolic" 4 | 5 | for file in os.listdir(directory): 6 | path = f"{directory}/{file}" 7 | file_name = file.split(".")[0] 8 | heap_allowance = 0 9 | stack_allowance = 0 10 | extra_flags = "--constant-propagation --linear-address-space --MMURAM" 11 | exit_code = os.system(f"./beator -c {path} - 0 --heap-allowance {heap_allowance} --stack-allowance {stack_allowance} {extra_flags}") 12 | assert(exit_code == 0) 13 | exit_code = os.system(f"mv {directory}/{file_name}.btor2 64symbolic_nomem/{file_name}.btor2") 14 | assert(exit_code == 0) -------------------------------------------------------------------------------- /tools/qubot/scripts/qubit_growth.py: -------------------------------------------------------------------------------- 1 | btor2files_32 = { 2 | '32const_mr': 37,'32_12bad_c_mr': 37,'32_12bad_c_lin': 37,'32_12bad_c_mmu': 37,'32_12bad_c_ram': 37, 3 | '32_12bad_const': 37, '32const_lin': 37, '32const_mmu': 37, '32const_prop': 37, '32const_ram': 37, 4 | } 5 | 6 | btor2files_64 = { 7 | '12bad_c_lin': 37, '12bad_c_mmu': 37, '12bad_c_ram': 37, '12bad_const': 37, 'const_lin': 37, 8 | 'const_mmu': 37, 'const_prop': 37, 'const_ram': 37, 'const_mr': 37, '12bad_c_mr': 37 9 | } 10 | 11 | 12 | file = open("./qubit_growth.csv", "w") 13 | file.write("file,n,qubits\n") 14 | 15 | from btor2bqm import BTor2BQM 16 | 17 | for (btor2, timesteps) in btor2files_32.items(): 18 | parser = BTor2BQM(80) 19 | parser.parse_file(f"./32bit_running_examples/{btor2}.btor2", "./temp/", with_init=True, modify_memory_sort=True, qubit_growth_file=file) 20 | 21 | for (btor2, timesteps) in btor2files_64.items(): 22 | parser = BTor2BQM(80) 23 | parser.parse_file(f"./btor2_running_example/{btor2}.btor2", "./temp/", with_init=True, modify_memory_sort=True, qubit_growth_file=file) 24 | -------------------------------------------------------------------------------- /tools/qubot/settings.py: -------------------------------------------------------------------------------- 1 | # this file declares constant values 2 | 3 | import dimod 4 | 5 | BQM_TYPE = dimod.BINARY 6 | 7 | CONSTD = "constd" 8 | SORT = "sort" 9 | STATE = "state" 10 | INPUT = "input" 11 | NEXT = "next" 12 | ADD = "add" 13 | SUB = "sub" 14 | ITE = "ite" 15 | MUL = "mul" 16 | UEXT = "uext" 17 | ZERO = "zero" 18 | ONE = "one" 19 | DEC = "dec" 20 | INC = "inc" 21 | AND = "and" 22 | NOT = "not" 23 | EQ = "eq" 24 | ULT = "ult" 25 | ULTE = "ulte" 26 | UGT = "ugt" 27 | UGTE = "ugte" 28 | UDIV = "udiv" 29 | UREM = "urem" 30 | WRITE = "write" 31 | READ = "read" 32 | BAD = "bad" 33 | NEQ = "neq" 34 | INIT = "init" 35 | SLICE = "slice" 36 | 37 | # rules 38 | NAND = "NAND" 39 | R_AND = "AND" 40 | OR = "OR" 41 | XNOR = "XNOR" 42 | AUX_HALF_ADDER = "AUX_HALF_ADDER" 43 | AUX_FULL_ADDER = "AUX_FULL_ADDER" 44 | R_NOT = "NOT" 45 | CARRY_HALF_ADDER = "CARRY_HALF_ADDER" 46 | CARRY_FULL_ADDER = "CARRY_FULL_ADDER" 47 | RESULT_HALF_ADDER = "RESULT_HALF_ADDER" 48 | RESULT_FULL_ADDER = "RESULT_FULL_ADDER" 49 | MATRIARCH1 = "MATRIARCH1" 50 | XOR = "XOR" 51 | QUOTIENT = "QUOTIENT" 52 | REMAINDER = "REMAINDER" 53 | 54 | -------------------------------------------------------------------------------- /tools/qubot/symbolic_experiment_statistics.csv: -------------------------------------------------------------------------------- 1 | architecture,file,logic_variables,time 2 | 32symbolic,division-by-zero-3-35,4616,0.62 3 | 64symbolic,division-by-zero-3-35,17416,1.3 4 | --------------------------------------------------------------------------------