The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .github
    └── workflows
    │   ├── in-game-tests.yml
    │   └── rust-tests.yml
├── .gitignore
├── .gitmodules
├── LICENSE
├── README.md
├── app
    ├── doom3d
    │   ├── .cargo
    │   │   └── config.toml
    │   ├── .vimspector.json
    │   ├── Cargo.lock
    │   ├── Cargo.toml
    │   ├── build.rs
    │   ├── copy-bin.sh
    │   └── src
    │   │   ├── main.rs
    │   │   ├── maps.rs
    │   │   └── raycaster.rs
    ├── game-of-life
    │   ├── .cargo
    │   │   └── config.toml
    │   ├── .vimspector.json
    │   ├── Cargo.lock
    │   ├── Cargo.toml
    │   ├── copy-bin.sh
    │   └── src
    │   │   └── main.rs
    ├── pong
    │   ├── .cargo
    │   │   └── config.toml
    │   ├── .vimspector.json
    │   ├── Cargo.lock
    │   ├── Cargo.toml
    │   ├── copy-bin.sh
    │   └── src
    │   │   └── main.rs
    ├── tdriver
    │   ├── .cargo
    │   │   └── config.toml
    │   ├── .gitignore
    │   ├── Cargo.lock
    │   ├── Cargo.toml
    │   ├── build.rs
    │   ├── link.x
    │   ├── rust-analyzer.toml
    │   └── src
    │   │   ├── graphics.rs
    │   │   └── lib.rs
    ├── template
    │   ├── .cargo
    │   │   └── config.toml
    │   ├── .vimspector.json
    │   ├── Cargo.lock
    │   ├── Cargo.toml
    │   ├── README.md
    │   ├── copy-bin.sh
    │   └── src
    │   │   └── main.rs
    ├── tetris
    │   ├── .cargo
    │   │   └── config.toml
    │   ├── .vimspector.json
    │   ├── Cargo.lock
    │   ├── Cargo.toml
    │   ├── copy-bin.sh
    │   └── src
    │   │   ├── main.rs
    │   │   └── tiles.rs
    └── video
    │   ├── .cargo
    │       └── config.toml
    │   ├── .vimspector.json
    │   ├── Cargo.lock
    │   ├── Cargo.toml
    │   ├── assets
    │       └── bad-apple.mp4
    │   ├── build.py
    │   ├── copy-bin.sh
    │   └── src
    │       ├── main.rs
    │       └── video.rs
├── computerraria.tar.gz
├── computerraria.twld
├── copy-world.sh
├── doc
    ├── img
    │   ├── control-panel.png
    │   ├── logo-old.png
    │   ├── logo.png
    │   ├── pong-still.png
    │   └── poster-small.png
    ├── logo-old.pixil
    ├── logo.pixil
    ├── notes.txt
    ├── old-worlds
    │   ├── blank.wld
    │   └── computer.wld
    ├── reference
    │   └── computer-old.wld
    └── riscv.pdf
├── docker
    ├── Dockerfile
    ├── build.sh
    ├── push.sh
    ├── run.sh
    └── tModLoader.targets
├── run-tests.sh
├── test
    ├── .gitignore
    ├── computerraria
    │   ├── computerraria_isa.yaml
    │   ├── computerraria_platform.yaml
    │   ├── env
    │   │   ├── link.ld
    │   │   └── model_test.h
    │   └── riscof_computerraria.py
    ├── config.ini
    ├── manual
    │   ├── inf.s
    │   ├── inf.txt
    │   ├── loop.s
    │   └── loop.txt
    └── sail_cSim
    │   ├── __init__.py
    │   ├── env
    │       ├── link.ld
    │       └── model_test.h
    │   └── riscof_sail_cSim.py
└── tinterface
    ├── bin
        └── tcli
    ├── setup.py
    └── tinterface
        └── __init__.py


/.github/workflows/in-game-tests.yml:
--------------------------------------------------------------------------------
 1 | name: Compliance Tests
 2 | run-name: Compliance Tests
 3 | on: 
 4 |   push:
 5 |     paths:
 6 |     - 'computer.wld'
 7 |     - 'test/**'
 8 |     - 'tinterface/**'
 9 |     branches:
10 |     - main
11 |   repository_dispatch:
12 |   workflow_dispatch:
13 | 
14 | jobs:
15 |   riscof:
16 |     name: RISCV Compliance Tests
17 |     runs-on: ubuntu-latest
18 |     container: misprit7/computerraria:latest
19 |     steps:
20 |     - name: Compile WireHead
21 |       run: |
22 |         cd /root/.local/share/Terraria/tModLoader/ModSources &&\
23 |         git clone https://github.com/misprit7/WireHead.git &&\
24 |         cd WireHead &&\
25 |         dotnet build
26 | 
27 |     - name: Checkout computerraria
28 |       uses: actions/checkout@v3
29 |       with:
30 |         submodules: recursive
31 | 
32 |     - name: Install tinterface
33 |       run: pip3 install --break-system-packages -e ./tinterface
34 | 
35 |     - name: Run riscof tests
36 |       run: ./run-tests.sh
37 | 
38 |     - name: Upload results
39 |       if: always()
40 |       uses: actions/upload-artifact@v3
41 |       with:
42 |         name: Result summary
43 |         path: |
44 |           ./test/riscof_work/
45 | 
46 | 


--------------------------------------------------------------------------------
/.github/workflows/rust-tests.yml:
--------------------------------------------------------------------------------
 1 | name: Rust Apps
 2 | run-name: Rust Apps
 3 | on: 
 4 |   push:
 5 |     paths:
 6 |       - 'app/**'
 7 |     branches:
 8 |     - main
 9 |   workflow_dispatch:
10 | 
11 | env:
12 |   CARGO_TERM_COLOR: always
13 | 
14 | jobs:
15 |   Build:
16 | 
17 |     runs-on: ubuntu-latest
18 | 
19 |     steps:
20 |     - name: Checkout computerraria
21 |       uses: actions/checkout@v3
22 | 
23 |     - name: Build
24 |       run: |
25 |         rustup target add riscv32i-unknown-none-elf
26 |         for i in app/* ; do
27 |           if [ -d "$i" ]; then
28 |             echo "::group::$i"
29 |             cargo build --verbose --manifest-path="$i/Cargo.toml"
30 |             cargo build --target=riscv32i-unknown-none-elf --verbose --manifest-path="$i/Cargo.toml"
31 |             echo "::endgroup"
32 |           fi
33 |         done
34 | 
35 | 
36 | 


--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
  1 | # Computerraria's world is very large (~400mb) but compresses very well. Since it's binary anyways I compress it so it's not stored directly
  2 | computerraria.wld
  3 | 
  4 | # Terraria world backups
  5 | *.twld.bak
  6 | *.wld.bak
  7 | *.wld.bak2
  8 | 
  9 | # Me being dumb
 10 | --to
 11 | 
 12 | # Docker secrets
 13 | docker/.env
 14 | 
 15 | # Docker build artifact
 16 | docker/riscv_sim_RV32
 17 | 
 18 | # Byte-compiled / optimized / DLL files
 19 | __pycache__/
 20 | *.py[cod]
 21 | *$py.class
 22 | 
 23 | # C extensions
 24 | *.so
 25 | 
 26 | # Distribution / packaging
 27 | .Python
 28 | build/
 29 | develop-eggs/
 30 | dist/
 31 | downloads/
 32 | eggs/
 33 | .eggs/
 34 | lib/
 35 | lib64/
 36 | parts/
 37 | sdist/
 38 | var/
 39 | wheels/
 40 | share/python-wheels/
 41 | *.egg-info/
 42 | .installed.cfg
 43 | *.egg
 44 | MANIFEST
 45 | 
 46 | # PyInstaller
 47 | #  Usually these files are written by a python script from a template
 48 | #  before PyInstaller builds the exe, so as to inject date/other infos into it.
 49 | *.manifest
 50 | *.spec
 51 | 
 52 | # Installer logs
 53 | pip-log.txt
 54 | pip-delete-this-directory.txt
 55 | 
 56 | # Unit test / coverage reports
 57 | htmlcov/
 58 | .tox/
 59 | .nox/
 60 | .coverage
 61 | .coverage.*
 62 | .cache
 63 | nosetests.xml
 64 | coverage.xml
 65 | *.cover
 66 | *.py,cover
 67 | .hypothesis/
 68 | .pytest_cache/
 69 | cover/
 70 | 
 71 | # Translations
 72 | *.mo
 73 | *.pot
 74 | 
 75 | # Django stuff:
 76 | *.log
 77 | local_settings.py
 78 | db.sqlite3
 79 | db.sqlite3-journal
 80 | 
 81 | # Flask stuff:
 82 | instance/
 83 | .webassets-cache
 84 | 
 85 | # Scrapy stuff:
 86 | .scrapy
 87 | 
 88 | # Sphinx documentation
 89 | docs/_build/
 90 | 
 91 | # PyBuilder
 92 | .pybuilder/
 93 | target/
 94 | 
 95 | # Jupyter Notebook
 96 | .ipynb_checkpoints
 97 | 
 98 | # IPython
 99 | profile_default/
100 | ipython_config.py
101 | 
102 | # pyenv
103 | #   For a library or package, you might want to ignore these files since the code is
104 | #   intended to run in multiple environments; otherwise, check them in:
105 | # .python-version
106 | 
107 | # pipenv
108 | #   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
109 | #   However, in case of collaboration, if having platform-specific dependencies or dependencies
110 | #   having no cross-platform support, pipenv may install dependencies that don't work, or not
111 | #   install all needed dependencies.
112 | #Pipfile.lock
113 | 
114 | # poetry
115 | #   Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
116 | #   This is especially recommended for binary packages to ensure reproducibility, and is more
117 | #   commonly ignored for libraries.
118 | #   https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
119 | #poetry.lock
120 | 
121 | # pdm
122 | #   Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
123 | #pdm.lock
124 | #   pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
125 | #   in version control.
126 | #   https://pdm.fming.dev/#use-with-ide
127 | .pdm.toml
128 | 
129 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
130 | __pypackages__/
131 | 
132 | # Celery stuff
133 | celerybeat-schedule
134 | celerybeat.pid
135 | 
136 | # SageMath parsed files
137 | *.sage.py
138 | 
139 | # Environments
140 | .env
141 | .venv
142 | # env/
143 | venv/
144 | ENV/
145 | env.bak/
146 | venv.bak/
147 | 
148 | # Spyder project settings
149 | .spyderproject
150 | .spyproject
151 | 
152 | # Rope project settings
153 | .ropeproject
154 | 
155 | # mkdocs documentation
156 | /site
157 | 
158 | # mypy
159 | .mypy_cache/
160 | .dmypy.json
161 | dmypy.json
162 | 
163 | # Pyre type checker
164 | .pyre/
165 | 
166 | # pytype static type analyzer
167 | .pytype/
168 | 
169 | # Cython debug symbols
170 | cython_debug/
171 | 
172 | 


--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "test/riscv-arch-test"]
2 | 	path = test/riscv-arch-test
3 | 	url = https://github.com/misprit7/riscv-arch-test-low-mem.git
4 | 


--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
 1 | MIT License
 2 | 
 3 | Copyright (c) 2023 Xander Naumenko
 4 | 
 5 | Permission is hereby granted, free of charge, to any person obtaining a copy
 6 | of this software and associated documentation files (the "Software"), to deal
 7 | in the Software without restriction, including without limitation the rights
 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 | 
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 | 
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 | 


--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
  1 | <h1 align="center">
  2 |   <picture><img src="./doc/img/logo.png" height="400"/></picture>
  3 |   <br />
  4 |   Computerraria
  5 | </h1>
  6 | <h2 align="center">
  7 |   A fully compliant RISC-V computer inside Terraria
  8 | </h2>
  9 | <h2 align="center">
 10 |   Video explanation: https://youtu.be/zXPiqk0-zDY
 11 | </h2>
 12 | 
 13 | <div align="center">
 14 |   <a href=https://github.com/misprit7/computerraria/actions/workflows/in-game-tests.yml>
 15 |     <img src=https://github.com/misprit7/computerraria/actions/workflows/in-game-tests.yml/badge.svg/>
 16 |   </a>
 17 |   <a href=https://github.com/misprit7/computerraria/actions/workflows/rust-tests.yml>
 18 |     <img src=https://github.com/misprit7/computerraria/actions/workflows/rust-tests.yml/badge.svg/>
 19 |   </a>
 20 | </div>
 21 | 
 22 | # Pitch
 23 | 
 24 | There are two fundamentally competing forces when it comes to computer speed. The first, and most famous, is Moore's law, where physical transistor densities scale exponentially. The second is the inevitable growth of software bloat that runs on top of increasingly modern processors. There's a kind of equilibrium between these two competing beasts, ensuring that a user always manages to get at least a split second of mindfulness while staring at a frozen screen whenever attempting to open the latest app. 
 25 | 
 26 | This project is an attempt to score a decisive rout in this ongoing battle in favor of the *programmer*. By emulating a complete rv32i instruction set inside the wiring system of [Terraria](https://www.terraria.org/), we push back speeds to the early 70s era, tossing the ball firmly back into the court of the silicon engineer without losing any software functionality. 
 27 | 
 28 | # Overview
 29 | 
 30 | <div align="center">
 31 |   <a href=https://easyzoom.com/image/412333>
 32 |     <img src="doc/img/poster-small.png"/>
 33 |     Click to see navigable image
 34 |   </a>
 35 | </div>
 36 | 
 37 | Despite what the pitch may lead one to believe the goal of this project is to maximize the compliance and processing ability of the in game cpu. This is only possible with the help of an accelerator mod, which maintains full compatibility with the vanilla wiring system but reimplements it in a much more efficient manner:
 38 | 
 39 | [WireHead](https://github.com/misprit7/WireHead) - A wiring accelerator and headless control mod
 40 | 
 41 | With this installed, the current specs of the computer are as follows: 
 42 | 
 43 | - Clock speed: ~5kHz
 44 | - Ram: 96kb
 45 | - Instruction set: rv32i
 46 | 
 47 | As an example of what it can do, here is Pong, running purely on the in-game cpu (see [app/pong/src/main.rs](app/pong/src/main.rs) for implementation):
 48 | 
 49 | https://user-images.githubusercontent.com/33139843/229342342-de4708e1-7467-4f99-834b-3d0fb28d0858.mp4
 50 | 
 51 | # Setup
 52 | 
 53 | Note that currently only Linux is fully supported, and only parts of this have been tested on Windows. However I've left some steps for anyone who wants to try getting Windows working, in theory using wsl it should be fairly straightforward and things should be identical.
 54 | 
 55 | ## Prerequisites
 56 | 
 57 | For a comprehensive list of everything that is needed to run all aspects of this project, see the [Dockerfile](docker/Dockerfile). However, to develop and run applications for the computer all you really need is a working Cargo/rustc installation, install it [here](https://www.rust-lang.org/tools/install) or through your package manager.
 58 | 
 59 | ## Setup Process
 60 | 
 61 | Navigate to where you want to keep this project and clone it. Copy computer.wld to your tModLoader world path. Depending on your platform, this is:
 62 | ```
 63 | Windows: Documents\My Games\Terraria\ModLoader\Worlds
 64 | Linux: ~/.local/share/Terraria/tModLoader/Worlds
 65 | ```
 66 | On Linux you can automate copying back and forth like this with the `copy-world.sh` script with either the `--to` (copy to world folder) or `--from` (copy from world folder) flags.
 67 | 
 68 | Next, navigate to the mod sources folder and clone [WireHead](https://github.com/misprit7/WireHead):
 69 | ```
 70 | #Windows
 71 | cd "%userprofile%\Documents\My Games\Terraria\ModLoader\ModSources" && git clone https://github.com/misprit7/WireHead.git
 72 | 
 73 | #Linux
 74 | cd "~/.local/share/Terraria/tModLoader/ModSources" && git clone https://github.com/misprit7/WireHead.git
 75 | ```
 76 | 
 77 | Prepare the binary you wish to run. For example for pong compile the rust app and copy the binary to a more convenient path:
 78 | 
 79 | ```
 80 | cd <path to computerraria>/app/pong
 81 | cargo rb
 82 | ./copy-bin.sh /tmp/pong.txt
 83 | ```
 84 | 
 85 | Start [tModLoader](https://store.steampowered.com/app/1281930/tModLoader/), and from the main menu go to Workshop->Develop and click on the Build button next to WireHead. For convenience I'd also recommend installing Cheat Sheet and HERO's Mod from the Download Mods section of the workshop if you haven't already. Then open the new world you copied earlier in game. In game type:
 86 | ```
 87 | /bin write /tmp/pong.txt
 88 | ```
 89 | 
 90 | Currently the NPCs that run the CPU clock are too far away to spawn immediately, this is a bug and should be fixed soon. As a workaround, go through the blue teleporter shown below, fly upwards a bit, come back down and go back through the same teleporter.
 91 | 
 92 | ![Control Panel](doc/img/control-panel.png)
 93 | 
 94 | After this workaround is done, press the first two of the three levers on the far right to start the program. Go through the orange teleporter to arrive at the screen area. Pong should be running and is controllable by the controller beneath the screen (use HERO's Mod's camera lock to see the screen and controls at the same time).
 95 | 
 96 | ![Pong](doc/img/pong-still.png)
 97 | 
 98 | ## Docker
 99 | 
100 | For advanced CI/headless usage you can use the docker image:
101 | 
102 | [Docker Image](https://hub.docker.com/r/misprit7/computerraria)
103 | 
104 | If you already have docker installed this can be pulled with
105 | 
106 | ```bash
107 | docker pull misprit7/computerraria
108 | ```
109 | 
110 | You can then start the container with
111 | 
112 | ```bash
113 | docker run -it misprit7/computerraria
114 | ```
115 | 
116 | This image already has all tooling installed so you should be able to build everything. 
117 | 
118 | # File Structure
119 | 
120 | The major relevant parts of the project are as follows:
121 | 
122 | ```
123 | .
124 | ├── app/
125 | │   ├── tdriver/
126 | │   └── template/
127 | ├── computer.wld
128 | ├── doc/
129 | ├── docker/
130 | ├── test/
131 | └── tinterface/
132 |     ├── bin/
133 |     └── tinterface/
134 | ```
135 | 
136 | `app/`
137 | 
138 | Higher level applications to be run on the computer, not including compliance tests. Currently all in rust but could also easily be in C. 
139 | 
140 | `app/tdriver/`
141 | 
142 | Driver API for interacting cpu from rust, mostly extremely low level startup code and graphics drivers.
143 | 
144 | `app/template/`
145 | 
146 | Template for new rust projects that implements minimal tdriver
147 | 
148 | `computer.wld`
149 | 
150 | The actual world file. This is technically a binary file, but given the context of the project it acts much more like source code given that it is edited manually and compresses extremely well. This generally isn't edited in place, it's copied back and forth to the user installation with [copy-world.sh](copy-world.sh). 
151 | 
152 | `doc/`
153 | 
154 | Documentation/notes for the project
155 | 
156 | `docker/`
157 | 
158 | Files required to build docker image for CI. 
159 | 
160 | `test/`
161 | 
162 | All automated tests written for the CPU. These are mostly handled through [riscof](https://github.com/riscv-software-src/riscof). This consists of both the computerraria plugin as well as a reference plugin ([sail_cSim](test/sail_cSim/)) to compare the results to. 
163 | 
164 | `tinterface/`
165 | 
166 | Interfaces programmatically with running Terraria instance. This consists of both a python module as well as a command line wrapper to upload binaries, start execution and manipulate other fine grain controls without needing a GUI. 
167 | 
168 | 
169 | 


--------------------------------------------------------------------------------
/app/doom3d/.cargo/config.toml:
--------------------------------------------------------------------------------
 1 | [target.riscv32i-unknown-none-elf]
 2 | rustflags = ["-C", "link-arg=-Tlink.x", "-C", "llvm-args=-ffast-math"]
 3 | 
 4 | [env]
 5 | EMU_TICK_RATE = "100"
 6 | 
 7 | [alias]
 8 | rbuild = "build --release --target riscv32i-unknown-none-elf"
 9 | rb = "rbuild"
10 | 
11 | rdoc = "doc --release --target riscv32i-unknown-none-elf"
12 | rd = "rdoc"
13 | 
14 | rsize = "size --release --target riscv32i-unknown-none-elf"
15 | rs = "rsize"
16 | 
17 | robjdump = "objdump --release --target riscv32i-unknown-none-elf"
18 | rod = "robjdump"
19 | 
20 | 


--------------------------------------------------------------------------------
/app/doom3d/.vimspector.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "configurations": {
 3 |     "Launch": {
 4 |       "adapter": "vscode-cpptools",
 5 |       "filetypes": [ "cpp", "c", "objc", "rust" ],
 6 |       "configuration": {
 7 |         "request": "launch",
 8 |         "program": "${workspaceRoot}/target/x86_64-unknown-linux-gnu/debug/doom3d",
 9 |         "args": [],
10 |         "cwd": ".",
11 |         "environment": [],
12 |         "externalConsole": true,
13 |         "MIMode": "gdb",
14 |         "stopAtEntry": true
15 |       }
16 |     },
17 |     "Attach": {
18 |       "adapter": "vscode-cpptools",
19 |       "filetypes": [ "cpp", "c", "objc", "rust" ],
20 |       "configuration": {
21 |         "request": "attach",
22 |         "program": "${workspaceRoot}/target/x86_64-unknown-linux-gnu/debug/doom3d",
23 |         "MIMode": "gdb",
24 |         "stopAtEntry": true
25 |       }
26 |     }
27 |   }
28 | }
29 | 


--------------------------------------------------------------------------------
/app/doom3d/Cargo.lock:
--------------------------------------------------------------------------------
  1 | # This file is automatically @generated by Cargo.
  2 | # It is not intended for manual editing.
  3 | version = 3
  4 | 
  5 | [[package]]
  6 | name = "autocfg"
  7 | version = "1.1.0"
  8 | source = "registry+https://github.com/rust-lang/crates.io-index"
  9 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 10 | 
 11 | [[package]]
 12 | name = "az"
 13 | version = "1.2.1"
 14 | source = "registry+https://github.com/rust-lang/crates.io-index"
 15 | checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973"
 16 | 
 17 | [[package]]
 18 | name = "bitflags"
 19 | version = "1.3.2"
 20 | source = "registry+https://github.com/rust-lang/crates.io-index"
 21 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 22 | 
 23 | [[package]]
 24 | name = "bytemuck"
 25 | version = "1.13.1"
 26 | source = "registry+https://github.com/rust-lang/crates.io-index"
 27 | checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea"
 28 | 
 29 | [[package]]
 30 | name = "cassowary"
 31 | version = "0.3.0"
 32 | source = "registry+https://github.com/rust-lang/crates.io-index"
 33 | checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
 34 | 
 35 | [[package]]
 36 | name = "cfg-if"
 37 | version = "1.0.0"
 38 | source = "registry+https://github.com/rust-lang/crates.io-index"
 39 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 40 | 
 41 | [[package]]
 42 | name = "cordic"
 43 | version = "0.1.5"
 44 | source = "registry+https://github.com/rust-lang/crates.io-index"
 45 | checksum = "0ed0a176c0b8c5c95fa0523177530364c5b68a8895d9745730dbfa692a7412d0"
 46 | dependencies = [
 47 |  "fixed",
 48 | ]
 49 | 
 50 | [[package]]
 51 | name = "crossterm"
 52 | version = "0.25.0"
 53 | source = "registry+https://github.com/rust-lang/crates.io-index"
 54 | checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
 55 | dependencies = [
 56 |  "bitflags",
 57 |  "crossterm_winapi",
 58 |  "libc",
 59 |  "mio",
 60 |  "parking_lot",
 61 |  "signal-hook",
 62 |  "signal-hook-mio",
 63 |  "winapi",
 64 | ]
 65 | 
 66 | [[package]]
 67 | name = "crossterm"
 68 | version = "0.26.1"
 69 | source = "registry+https://github.com/rust-lang/crates.io-index"
 70 | checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13"
 71 | dependencies = [
 72 |  "bitflags",
 73 |  "crossterm_winapi",
 74 |  "libc",
 75 |  "mio",
 76 |  "parking_lot",
 77 |  "signal-hook",
 78 |  "signal-hook-mio",
 79 |  "winapi",
 80 | ]
 81 | 
 82 | [[package]]
 83 | name = "crossterm_winapi"
 84 | version = "0.9.0"
 85 | source = "registry+https://github.com/rust-lang/crates.io-index"
 86 | checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c"
 87 | dependencies = [
 88 |  "winapi",
 89 | ]
 90 | 
 91 | [[package]]
 92 | name = "crunchy"
 93 | version = "0.2.2"
 94 | source = "registry+https://github.com/rust-lang/crates.io-index"
 95 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
 96 | 
 97 | [[package]]
 98 | name = "doom3d"
 99 | version = "0.1.0"
100 | dependencies = [
101 |  "cordic",
102 |  "fixed",
103 |  "libm",
104 |  "tdriver",
105 | ]
106 | 
107 | [[package]]
108 | name = "fixed"
109 | version = "1.23.1"
110 | source = "registry+https://github.com/rust-lang/crates.io-index"
111 | checksum = "79386fdcec5e0fde91b1a6a5bcd89677d1f9304f7f986b154a1b9109038854d9"
112 | dependencies = [
113 |  "az",
114 |  "bytemuck",
115 |  "half",
116 |  "typenum",
117 | ]
118 | 
119 | [[package]]
120 | name = "half"
121 | version = "2.2.1"
122 | source = "registry+https://github.com/rust-lang/crates.io-index"
123 | checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0"
124 | dependencies = [
125 |  "crunchy",
126 | ]
127 | 
128 | [[package]]
129 | name = "libc"
130 | version = "0.2.141"
131 | source = "registry+https://github.com/rust-lang/crates.io-index"
132 | checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
133 | 
134 | [[package]]
135 | name = "libm"
136 | version = "0.2.6"
137 | source = "registry+https://github.com/rust-lang/crates.io-index"
138 | checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb"
139 | 
140 | [[package]]
141 | name = "lock_api"
142 | version = "0.4.9"
143 | source = "registry+https://github.com/rust-lang/crates.io-index"
144 | checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
145 | dependencies = [
146 |  "autocfg",
147 |  "scopeguard",
148 | ]
149 | 
150 | [[package]]
151 | name = "log"
152 | version = "0.4.17"
153 | source = "registry+https://github.com/rust-lang/crates.io-index"
154 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
155 | dependencies = [
156 |  "cfg-if",
157 | ]
158 | 
159 | [[package]]
160 | name = "mio"
161 | version = "0.8.6"
162 | source = "registry+https://github.com/rust-lang/crates.io-index"
163 | checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
164 | dependencies = [
165 |  "libc",
166 |  "log",
167 |  "wasi",
168 |  "windows-sys",
169 | ]
170 | 
171 | [[package]]
172 | name = "parking_lot"
173 | version = "0.12.1"
174 | source = "registry+https://github.com/rust-lang/crates.io-index"
175 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
176 | dependencies = [
177 |  "lock_api",
178 |  "parking_lot_core",
179 | ]
180 | 
181 | [[package]]
182 | name = "parking_lot_core"
183 | version = "0.9.7"
184 | source = "registry+https://github.com/rust-lang/crates.io-index"
185 | checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
186 | dependencies = [
187 |  "cfg-if",
188 |  "libc",
189 |  "redox_syscall",
190 |  "smallvec",
191 |  "windows-sys",
192 | ]
193 | 
194 | [[package]]
195 | name = "ratatui"
196 | version = "0.20.1"
197 | source = "registry+https://github.com/rust-lang/crates.io-index"
198 | checksum = "dcc0d032bccba900ee32151ec0265667535c230169f5a011154cdcd984e16829"
199 | dependencies = [
200 |  "bitflags",
201 |  "cassowary",
202 |  "crossterm 0.26.1",
203 |  "unicode-segmentation",
204 |  "unicode-width",
205 | ]
206 | 
207 | [[package]]
208 | name = "redox_syscall"
209 | version = "0.2.16"
210 | source = "registry+https://github.com/rust-lang/crates.io-index"
211 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
212 | dependencies = [
213 |  "bitflags",
214 | ]
215 | 
216 | [[package]]
217 | name = "scopeguard"
218 | version = "1.1.0"
219 | source = "registry+https://github.com/rust-lang/crates.io-index"
220 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
221 | 
222 | [[package]]
223 | name = "signal-hook"
224 | version = "0.3.15"
225 | source = "registry+https://github.com/rust-lang/crates.io-index"
226 | checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9"
227 | dependencies = [
228 |  "libc",
229 |  "signal-hook-registry",
230 | ]
231 | 
232 | [[package]]
233 | name = "signal-hook-mio"
234 | version = "0.2.3"
235 | source = "registry+https://github.com/rust-lang/crates.io-index"
236 | checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
237 | dependencies = [
238 |  "libc",
239 |  "mio",
240 |  "signal-hook",
241 | ]
242 | 
243 | [[package]]
244 | name = "signal-hook-registry"
245 | version = "1.4.1"
246 | source = "registry+https://github.com/rust-lang/crates.io-index"
247 | checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
248 | dependencies = [
249 |  "libc",
250 | ]
251 | 
252 | [[package]]
253 | name = "smallvec"
254 | version = "1.10.0"
255 | source = "registry+https://github.com/rust-lang/crates.io-index"
256 | checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
257 | 
258 | [[package]]
259 | name = "tdriver"
260 | version = "0.1.0"
261 | dependencies = [
262 |  "crossterm 0.25.0",
263 |  "ratatui",
264 | ]
265 | 
266 | [[package]]
267 | name = "typenum"
268 | version = "1.16.0"
269 | source = "registry+https://github.com/rust-lang/crates.io-index"
270 | checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
271 | 
272 | [[package]]
273 | name = "unicode-segmentation"
274 | version = "1.10.1"
275 | source = "registry+https://github.com/rust-lang/crates.io-index"
276 | checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
277 | 
278 | [[package]]
279 | name = "unicode-width"
280 | version = "0.1.10"
281 | source = "registry+https://github.com/rust-lang/crates.io-index"
282 | checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
283 | 
284 | [[package]]
285 | name = "wasi"
286 | version = "0.11.0+wasi-snapshot-preview1"
287 | source = "registry+https://github.com/rust-lang/crates.io-index"
288 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
289 | 
290 | [[package]]
291 | name = "winapi"
292 | version = "0.3.9"
293 | source = "registry+https://github.com/rust-lang/crates.io-index"
294 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
295 | dependencies = [
296 |  "winapi-i686-pc-windows-gnu",
297 |  "winapi-x86_64-pc-windows-gnu",
298 | ]
299 | 
300 | [[package]]
301 | name = "winapi-i686-pc-windows-gnu"
302 | version = "0.4.0"
303 | source = "registry+https://github.com/rust-lang/crates.io-index"
304 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
305 | 
306 | [[package]]
307 | name = "winapi-x86_64-pc-windows-gnu"
308 | version = "0.4.0"
309 | source = "registry+https://github.com/rust-lang/crates.io-index"
310 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
311 | 
312 | [[package]]
313 | name = "windows-sys"
314 | version = "0.45.0"
315 | source = "registry+https://github.com/rust-lang/crates.io-index"
316 | checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
317 | dependencies = [
318 |  "windows-targets",
319 | ]
320 | 
321 | [[package]]
322 | name = "windows-targets"
323 | version = "0.42.2"
324 | source = "registry+https://github.com/rust-lang/crates.io-index"
325 | checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
326 | dependencies = [
327 |  "windows_aarch64_gnullvm",
328 |  "windows_aarch64_msvc",
329 |  "windows_i686_gnu",
330 |  "windows_i686_msvc",
331 |  "windows_x86_64_gnu",
332 |  "windows_x86_64_gnullvm",
333 |  "windows_x86_64_msvc",
334 | ]
335 | 
336 | [[package]]
337 | name = "windows_aarch64_gnullvm"
338 | version = "0.42.2"
339 | source = "registry+https://github.com/rust-lang/crates.io-index"
340 | checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
341 | 
342 | [[package]]
343 | name = "windows_aarch64_msvc"
344 | version = "0.42.2"
345 | source = "registry+https://github.com/rust-lang/crates.io-index"
346 | checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
347 | 
348 | [[package]]
349 | name = "windows_i686_gnu"
350 | version = "0.42.2"
351 | source = "registry+https://github.com/rust-lang/crates.io-index"
352 | checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
353 | 
354 | [[package]]
355 | name = "windows_i686_msvc"
356 | version = "0.42.2"
357 | source = "registry+https://github.com/rust-lang/crates.io-index"
358 | checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
359 | 
360 | [[package]]
361 | name = "windows_x86_64_gnu"
362 | version = "0.42.2"
363 | source = "registry+https://github.com/rust-lang/crates.io-index"
364 | checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
365 | 
366 | [[package]]
367 | name = "windows_x86_64_gnullvm"
368 | version = "0.42.2"
369 | source = "registry+https://github.com/rust-lang/crates.io-index"
370 | checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
371 | 
372 | [[package]]
373 | name = "windows_x86_64_msvc"
374 | version = "0.42.2"
375 | source = "registry+https://github.com/rust-lang/crates.io-index"
376 | checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
377 | 


--------------------------------------------------------------------------------
/app/doom3d/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "doom3d"
 3 | version = "0.1.0"
 4 | edition = "2021"
 5 | 
 6 | [dependencies]
 7 | cordic = "0.1.5"
 8 | fixed = "1.23.1"
 9 | libm = "0.2.6"
10 | tdriver = { path = "../tdriver" }
11 | 
12 | [build_dependencies]
13 | tdriver = { path = "../tdriver" }
14 | 
15 | # Don't ever use this for riscv builds or they will be massive
16 | [profile.dev]
17 | 
18 | [profile.release]
19 | panic = "abort"
20 | # Use either 2, 3, s or z
21 | opt-level = 3
22 | overflow-checks = false
23 | lto = true
24 | 
25 | 


--------------------------------------------------------------------------------
/app/doom3d/build.rs:
--------------------------------------------------------------------------------
 1 | use std::fs::File;
 2 | use std::io::prelude::*;
 3 | use tdriver::graphics;
 4 | 
 5 | const PI: f32 = 3.14159;
 6 | const FOV_DEG: f32 = 60.0;
 7 | const FOV_RAD: f32 = FOV_DEG * PI / 180.0;
 8 | 
 9 | fn main() {
10 |     let out_dir = std::env::var("OUT_DIR").unwrap();
11 |     let dest_path = std::path::Path::new(&out_dir).join("pixel_to_ray_angle_lookup.rs");
12 |     let mut file = File::create(&dest_path).unwrap();
13 |     write!(
14 |         file,
15 |         "pub const PIXEL_TO_RAY_ANGLE_TABLE: [I5F11; {}] = [\n",
16 |         graphics::WIDTH
17 |     )
18 |     .unwrap();
19 | 
20 |     let tan_half_fov = (FOV_RAD / 2.0).tan();
21 |     for x_pixel in 0..graphics::WIDTH {
22 |         // Create a lookup table to map x pixel index to the ray angle pointing in the direction of that pixel, in rad
23 |         let screen_coord = x_pixel as f32 / graphics::WIDTH as f32;
24 |         let angle_rad = ((2.0 * screen_coord - 1.0) * tan_half_fov).atan();
25 | 
26 |         // Couldn't find a const fn to make a fixed point from a f32, but for some reason there's one for a string
27 |         write!(file, "   I5F11::unwrapped_from_str(\"{}\"),\n", angle_rad).unwrap();
28 |     }
29 | 
30 |     write!(file, "];\n").unwrap();
31 | }
32 | 


--------------------------------------------------------------------------------
/app/doom3d/copy-bin.sh:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/sh
 2 | 
 3 | # Helper script to copy file to txt file format WireHead expects
 4 | # Example: ./copy_bin.sh /tmp/in.txt
 5 | 
 6 | # Rebuild project
 7 | cargo rbuild --release
 8 | 
 9 | # Convert from elf to bin
10 | # Fancy glob matching! https://zsh.sourceforge.io/Doc/Release/Expansion.html#Glob-Qualifiers
11 | # rust-objcopy -O binary ./target/riscv32i-unknown-none-elf/release/*(x.) /tmp/rust.bin 
12 | rust-objcopy -O binary ./target/riscv32i-unknown-none-elf/release/doom3d /tmp/rust.bin 
13 | 
14 | # Convert from bin to txt
15 | hexdump -ve '1/1 "%.2x "' /tmp/rust.bin | head -c -1 > $1
16 | 
17 | 


--------------------------------------------------------------------------------
/app/doom3d/src/main.rs:
--------------------------------------------------------------------------------
 1 | #![no_std]
 2 | #![no_main]
 3 | 
 4 | mod maps;
 5 | mod raycaster;
 6 | 
 7 | use maps::MAP;
 8 | use tdriver::entry;
 9 | use tdriver::graphics;
10 | use tdriver::graphics::Screen;
11 | 
12 | use fixed::types::{I5F11};
13 | 
14 | entry!(main);
15 | 
16 | fn main() -> ! {
17 |     let mut screen = graphics::init();
18 |     let raycaster = raycaster::Raycaster::new(MAP);
19 |     let mut pixels: [[bool; graphics::WIDTH]; graphics::HEIGHT] =
20 |         [[false; graphics::WIDTH]; graphics::HEIGHT];
21 | 
22 |     let mut angle = I5F11::const_from_int(0);
23 |     let x = I5F11::from_num(2.5);
24 |     let y = I5F11::from_num(3.5);
25 |     // let mut forward = true;
26 |     loop {
27 |         raycaster.render(x, y, angle, &mut pixels);
28 |         angle += I5F11::from_num(0.04);
29 |         angle %= 2 * I5F11::PI;
30 |         // if x < 2 { forward = false }
31 |         // if x > 3 { forward = true }
32 |         // if forward { x += I5F11::from_num(0.01) }
33 |         // else { x -= I5F11::from_num(0.01) }
34 |         // y += I5F11::from_num(0.01);
35 |         update_screen(&mut screen, &pixels);
36 |     }
37 | }
38 | 
39 | fn update_screen(screen: &mut Screen, pixels: &[[bool; graphics::WIDTH]; graphics::HEIGHT]) {
40 |     for y_pix in 0..graphics::HEIGHT {
41 |         let mut word: u64 = 0;
42 |         for x_pix in 0..graphics::WIDTH {
43 |             if pixels[y_pix][x_pix] {
44 |                 word |= 0b1 << x_pix;
45 |             }
46 |         }
47 | 
48 |         graphics::write_line(screen, word as u32, y_pix, 0);
49 |         graphics::write_line(screen, (word >> 32) as u32, y_pix, 1);
50 |     }
51 | 
52 |     graphics::update(screen);
53 | }
54 | 
55 | 
56 | 
57 | 


--------------------------------------------------------------------------------
/app/doom3d/src/maps.rs:
--------------------------------------------------------------------------------
 1 | pub const MAP_WIDTH: usize = 5;
 2 | pub const MAP_HEIGHT: usize = 7;
 3 | 
 4 | // pub const MAP: [[bool; MAP_WIDTH]; MAP_HEIGHT] =
 5 | //     [[true, true, true], 
 6 | //     [true, false, true],
 7 | //     [true, true, true]];
 8 | 
 9 | pub const MAP: [[bool; MAP_WIDTH]; MAP_HEIGHT] =
10 |     [[true, true, true, true, true], 
11 |     [true, true, false, true, true], 
12 |     [true, false, false, false, true],
13 |     [true, false, false, false, true],
14 |     [true, false, false, false, true],
15 |     [true, true, false, true, true],
16 |     [true, true, true, true, true]];
17 | 
18 | // pub const MAP: [[bool; MAP_WIDTH]; MAP_HEIGHT] = [
19 | //     [true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],
20 | //     [true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true],
21 | //     [true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true],
22 | //     [true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true],
23 | //     [true,false,false,false,false,false,true,true,true,true,true,false,false,false,false,true,false,true,false,true,false,false,false,true],
24 | //     [true,false,false,false,false,false,true,false,false,false,true,false,false,false,false,false,false,false,false,false,false,false,false,true],
25 | //     [true,false,false,false,false,false,true,false,false,false,true,false,false,false,false,true,false,false,false,true,false,false,false,true],
26 | //     [true,false,false,false,false,false,true,false,false,false,true,false,false,false,false,false,false,false,false,false,false,false,false,true],
27 | //     [true,false,false,false,false,false,true,true,false,true,true,false,false,false,false,true,false,true,false,true,false,false,false,true],
28 | //     [true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true],
29 | //     [true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true],
30 | //     [true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true],
31 | //     [true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true],
32 | //     [true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true],
33 | //     [true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true],
34 | //     [true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true],
35 | //     [true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true],
36 | //     [true,true,false,true,false,false,false,false,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true],
37 | //     [true,true,false,false,false,false,true,false,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true],
38 | //     [true,true,false,true,false,false,false,false,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true],
39 | //     [true,true,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true],
40 | //     [true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true],
41 | //     [true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true],
42 | //     [true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]
43 | // ];
44 | 


--------------------------------------------------------------------------------
/app/doom3d/src/raycaster.rs:
--------------------------------------------------------------------------------
  1 | use core::cmp::{max, min};
  2 | use tdriver::graphics;
  3 | use crate::maps::{MAP_WIDTH, MAP_HEIGHT};
  4 | use fixed::types::{I9F7, I5F11};
  5 | use cordic;
  6 | 
  7 | use fixed::prelude::*;
  8 | 
  9 | include!(concat!(env!("OUT_DIR"), "/pixel_to_ray_angle_lookup.rs"));
 10 | 
 11 | pub struct Raycaster {
 12 |     map: [[bool; MAP_WIDTH]; MAP_HEIGHT],
 13 | }
 14 | 
 15 | struct RayHit {
 16 |     length: I5F11,
 17 |     idx_x: usize,
 18 |     idx_y: usize,
 19 |     normal_along_x: bool,
 20 | }
 21 | 
 22 | impl Raycaster {
 23 |     pub fn new(map: [[bool; MAP_WIDTH]; MAP_HEIGHT]) -> Self {
 24 |         Raycaster {
 25 |             map,
 26 |         }
 27 |     }
 28 | 
 29 |     pub fn render(
 30 |         &self,
 31 |         start_x: I5F11,
 32 |         start_y: I5F11,
 33 |         cam_angle_rad: I5F11,
 34 |         pixels: &mut [[bool; graphics::WIDTH]; graphics::HEIGHT],
 35 |     ) {
 36 |         let mut last_hit = RayHit {
 37 |             length: I5F11::const_from_int(0),
 38 |             idx_x: 0,
 39 |             idx_y: 0,
 40 |             normal_along_x: false,
 41 |         };
 42 |         let mut last_top = 0;
 43 |         let mut last_bottom = 0;
 44 |         let mut last_on_wall = false;
 45 | 
 46 |         for x_pixel in 0..graphics::WIDTH {
 47 |             let ray_angle_rad = PIXEL_TO_RAY_ANGLE_TABLE[x_pixel] + cam_angle_rad;
 48 |             let hit = self.cast_ray(start_x, start_y, ray_angle_rad);
 49 | 
 50 |             if let Some(hit) = hit {
 51 |                 let height: i32 = (graphics::HEIGHT.to_fixed::<I9F7>().wide_div(hit.length)).to_num();
 52 |                 let top: usize = min(
 53 |                     (graphics::HEIGHT as i32 / 2) + (height / 2),
 54 |                     graphics::HEIGHT as i32 - 1,
 55 |                 ) as usize;
 56 |                 let bottom: usize = max((graphics::HEIGHT as i32 / 2) - (height / 2), 0) as usize;
 57 | 
 58 |                 let x_diff = hit.idx_x.abs_diff(last_hit.idx_x);
 59 |                 let y_diff = hit.idx_y.abs_diff(last_hit.idx_y);
 60 |                 let diagonal = x_diff == 1 && y_diff == 1; 
 61 |                 let far_away = x_diff >= 2 || y_diff >= 2; 
 62 |                 let new_normal = hit.normal_along_x != last_hit.normal_along_x; 
 63 |                 
 64 |                 if (diagonal || far_away || new_normal || !last_on_wall) && x_pixel > 0 {
 65 |                     // hit a wall corner, draw a vertical line
 66 |                     for y_pixel in 0..graphics::HEIGHT {
 67 |                         pixels[y_pixel][x_pixel] = y_pixel >= min(bottom, last_bottom) && y_pixel <= max(top, last_top);
 68 |                     }
 69 |                 } else {
 70 |                     // hit a wall, draw top and bottom only
 71 |                     for y_pixel in 0..graphics::HEIGHT {
 72 |                         pixels[y_pixel][x_pixel] = false;
 73 |                     }
 74 | 
 75 |                     pixels[top][x_pixel] = true;
 76 |                     pixels[bottom][x_pixel] = true;
 77 |                 }
 78 | 
 79 |                 last_hit = hit;
 80 |                 last_top = top;
 81 |                 last_bottom = bottom;
 82 |                 last_on_wall = true;
 83 |             } else {
 84 |                 if last_on_wall {
 85 |                     // hit blank space after seeing wall, draw a vertical line
 86 |                     for y_pixel in 0..graphics::HEIGHT {
 87 |                         pixels[y_pixel][x_pixel] = y_pixel >= last_bottom && y_pixel <= last_top;
 88 |                     }
 89 |                 } else {
 90 |                     // hit blank space, draw nothing
 91 |                     for y_pixel in 0..graphics::HEIGHT {
 92 |                         pixels[y_pixel][x_pixel] = false;
 93 |                     }
 94 |                 }
 95 | 
 96 |                 last_on_wall = false;
 97 |             }
 98 |         }
 99 |     }
100 | 
101 |     // DDA algorithm (https://www.youtube.com/watch?v=NbSee-XM7WA&ab_channel=javidx9)
102 |     fn cast_ray(&self, start_x: I5F11, start_y: I5F11, ray_angle_rad: I5F11) -> Option<RayHit> {
103 |         let (dir_y, dir_x) = cordic::sin_cos(ray_angle_rad);
104 |         let ray_unit_step_size_x = match dir_x.abs().checked_recip() {
105 |             Some(v) => v,
106 |             None => I5F11::MAX
107 |         }; // Length of step if moving 1 unit in x
108 |         let ray_unit_step_size_y = match dir_y.abs().checked_recip() {
109 |             Some(v) => v,
110 |             None => I5F11::MAX
111 |         }; // Length of step if moving 1 unit in y
112 |         let mut last_hit_x_normal = false; // Normal of last wall hit
113 | 
114 |         // Length of ray if next step is 1 unit in x (account for off-grid start)
115 |         let mut ray_length_x = if dir_x >= 0.0 {
116 |             last_hit_x_normal = true;
117 |             start_x.ceil() - start_x
118 |         } else {
119 |             start_x - start_x.floor()
120 |         } * ray_unit_step_size_x;
121 | 
122 |         // Length of ray if next step is 1 unit in y (account for off-grid start)
123 |         let mut ray_length_y = if dir_y >= 0.0 {
124 |             start_y.ceil() - start_y
125 |         } else {
126 |             start_y - start_y.floor()
127 |         } * ray_unit_step_size_y;
128 | 
129 |         let step_x = if dir_x > 0.0 {1} else {-1};
130 |         let step_y = if dir_y > 0.0 {1} else {-1};
131 |         let mut idx_x = start_x.to_num::<i32>();
132 |         let mut idx_y = start_y.to_num::<i32>();
133 | 
134 |         let mut ray_length = I5F11::const_from_int(0);
135 |         loop {
136 |             if self.valid_map_idx(idx_x, idx_y) {
137 |                 if self.map[idx_y as usize][idx_x as usize] {
138 |                     // ray has collided with a wall!
139 |                     return Some(RayHit {
140 |                         length: ray_length,
141 |                         idx_x: idx_x as usize,
142 |                         idx_y: idx_y as usize,
143 |                         normal_along_x: last_hit_x_normal,
144 |                     });
145 |                 }
146 |             } else {
147 |                 // ray has left map area, exit
148 |                 return None;
149 |             }
150 | 
151 |             // Walk along shortest ray
152 |             if ray_length_x <= ray_length_y {
153 |                 idx_x += step_x;
154 |                 ray_length = ray_length_x;
155 |                 ray_length_x += ray_unit_step_size_x;
156 |                 last_hit_x_normal = true;
157 |             } else {
158 |                 idx_y += step_y;
159 |                 ray_length = ray_length_y;
160 |                 ray_length_y += ray_unit_step_size_y;
161 |                 last_hit_x_normal = false;
162 |             }
163 |         }
164 |     }
165 | 
166 |     fn valid_map_idx(&self, pos_x: i32, pos_y: i32) -> bool {
167 |         pos_x >= 0 && pos_y >= 0 && pos_x < MAP_WIDTH as i32 && pos_y < MAP_HEIGHT as i32
168 |     }
169 | }
170 | 


--------------------------------------------------------------------------------
/app/game-of-life/.cargo/config.toml:
--------------------------------------------------------------------------------
 1 | [target.riscv32i-unknown-none-elf]
 2 | rustflags = ["-C", "link-arg=-Tlink.x"]
 3 | 
 4 | [alias]
 5 | rbuild = "build --release --target riscv32i-unknown-none-elf"
 6 | rb = "rbuild"
 7 | 
 8 | rdoc = "doc --release --target riscv32i-unknown-none-elf"
 9 | rd = "rdoc"
10 | 
11 | rsize = "size --release --target riscv32i-unknown-none-elf"
12 | rs = "rsize"
13 | 
14 | robjdump = "objdump --release --target riscv32i-unknown-none-elf"
15 | rod = "robjdump"
16 | 
17 | 


--------------------------------------------------------------------------------
/app/game-of-life/.vimspector.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "configurations": {
 3 |     "Launch": {
 4 |       "adapter": "vscode-cpptools",
 5 |       "filetypes": [ "cpp", "c", "objc", "rust" ],
 6 |       "configuration": {
 7 |         "request": "launch",
 8 |         "program": "${workspaceRoot}/target/x86_64-unknown-linux-gnu/debug/game-of-life",
 9 |         "args": [],
10 |         "cwd": ".",
11 |         "environment": [],
12 |         "externalConsole": true,
13 |         "MIMode": "gdb",
14 |         "stopAtEntry": true
15 |       }
16 |     },
17 |     "Attach": {
18 |       "adapter": "vscode-cpptools",
19 |       "filetypes": [ "cpp", "c", "objc", "rust" ],
20 |       "configuration": {
21 |         "request": "attach",
22 |         "program": "${workspaceRoot}/target/x86_64-unknown-linux-gnu/debug/game-of-life",
23 |         "MIMode": "gdb",
24 |         "stopAtEntry": true
25 |       }
26 |     }
27 |   }
28 | }
29 | 


--------------------------------------------------------------------------------
/app/game-of-life/Cargo.lock:
--------------------------------------------------------------------------------
  1 | # This file is automatically @generated by Cargo.
  2 | # It is not intended for manual editing.
  3 | version = 3
  4 | 
  5 | [[package]]
  6 | name = "autocfg"
  7 | version = "1.1.0"
  8 | source = "registry+https://github.com/rust-lang/crates.io-index"
  9 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 10 | 
 11 | [[package]]
 12 | name = "bitflags"
 13 | version = "1.3.2"
 14 | source = "registry+https://github.com/rust-lang/crates.io-index"
 15 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 16 | 
 17 | [[package]]
 18 | name = "cassowary"
 19 | version = "0.3.0"
 20 | source = "registry+https://github.com/rust-lang/crates.io-index"
 21 | checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
 22 | 
 23 | [[package]]
 24 | name = "cfg-if"
 25 | version = "1.0.0"
 26 | source = "registry+https://github.com/rust-lang/crates.io-index"
 27 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 28 | 
 29 | [[package]]
 30 | name = "crossterm"
 31 | version = "0.25.0"
 32 | source = "registry+https://github.com/rust-lang/crates.io-index"
 33 | checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
 34 | dependencies = [
 35 |  "bitflags",
 36 |  "crossterm_winapi",
 37 |  "libc",
 38 |  "mio",
 39 |  "parking_lot",
 40 |  "signal-hook",
 41 |  "signal-hook-mio",
 42 |  "winapi",
 43 | ]
 44 | 
 45 | [[package]]
 46 | name = "crossterm"
 47 | version = "0.26.1"
 48 | source = "registry+https://github.com/rust-lang/crates.io-index"
 49 | checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13"
 50 | dependencies = [
 51 |  "bitflags",
 52 |  "crossterm_winapi",
 53 |  "libc",
 54 |  "mio",
 55 |  "parking_lot",
 56 |  "signal-hook",
 57 |  "signal-hook-mio",
 58 |  "winapi",
 59 | ]
 60 | 
 61 | [[package]]
 62 | name = "crossterm_winapi"
 63 | version = "0.9.0"
 64 | source = "registry+https://github.com/rust-lang/crates.io-index"
 65 | checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c"
 66 | dependencies = [
 67 |  "winapi",
 68 | ]
 69 | 
 70 | [[package]]
 71 | name = "game-of-life"
 72 | version = "0.1.0"
 73 | dependencies = [
 74 |  "tdriver",
 75 | ]
 76 | 
 77 | [[package]]
 78 | name = "libc"
 79 | version = "0.2.140"
 80 | source = "registry+https://github.com/rust-lang/crates.io-index"
 81 | checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
 82 | 
 83 | [[package]]
 84 | name = "lock_api"
 85 | version = "0.4.9"
 86 | source = "registry+https://github.com/rust-lang/crates.io-index"
 87 | checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
 88 | dependencies = [
 89 |  "autocfg",
 90 |  "scopeguard",
 91 | ]
 92 | 
 93 | [[package]]
 94 | name = "log"
 95 | version = "0.4.17"
 96 | source = "registry+https://github.com/rust-lang/crates.io-index"
 97 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
 98 | dependencies = [
 99 |  "cfg-if",
100 | ]
101 | 
102 | [[package]]
103 | name = "mio"
104 | version = "0.8.6"
105 | source = "registry+https://github.com/rust-lang/crates.io-index"
106 | checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
107 | dependencies = [
108 |  "libc",
109 |  "log",
110 |  "wasi",
111 |  "windows-sys",
112 | ]
113 | 
114 | [[package]]
115 | name = "parking_lot"
116 | version = "0.12.1"
117 | source = "registry+https://github.com/rust-lang/crates.io-index"
118 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
119 | dependencies = [
120 |  "lock_api",
121 |  "parking_lot_core",
122 | ]
123 | 
124 | [[package]]
125 | name = "parking_lot_core"
126 | version = "0.9.7"
127 | source = "registry+https://github.com/rust-lang/crates.io-index"
128 | checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
129 | dependencies = [
130 |  "cfg-if",
131 |  "libc",
132 |  "redox_syscall",
133 |  "smallvec",
134 |  "windows-sys",
135 | ]
136 | 
137 | [[package]]
138 | name = "ratatui"
139 | version = "0.20.1"
140 | source = "registry+https://github.com/rust-lang/crates.io-index"
141 | checksum = "dcc0d032bccba900ee32151ec0265667535c230169f5a011154cdcd984e16829"
142 | dependencies = [
143 |  "bitflags",
144 |  "cassowary",
145 |  "crossterm 0.26.1",
146 |  "unicode-segmentation",
147 |  "unicode-width",
148 | ]
149 | 
150 | [[package]]
151 | name = "redox_syscall"
152 | version = "0.2.16"
153 | source = "registry+https://github.com/rust-lang/crates.io-index"
154 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
155 | dependencies = [
156 |  "bitflags",
157 | ]
158 | 
159 | [[package]]
160 | name = "scopeguard"
161 | version = "1.1.0"
162 | source = "registry+https://github.com/rust-lang/crates.io-index"
163 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
164 | 
165 | [[package]]
166 | name = "signal-hook"
167 | version = "0.3.15"
168 | source = "registry+https://github.com/rust-lang/crates.io-index"
169 | checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9"
170 | dependencies = [
171 |  "libc",
172 |  "signal-hook-registry",
173 | ]
174 | 
175 | [[package]]
176 | name = "signal-hook-mio"
177 | version = "0.2.3"
178 | source = "registry+https://github.com/rust-lang/crates.io-index"
179 | checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
180 | dependencies = [
181 |  "libc",
182 |  "mio",
183 |  "signal-hook",
184 | ]
185 | 
186 | [[package]]
187 | name = "signal-hook-registry"
188 | version = "1.4.1"
189 | source = "registry+https://github.com/rust-lang/crates.io-index"
190 | checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
191 | dependencies = [
192 |  "libc",
193 | ]
194 | 
195 | [[package]]
196 | name = "smallvec"
197 | version = "1.10.0"
198 | source = "registry+https://github.com/rust-lang/crates.io-index"
199 | checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
200 | 
201 | [[package]]
202 | name = "tdriver"
203 | version = "0.1.0"
204 | dependencies = [
205 |  "crossterm 0.25.0",
206 |  "ratatui",
207 | ]
208 | 
209 | [[package]]
210 | name = "unicode-segmentation"
211 | version = "1.10.1"
212 | source = "registry+https://github.com/rust-lang/crates.io-index"
213 | checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
214 | 
215 | [[package]]
216 | name = "unicode-width"
217 | version = "0.1.10"
218 | source = "registry+https://github.com/rust-lang/crates.io-index"
219 | checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
220 | 
221 | [[package]]
222 | name = "wasi"
223 | version = "0.11.0+wasi-snapshot-preview1"
224 | source = "registry+https://github.com/rust-lang/crates.io-index"
225 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
226 | 
227 | [[package]]
228 | name = "winapi"
229 | version = "0.3.9"
230 | source = "registry+https://github.com/rust-lang/crates.io-index"
231 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
232 | dependencies = [
233 |  "winapi-i686-pc-windows-gnu",
234 |  "winapi-x86_64-pc-windows-gnu",
235 | ]
236 | 
237 | [[package]]
238 | name = "winapi-i686-pc-windows-gnu"
239 | version = "0.4.0"
240 | source = "registry+https://github.com/rust-lang/crates.io-index"
241 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
242 | 
243 | [[package]]
244 | name = "winapi-x86_64-pc-windows-gnu"
245 | version = "0.4.0"
246 | source = "registry+https://github.com/rust-lang/crates.io-index"
247 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
248 | 
249 | [[package]]
250 | name = "windows-sys"
251 | version = "0.45.0"
252 | source = "registry+https://github.com/rust-lang/crates.io-index"
253 | checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
254 | dependencies = [
255 |  "windows-targets",
256 | ]
257 | 
258 | [[package]]
259 | name = "windows-targets"
260 | version = "0.42.2"
261 | source = "registry+https://github.com/rust-lang/crates.io-index"
262 | checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
263 | dependencies = [
264 |  "windows_aarch64_gnullvm",
265 |  "windows_aarch64_msvc",
266 |  "windows_i686_gnu",
267 |  "windows_i686_msvc",
268 |  "windows_x86_64_gnu",
269 |  "windows_x86_64_gnullvm",
270 |  "windows_x86_64_msvc",
271 | ]
272 | 
273 | [[package]]
274 | name = "windows_aarch64_gnullvm"
275 | version = "0.42.2"
276 | source = "registry+https://github.com/rust-lang/crates.io-index"
277 | checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
278 | 
279 | [[package]]
280 | name = "windows_aarch64_msvc"
281 | version = "0.42.2"
282 | source = "registry+https://github.com/rust-lang/crates.io-index"
283 | checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
284 | 
285 | [[package]]
286 | name = "windows_i686_gnu"
287 | version = "0.42.2"
288 | source = "registry+https://github.com/rust-lang/crates.io-index"
289 | checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
290 | 
291 | [[package]]
292 | name = "windows_i686_msvc"
293 | version = "0.42.2"
294 | source = "registry+https://github.com/rust-lang/crates.io-index"
295 | checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
296 | 
297 | [[package]]
298 | name = "windows_x86_64_gnu"
299 | version = "0.42.2"
300 | source = "registry+https://github.com/rust-lang/crates.io-index"
301 | checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
302 | 
303 | [[package]]
304 | name = "windows_x86_64_gnullvm"
305 | version = "0.42.2"
306 | source = "registry+https://github.com/rust-lang/crates.io-index"
307 | checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
308 | 
309 | [[package]]
310 | name = "windows_x86_64_msvc"
311 | version = "0.42.2"
312 | source = "registry+https://github.com/rust-lang/crates.io-index"
313 | checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
314 | 


--------------------------------------------------------------------------------
/app/game-of-life/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "game-of-life"
 3 | version = "0.1.0"
 4 | edition = "2021"
 5 | 
 6 | [dependencies]
 7 | tdriver = { path = "../tdriver" }
 8 | 
 9 | # Don't ever use this for riscv builds or they will be massive
10 | [profile.dev]
11 | 
12 | [profile.release]
13 | panic = "abort"
14 | # Use either 2, 3, s or z
15 | opt-level = 3
16 | overflow-checks = false
17 | lto = true
18 | 
19 | 


--------------------------------------------------------------------------------
/app/game-of-life/copy-bin.sh:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/sh
 2 | 
 3 | # Helper script to copy file to txt file format WireHead expects
 4 | # Example: ./copy_bin.sh /tmp/in.txt
 5 | 
 6 | # Rebuild project
 7 | cargo rbuild --release
 8 | 
 9 | # Convert from elf to bin
10 | # Fancy glob matching! https://zsh.sourceforge.io/Doc/Release/Expansion.html#Glob-Qualifiers
11 | # rust-objcopy -O binary ./target/riscv32i-unknown-none-elf/release/*(x.) /tmp/rust.bin 
12 | rust-objcopy -O binary ./target/riscv32i-unknown-none-elf/release/game-of-life /tmp/rust.bin 
13 | 
14 | # Convert from bin to txt
15 | hexdump -ve '1/1 "%.2x "' /tmp/rust.bin | head -c -1 > $1
16 | 
17 | 


--------------------------------------------------------------------------------
/app/game-of-life/src/main.rs:
--------------------------------------------------------------------------------
  1 | #![no_std]
  2 | #![no_main]
  3 | 
  4 | use tdriver::entry;
  5 | use tdriver::graphics;
  6 | 
  7 | entry!(main);
  8 | 
  9 | const WIDTH: usize = 64;
 10 | const HEIGHT: usize = 48;
 11 | 
 12 | fn update_board(board: &[[u8; WIDTH]; HEIGHT]) -> [[u8; WIDTH]; HEIGHT] {
 13 |     let mut board_next: [[u8; WIDTH]; HEIGHT] = board.clone();
 14 |     // board_next[1][1] = board[1][1];
 15 |     for r in 1..HEIGHT-1 {
 16 |         // board_next[r+1][1] = board[r+1][1];
 17 |         // board_next[r][0] = board[r][0];
 18 |         // board_next[r+1][0] = board[r+1][0];
 19 |         for c in 1..WIDTH-1 {
 20 |             // board_next[r][c+1] = board[r][c+1];
 21 |             // board_next[r+1][c+1] = board[r+1][c+1];
 22 |             let neighbors_alive = (board[r][c] & 0b1110) >> 1;
 23 |             if board[r][c] & 1 == 0 {
 24 |                 if neighbors_alive != 3 { continue }
 25 |                 board_next[r][c] |= 1;
 26 |                 board_next[r-1][c-1] += 0b10;
 27 |                 board_next[r-1][c] += 0b10;
 28 |                 board_next[r-1][c+1] += 0b10;
 29 |                 board_next[r][c-1] += 0b10;
 30 |                 board_next[r][c+1] += 0b10;
 31 |                 board_next[r+1][c-1] += 0b10;
 32 |                 board_next[r+1][c] += 0b10;
 33 |                 board_next[r+1][c+1] += 0b10;
 34 |             } else {
 35 |                 if neighbors_alive == 2 || neighbors_alive == 3 { continue }
 36 |                 board_next[r][c] &= !1;
 37 |                 board_next[r-1][c-1] -= 0b10;
 38 |                 board_next[r-1][c] -= 0b10;
 39 |                 board_next[r-1][c+1] -= 0b10;
 40 |                 board_next[r][c-1] -= 0b10;
 41 |                 board_next[r][c+1] -= 0b10;
 42 |                 board_next[r+1][c-1] -= 0b10;
 43 |                 board_next[r+1][c] -= 0b10;
 44 |                 board_next[r+1][c+1] -= 0b10;
 45 |             }
 46 |             
 47 |         }
 48 |     }
 49 |     board_next
 50 | }
 51 | 
 52 | // Following technique from https://www.jagregory.com/abrash-black-book/#chapter-17-the-game-of-life
 53 | fn main() -> ! {
 54 |     let mut board: [[u8; WIDTH]; HEIGHT] =  [
 55 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 56 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 57 |         [0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 58 |         [0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 59 |         [0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 60 |         [0,0,1,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 61 |         [0,0,1,1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 62 |         [0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 63 |         [0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 64 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 65 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 66 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 67 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 68 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 69 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 70 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 71 |         [0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 72 |         [0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 73 |         [0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 74 |         [0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 75 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 76 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 77 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 78 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 79 |         [0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 80 |         [0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 81 |         [0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 82 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 83 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 84 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 85 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 86 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 87 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 88 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 89 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 90 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 91 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 92 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 93 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 94 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 95 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 96 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 97 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 98 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
 99 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
100 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
101 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
102 |         [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
103 |     ];
104 |     for r in 0..board.len() {
105 |         for c in 0..board[0].len() {
106 |             if r == 0 || r == board.len() - 1 || c == 0 || c == board[0].len() - 1 { 
107 |                 board[r][c] = 0b1110;
108 |                 continue
109 |             }
110 |             let neighbors_alive =   (board[r-1][c-1] & 1) +
111 |                 (board[r-1][c] & 1) +
112 |                 (board[r-1][c+1] & 1) +
113 |                 (board[r][c-1] & 1) +
114 |                 (board[r][c+1] & 1) +
115 |                 (board[r+1][c-1] & 1) +
116 |                 (board[r+1][c] & 1) +
117 |                 (board[r+1][c+1] & 1);
118 |             board[r][c] |= neighbors_alive << 1;
119 |         }
120 |     }
121 |     let mut pixels: [u64; graphics::HEIGHT] = [0; graphics::HEIGHT];
122 |     let mut screen = graphics::init();
123 |     graphics::write_long(&mut screen, &pixels);
124 |     graphics::update(&mut screen);
125 |     loop {
126 |         board = update_board(&board);
127 |         for r in 0..HEIGHT {
128 |             pixels[r] = 0;
129 |             for c in 0..WIDTH {
130 |                 if board[r][c] & 1 == 1 {
131 |                     pixels[r] |= 1 << c;
132 |                 }
133 |             }
134 |         }
135 |         graphics::write_long(&mut screen, &pixels);
136 |         graphics::update(&mut screen);
137 |     }
138 | }
139 | 


--------------------------------------------------------------------------------
/app/pong/.cargo/config.toml:
--------------------------------------------------------------------------------
 1 | [target.riscv32i-unknown-none-elf]
 2 | rustflags = ["-C", "link-arg=-Tlink.x"]
 3 | 
 4 | [alias]
 5 | rbuild = "build --release --target riscv32i-unknown-none-elf"
 6 | rb = "rbuild"
 7 | 
 8 | rdoc = "doc --release --target riscv32i-unknown-none-elf"
 9 | rd = "rdoc"
10 | 
11 | rsize = "size --release --target riscv32i-unknown-none-elf"
12 | rs = "rsize"
13 | 
14 | robjdump = "objdump --release --target riscv32i-unknown-none-elf"
15 | rod = "robjdump"
16 | 
17 | 


--------------------------------------------------------------------------------
/app/pong/.vimspector.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "configurations": {
 3 |     "Launch": {
 4 |       "adapter": "vscode-cpptools",
 5 |       "filetypes": [ "cpp", "c", "objc", "rust" ],
 6 |       "configuration": {
 7 |         "request": "launch",
 8 |         "program": "${workspaceRoot}/target/x86_64-unknown-linux-gnu/debug/pong",
 9 |         "args": [],
10 |         "cwd": ".",
11 |         "environment": [],
12 |         "externalConsole": true,
13 |         "MIMode": "gdb",
14 |         "stopAtEntry": true
15 |       }
16 |     },
17 |     "Attach": {
18 |       "adapter": "vscode-cpptools",
19 |       "filetypes": [ "cpp", "c", "objc", "rust" ],
20 |       "configuration": {
21 |         "request": "attach",
22 |         "program": "${workspaceRoot}/target/x86_64-unknown-linux-gnu/debug/pong",
23 |         "MIMode": "gdb",
24 |         "stopAtEntry": true
25 |       }
26 |     }
27 |   }
28 | }
29 | 


--------------------------------------------------------------------------------
/app/pong/Cargo.lock:
--------------------------------------------------------------------------------
  1 | # This file is automatically @generated by Cargo.
  2 | # It is not intended for manual editing.
  3 | version = 3
  4 | 
  5 | [[package]]
  6 | name = "autocfg"
  7 | version = "1.1.0"
  8 | source = "registry+https://github.com/rust-lang/crates.io-index"
  9 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 10 | 
 11 | [[package]]
 12 | name = "bitflags"
 13 | version = "1.3.2"
 14 | source = "registry+https://github.com/rust-lang/crates.io-index"
 15 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 16 | 
 17 | [[package]]
 18 | name = "cassowary"
 19 | version = "0.3.0"
 20 | source = "registry+https://github.com/rust-lang/crates.io-index"
 21 | checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
 22 | 
 23 | [[package]]
 24 | name = "cfg-if"
 25 | version = "1.0.0"
 26 | source = "registry+https://github.com/rust-lang/crates.io-index"
 27 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 28 | 
 29 | [[package]]
 30 | name = "crossterm"
 31 | version = "0.25.0"
 32 | source = "registry+https://github.com/rust-lang/crates.io-index"
 33 | checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
 34 | dependencies = [
 35 |  "bitflags",
 36 |  "crossterm_winapi",
 37 |  "libc",
 38 |  "mio",
 39 |  "parking_lot",
 40 |  "signal-hook",
 41 |  "signal-hook-mio",
 42 |  "winapi",
 43 | ]
 44 | 
 45 | [[package]]
 46 | name = "crossterm"
 47 | version = "0.26.1"
 48 | source = "registry+https://github.com/rust-lang/crates.io-index"
 49 | checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13"
 50 | dependencies = [
 51 |  "bitflags",
 52 |  "crossterm_winapi",
 53 |  "libc",
 54 |  "mio",
 55 |  "parking_lot",
 56 |  "signal-hook",
 57 |  "signal-hook-mio",
 58 |  "winapi",
 59 | ]
 60 | 
 61 | [[package]]
 62 | name = "crossterm_winapi"
 63 | version = "0.9.0"
 64 | source = "registry+https://github.com/rust-lang/crates.io-index"
 65 | checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c"
 66 | dependencies = [
 67 |  "winapi",
 68 | ]
 69 | 
 70 | [[package]]
 71 | name = "libc"
 72 | version = "0.2.140"
 73 | source = "registry+https://github.com/rust-lang/crates.io-index"
 74 | checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
 75 | 
 76 | [[package]]
 77 | name = "lock_api"
 78 | version = "0.4.9"
 79 | source = "registry+https://github.com/rust-lang/crates.io-index"
 80 | checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
 81 | dependencies = [
 82 |  "autocfg",
 83 |  "scopeguard",
 84 | ]
 85 | 
 86 | [[package]]
 87 | name = "log"
 88 | version = "0.4.17"
 89 | source = "registry+https://github.com/rust-lang/crates.io-index"
 90 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
 91 | dependencies = [
 92 |  "cfg-if",
 93 | ]
 94 | 
 95 | [[package]]
 96 | name = "mio"
 97 | version = "0.8.6"
 98 | source = "registry+https://github.com/rust-lang/crates.io-index"
 99 | checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
100 | dependencies = [
101 |  "libc",
102 |  "log",
103 |  "wasi",
104 |  "windows-sys",
105 | ]
106 | 
107 | [[package]]
108 | name = "parking_lot"
109 | version = "0.12.1"
110 | source = "registry+https://github.com/rust-lang/crates.io-index"
111 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
112 | dependencies = [
113 |  "lock_api",
114 |  "parking_lot_core",
115 | ]
116 | 
117 | [[package]]
118 | name = "parking_lot_core"
119 | version = "0.9.7"
120 | source = "registry+https://github.com/rust-lang/crates.io-index"
121 | checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
122 | dependencies = [
123 |  "cfg-if",
124 |  "libc",
125 |  "redox_syscall",
126 |  "smallvec",
127 |  "windows-sys",
128 | ]
129 | 
130 | [[package]]
131 | name = "pong"
132 | version = "0.1.0"
133 | dependencies = [
134 |  "tdriver",
135 | ]
136 | 
137 | [[package]]
138 | name = "ratatui"
139 | version = "0.20.1"
140 | source = "registry+https://github.com/rust-lang/crates.io-index"
141 | checksum = "dcc0d032bccba900ee32151ec0265667535c230169f5a011154cdcd984e16829"
142 | dependencies = [
143 |  "bitflags",
144 |  "cassowary",
145 |  "crossterm 0.26.1",
146 |  "unicode-segmentation",
147 |  "unicode-width",
148 | ]
149 | 
150 | [[package]]
151 | name = "redox_syscall"
152 | version = "0.2.16"
153 | source = "registry+https://github.com/rust-lang/crates.io-index"
154 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
155 | dependencies = [
156 |  "bitflags",
157 | ]
158 | 
159 | [[package]]
160 | name = "scopeguard"
161 | version = "1.1.0"
162 | source = "registry+https://github.com/rust-lang/crates.io-index"
163 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
164 | 
165 | [[package]]
166 | name = "signal-hook"
167 | version = "0.3.15"
168 | source = "registry+https://github.com/rust-lang/crates.io-index"
169 | checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9"
170 | dependencies = [
171 |  "libc",
172 |  "signal-hook-registry",
173 | ]
174 | 
175 | [[package]]
176 | name = "signal-hook-mio"
177 | version = "0.2.3"
178 | source = "registry+https://github.com/rust-lang/crates.io-index"
179 | checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
180 | dependencies = [
181 |  "libc",
182 |  "mio",
183 |  "signal-hook",
184 | ]
185 | 
186 | [[package]]
187 | name = "signal-hook-registry"
188 | version = "1.4.1"
189 | source = "registry+https://github.com/rust-lang/crates.io-index"
190 | checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
191 | dependencies = [
192 |  "libc",
193 | ]
194 | 
195 | [[package]]
196 | name = "smallvec"
197 | version = "1.10.0"
198 | source = "registry+https://github.com/rust-lang/crates.io-index"
199 | checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
200 | 
201 | [[package]]
202 | name = "tdriver"
203 | version = "0.1.0"
204 | dependencies = [
205 |  "crossterm 0.25.0",
206 |  "ratatui",
207 | ]
208 | 
209 | [[package]]
210 | name = "unicode-segmentation"
211 | version = "1.10.1"
212 | source = "registry+https://github.com/rust-lang/crates.io-index"
213 | checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
214 | 
215 | [[package]]
216 | name = "unicode-width"
217 | version = "0.1.10"
218 | source = "registry+https://github.com/rust-lang/crates.io-index"
219 | checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
220 | 
221 | [[package]]
222 | name = "wasi"
223 | version = "0.11.0+wasi-snapshot-preview1"
224 | source = "registry+https://github.com/rust-lang/crates.io-index"
225 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
226 | 
227 | [[package]]
228 | name = "winapi"
229 | version = "0.3.9"
230 | source = "registry+https://github.com/rust-lang/crates.io-index"
231 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
232 | dependencies = [
233 |  "winapi-i686-pc-windows-gnu",
234 |  "winapi-x86_64-pc-windows-gnu",
235 | ]
236 | 
237 | [[package]]
238 | name = "winapi-i686-pc-windows-gnu"
239 | version = "0.4.0"
240 | source = "registry+https://github.com/rust-lang/crates.io-index"
241 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
242 | 
243 | [[package]]
244 | name = "winapi-x86_64-pc-windows-gnu"
245 | version = "0.4.0"
246 | source = "registry+https://github.com/rust-lang/crates.io-index"
247 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
248 | 
249 | [[package]]
250 | name = "windows-sys"
251 | version = "0.45.0"
252 | source = "registry+https://github.com/rust-lang/crates.io-index"
253 | checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
254 | dependencies = [
255 |  "windows-targets",
256 | ]
257 | 
258 | [[package]]
259 | name = "windows-targets"
260 | version = "0.42.2"
261 | source = "registry+https://github.com/rust-lang/crates.io-index"
262 | checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
263 | dependencies = [
264 |  "windows_aarch64_gnullvm",
265 |  "windows_aarch64_msvc",
266 |  "windows_i686_gnu",
267 |  "windows_i686_msvc",
268 |  "windows_x86_64_gnu",
269 |  "windows_x86_64_gnullvm",
270 |  "windows_x86_64_msvc",
271 | ]
272 | 
273 | [[package]]
274 | name = "windows_aarch64_gnullvm"
275 | version = "0.42.2"
276 | source = "registry+https://github.com/rust-lang/crates.io-index"
277 | checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
278 | 
279 | [[package]]
280 | name = "windows_aarch64_msvc"
281 | version = "0.42.2"
282 | source = "registry+https://github.com/rust-lang/crates.io-index"
283 | checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
284 | 
285 | [[package]]
286 | name = "windows_i686_gnu"
287 | version = "0.42.2"
288 | source = "registry+https://github.com/rust-lang/crates.io-index"
289 | checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
290 | 
291 | [[package]]
292 | name = "windows_i686_msvc"
293 | version = "0.42.2"
294 | source = "registry+https://github.com/rust-lang/crates.io-index"
295 | checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
296 | 
297 | [[package]]
298 | name = "windows_x86_64_gnu"
299 | version = "0.42.2"
300 | source = "registry+https://github.com/rust-lang/crates.io-index"
301 | checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
302 | 
303 | [[package]]
304 | name = "windows_x86_64_gnullvm"
305 | version = "0.42.2"
306 | source = "registry+https://github.com/rust-lang/crates.io-index"
307 | checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
308 | 
309 | [[package]]
310 | name = "windows_x86_64_msvc"
311 | version = "0.42.2"
312 | source = "registry+https://github.com/rust-lang/crates.io-index"
313 | checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
314 | 


--------------------------------------------------------------------------------
/app/pong/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "pong"
 3 | version = "0.1.0"
 4 | edition = "2021"
 5 | 
 6 | [dependencies]
 7 | tdriver = { path = "../tdriver" }
 8 | 
 9 | # Don't ever use this for riscv builds or they will be massive
10 | [profile.dev]
11 | 
12 | [profile.release]
13 | panic = "abort"
14 | # Use either 2, 3, s or z
15 | opt-level = 3
16 | overflow-checks = false
17 | lto = true
18 | 
19 | 


--------------------------------------------------------------------------------
/app/pong/copy-bin.sh:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/sh
 2 | 
 3 | # Helper script to copy file to txt file format WireHead expects
 4 | # Example: ./copy_bin.sh /tmp/in.txt
 5 | 
 6 | # Rebuild project
 7 | cargo rbuild
 8 | 
 9 | # Convert from elf to bin
10 | # Fancy glob matching! https://zsh.sourceforge.io/Doc/Release/Expansion.html#Glob-Qualifiers
11 | # rust-objcopy -O binary ./target/riscv32i-unknown-none-elf/release/*(x.) /tmp/rust.bin 
12 | rust-objcopy -O binary ./target/riscv32i-unknown-none-elf/release/pong /tmp/rust.bin 
13 | 
14 | # Convert from bin to txt
15 | hexdump -ve '1/1 "%.2x "' /tmp/rust.bin | head -c -1 > $1
16 | 
17 | 


--------------------------------------------------------------------------------
/app/pong/src/main.rs:
--------------------------------------------------------------------------------
  1 | #![no_std]
  2 | #![no_main]
  3 | 
  4 | use tdriver::entry;
  5 | use tdriver::graphics;
  6 | use tdriver::graphics::WIDTH;
  7 | use tdriver::graphics::HEIGHT;
  8 | 
  9 | entry!(main);
 10 | 
 11 | 
 12 | // Entry point of user code
 13 | fn main() -> ! {
 14 |     let mut pixels: [u64; graphics::HEIGHT] = [0x0000000000000000; graphics::HEIGHT];
 15 |     let mut ball_pos: (usize, usize) = ((WIDTH / 2) as usize, (HEIGHT / 2) as usize);
 16 |     let mut ball_vel: (i8, i8) = (3, 1);
 17 |     let mut screen = graphics::init();
 18 | 
 19 |     let mut p_left = HEIGHT / 2;
 20 |     let mut p_right = HEIGHT / 2;
 21 |     let p_size: usize = 5;
 22 | 
 23 |     // Init paddles
 24 |     for i in p_left-p_size..=p_left+p_size {
 25 |         let data: u32 = 0x00000001;
 26 |         graphics::write_line(&mut screen, data, i, 0);
 27 |         pixels[i] |= (0xFFFFFFFF & data) as u64;
 28 |     }
 29 |     for i in p_right-p_size..=p_right+p_size {
 30 |         let data: u32 = 0x80000000;
 31 |         graphics::write_line(&mut screen, data, i, 1);
 32 |         pixels[i] |= (data as u64) << 32;
 33 |     }
 34 |     graphics::update(&mut screen);
 35 | 
 36 |     loop {
 37 |         // Move left platform
 38 |         let input = graphics::input(&mut screen);
 39 |         let up = input & graphics::input_flags::UP != 0;
 40 |         let down = input & graphics::input_flags::DOWN != 0;
 41 | 
 42 |         if up && down {}
 43 |         else if down {
 44 |             if p_left + p_size < HEIGHT - 1 {
 45 |                 graphics::write_line(&mut screen, 0, p_left-p_size, 0);
 46 |                 pixels[p_left-p_size] &= !1;
 47 |                 graphics::write_line(&mut screen, 1, p_left+p_size, 0);
 48 |                 pixels[p_left+p_size] |= 1;
 49 |                 p_left += 1;
 50 |             }
 51 |         } else if up {
 52 |             if p_left - p_size > 0 {
 53 |                 graphics::write_line(&mut screen, 1, p_left-p_size, 0);
 54 |                 pixels[p_left-p_size] |= 1;
 55 |                 graphics::write_line(&mut screen, 0, p_left+p_size, 0);
 56 |                 pixels[p_left+p_size] &= !1;
 57 |                 p_left -= 1;
 58 |             }
 59 |         }
 60 | 
 61 |         // Move right platform
 62 |         let defense_right = ball_vel.0 > 0;
 63 |         if (defense_right && ball_pos.1 > p_right) || (!defense_right && p_right < HEIGHT / 2) {
 64 |             if p_right + p_size < HEIGHT - 1 {
 65 |                 graphics::write_line(&mut screen, 0, p_right-p_size, 1);
 66 |                 pixels[p_right-p_size] &= !(1 << 63);
 67 |                 graphics::write_line(&mut screen, 1 << 31, p_right+p_size, 1);
 68 |                 pixels[p_right+p_size] |= 1 << 63;
 69 |                 p_right += 1;
 70 |             }
 71 |         } else {
 72 |             if p_right - p_size > 0 {
 73 |                 graphics::write_line(&mut screen, 1 << 31, p_right-p_size, 1);
 74 |                 pixels[p_right-p_size] |= 1 << 63;
 75 |                 graphics::write_line(&mut screen, 0, p_right+p_size, 1);
 76 |                 pixels[p_right+p_size] &= !(1 << 63);
 77 |                 p_right -= 1;
 78 |             }
 79 |         }
 80 |         
 81 |         // Erase old ball
 82 |         let mut word = ball_pos.0 / 32;
 83 |         if !(ball_pos.0 == 0 && ball_pos.1 >= p_left - p_size && ball_pos.1 <= p_left + p_size) &&
 84 |             !(ball_pos.0 == WIDTH-1 && ball_pos.1 >= p_right - p_size && ball_pos.1 <= p_right + p_size) {
 85 |             pixels[ball_pos.1 as usize] &= !(1 << ball_pos.0);
 86 |         }
 87 |         graphics::write_line(&mut screen, (pixels[ball_pos.1 as usize] >> (32 * word)) as u32, ball_pos.1, word);
 88 | 
 89 |         // Update new ball position
 90 |         ball_pos = ((ball_pos.0 as i8 + ball_vel.0) as usize, (ball_pos.1 as i8 + ball_vel.1) as usize);
 91 | 
 92 |         // If close snap to edge
 93 |         if ball_vel.0 < 0 && ball_pos.0 <= -ball_vel.0 as usize + 1 { ball_pos.0 = 1; ball_vel.0 *= -1 }
 94 |         if ball_vel.0 > 0 && ball_pos.0 >= WIDTH - ball_vel.0 as usize { ball_pos.0 = WIDTH-2; ball_vel.0 *= -1 }
 95 | 
 96 |         // Bounce
 97 |         if ball_pos.0 as i8 + ball_vel.0 < 0 {
 98 |             ball_vel.0 *= -1;
 99 |         }
100 |         else if ball_pos.0 as i8 + ball_vel.0 >= WIDTH as i8 {
101 |             ball_vel.0 *= -1;
102 |         }
103 |         if ball_pos.1 as i8 + ball_vel.1 < 1 || ball_pos.1 as i8 + ball_vel.1 >= HEIGHT as i8 {
104 |             ball_vel.1 *= -1;
105 |         }
106 |         // Draw new ball
107 |         word = ball_pos.0 / 32;
108 |         pixels[ball_pos.1 as usize] |= 1 << ball_pos.0;
109 |         graphics::write_line(&mut screen, (pixels[ball_pos.1 as usize] >> (32 * word)) as u32, ball_pos.1, word);
110 |         graphics::update(&mut screen);
111 |     }
112 | }
113 | 


--------------------------------------------------------------------------------
/app/tdriver/.cargo/config.toml:
--------------------------------------------------------------------------------
 1 | [target.riscv32i-unknown-none-elf]
 2 | rustflags = ["-C", "link-arg=-Tlink.x"]
 3 | 
 4 | [env]
 5 | EMU_TICK_RATE = "100"
 6 | 
 7 | [alias]
 8 | rbuild = "build --target riscv32i-unknown-none-elf --release"
 9 | rb = "rbuild"
10 | 
11 | rdoc = "doc --target riscv32i-unknown-none-elf --release"
12 | rd = "rdoc"
13 | 
14 | 


--------------------------------------------------------------------------------
/app/tdriver/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | 


--------------------------------------------------------------------------------
/app/tdriver/Cargo.lock:
--------------------------------------------------------------------------------
  1 | # This file is automatically @generated by Cargo.
  2 | # It is not intended for manual editing.
  3 | version = 3
  4 | 
  5 | [[package]]
  6 | name = "autocfg"
  7 | version = "1.1.0"
  8 | source = "registry+https://github.com/rust-lang/crates.io-index"
  9 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 10 | 
 11 | [[package]]
 12 | name = "bitflags"
 13 | version = "1.3.2"
 14 | source = "registry+https://github.com/rust-lang/crates.io-index"
 15 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 16 | 
 17 | [[package]]
 18 | name = "cassowary"
 19 | version = "0.3.0"
 20 | source = "registry+https://github.com/rust-lang/crates.io-index"
 21 | checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
 22 | 
 23 | [[package]]
 24 | name = "cfg-if"
 25 | version = "1.0.0"
 26 | source = "registry+https://github.com/rust-lang/crates.io-index"
 27 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 28 | 
 29 | [[package]]
 30 | name = "crossterm"
 31 | version = "0.25.0"
 32 | source = "registry+https://github.com/rust-lang/crates.io-index"
 33 | checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
 34 | dependencies = [
 35 |  "bitflags",
 36 |  "crossterm_winapi",
 37 |  "libc",
 38 |  "mio",
 39 |  "parking_lot",
 40 |  "signal-hook",
 41 |  "signal-hook-mio",
 42 |  "winapi",
 43 | ]
 44 | 
 45 | [[package]]
 46 | name = "crossterm"
 47 | version = "0.26.1"
 48 | source = "registry+https://github.com/rust-lang/crates.io-index"
 49 | checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13"
 50 | dependencies = [
 51 |  "bitflags",
 52 |  "crossterm_winapi",
 53 |  "libc",
 54 |  "mio",
 55 |  "parking_lot",
 56 |  "signal-hook",
 57 |  "signal-hook-mio",
 58 |  "winapi",
 59 | ]
 60 | 
 61 | [[package]]
 62 | name = "crossterm_winapi"
 63 | version = "0.9.0"
 64 | source = "registry+https://github.com/rust-lang/crates.io-index"
 65 | checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c"
 66 | dependencies = [
 67 |  "winapi",
 68 | ]
 69 | 
 70 | [[package]]
 71 | name = "libc"
 72 | version = "0.2.140"
 73 | source = "registry+https://github.com/rust-lang/crates.io-index"
 74 | checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
 75 | 
 76 | [[package]]
 77 | name = "lock_api"
 78 | version = "0.4.9"
 79 | source = "registry+https://github.com/rust-lang/crates.io-index"
 80 | checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
 81 | dependencies = [
 82 |  "autocfg",
 83 |  "scopeguard",
 84 | ]
 85 | 
 86 | [[package]]
 87 | name = "log"
 88 | version = "0.4.17"
 89 | source = "registry+https://github.com/rust-lang/crates.io-index"
 90 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
 91 | dependencies = [
 92 |  "cfg-if",
 93 | ]
 94 | 
 95 | [[package]]
 96 | name = "mio"
 97 | version = "0.8.6"
 98 | source = "registry+https://github.com/rust-lang/crates.io-index"
 99 | checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
100 | dependencies = [
101 |  "libc",
102 |  "log",
103 |  "wasi",
104 |  "windows-sys",
105 | ]
106 | 
107 | [[package]]
108 | name = "parking_lot"
109 | version = "0.12.1"
110 | source = "registry+https://github.com/rust-lang/crates.io-index"
111 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
112 | dependencies = [
113 |  "lock_api",
114 |  "parking_lot_core",
115 | ]
116 | 
117 | [[package]]
118 | name = "parking_lot_core"
119 | version = "0.9.7"
120 | source = "registry+https://github.com/rust-lang/crates.io-index"
121 | checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
122 | dependencies = [
123 |  "cfg-if",
124 |  "libc",
125 |  "redox_syscall",
126 |  "smallvec",
127 |  "windows-sys",
128 | ]
129 | 
130 | [[package]]
131 | name = "ratatui"
132 | version = "0.20.1"
133 | source = "registry+https://github.com/rust-lang/crates.io-index"
134 | checksum = "dcc0d032bccba900ee32151ec0265667535c230169f5a011154cdcd984e16829"
135 | dependencies = [
136 |  "bitflags",
137 |  "cassowary",
138 |  "crossterm 0.26.1",
139 |  "unicode-segmentation",
140 |  "unicode-width",
141 | ]
142 | 
143 | [[package]]
144 | name = "redox_syscall"
145 | version = "0.2.16"
146 | source = "registry+https://github.com/rust-lang/crates.io-index"
147 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
148 | dependencies = [
149 |  "bitflags",
150 | ]
151 | 
152 | [[package]]
153 | name = "scopeguard"
154 | version = "1.1.0"
155 | source = "registry+https://github.com/rust-lang/crates.io-index"
156 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
157 | 
158 | [[package]]
159 | name = "signal-hook"
160 | version = "0.3.15"
161 | source = "registry+https://github.com/rust-lang/crates.io-index"
162 | checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9"
163 | dependencies = [
164 |  "libc",
165 |  "signal-hook-registry",
166 | ]
167 | 
168 | [[package]]
169 | name = "signal-hook-mio"
170 | version = "0.2.3"
171 | source = "registry+https://github.com/rust-lang/crates.io-index"
172 | checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
173 | dependencies = [
174 |  "libc",
175 |  "mio",
176 |  "signal-hook",
177 | ]
178 | 
179 | [[package]]
180 | name = "signal-hook-registry"
181 | version = "1.4.1"
182 | source = "registry+https://github.com/rust-lang/crates.io-index"
183 | checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
184 | dependencies = [
185 |  "libc",
186 | ]
187 | 
188 | [[package]]
189 | name = "smallvec"
190 | version = "1.10.0"
191 | source = "registry+https://github.com/rust-lang/crates.io-index"
192 | checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
193 | 
194 | [[package]]
195 | name = "tdriver"
196 | version = "0.1.0"
197 | dependencies = [
198 |  "crossterm 0.25.0",
199 |  "ratatui",
200 | ]
201 | 
202 | [[package]]
203 | name = "unicode-segmentation"
204 | version = "1.10.1"
205 | source = "registry+https://github.com/rust-lang/crates.io-index"
206 | checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
207 | 
208 | [[package]]
209 | name = "unicode-width"
210 | version = "0.1.10"
211 | source = "registry+https://github.com/rust-lang/crates.io-index"
212 | checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
213 | 
214 | [[package]]
215 | name = "wasi"
216 | version = "0.11.0+wasi-snapshot-preview1"
217 | source = "registry+https://github.com/rust-lang/crates.io-index"
218 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
219 | 
220 | [[package]]
221 | name = "winapi"
222 | version = "0.3.9"
223 | source = "registry+https://github.com/rust-lang/crates.io-index"
224 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
225 | dependencies = [
226 |  "winapi-i686-pc-windows-gnu",
227 |  "winapi-x86_64-pc-windows-gnu",
228 | ]
229 | 
230 | [[package]]
231 | name = "winapi-i686-pc-windows-gnu"
232 | version = "0.4.0"
233 | source = "registry+https://github.com/rust-lang/crates.io-index"
234 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
235 | 
236 | [[package]]
237 | name = "winapi-x86_64-pc-windows-gnu"
238 | version = "0.4.0"
239 | source = "registry+https://github.com/rust-lang/crates.io-index"
240 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
241 | 
242 | [[package]]
243 | name = "windows-sys"
244 | version = "0.45.0"
245 | source = "registry+https://github.com/rust-lang/crates.io-index"
246 | checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
247 | dependencies = [
248 |  "windows-targets",
249 | ]
250 | 
251 | [[package]]
252 | name = "windows-targets"
253 | version = "0.42.2"
254 | source = "registry+https://github.com/rust-lang/crates.io-index"
255 | checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
256 | dependencies = [
257 |  "windows_aarch64_gnullvm",
258 |  "windows_aarch64_msvc",
259 |  "windows_i686_gnu",
260 |  "windows_i686_msvc",
261 |  "windows_x86_64_gnu",
262 |  "windows_x86_64_gnullvm",
263 |  "windows_x86_64_msvc",
264 | ]
265 | 
266 | [[package]]
267 | name = "windows_aarch64_gnullvm"
268 | version = "0.42.2"
269 | source = "registry+https://github.com/rust-lang/crates.io-index"
270 | checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
271 | 
272 | [[package]]
273 | name = "windows_aarch64_msvc"
274 | version = "0.42.2"
275 | source = "registry+https://github.com/rust-lang/crates.io-index"
276 | checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
277 | 
278 | [[package]]
279 | name = "windows_i686_gnu"
280 | version = "0.42.2"
281 | source = "registry+https://github.com/rust-lang/crates.io-index"
282 | checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
283 | 
284 | [[package]]
285 | name = "windows_i686_msvc"
286 | version = "0.42.2"
287 | source = "registry+https://github.com/rust-lang/crates.io-index"
288 | checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
289 | 
290 | [[package]]
291 | name = "windows_x86_64_gnu"
292 | version = "0.42.2"
293 | source = "registry+https://github.com/rust-lang/crates.io-index"
294 | checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
295 | 
296 | [[package]]
297 | name = "windows_x86_64_gnullvm"
298 | version = "0.42.2"
299 | source = "registry+https://github.com/rust-lang/crates.io-index"
300 | checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
301 | 
302 | [[package]]
303 | name = "windows_x86_64_msvc"
304 | version = "0.42.2"
305 | source = "registry+https://github.com/rust-lang/crates.io-index"
306 | checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
307 | 


--------------------------------------------------------------------------------
/app/tdriver/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "tdriver"
 3 | version = "0.1.0"
 4 | edition = "2021"
 5 | 
 6 | [profile.dev]
 7 | 
 8 | # [target.'cfg(target_arch="riscv32")'.profile.release]
 9 | [profile.release]
10 | panic = "abort"
11 | opt-level = "z"
12 | overflow-checks = false
13 | lto = true
14 | 
15 | [target.'cfg(not(target_arch = "riscv32"))'.dependencies]
16 | tui = { package = "ratatui", version = "0.20.1" }
17 | crossterm = "0.25"
18 | 
19 | 


--------------------------------------------------------------------------------
/app/tdriver/build.rs:
--------------------------------------------------------------------------------
 1 | use std::{env, error::Error, fs::File, io::Write, path::PathBuf};
 2 | 
 3 | fn main() -> Result<(), Box<dyn Error>> {
 4 |     // build directory for this crate
 5 |     let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
 6 | 
 7 |     // extend the library search path
 8 |     println!("cargo:rustc-link-search={}", out_dir.display());
 9 | 
10 |     // put `link.x` in the build directory
11 |     File::create(out_dir.join("link.x"))?.write_all(include_bytes!("link.x"))?;
12 | 
13 |     Ok(())
14 | }
15 | 


--------------------------------------------------------------------------------
/app/tdriver/link.x:
--------------------------------------------------------------------------------
 1 | MEMORY
 2 | {
 3 |   FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 768K
 4 |   RAM (rwx) : ORIGIN = 0x00100000, LENGTH = 368K
 5 |   /* Memory mapped io */
 6 |   SCREEN (w) : ORIGIN = 0x00200000, LENGTH = 16K
 7 |   BW_SCREEN (rw) : ORIGIN = 0x0020E000, LENGTH = 8K
 8 | }
 9 | 
10 | /* The entry point is the reset handler */
11 | ENTRY(Reset);
12 | 
13 | SECTIONS
14 | {
15 |   .text :
16 |   {
17 |     KEEP(*(.text.start));
18 |     *(.text.reset);
19 |     *(.text .text.*);
20 |   } > FLASH
21 | 
22 |   .rodata :
23 |   {
24 |     *(.rodata .rodata.*);
25 |   } > FLASH
26 | 
27 |   .bss :
28 |   {
29 |     _sbss = .;
30 |     *(.bss .bss.*);
31 |     _ebss = .;
32 |   } > RAM
33 | 
34 |   .data : AT(ADDR(.rodata) + SIZEOF(.rodata))
35 |   {
36 |     _sdata = .;
37 |     *(.data .data.*);
38 |     _edata = .;
39 |   } > RAM
40 | 
41 |   _sidata = LOADADDR(.data);
42 |   _stack_start = ORIGIN(RAM) + LENGTH(RAM);
43 | 
44 | 
45 | }
46 | 


--------------------------------------------------------------------------------
/app/tdriver/rust-analyzer.toml:
--------------------------------------------------------------------------------
1 | [diagnostics]
2 | disabled = ["inactive-code"]
3 | 


--------------------------------------------------------------------------------
/app/tdriver/src/graphics.rs:
--------------------------------------------------------------------------------
  1 | #[cfg(not(target_arch = "riscv32"))]
  2 | use {
  3 |     tui::{
  4 |         backend::{Backend, CrosstermBackend},
  5 |         layout::{Constraint, Direction, Layout},
  6 |         widgets::{
  7 |             Block, Borders,
  8 |             canvas::{Canvas, Rectangle},
  9 |         },
 10 |         style::Color,
 11 |         Terminal, symbols, Frame,
 12 |     },
 13 |     std::{io, time::{Duration, Instant}, process},
 14 |     crossterm::{
 15 |         event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},
 16 |         execute,
 17 |         terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
 18 |     },
 19 | };
 20 | 
 21 | /******************************************************************************
 22 |  * Constants
 23 |  ******************************************************************************/
 24 | 
 25 | /// Number of pixels in horizontal direction
 26 | pub const WIDTH: usize = 64;
 27 | /// Number of pixels in vertical direction
 28 | pub const HEIGHT: usize = 48;
 29 | 
 30 | /// Width in number of 32 bit words that can fit horizontally
 31 | pub const WORDS: usize = WIDTH / 32;
 32 | 
 33 | /// Bitflag definitions for controller inputs
 34 | pub mod input_flags {
 35 |     pub const DOWN: u32 =   0b0001;
 36 |     pub const LEFT: u32 =   0b0010;
 37 |     pub const RIGHT: u32 =  0b0100;
 38 |     pub const UP: u32 =     0b1000;
 39 | }
 40 | 
 41 | /******************************************************************************
 42 |  * Types
 43 |  ******************************************************************************/
 44 | 
 45 | /**
 46 |  * Struct describing the current state of screen
 47 |  */
 48 | pub struct Screen {
 49 |     #[cfg(target_arch = "riscv32")]
 50 |     base_addr: *mut u32,
 51 |     #[cfg(target_arch = "riscv32")]
 52 |     update_addr: *mut u32,
 53 |     #[cfg(target_arch = "riscv32")]
 54 |     input_addr: *mut u32,
 55 | 
 56 |     #[cfg(not(target_arch = "riscv32"))]
 57 |     terminal: Terminal<tui::backend::CrosstermBackend<std::io::Stdout>>,
 58 |     #[cfg(not(target_arch = "riscv32"))]
 59 |     state: [[bool; WIDTH]; HEIGHT],
 60 |     #[cfg(not(target_arch = "riscv32"))]
 61 |     tick_rate: Duration,
 62 |     #[cfg(not(target_arch = "riscv32"))]
 63 |     last_tick: Instant,
 64 |     #[cfg(not(target_arch = "riscv32"))]
 65 |     input: u32,
 66 | }
 67 | 
 68 | 
 69 | /******************************************************************************
 70 |  * x86 HAL
 71 |  ******************************************************************************/
 72 | 
 73 | #[cfg(not(target_arch = "riscv32"))]
 74 | fn write_screen(screen: &mut Screen) {
 75 |     while screen.last_tick.elapsed() < screen.tick_rate {
 76 |         screen.terminal.draw(|f| { ui(f, &screen.state) }).unwrap();
 77 |             if event::poll(Duration::from_millis(0)).unwrap() {
 78 |                 if let Event::Key(key) = event::read().unwrap() {
 79 |                     match key.code { 
 80 |                         KeyCode::Char('q') => {
 81 |                         disable_raw_mode().unwrap();
 82 |                         execute!(
 83 |                             screen.terminal.backend_mut(),
 84 |                             LeaveAlternateScreen,
 85 |                             DisableMouseCapture
 86 |                         ).unwrap();
 87 |                         screen.terminal.show_cursor().unwrap();
 88 |                         process::exit(0)
 89 |                     }, 
 90 |                     KeyCode::Char('w') => screen.input |= input_flags::UP,
 91 |                     KeyCode::Char('d') => screen.input |= input_flags::RIGHT,
 92 |                     KeyCode::Char('a') => screen.input |= input_flags::LEFT,
 93 |                     KeyCode::Char('s') => screen.input |= input_flags::DOWN,
 94 |                     _ => {}
 95 |                 }
 96 |             }
 97 |         }
 98 |     }
 99 | 
100 |     screen.last_tick = Instant::now();
101 | }
102 | 
103 | #[cfg(not(target_arch = "riscv32"))]
104 | fn ui<B: Backend>(f: &mut Frame<B>, state: &[[bool; WIDTH]; HEIGHT]) {
105 |     let vertical_chunks = Layout::default()
106 |         .direction(Direction::Vertical)
107 |         .constraints(
108 |             [
109 |                 Constraint::Length((HEIGHT) as u16), Constraint::Min(0)
110 |             ].as_ref()
111 |         )
112 |         .split(f.size());
113 | 
114 |     let chunks = Layout::default()
115 |         .direction(Direction::Horizontal)
116 |         .constraints(
117 |             [
118 |                 Constraint::Length(((WIDTH+1) * 2) as u16), Constraint::Min(0)
119 |             ].as_ref()
120 |         )
121 |         .split(vertical_chunks[0]);
122 | 
123 |     let canvas = Canvas::default()
124 |         .marker(symbols::Marker::Braille)
125 |         .block(Block::default().borders(Borders::ALL).title("Screen"))
126 |         .paint(|ctx| {
127 |             for h in 0..state.len() {
128 |                 for w in 0..state[0].len() {
129 |                     if state[h][w] {
130 |                         ctx.draw(&Rectangle {
131 |                             x: w as f64, y: HEIGHT as f64 - h as f64-1.0,
132 |                             width: 1.0, height: 1.0,
133 |                             color: Color::White
134 |                         });
135 |                     }
136 |                 }
137 |             }
138 |         })
139 |         .x_bounds([0.0, WIDTH as f64])
140 |         .y_bounds([0.0, HEIGHT as f64]);
141 |     f.render_widget(canvas, chunks[0]);
142 | }
143 | 
144 | /******************************************************************************
145 |  * Public Functions
146 |  ******************************************************************************/
147 | 
148 | /**
149 |  * Initializes screen and returns screen struct
150 |  */
151 | pub fn init() -> Screen {
152 | 
153 | #[cfg(target_arch = "riscv32")] {
154 |     Screen {
155 |         base_addr: 0x20E000 as *mut u32,
156 |         update_addr: 0x20E1FC as *mut u32,
157 |         input_addr: 0x20E1F8 as *mut u32,
158 |     }
159 | }
160 | 
161 | #[cfg(not(target_arch = "riscv32"))] {
162 |     enable_raw_mode().unwrap();
163 |     let mut stdout = io::stdout();
164 |     execute!(stdout, EnterAlternateScreen, EnableMouseCapture).unwrap();
165 |     let backend = CrosstermBackend::new(stdout);
166 |     let terminal = Terminal::new(backend).unwrap();
167 | 
168 |     let mut screen = Screen { 
169 |         terminal,
170 |         state: [[false; WIDTH]; HEIGHT],
171 |         tick_rate: Duration::from_millis(
172 |             std::option_env!("EMU_TICK_RATE").unwrap_or("100").parse().unwrap()
173 |             // std::env!("EMU_TICK_RATE").parse().unwrap()
174 |             ),
175 |         last_tick: Instant::now(),
176 |         input: 0,
177 |     };
178 | 
179 |     write_screen(&mut screen);
180 | 
181 |     screen
182 | }}
183 | 
184 | /**
185 |  * Writes a pixel array into screen as implemented in hardware
186 |  */
187 | pub fn write_raw(screen: &mut Screen, pixels: &[[u32; WORDS]; HEIGHT]) {
188 | 
189 | #[cfg(target_arch = "riscv32")] {
190 |     unsafe {
191 |         for w in 0..WORDS {
192 |             for h in 0..HEIGHT{
193 |                 screen.base_addr.add(w + WORDS * h).write_volatile(pixels[h][w]);
194 |             }
195 |         }
196 |     }
197 | }
198 | 
199 | #[cfg(not(target_arch = "riscv32"))] {
200 |     for h in 0..screen.state.len() {
201 |         for w in 0..screen.state[0].len() {
202 |             screen.state[h][w] = (pixels[h][w/32] >> (w%32)) & 0b1 == 1
203 |         }
204 |     }
205 | }}
206 | 
207 | 
208 | /**
209 |  * Equivalent to write_raw except with u64 instead of [u32; 2]
210 |  */
211 | pub fn write_long(screen: &mut Screen, pixels: &[u64; HEIGHT]) {
212 | 
213 | #[cfg(target_arch = "riscv32")] {
214 |     unsafe {
215 |         for h in 0..pixels.len(){
216 |             screen.base_addr.add(2 * h).write_volatile(pixels[h] as u32);
217 |             screen.base_addr.add(2 * h + 1).write_volatile((pixels[h] >> 32) as u32);
218 |         }
219 |     }
220 | }
221 | 
222 | #[cfg(not(target_arch = "riscv32"))] {
223 |     for h in 0..screen.state.len() {
224 |         for w in 0..screen.state[0].len() {
225 |             screen.state[h][w] = (pixels[h] >> w) & 0b1 == 1
226 |         }
227 |     }
228 | }}
229 | 
230 | /**
231 |  * Writes a line to screen at a specified row, word is 0 for lower word and 1 for upper
232 |  */
233 | pub fn write_line(screen: &mut Screen, data: u32, row: usize, word: usize) {
234 | 
235 | #[cfg(target_arch = "riscv32")] {
236 |     unsafe {
237 |         screen.base_addr.add((2*row + word) as usize).write_volatile(data);
238 |     }
239 | }
240 | 
241 | #[cfg(not(target_arch = "riscv32"))] {
242 |     for w in 0..32 {
243 |         screen.state[row as usize][(word * 32 + w) as usize] = (data >> w) & 0b1 == 1;
244 |     }
245 | }}
246 | 
247 | /**
248 |  * Updates screen by writing to screen register
249 |  */
250 | pub fn update(screen: &mut Screen) {
251 | 
252 | #[cfg(target_arch = "riscv32")] {
253 |     unsafe {
254 |         screen.update_addr.write_volatile(0b1);
255 |     }
256 | }
257 | 
258 | #[cfg(not(target_arch = "riscv32"))] {
259 |     write_screen(screen);
260 | }}
261 | 
262 | /**
263 |  * Reads input from controller since last call to this
264 |  *
265 |  * Returns a bitmask of the buttons pressed, see input_flags for bit position
266 |  * definitions
267 |  */
268 | pub fn input(screen: &mut Screen) -> u32 {
269 |     
270 | #[cfg(target_arch = "riscv32")] {
271 |     unsafe {
272 |         return screen.input_addr.read_volatile()
273 |     }
274 | }
275 | 
276 | #[cfg(not(target_arch = "riscv32"))] {
277 |     let input: u32 = screen.input;
278 |     screen.input = 0;
279 |     input
280 | }}
281 | 
282 | /******************************************************************************
283 |  * Legacy Functions
284 |  ******************************************************************************/
285 | 
286 | /**
287 |  * Sanity check to ensure all pixels in screen work by running a pixel accross the entire screen
288 |  *
289 |  * This is kept as super low level/hardcoded intentionally to prevent other stuff in this module
290 |  * from breaking this, might change this later when I'm more confident in my code
291 |  */
292 | #[cfg(target_arch = "riscv32")]
293 | pub fn sanity_check() {
294 |     let screen: *mut u32 = 0x1E000 as *mut u32;
295 |     let screen_write: *mut u32 = 0x1E1FC as *mut u32;
296 |     unsafe {
297 |         for i in 0..96 {
298 |             for j in 0..32 {
299 |                 screen.add(i).write_volatile(1 << j);
300 |                 screen_write.write_volatile(1);
301 |             }
302 |             screen.add(i).write_volatile(0);
303 |         }
304 |     }
305 | }
306 | 
307 | 


--------------------------------------------------------------------------------
/app/tdriver/src/lib.rs:
--------------------------------------------------------------------------------
  1 | // Conditional version of #![no_std]
  2 | #![cfg_attr(target_arch = "riscv32", no_std)]
  3 | 
  4 | #[cfg(target_arch = "riscv32")]
  5 | use {
  6 |     core::arch::global_asm,
  7 |     core::panic::PanicInfo,
  8 |     core::ptr,
  9 | };
 10 | 
 11 | 
 12 | pub mod graphics;
 13 | 
 14 | /******************************************************************************
 15 |  * Reset handling
 16 |  ******************************************************************************/
 17 | 
 18 | // Init stack pointer
 19 | // This has to be before Reset in linker script since otherwise function can't
 20 | // enter
 21 | #[cfg(target_arch = "riscv32")]
 22 | global_asm!("
 23 |     .section .text.start
 24 |     la sp, _stack_start
 25 | ");
 26 | 
 27 | // Entry point of program
 28 | // Sets up abi and initializes memory
 29 | #[no_mangle]
 30 | #[link_section = ".text.reset"]
 31 | #[cfg(target_arch = "riscv32")]
 32 | unsafe extern "C" fn Reset() -> ! {
 33 | 
 34 |     // Occasionaly useful for debuggin, should write to screen
 35 |     // If it doesn't then something is probably wrong with hardware
 36 |     // let base_addr = 0x20E000 as *mut u32;
 37 |     // let update_addr = 0x20E1FC as *mut u32;
 38 |     // base_addr.write_volatile(0b11111111111110010011);
 39 |     // update_addr.write_volatile(0b101);
 40 | 
 41 |     // Initialize RAM
 42 |     extern "C" {
 43 |         static mut _sbss: u8;
 44 |         static mut _ebss: u8;
 45 | 
 46 |         static mut _sdata: u8;
 47 |         static mut _edata: u8;
 48 |         static _sidata: u8;
 49 |     }
 50 | 
 51 |     // Copy static variables
 52 |     let count = &_ebss as *const u8 as usize - &_sbss as *const u8 as usize;
 53 |     ptr::write_bytes(&mut _sbss as *mut u8, 0, count);
 54 | 
 55 |     let count = &_edata as *const u8 as usize - &_sdata as *const u8 as usize;
 56 |     ptr::copy_nonoverlapping(&_sidata as *const u8, &mut _sdata as *mut u8, count);
 57 | 
 58 |     extern "Rust" {
 59 |         fn main() -> !;
 60 |     }
 61 | 
 62 |     main()
 63 | }
 64 | 
 65 | #[panic_handler]
 66 | #[cfg(target_arch = "riscv32")]
 67 | fn panic(_info: &PanicInfo) -> ! {
 68 |     loop {}
 69 | }
 70 | 
 71 | /******************************************************************************
 72 |  * Macros
 73 |  ******************************************************************************/
 74 | 
 75 | /**
 76 |  * Macro to define entry point of program in a type safe way.
 77 |  *
 78 |  * To use, define a divergent function (a function with `-> !`) and call this macro:
 79 |  * ```
 80 |  * entry!(main);
 81 |  *
 82 |  * fn main() -> ! {
 83 |  *     // Your code here
 84 |  *  }
 85 |  * ```
 86 |  */
 87 | #[macro_export]
 88 | macro_rules! entry {
 89 |     ($path:path) => {
 90 |         #[export_name = "main"]
 91 |         pub unsafe fn __main() -> ! {
 92 |             // type check the given path
 93 |             let f: fn() -> ! = $path;
 94 | 
 95 |             f()
 96 |         }
 97 |     }
 98 | }
 99 | 
100 | 


--------------------------------------------------------------------------------
/app/template/.cargo/config.toml:
--------------------------------------------------------------------------------
 1 | [target.riscv32i-unknown-none-elf]
 2 | rustflags = ["-C", "link-arg=-Tlink.x"]
 3 | 
 4 | [env]
 5 | EMU_TICK_RATE = "100"
 6 | 
 7 | [alias]
 8 | rbuild = "build --release --target riscv32i-unknown-none-elf"
 9 | rb = "rbuild"
10 | 
11 | rdoc = "doc --release --target riscv32i-unknown-none-elf"
12 | rd = "rdoc"
13 | 
14 | rsize = "size --release --target riscv32i-unknown-none-elf"
15 | rs = "rsize"
16 | 
17 | robjdump = "objdump --release --target riscv32i-unknown-none-elf"
18 | rod = "robjdump"
19 | 
20 | 


--------------------------------------------------------------------------------
/app/template/.vimspector.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "configurations": {
 3 |     "Launch": {
 4 |       "adapter": "vscode-cpptools",
 5 |       "filetypes": [ "cpp", "c", "objc", "rust" ],
 6 |       "configuration": {
 7 |         "request": "launch",
 8 |         "program": "${workspaceRoot}/target/x86_64-unknown-linux-gnu/debug/template",
 9 |         "args": [],
10 |         "cwd": ".",
11 |         "environment": [],
12 |         "externalConsole": true,
13 |         "MIMode": "gdb",
14 |         "stopAtEntry": true
15 |       }
16 |     },
17 |     "Attach": {
18 |       "adapter": "vscode-cpptools",
19 |       "filetypes": [ "cpp", "c", "objc", "rust" ],
20 |       "configuration": {
21 |         "request": "attach",
22 |         "program": "${workspaceRoot}/target/x86_64-unknown-linux-gnu/debug/template",
23 |         "MIMode": "gdb",
24 |         "stopAtEntry": true
25 |       }
26 |     }
27 |   }
28 | }
29 | 


--------------------------------------------------------------------------------
/app/template/Cargo.lock:
--------------------------------------------------------------------------------
  1 | # This file is automatically @generated by Cargo.
  2 | # It is not intended for manual editing.
  3 | version = 3
  4 | 
  5 | [[package]]
  6 | name = "autocfg"
  7 | version = "1.1.0"
  8 | source = "registry+https://github.com/rust-lang/crates.io-index"
  9 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 10 | 
 11 | [[package]]
 12 | name = "bitflags"
 13 | version = "1.3.2"
 14 | source = "registry+https://github.com/rust-lang/crates.io-index"
 15 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 16 | 
 17 | [[package]]
 18 | name = "cassowary"
 19 | version = "0.3.0"
 20 | source = "registry+https://github.com/rust-lang/crates.io-index"
 21 | checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
 22 | 
 23 | [[package]]
 24 | name = "cfg-if"
 25 | version = "1.0.0"
 26 | source = "registry+https://github.com/rust-lang/crates.io-index"
 27 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 28 | 
 29 | [[package]]
 30 | name = "crossterm"
 31 | version = "0.25.0"
 32 | source = "registry+https://github.com/rust-lang/crates.io-index"
 33 | checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
 34 | dependencies = [
 35 |  "bitflags",
 36 |  "crossterm_winapi",
 37 |  "libc",
 38 |  "mio",
 39 |  "parking_lot",
 40 |  "signal-hook",
 41 |  "signal-hook-mio",
 42 |  "winapi",
 43 | ]
 44 | 
 45 | [[package]]
 46 | name = "crossterm"
 47 | version = "0.26.1"
 48 | source = "registry+https://github.com/rust-lang/crates.io-index"
 49 | checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13"
 50 | dependencies = [
 51 |  "bitflags",
 52 |  "crossterm_winapi",
 53 |  "libc",
 54 |  "mio",
 55 |  "parking_lot",
 56 |  "signal-hook",
 57 |  "signal-hook-mio",
 58 |  "winapi",
 59 | ]
 60 | 
 61 | [[package]]
 62 | name = "crossterm_winapi"
 63 | version = "0.9.0"
 64 | source = "registry+https://github.com/rust-lang/crates.io-index"
 65 | checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c"
 66 | dependencies = [
 67 |  "winapi",
 68 | ]
 69 | 
 70 | [[package]]
 71 | name = "libc"
 72 | version = "0.2.140"
 73 | source = "registry+https://github.com/rust-lang/crates.io-index"
 74 | checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
 75 | 
 76 | [[package]]
 77 | name = "lock_api"
 78 | version = "0.4.9"
 79 | source = "registry+https://github.com/rust-lang/crates.io-index"
 80 | checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
 81 | dependencies = [
 82 |  "autocfg",
 83 |  "scopeguard",
 84 | ]
 85 | 
 86 | [[package]]
 87 | name = "log"
 88 | version = "0.4.17"
 89 | source = "registry+https://github.com/rust-lang/crates.io-index"
 90 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
 91 | dependencies = [
 92 |  "cfg-if",
 93 | ]
 94 | 
 95 | [[package]]
 96 | name = "mio"
 97 | version = "0.8.6"
 98 | source = "registry+https://github.com/rust-lang/crates.io-index"
 99 | checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
100 | dependencies = [
101 |  "libc",
102 |  "log",
103 |  "wasi",
104 |  "windows-sys",
105 | ]
106 | 
107 | [[package]]
108 | name = "parking_lot"
109 | version = "0.12.1"
110 | source = "registry+https://github.com/rust-lang/crates.io-index"
111 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
112 | dependencies = [
113 |  "lock_api",
114 |  "parking_lot_core",
115 | ]
116 | 
117 | [[package]]
118 | name = "parking_lot_core"
119 | version = "0.9.7"
120 | source = "registry+https://github.com/rust-lang/crates.io-index"
121 | checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
122 | dependencies = [
123 |  "cfg-if",
124 |  "libc",
125 |  "redox_syscall",
126 |  "smallvec",
127 |  "windows-sys",
128 | ]
129 | 
130 | [[package]]
131 | name = "ratatui"
132 | version = "0.20.1"
133 | source = "registry+https://github.com/rust-lang/crates.io-index"
134 | checksum = "dcc0d032bccba900ee32151ec0265667535c230169f5a011154cdcd984e16829"
135 | dependencies = [
136 |  "bitflags",
137 |  "cassowary",
138 |  "crossterm 0.26.1",
139 |  "unicode-segmentation",
140 |  "unicode-width",
141 | ]
142 | 
143 | [[package]]
144 | name = "redox_syscall"
145 | version = "0.2.16"
146 | source = "registry+https://github.com/rust-lang/crates.io-index"
147 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
148 | dependencies = [
149 |  "bitflags",
150 | ]
151 | 
152 | [[package]]
153 | name = "scopeguard"
154 | version = "1.1.0"
155 | source = "registry+https://github.com/rust-lang/crates.io-index"
156 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
157 | 
158 | [[package]]
159 | name = "signal-hook"
160 | version = "0.3.15"
161 | source = "registry+https://github.com/rust-lang/crates.io-index"
162 | checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9"
163 | dependencies = [
164 |  "libc",
165 |  "signal-hook-registry",
166 | ]
167 | 
168 | [[package]]
169 | name = "signal-hook-mio"
170 | version = "0.2.3"
171 | source = "registry+https://github.com/rust-lang/crates.io-index"
172 | checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
173 | dependencies = [
174 |  "libc",
175 |  "mio",
176 |  "signal-hook",
177 | ]
178 | 
179 | [[package]]
180 | name = "signal-hook-registry"
181 | version = "1.4.1"
182 | source = "registry+https://github.com/rust-lang/crates.io-index"
183 | checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
184 | dependencies = [
185 |  "libc",
186 | ]
187 | 
188 | [[package]]
189 | name = "smallvec"
190 | version = "1.10.0"
191 | source = "registry+https://github.com/rust-lang/crates.io-index"
192 | checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
193 | 
194 | [[package]]
195 | name = "tdriver"
196 | version = "0.1.0"
197 | dependencies = [
198 |  "crossterm 0.25.0",
199 |  "ratatui",
200 | ]
201 | 
202 | [[package]]
203 | name = "template"
204 | version = "0.1.0"
205 | dependencies = [
206 |  "tdriver",
207 | ]
208 | 
209 | [[package]]
210 | name = "unicode-segmentation"
211 | version = "1.10.1"
212 | source = "registry+https://github.com/rust-lang/crates.io-index"
213 | checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
214 | 
215 | [[package]]
216 | name = "unicode-width"
217 | version = "0.1.10"
218 | source = "registry+https://github.com/rust-lang/crates.io-index"
219 | checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
220 | 
221 | [[package]]
222 | name = "wasi"
223 | version = "0.11.0+wasi-snapshot-preview1"
224 | source = "registry+https://github.com/rust-lang/crates.io-index"
225 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
226 | 
227 | [[package]]
228 | name = "winapi"
229 | version = "0.3.9"
230 | source = "registry+https://github.com/rust-lang/crates.io-index"
231 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
232 | dependencies = [
233 |  "winapi-i686-pc-windows-gnu",
234 |  "winapi-x86_64-pc-windows-gnu",
235 | ]
236 | 
237 | [[package]]
238 | name = "winapi-i686-pc-windows-gnu"
239 | version = "0.4.0"
240 | source = "registry+https://github.com/rust-lang/crates.io-index"
241 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
242 | 
243 | [[package]]
244 | name = "winapi-x86_64-pc-windows-gnu"
245 | version = "0.4.0"
246 | source = "registry+https://github.com/rust-lang/crates.io-index"
247 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
248 | 
249 | [[package]]
250 | name = "windows-sys"
251 | version = "0.45.0"
252 | source = "registry+https://github.com/rust-lang/crates.io-index"
253 | checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
254 | dependencies = [
255 |  "windows-targets",
256 | ]
257 | 
258 | [[package]]
259 | name = "windows-targets"
260 | version = "0.42.2"
261 | source = "registry+https://github.com/rust-lang/crates.io-index"
262 | checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
263 | dependencies = [
264 |  "windows_aarch64_gnullvm",
265 |  "windows_aarch64_msvc",
266 |  "windows_i686_gnu",
267 |  "windows_i686_msvc",
268 |  "windows_x86_64_gnu",
269 |  "windows_x86_64_gnullvm",
270 |  "windows_x86_64_msvc",
271 | ]
272 | 
273 | [[package]]
274 | name = "windows_aarch64_gnullvm"
275 | version = "0.42.2"
276 | source = "registry+https://github.com/rust-lang/crates.io-index"
277 | checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
278 | 
279 | [[package]]
280 | name = "windows_aarch64_msvc"
281 | version = "0.42.2"
282 | source = "registry+https://github.com/rust-lang/crates.io-index"
283 | checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
284 | 
285 | [[package]]
286 | name = "windows_i686_gnu"
287 | version = "0.42.2"
288 | source = "registry+https://github.com/rust-lang/crates.io-index"
289 | checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
290 | 
291 | [[package]]
292 | name = "windows_i686_msvc"
293 | version = "0.42.2"
294 | source = "registry+https://github.com/rust-lang/crates.io-index"
295 | checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
296 | 
297 | [[package]]
298 | name = "windows_x86_64_gnu"
299 | version = "0.42.2"
300 | source = "registry+https://github.com/rust-lang/crates.io-index"
301 | checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
302 | 
303 | [[package]]
304 | name = "windows_x86_64_gnullvm"
305 | version = "0.42.2"
306 | source = "registry+https://github.com/rust-lang/crates.io-index"
307 | checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
308 | 
309 | [[package]]
310 | name = "windows_x86_64_msvc"
311 | version = "0.42.2"
312 | source = "registry+https://github.com/rust-lang/crates.io-index"
313 | checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
314 | 


--------------------------------------------------------------------------------
/app/template/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "template"
 3 | version = "0.1.0"
 4 | edition = "2021"
 5 | 
 6 | [dependencies]
 7 | tdriver = { path = "../tdriver" }
 8 | 
 9 | # Don't ever use this for riscv builds or they will be massive
10 | [profile.dev]
11 | 
12 | [profile.release]
13 | panic = "abort"
14 | # Use either 2, 3, s or z
15 | opt-level = 3
16 | overflow-checks = false
17 | lto = true
18 | 
19 | 


--------------------------------------------------------------------------------
/app/template/README.md:
--------------------------------------------------------------------------------
 1 | # Computerraria Rust Template
 2 | 
 3 | This is a template for building Rust applications targeting [Computerraria](https://github.com/misprit7/computerraria). 
 4 | 
 5 | ## Setup
 6 | 
 7 | To set up a new project, run the following: 
 8 | ```bash
 9 | cp -r template PATH/NAME_OF_PROJECT
10 | cd PATH/NAME_OF_PROJECT
11 | sed -i s/template/NAME_OF_PROJECT/ Cargo.toml copy-bin.sh .vimspector.json
12 | cargo build --release
13 | ```
14 | To actually use the project, you can convert the file to the required [WireHead](https://github.com/misprit7/WireHead) file format with the provided script: 
15 | ```bash
16 | ./copy_bin.sh /tmp/in.txt
17 | ```
18 | You can then load it into Computerraria with the following command, written in the in-game chat (NOT your terminal):
19 | ```
20 | /bin write /tmp/in.txt
21 | ```
22 | Once you start the clock the screen should update to be on in the outer horizontal border.
23 | 
24 | ## Development
25 | The entrance point of the program is `main` in [`src/main.rs`](src/main.rs), make changes there. You can change the tick rate of the emulator in the `[env]` section of [`.cargo/config.toml`](.cargo/config.toml).
26 | 


--------------------------------------------------------------------------------
/app/template/copy-bin.sh:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/sh
 2 | 
 3 | # Helper script to copy file to txt file format WireHead expects
 4 | # Example: ./copy_bin.sh /tmp/in.txt
 5 | 
 6 | # Rebuild project
 7 | cargo rbuild --release
 8 | 
 9 | # Convert from elf to bin
10 | # Fancy glob matching! https://zsh.sourceforge.io/Doc/Release/Expansion.html#Glob-Qualifiers
11 | # rust-objcopy -O binary ./target/riscv32i-unknown-none-elf/release/*(x.) /tmp/rust.bin 
12 | rust-objcopy -O binary ./target/riscv32i-unknown-none-elf/release/template /tmp/rust.bin 
13 | 
14 | # Convert from bin to txt
15 | hexdump -ve '1/1 "%.2x "' /tmp/rust.bin | head -c -1 > $1
16 | 
17 | 


--------------------------------------------------------------------------------
/app/template/src/main.rs:
--------------------------------------------------------------------------------
 1 | #![no_std]
 2 | #![no_main]
 3 | 
 4 | use tdriver::entry;
 5 | use tdriver::graphics;
 6 | 
 7 | entry!(main);
 8 | 
 9 | // Entry point of user code
10 | fn main() -> ! {
11 |     let arr: [u64; graphics::HEIGHT] = [0xF00000000000000F; graphics::HEIGHT];
12 |     let mut screen = graphics::init();
13 |     loop {
14 |         graphics::write_long(&mut screen, &arr);
15 |         graphics::update(&mut screen);
16 |     }
17 | }
18 | 


--------------------------------------------------------------------------------
/app/tetris/.cargo/config.toml:
--------------------------------------------------------------------------------
 1 | [target.riscv32i-unknown-none-elf]
 2 | rustflags = ["-C", "link-arg=-Tlink.x"]
 3 | 
 4 | [alias]
 5 | rbuild = "build --release --target riscv32i-unknown-none-elf"
 6 | rb = "rbuild"
 7 | 
 8 | rdoc = "doc --release --target riscv32i-unknown-none-elf"
 9 | rd = "rdoc"
10 | 
11 | rsize = "size --release --target riscv32i-unknown-none-elf"
12 | rs = "rsize"
13 | 
14 | robjdump = "objdump --release --target riscv32i-unknown-none-elf"
15 | rod = "robjdump"
16 | 
17 | 


--------------------------------------------------------------------------------
/app/tetris/.vimspector.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "configurations": {
 3 |     "Launch": {
 4 |       "adapter": "vscode-cpptools",
 5 |       "filetypes": [ "cpp", "c", "objc", "rust" ],
 6 |       "configuration": {
 7 |         "request": "launch",
 8 |         "program": "${workspaceRoot}/target/x86_64-unknown-linux-gnu/debug/tetris",
 9 |         "args": [],
10 |         "cwd": ".",
11 |         "environment": [],
12 |         "externalConsole": true,
13 |         "MIMode": "gdb",
14 |         "stopAtEntry": true
15 |       }
16 |     },
17 |     "Attach": {
18 |       "adapter": "vscode-cpptools",
19 |       "filetypes": [ "cpp", "c", "objc", "rust" ],
20 |       "configuration": {
21 |         "request": "attach",
22 |         "program": "${workspaceRoot}/target/x86_64-unknown-linux-gnu/debug/tetris",
23 |         "MIMode": "gdb",
24 |         "stopAtEntry": true
25 |       }
26 |     }
27 |   }
28 | }
29 | 


--------------------------------------------------------------------------------
/app/tetris/Cargo.lock:
--------------------------------------------------------------------------------
  1 | # This file is automatically @generated by Cargo.
  2 | # It is not intended for manual editing.
  3 | version = 3
  4 | 
  5 | [[package]]
  6 | name = "autocfg"
  7 | version = "1.1.0"
  8 | source = "registry+https://github.com/rust-lang/crates.io-index"
  9 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 10 | 
 11 | [[package]]
 12 | name = "bitflags"
 13 | version = "1.3.2"
 14 | source = "registry+https://github.com/rust-lang/crates.io-index"
 15 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 16 | 
 17 | [[package]]
 18 | name = "cassowary"
 19 | version = "0.3.0"
 20 | source = "registry+https://github.com/rust-lang/crates.io-index"
 21 | checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
 22 | 
 23 | [[package]]
 24 | name = "cfg-if"
 25 | version = "1.0.0"
 26 | source = "registry+https://github.com/rust-lang/crates.io-index"
 27 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 28 | 
 29 | [[package]]
 30 | name = "crossterm"
 31 | version = "0.25.0"
 32 | source = "registry+https://github.com/rust-lang/crates.io-index"
 33 | checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
 34 | dependencies = [
 35 |  "bitflags",
 36 |  "crossterm_winapi",
 37 |  "libc",
 38 |  "mio",
 39 |  "parking_lot",
 40 |  "signal-hook",
 41 |  "signal-hook-mio",
 42 |  "winapi",
 43 | ]
 44 | 
 45 | [[package]]
 46 | name = "crossterm"
 47 | version = "0.26.1"
 48 | source = "registry+https://github.com/rust-lang/crates.io-index"
 49 | checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13"
 50 | dependencies = [
 51 |  "bitflags",
 52 |  "crossterm_winapi",
 53 |  "libc",
 54 |  "mio",
 55 |  "parking_lot",
 56 |  "signal-hook",
 57 |  "signal-hook-mio",
 58 |  "winapi",
 59 | ]
 60 | 
 61 | [[package]]
 62 | name = "crossterm_winapi"
 63 | version = "0.9.1"
 64 | source = "registry+https://github.com/rust-lang/crates.io-index"
 65 | checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
 66 | dependencies = [
 67 |  "winapi",
 68 | ]
 69 | 
 70 | [[package]]
 71 | name = "libc"
 72 | version = "0.2.147"
 73 | source = "registry+https://github.com/rust-lang/crates.io-index"
 74 | checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
 75 | 
 76 | [[package]]
 77 | name = "lock_api"
 78 | version = "0.4.10"
 79 | source = "registry+https://github.com/rust-lang/crates.io-index"
 80 | checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
 81 | dependencies = [
 82 |  "autocfg",
 83 |  "scopeguard",
 84 | ]
 85 | 
 86 | [[package]]
 87 | name = "log"
 88 | version = "0.4.20"
 89 | source = "registry+https://github.com/rust-lang/crates.io-index"
 90 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
 91 | 
 92 | [[package]]
 93 | name = "mio"
 94 | version = "0.8.8"
 95 | source = "registry+https://github.com/rust-lang/crates.io-index"
 96 | checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
 97 | dependencies = [
 98 |  "libc",
 99 |  "log",
100 |  "wasi",
101 |  "windows-sys",
102 | ]
103 | 
104 | [[package]]
105 | name = "parking_lot"
106 | version = "0.12.1"
107 | source = "registry+https://github.com/rust-lang/crates.io-index"
108 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
109 | dependencies = [
110 |  "lock_api",
111 |  "parking_lot_core",
112 | ]
113 | 
114 | [[package]]
115 | name = "parking_lot_core"
116 | version = "0.9.8"
117 | source = "registry+https://github.com/rust-lang/crates.io-index"
118 | checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
119 | dependencies = [
120 |  "cfg-if",
121 |  "libc",
122 |  "redox_syscall",
123 |  "smallvec",
124 |  "windows-targets",
125 | ]
126 | 
127 | [[package]]
128 | name = "ratatui"
129 | version = "0.20.1"
130 | source = "registry+https://github.com/rust-lang/crates.io-index"
131 | checksum = "dcc0d032bccba900ee32151ec0265667535c230169f5a011154cdcd984e16829"
132 | dependencies = [
133 |  "bitflags",
134 |  "cassowary",
135 |  "crossterm 0.26.1",
136 |  "unicode-segmentation",
137 |  "unicode-width",
138 | ]
139 | 
140 | [[package]]
141 | name = "redox_syscall"
142 | version = "0.3.5"
143 | source = "registry+https://github.com/rust-lang/crates.io-index"
144 | checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
145 | dependencies = [
146 |  "bitflags",
147 | ]
148 | 
149 | [[package]]
150 | name = "scopeguard"
151 | version = "1.2.0"
152 | source = "registry+https://github.com/rust-lang/crates.io-index"
153 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
154 | 
155 | [[package]]
156 | name = "signal-hook"
157 | version = "0.3.17"
158 | source = "registry+https://github.com/rust-lang/crates.io-index"
159 | checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
160 | dependencies = [
161 |  "libc",
162 |  "signal-hook-registry",
163 | ]
164 | 
165 | [[package]]
166 | name = "signal-hook-mio"
167 | version = "0.2.3"
168 | source = "registry+https://github.com/rust-lang/crates.io-index"
169 | checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
170 | dependencies = [
171 |  "libc",
172 |  "mio",
173 |  "signal-hook",
174 | ]
175 | 
176 | [[package]]
177 | name = "signal-hook-registry"
178 | version = "1.4.1"
179 | source = "registry+https://github.com/rust-lang/crates.io-index"
180 | checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
181 | dependencies = [
182 |  "libc",
183 | ]
184 | 
185 | [[package]]
186 | name = "smallvec"
187 | version = "1.11.0"
188 | source = "registry+https://github.com/rust-lang/crates.io-index"
189 | checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
190 | 
191 | [[package]]
192 | name = "tdriver"
193 | version = "0.1.0"
194 | dependencies = [
195 |  "crossterm 0.25.0",
196 |  "ratatui",
197 | ]
198 | 
199 | [[package]]
200 | name = "tetris"
201 | version = "0.1.0"
202 | dependencies = [
203 |  "tdriver",
204 | ]
205 | 
206 | [[package]]
207 | name = "unicode-segmentation"
208 | version = "1.10.1"
209 | source = "registry+https://github.com/rust-lang/crates.io-index"
210 | checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
211 | 
212 | [[package]]
213 | name = "unicode-width"
214 | version = "0.1.10"
215 | source = "registry+https://github.com/rust-lang/crates.io-index"
216 | checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
217 | 
218 | [[package]]
219 | name = "wasi"
220 | version = "0.11.0+wasi-snapshot-preview1"
221 | source = "registry+https://github.com/rust-lang/crates.io-index"
222 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
223 | 
224 | [[package]]
225 | name = "winapi"
226 | version = "0.3.9"
227 | source = "registry+https://github.com/rust-lang/crates.io-index"
228 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
229 | dependencies = [
230 |  "winapi-i686-pc-windows-gnu",
231 |  "winapi-x86_64-pc-windows-gnu",
232 | ]
233 | 
234 | [[package]]
235 | name = "winapi-i686-pc-windows-gnu"
236 | version = "0.4.0"
237 | source = "registry+https://github.com/rust-lang/crates.io-index"
238 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
239 | 
240 | [[package]]
241 | name = "winapi-x86_64-pc-windows-gnu"
242 | version = "0.4.0"
243 | source = "registry+https://github.com/rust-lang/crates.io-index"
244 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
245 | 
246 | [[package]]
247 | name = "windows-sys"
248 | version = "0.48.0"
249 | source = "registry+https://github.com/rust-lang/crates.io-index"
250 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
251 | dependencies = [
252 |  "windows-targets",
253 | ]
254 | 
255 | [[package]]
256 | name = "windows-targets"
257 | version = "0.48.5"
258 | source = "registry+https://github.com/rust-lang/crates.io-index"
259 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
260 | dependencies = [
261 |  "windows_aarch64_gnullvm",
262 |  "windows_aarch64_msvc",
263 |  "windows_i686_gnu",
264 |  "windows_i686_msvc",
265 |  "windows_x86_64_gnu",
266 |  "windows_x86_64_gnullvm",
267 |  "windows_x86_64_msvc",
268 | ]
269 | 
270 | [[package]]
271 | name = "windows_aarch64_gnullvm"
272 | version = "0.48.5"
273 | source = "registry+https://github.com/rust-lang/crates.io-index"
274 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
275 | 
276 | [[package]]
277 | name = "windows_aarch64_msvc"
278 | version = "0.48.5"
279 | source = "registry+https://github.com/rust-lang/crates.io-index"
280 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
281 | 
282 | [[package]]
283 | name = "windows_i686_gnu"
284 | version = "0.48.5"
285 | source = "registry+https://github.com/rust-lang/crates.io-index"
286 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
287 | 
288 | [[package]]
289 | name = "windows_i686_msvc"
290 | version = "0.48.5"
291 | source = "registry+https://github.com/rust-lang/crates.io-index"
292 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
293 | 
294 | [[package]]
295 | name = "windows_x86_64_gnu"
296 | version = "0.48.5"
297 | source = "registry+https://github.com/rust-lang/crates.io-index"
298 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
299 | 
300 | [[package]]
301 | name = "windows_x86_64_gnullvm"
302 | version = "0.48.5"
303 | source = "registry+https://github.com/rust-lang/crates.io-index"
304 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
305 | 
306 | [[package]]
307 | name = "windows_x86_64_msvc"
308 | version = "0.48.5"
309 | source = "registry+https://github.com/rust-lang/crates.io-index"
310 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
311 | 


--------------------------------------------------------------------------------
/app/tetris/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "tetris"
 3 | version = "0.1.0"
 4 | edition = "2021"
 5 | 
 6 | [dependencies]
 7 | tdriver = { path = "../tdriver" }
 8 | 
 9 | # Don't ever use this for riscv builds or they will be massive
10 | [profile.dev]
11 | 
12 | [profile.release]
13 | panic = "abort"
14 | # Use either 2, 3, s or z
15 | opt-level = 3
16 | overflow-checks = false
17 | lto = true
18 | 
19 | 


--------------------------------------------------------------------------------
/app/tetris/copy-bin.sh:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/sh
 2 | 
 3 | # Helper script to copy file to txt file format WireHead expects
 4 | # Example: ./copy_bin.sh /tmp/in.txt
 5 | 
 6 | # Rebuild project
 7 | cargo rbuild --release
 8 | 
 9 | # Convert from elf to bin
10 | # Fancy glob matching! https://zsh.sourceforge.io/Doc/Release/Expansion.html#Glob-Qualifiers
11 | # rust-objcopy -O binary ./target/riscv32i-unknown-none-elf/release/*(x.) /tmp/rust.bin 
12 | rust-objcopy -O binary ./target/riscv32i-unknown-none-elf/release/tetris /tmp/rust.bin 
13 | 
14 | # Convert from bin to txt
15 | hexdump -ve '1/1 "%.2x "' /tmp/rust.bin | head -c -1 > $1
16 | 
17 | 


--------------------------------------------------------------------------------
/app/tetris/src/main.rs:
--------------------------------------------------------------------------------
  1 | #![no_std]
  2 | #![no_main]
  3 | 
  4 | use tdriver::entry;
  5 | use tdriver::graphics;
  6 | use tiles::SHAPES;
  7 | 
  8 | mod tiles;
  9 | 
 10 | entry!(main);
 11 | 
 12 | const TOP: usize = 7;
 13 | const MIDDLE: usize = 30;
 14 | 
 15 | 
 16 | // Entry point of user code
 17 | 
 18 | fn create_board() -> [u64; graphics::HEIGHT] {
 19 |     let mut base_board : [u64; graphics::HEIGHT] = [0;graphics::HEIGHT];
 20 |     for i in 0..8{
 21 |         base_board[i] |= u64::MAX;
 22 |     }
 23 |     for i in 8..40{
 24 |         base_board[i] |= 0xFFFFFF0000FFFFFF;
 25 |     }
 26 |     for i in 40..48{
 27 |         base_board[i] |= u64::MAX;
 28 |     }
 29 |     base_board
 30 | }
 31 | 
 32 | fn find_bottom(curr_pos: &[u64;4]) -> usize{
 33 |     for i in 0..4{
 34 |         if curr_pos[3-i] != 0{
 35 |             return 3-i
 36 |         }
 37 |     }
 38 |     return 0;
 39 | }
 40 | 
 41 | fn find_top(curr_pos: &[u64;4]) -> usize{
 42 |     for i in 0..4{
 43 |         if curr_pos[i] != 0{
 44 |             return i
 45 |         }
 46 |     }
 47 |     return 0;
 48 | }
 49 | 
 50 | fn get_rand(x: usize)->usize{
 51 |     ((690697*x+1)%3_usize.pow(4)).into()
 52 | }
 53 | 
 54 | fn clear_tiles(curr_board: &mut [u64; graphics::HEIGHT]) {
 55 |     let mut row_index = 8;
 56 | 
 57 |     while row_index < 40 {
 58 |         if curr_board[row_index] == u64::MAX {
 59 |             for j in (8..row_index).rev() {
 60 |                 curr_board[j + 1] = curr_board[j];
 61 |             }
 62 |             curr_board[8] = 0;
 63 |         } else {
 64 |             row_index += 1;
 65 |         }
 66 |     }
 67 | }
 68 | 
 69 | fn main() -> ! {
 70 |     let base_board = create_board();
 71 |     let mut curr_board: [u64; graphics::HEIGHT] = create_board();
 72 |     let mut screen = graphics::init();
 73 | 
 74 |     let mut new_tile = true;
 75 | 
 76 |     let mut shape: [[u64;4];4] = [[0;4];4];
 77 |     let mut a = tiles::I[1];
 78 |     let mut new_pos: [u64;4] = [0;4];
 79 |     let mut curr_pos: [u64;4] = [0;4];
 80 |     let mut n = find_bottom(&a);
 81 | 
 82 | 
 83 |     let mut r = TOP + n;
 84 |     let mut tile_pos = MIDDLE;
 85 |     let mut rot: usize = 0;
 86 |     let mut rand = 67;
 87 | 
 88 | 
 89 |     loop {
 90 |         graphics::write_long(&mut screen, &curr_board);
 91 |         graphics::update(&mut screen);
 92 | 
 93 |         if (curr_board[r+n] & curr_pos[n]) > 0{
 94 |             if r == TOP-find_top(&a)+2{
 95 |                 curr_board = [u64::MAX;graphics::HEIGHT];
 96 |                 continue;
 97 |             }
 98 |             new_tile = true;
 99 |         }
100 |         if ((!curr_pos[n] & curr_board[r+n-1]) & curr_pos[n-1])>0{
101 |             if r == TOP-find_top(&a)+2{
102 |                 curr_board = [u64::MAX;graphics::HEIGHT];
103 |                 continue;
104 |             }
105 |             new_tile = true;
106 |         }
107 | 
108 |         if new_tile{
109 |             //clear board
110 |             clear_tiles(&mut curr_board);
111 | 
112 |             rand = get_rand(rand);
113 |             shape = SHAPES[rand%7];
114 |             rand = get_rand(rand);
115 |             rot = rand%4;
116 |             a = shape[rot];
117 |             tile_pos = MIDDLE;
118 |             r = TOP-find_top(&a)+1;
119 | 
120 |             for i in 0..4{
121 |                 new_pos[i] = a[i]<<MIDDLE;
122 |             }
123 | 
124 |             new_tile = false;
125 |         }else{
126 |             for i in 0..4{
127 |                 curr_board[i+r-1] = !curr_pos[i] & curr_board[i+r-1];
128 |             }
129 | 
130 |             let input = graphics::input(&mut screen);
131 |             let up = input & graphics::input_flags::UP != 0;
132 |             let down = input & graphics::input_flags::DOWN != 0;
133 |             let left = input & graphics::input_flags::LEFT != 0;
134 |             let right = input & graphics::input_flags::RIGHT != 0;
135 |     
136 |             if left{
137 |                 tile_pos -= 1;
138 |                 for i in 0..4{
139 |                     new_pos[i] = curr_pos[i]>>1;
140 |                 }
141 |             }
142 |             else if right {
143 |                 tile_pos += 1;
144 |                 for i in 0..4{
145 |                     new_pos[i] = curr_pos[i]<<1;
146 |                 }
147 |             }
148 |             else if up {
149 |                 if !(rot == 3){
150 |                     rot += 1;
151 |                 }
152 |                 else{
153 |                     rot = 0;
154 |                 }
155 |                 a = shape[rot];
156 |                 for i in 0..4{
157 |                     new_pos[i] = a[i]<<tile_pos;
158 |                 }
159 |             }
160 |             else if down {
161 |                 if !(rot == 0){
162 |                     rot -= 1;
163 |                 }
164 |                 else{
165 |                     rot = 3;
166 |                 }
167 |                 a = shape[rot];
168 |                 for i in 0..4{
169 |                     new_pos[i] = a[i]<<tile_pos;
170 |                 }
171 |             }
172 |     
173 |             //check for conflicts with current board and new tile
174 |             for i in 0..4{
175 |                 if (curr_board[i+r] & new_pos[i]) != 0{
176 |                     new_pos = curr_pos;
177 |                 }
178 |             }
179 |         }
180 | 
181 | 
182 | 
183 |         //draw new tile on curr_board
184 |         curr_pos = new_pos;
185 |         n = find_bottom(&curr_pos);
186 |         for i in 0..4{
187 |             curr_board[i+r] = curr_pos[i] | curr_board[i+r];
188 |         }
189 |         for i in 0..graphics::HEIGHT{
190 |             curr_board[i] = curr_board[i] | base_board[i];
191 |         }
192 | 
193 |         if r<40{
194 |             r+=1;
195 |         }
196 | 
197 |         
198 |     }
199 | }
200 | 


--------------------------------------------------------------------------------
/app/tetris/src/tiles.rs:
--------------------------------------------------------------------------------
 1 | pub const SQ: [[u64;4];4] = [[0b0000, 0b0110, 0b0110, 0b0000],
 2 |                             [0b0000, 0b0110, 0b0110, 0b0000],
 3 |                             [0b0000, 0b0110, 0b0110, 0b0000],
 4 |                             [0b0000, 0b0110, 0b0110, 0b0000]];
 5 | 
 6 | pub const T: [[u64;4];4] = [[0b0000, 0b1110, 0b0100, 0b0000],
 7 |                             [0b0010, 0b0110, 0b0010, 0b0000],
 8 |                             [0b0000, 0b0100, 0b1110, 0b0000],
 9 |                             [0b0100, 0b1100, 0b0100, 0b0000]];
10 | 
11 | pub const I: [[u64;4];4] = [[0b0100, 0b0100, 0b0100, 0b0100],
12 |                             [0b0000, 0b0000, 0b1111, 0b0000],
13 |                             [0b0100, 0b0100, 0b0100, 0b0100],
14 |                             [0b0000, 0b1111, 0b0000, 0b0000]];
15 | 
16 | pub const L: [[u64;4];4] = [[0b0100, 0b0100, 0b0110, 0b0000],
17 |                             [0b0000, 0b0111, 0b0100, 0b0000],
18 |                             [0b0010, 0b0010, 0b0110, 0b0000],
19 |                             [0b0000, 0b0100, 0b0111, 0b0000]];
20 | 
21 | pub const J: [[u64; 4]; 4] = [[0b0100, 0b0100, 0b1100, 0b0000],
22 |                               [0b1000, 0b1110, 0b0000, 0b0000],
23 |                               [0b0110, 0b0100, 0b0100, 0b0000],
24 |                               [0b0000, 0b1110, 0b0010, 0b0000]];
25 | 
26 | pub const S: [[u64; 4]; 4] = [[0b0000, 0b0110, 0b1100, 0b0000],
27 |                               [0b0100, 0b0110, 0b0010, 0b0000],
28 |                               [0b0000, 0b0011, 0b0110, 0b0000],
29 |                               [0b0000, 0b0100, 0b0110, 0b0010]];
30 | 
31 | pub const Z: [[u64; 4]; 4] = [[0b0000, 0b0110, 0b0011, 0b0000],
32 |                               [0b0000, 0b0010, 0b0110, 0b0100],
33 |                               [0b0000, 0b1100, 0b0110, 0b0000],
34 |                               [0b0010, 0b0110, 0b0100, 0b0000]];
35 | 
36 | pub const SHAPES: [[[u64;4];4];7] = [T, Z, I, L, S, J, SQ];


--------------------------------------------------------------------------------
/app/video/.cargo/config.toml:
--------------------------------------------------------------------------------
 1 | [target.riscv32i-unknown-none-elf]
 2 | rustflags = ["-C", "link-arg=-Tlink.x"]
 3 | 
 4 | [env]
 5 | EMU_TICK_RATE = "68"
 6 | 
 7 | [alias]
 8 | rbuild = "build --release --target riscv32i-unknown-none-elf"
 9 | rb = "rbuild"
10 | 
11 | rdoc = "doc --release --target riscv32i-unknown-none-elf"
12 | rd = "rdoc"
13 | 
14 | rsize = "size --release --target riscv32i-unknown-none-elf"
15 | rs = "rsize"
16 | 
17 | robjdump = "objdump --release --target riscv32i-unknown-none-elf"
18 | rod = "robjdump"
19 | 
20 | 


--------------------------------------------------------------------------------
/app/video/.vimspector.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "configurations": {
 3 |     "Launch": {
 4 |       "adapter": "vscode-cpptools",
 5 |       "filetypes": [ "cpp", "c", "objc", "rust" ],
 6 |       "configuration": {
 7 |         "request": "launch",
 8 |         "program": "${workspaceRoot}/target/x86_64-unknown-linux-gnu/debug/video",
 9 |         "args": [],
10 |         "cwd": ".",
11 |         "environment": [],
12 |         "externalConsole": true,
13 |         "MIMode": "gdb",
14 |         "stopAtEntry": true
15 |       }
16 |     },
17 |     "Attach": {
18 |       "adapter": "vscode-cpptools",
19 |       "filetypes": [ "cpp", "c", "objc", "rust" ],
20 |       "configuration": {
21 |         "request": "attach",
22 |         "program": "${workspaceRoot}/target/x86_64-unknown-linux-gnu/debug/video",
23 |         "MIMode": "gdb",
24 |         "stopAtEntry": true
25 |       }
26 |     }
27 |   }
28 | }
29 | 


--------------------------------------------------------------------------------
/app/video/Cargo.lock:
--------------------------------------------------------------------------------
  1 | # This file is automatically @generated by Cargo.
  2 | # It is not intended for manual editing.
  3 | version = 3
  4 | 
  5 | [[package]]
  6 | name = "autocfg"
  7 | version = "1.1.0"
  8 | source = "registry+https://github.com/rust-lang/crates.io-index"
  9 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 10 | 
 11 | [[package]]
 12 | name = "bitflags"
 13 | version = "1.3.2"
 14 | source = "registry+https://github.com/rust-lang/crates.io-index"
 15 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 16 | 
 17 | [[package]]
 18 | name = "cassowary"
 19 | version = "0.3.0"
 20 | source = "registry+https://github.com/rust-lang/crates.io-index"
 21 | checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
 22 | 
 23 | [[package]]
 24 | name = "cfg-if"
 25 | version = "1.0.0"
 26 | source = "registry+https://github.com/rust-lang/crates.io-index"
 27 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 28 | 
 29 | [[package]]
 30 | name = "crossterm"
 31 | version = "0.25.0"
 32 | source = "registry+https://github.com/rust-lang/crates.io-index"
 33 | checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
 34 | dependencies = [
 35 |  "bitflags",
 36 |  "crossterm_winapi",
 37 |  "libc",
 38 |  "mio",
 39 |  "parking_lot",
 40 |  "signal-hook",
 41 |  "signal-hook-mio",
 42 |  "winapi",
 43 | ]
 44 | 
 45 | [[package]]
 46 | name = "crossterm"
 47 | version = "0.26.1"
 48 | source = "registry+https://github.com/rust-lang/crates.io-index"
 49 | checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13"
 50 | dependencies = [
 51 |  "bitflags",
 52 |  "crossterm_winapi",
 53 |  "libc",
 54 |  "mio",
 55 |  "parking_lot",
 56 |  "signal-hook",
 57 |  "signal-hook-mio",
 58 |  "winapi",
 59 | ]
 60 | 
 61 | [[package]]
 62 | name = "crossterm_winapi"
 63 | version = "0.9.0"
 64 | source = "registry+https://github.com/rust-lang/crates.io-index"
 65 | checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c"
 66 | dependencies = [
 67 |  "winapi",
 68 | ]
 69 | 
 70 | [[package]]
 71 | name = "libc"
 72 | version = "0.2.147"
 73 | source = "registry+https://github.com/rust-lang/crates.io-index"
 74 | checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
 75 | 
 76 | [[package]]
 77 | name = "lock_api"
 78 | version = "0.4.9"
 79 | source = "registry+https://github.com/rust-lang/crates.io-index"
 80 | checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
 81 | dependencies = [
 82 |  "autocfg",
 83 |  "scopeguard",
 84 | ]
 85 | 
 86 | [[package]]
 87 | name = "log"
 88 | version = "0.4.17"
 89 | source = "registry+https://github.com/rust-lang/crates.io-index"
 90 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
 91 | dependencies = [
 92 |  "cfg-if",
 93 | ]
 94 | 
 95 | [[package]]
 96 | name = "mio"
 97 | version = "0.8.6"
 98 | source = "registry+https://github.com/rust-lang/crates.io-index"
 99 | checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
100 | dependencies = [
101 |  "libc",
102 |  "log",
103 |  "wasi",
104 |  "windows-sys",
105 | ]
106 | 
107 | [[package]]
108 | name = "parking_lot"
109 | version = "0.12.1"
110 | source = "registry+https://github.com/rust-lang/crates.io-index"
111 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
112 | dependencies = [
113 |  "lock_api",
114 |  "parking_lot_core",
115 | ]
116 | 
117 | [[package]]
118 | name = "parking_lot_core"
119 | version = "0.9.7"
120 | source = "registry+https://github.com/rust-lang/crates.io-index"
121 | checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
122 | dependencies = [
123 |  "cfg-if",
124 |  "libc",
125 |  "redox_syscall",
126 |  "smallvec",
127 |  "windows-sys",
128 | ]
129 | 
130 | [[package]]
131 | name = "ratatui"
132 | version = "0.20.1"
133 | source = "registry+https://github.com/rust-lang/crates.io-index"
134 | checksum = "dcc0d032bccba900ee32151ec0265667535c230169f5a011154cdcd984e16829"
135 | dependencies = [
136 |  "bitflags",
137 |  "cassowary",
138 |  "crossterm 0.26.1",
139 |  "unicode-segmentation",
140 |  "unicode-width",
141 | ]
142 | 
143 | [[package]]
144 | name = "redox_syscall"
145 | version = "0.2.16"
146 | source = "registry+https://github.com/rust-lang/crates.io-index"
147 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
148 | dependencies = [
149 |  "bitflags",
150 | ]
151 | 
152 | [[package]]
153 | name = "scopeguard"
154 | version = "1.1.0"
155 | source = "registry+https://github.com/rust-lang/crates.io-index"
156 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
157 | 
158 | [[package]]
159 | name = "signal-hook"
160 | version = "0.3.15"
161 | source = "registry+https://github.com/rust-lang/crates.io-index"
162 | checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9"
163 | dependencies = [
164 |  "libc",
165 |  "signal-hook-registry",
166 | ]
167 | 
168 | [[package]]
169 | name = "signal-hook-mio"
170 | version = "0.2.3"
171 | source = "registry+https://github.com/rust-lang/crates.io-index"
172 | checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
173 | dependencies = [
174 |  "libc",
175 |  "mio",
176 |  "signal-hook",
177 | ]
178 | 
179 | [[package]]
180 | name = "signal-hook-registry"
181 | version = "1.4.1"
182 | source = "registry+https://github.com/rust-lang/crates.io-index"
183 | checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
184 | dependencies = [
185 |  "libc",
186 | ]
187 | 
188 | [[package]]
189 | name = "smallvec"
190 | version = "1.10.0"
191 | source = "registry+https://github.com/rust-lang/crates.io-index"
192 | checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
193 | 
194 | [[package]]
195 | name = "tdriver"
196 | version = "0.1.0"
197 | dependencies = [
198 |  "crossterm 0.25.0",
199 |  "ratatui",
200 | ]
201 | 
202 | [[package]]
203 | name = "unicode-segmentation"
204 | version = "1.10.1"
205 | source = "registry+https://github.com/rust-lang/crates.io-index"
206 | checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
207 | 
208 | [[package]]
209 | name = "unicode-width"
210 | version = "0.1.10"
211 | source = "registry+https://github.com/rust-lang/crates.io-index"
212 | checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
213 | 
214 | [[package]]
215 | name = "video"
216 | version = "0.1.0"
217 | dependencies = [
218 |  "tdriver",
219 | ]
220 | 
221 | [[package]]
222 | name = "wasi"
223 | version = "0.11.0+wasi-snapshot-preview1"
224 | source = "registry+https://github.com/rust-lang/crates.io-index"
225 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
226 | 
227 | [[package]]
228 | name = "winapi"
229 | version = "0.3.9"
230 | source = "registry+https://github.com/rust-lang/crates.io-index"
231 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
232 | dependencies = [
233 |  "winapi-i686-pc-windows-gnu",
234 |  "winapi-x86_64-pc-windows-gnu",
235 | ]
236 | 
237 | [[package]]
238 | name = "winapi-i686-pc-windows-gnu"
239 | version = "0.4.0"
240 | source = "registry+https://github.com/rust-lang/crates.io-index"
241 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
242 | 
243 | [[package]]
244 | name = "winapi-x86_64-pc-windows-gnu"
245 | version = "0.4.0"
246 | source = "registry+https://github.com/rust-lang/crates.io-index"
247 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
248 | 
249 | [[package]]
250 | name = "windows-sys"
251 | version = "0.45.0"
252 | source = "registry+https://github.com/rust-lang/crates.io-index"
253 | checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
254 | dependencies = [
255 |  "windows-targets",
256 | ]
257 | 
258 | [[package]]
259 | name = "windows-targets"
260 | version = "0.42.2"
261 | source = "registry+https://github.com/rust-lang/crates.io-index"
262 | checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
263 | dependencies = [
264 |  "windows_aarch64_gnullvm",
265 |  "windows_aarch64_msvc",
266 |  "windows_i686_gnu",
267 |  "windows_i686_msvc",
268 |  "windows_x86_64_gnu",
269 |  "windows_x86_64_gnullvm",
270 |  "windows_x86_64_msvc",
271 | ]
272 | 
273 | [[package]]
274 | name = "windows_aarch64_gnullvm"
275 | version = "0.42.2"
276 | source = "registry+https://github.com/rust-lang/crates.io-index"
277 | checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
278 | 
279 | [[package]]
280 | name = "windows_aarch64_msvc"
281 | version = "0.42.2"
282 | source = "registry+https://github.com/rust-lang/crates.io-index"
283 | checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
284 | 
285 | [[package]]
286 | name = "windows_i686_gnu"
287 | version = "0.42.2"
288 | source = "registry+https://github.com/rust-lang/crates.io-index"
289 | checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
290 | 
291 | [[package]]
292 | name = "windows_i686_msvc"
293 | version = "0.42.2"
294 | source = "registry+https://github.com/rust-lang/crates.io-index"
295 | checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
296 | 
297 | [[package]]
298 | name = "windows_x86_64_gnu"
299 | version = "0.42.2"
300 | source = "registry+https://github.com/rust-lang/crates.io-index"
301 | checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
302 | 
303 | [[package]]
304 | name = "windows_x86_64_gnullvm"
305 | version = "0.42.2"
306 | source = "registry+https://github.com/rust-lang/crates.io-index"
307 | checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
308 | 
309 | [[package]]
310 | name = "windows_x86_64_msvc"
311 | version = "0.42.2"
312 | source = "registry+https://github.com/rust-lang/crates.io-index"
313 | checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
314 | 


--------------------------------------------------------------------------------
/app/video/Cargo.toml:
--------------------------------------------------------------------------------
 1 | [package]
 2 | name = "video"
 3 | version = "0.1.0"
 4 | edition = "2021"
 5 | 
 6 | [dependencies]
 7 | tdriver = { path = "../tdriver" }
 8 | # brotli = "3.3.4"
 9 | 
10 | [profile.release]
11 | panic = "abort"
12 | # Use either 2, 3, s or z
13 | opt-level = 3
14 | overflow-checks = false
15 | lto = true
16 | 
17 | 


--------------------------------------------------------------------------------
/app/video/assets/bad-apple.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/misprit7/computerraria/7d761296af5a3f8764ccb2af44a171e0a57e0e6b/app/video/assets/bad-apple.mp4


--------------------------------------------------------------------------------
/app/video/build.py:
--------------------------------------------------------------------------------
  1 | #!/usr/bin/env python3
  2 | 
  3 | # This should be run manually whenever the video is changed, don't expect this to be often
  4 | 
  5 | # Taken and adapted from here:
  6 | # https://github.com/AlexandreSenpai/Bad-Apple/blob/main/run.py
  7 | 
  8 | from multiprocessing.pool import ThreadPool
  9 | from multiprocessing import cpu_count
 10 | from typing import Tuple
 11 | import time
 12 | 
 13 | import cv2
 14 | import tqdm
 15 | 
 16 | 
 17 | video_path = './assets/bad-apple.mp4'
 18 | code_gen_path = './src/video.rs'
 19 | width, height = (64, 48)
 20 | 
 21 | # Set 1
 22 | # start_frame = 0
 23 | # end_frame = 326
 24 | # Set 2
 25 | # start_frame = 326
 26 | # end_frame = 326*2
 27 | # Set 3
 28 | # start_frame = 326*2
 29 | # end_frame = 326*3
 30 | # Set 4
 31 | start_frame = 326*3
 32 | end_frame = 326*4
 33 | # Set 5
 34 | # start_frame = 326*4
 35 | # end_frame = 326*5
 36 | # Set 5
 37 | # start_frame = 326*5
 38 | # end_frame = 326*6
 39 | 
 40 | 
 41 | def write_frame(frame_information: Tuple[int, cv2.VideoCapture]):
 42 |     order, frame = frame_information
 43 |     
 44 |     y, x, _ = frame.shape
 45 |     pixel_row = 0
 46 |     
 47 |     frame_str = '    [\n'
 48 |     for j in range(height):
 49 |         frame_str += '        ['
 50 |         for i in reversed(range(width // 32)):
 51 |             # Assume width is always divisible by 32
 52 |             frame_str += '0b'
 53 |             for b in range(32):
 54 |                 frame_str += '0' if frame[j, 31*i-b].all() == 0 else '1'
 55 |             frame_str += ', '
 56 | 
 57 |         frame_str += '],\n'
 58 |     frame_str += '    ],\n'
 59 |     
 60 |     return order, frame_str
 61 |     
 62 | 
 63 | def generate_frames(video: cv2.VideoCapture):
 64 |     success = True
 65 |     order = 0
 66 |     i = 0
 67 |     
 68 |     while success and i < end_frame:
 69 |         i += 1
 70 |         success, frame = video.read()
 71 |         if i < start_frame:
 72 |             continue
 73 | 
 74 |         if i % 2 == 0:
 75 |             continue
 76 | 
 77 |         _, bw_frame = cv2.threshold(frame, 128, 255, cv2.THRESH_BINARY)
 78 | 
 79 | 
 80 |         if bw_frame is None:
 81 |             break
 82 |         
 83 |         y, x, _ = bw_frame.shape
 84 |         bw_frame = cv2.resize(bw_frame, (width, height))
 85 |         
 86 |         yield order, bw_frame
 87 |         
 88 |         order += 1
 89 | 
 90 | if __name__ == '__main__':
 91 |     
 92 |     video = cv2.VideoCapture(video_path)
 93 |     frame_cnt = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
 94 |     
 95 |     with ThreadPool(processes=cpu_count()) as pool:
 96 |         frames = list(tqdm.tqdm(pool.imap(write_frame, generate_frames(video)), total=min(frame_cnt, (end_frame-start_frame)/2)))
 97 |         pool.close()
 98 |         pool.join()
 99 |         
100 |     frames = sorted(frames, key=lambda x: x[0])
101 |     
102 |     with open(code_gen_path, 'w') as f:
103 |         f.write('// This is an autogenerated array of pixel data made through build.py, do not edit this manually\n')
104 |         f.write('use tdriver::graphics;\n')
105 |         f.write(f'pub const FRAMES: [[[u32; graphics::WORDS]; graphics::HEIGHT]; {len(frames)}] = [\n')
106 |         for _, frame in frames:
107 |             f.write(frame)
108 | 
109 |         f.write('];\n')
110 | 


--------------------------------------------------------------------------------
/app/video/copy-bin.sh:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/sh
 2 | 
 3 | # Helper script to copy file to txt file format WireHead expects
 4 | # Example: ./copy_bin.sh /tmp/in.txt
 5 | 
 6 | # Rebuild project
 7 | cargo rbuild --release
 8 | 
 9 | # Convert from elf to bin
10 | # Fancy glob matching! https://zsh.sourceforge.io/Doc/Release/Expansion.html#Glob-Qualifiers
11 | # rust-objcopy -O binary ./target/riscv32i-unknown-none-elf/release/*(x.) /tmp/rust.bin 
12 | rust-objcopy -O binary ./target/riscv32i-unknown-none-elf/release/video /tmp/rust.bin 
13 | 
14 | # Convert from bin to txt
15 | hexdump -ve '1/1 "%.2x "' /tmp/rust.bin | head -c -1 > $1
16 | 
17 | 


--------------------------------------------------------------------------------
/app/video/src/main.rs:
--------------------------------------------------------------------------------
 1 | #![no_std]
 2 | #![no_main]
 3 | 
 4 | use tdriver::entry;
 5 | use tdriver::graphics;
 6 | 
 7 | mod video;
 8 | 
 9 | entry!(main);
10 | 
11 | // Entry point of user code
12 | fn main() -> ! {
13 |     let mut screen = graphics::init();
14 |     let mut i = 0;
15 |     loop {
16 |         if i >= video::FRAMES.len() {
17 |             i = 0;
18 |         }
19 |         graphics::write_raw(&mut screen, &video::FRAMES[i]);
20 |         i += 1;
21 |         graphics::update(&mut screen);
22 |     }
23 | }
24 | 


--------------------------------------------------------------------------------
/computerraria.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/misprit7/computerraria/7d761296af5a3f8764ccb2af44a171e0a57e0e6b/computerraria.tar.gz


--------------------------------------------------------------------------------
/computerraria.twld:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/misprit7/computerraria/7d761296af5a3f8764ccb2af44a171e0a57e0e6b/computerraria.twld


--------------------------------------------------------------------------------
/copy-world.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/sh
 2 | 
 3 | #################################################
 4 | # Copies world to/from game files
 5 | #################################################
 6 | 
 7 | TARGET_DIR="$HOME/.local/share/Terraria/tModLoader/Worlds"
 8 | TO_FLAG=0
 9 | FROM_FLAG=0
10 | MNT_FLAG=0
11 | 
12 | for arg in "$@"
13 | do
14 |     case $arg in
15 |         -t|--to)
16 |             TO_FLAG=1
17 |             ;;
18 |         -f|--from)
19 |             FROM_FLAG=1
20 |             ;;
21 |         --mnt)
22 |             MNT_FLAG=1
23 |             ;;
24 |         *)
25 |             echo "Invalid option: $arg"
26 |             echo "Supply either --to or --from and optionally --mnt to specify directory"
27 |             exit 1
28 |             ;;
29 |     esac
30 | done
31 | 
32 | if [ "$MNT_FLAG" -eq 1 ]; then
33 |     TARGET_DIR="/mnt/d/computerraria"
34 | fi
35 | 
36 | if [ "$TO_FLAG" -eq 1 ]; then
37 |     tar -xzf $(dirname "$0")/computerraria.tar.gz -C $(dirname "$0")
38 |     cp $(dirname "$0")/computerraria.wld $TARGET_DIR
39 |     cp $(dirname "$0")/computerraria.twld $TARGET_DIR
40 | elif [ "$FROM_FLAG" -eq 1 ]; then
41 |     cp "$TARGET_DIR/computerraria.wld" $(dirname "$0")
42 |     cp "$TARGET_DIR/computerraria.twld" $(dirname "$0")
43 |     tar -czf $(dirname "$0")/computerraria.tar.gz $(dirname "$0")/computerraria.wld
44 | else
45 |     echo "Supply either --to or --from to copy either to or from the Terraria world files"
46 |     exit 1
47 | fi
48 | 


--------------------------------------------------------------------------------
/doc/img/control-panel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/misprit7/computerraria/7d761296af5a3f8764ccb2af44a171e0a57e0e6b/doc/img/control-panel.png


--------------------------------------------------------------------------------
/doc/img/logo-old.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/misprit7/computerraria/7d761296af5a3f8764ccb2af44a171e0a57e0e6b/doc/img/logo-old.png


--------------------------------------------------------------------------------
/doc/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/misprit7/computerraria/7d761296af5a3f8764ccb2af44a171e0a57e0e6b/doc/img/logo.png


--------------------------------------------------------------------------------
/doc/img/pong-still.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/misprit7/computerraria/7d761296af5a3f8764ccb2af44a171e0a57e0e6b/doc/img/pong-still.png


--------------------------------------------------------------------------------
/doc/img/poster-small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/misprit7/computerraria/7d761296af5a3f8764ccb2af44a171e0a57e0e6b/doc/img/poster-small.png


--------------------------------------------------------------------------------
/doc/logo.pixil:
--------------------------------------------------------------------------------
1 | {"application":"pixil","type":".pixil","version":"2.7.0","website":"pixilart.com","author":"https://www.pixilart.com","contact":"support@pixilart.com","width":"42","height":"105","colors":{"default":["000000","ffffff","f44336","E91E63","9C27B0","673AB7","3F51B5","2196F3","03A9F4","00BCD4","009688","4CAF50","8BC34A","CDDC39","FFEB3B","FFC107","FF9800","FF5722","795548","9E9E9E","607D8B","ffebee","ffcdd2","ef9a9a","e57373","ef5350","e53935","d32f2f","c62828","b71c1c","ff8a80","ff5252","ff1744","d50000","fce4ec","f8bbd0","f48fb1","f06292","ec407a","e91e63","d81b60","c2185b","ad1457","880e4f","ff80ab","ff4081","f50057","c51162","f3e5f5","e1bee7","ce93d8","ba68c8","ab47bc","9c27b0","8e24aa","7b1fa2","6a1b9a","4a148c","ea80fc","e040fb","d500f9","aa00ff","ede7f6","d1c4e9","b39ddb","9575cd","7e57c2","673ab7","5e35b1","512da8","4527a0","311b92","b388ff","7c4dff","651fff","6200ea","e8eaf6","c5cae9","9fa8da","7986cb","5c6bc0","3f51b5","3949ab","303f9f","283593","1a237e","8c9eff","536dfe","3d5afe","304ffe","e3f2fd","bbdefb","90caf9","64b5f6","42a5f5","2196f3","1e88e5","1976d2","1565c0","0d47a1","82b1ff","448aff","2979ff","2962ff","e1f5fe","b3e5fc","81d4fa","4fc3f7","29b6f6","03a9f4","039be5","0288d1","0277bd","01579b","80d8ff","40c4ff","00b0ff","0091ea","e0f7fa","b2ebf2","80deea","4dd0e1","26c6da","00bcd4","00acc1","0097a7","00838f","006064","84ffff","18ffff","00e5ff","00b8d4","e0f2f1","b2dfdb","80cbc4","4db6ac","26a69a","009688","00897b","00796b","00695c","004d40","a7ffeb","64ffda","1de9b6","00bfa5","e8f5e9","c8e6c9","a5d6a7","81c784","66bb6a","4caf50","43a047","388e3c","2e7d32","1b5e20","b9f6ca","69f0ae","00e676","00c853","f1f8e9","dcedc8","c5e1a5","aed581","9ccc65","8bc34a","7cb342","689f38","558b2f","33691e","ccff90","b2ff59","76ff03","64dd17","f9fbe7","f0f4c3","e6ee9c","dce775","d4e157","cddc39","c0ca33","afb42b","9e9d24","827717","f4ff81","eeff41","c6ff00","aeea00","fffde7","fff9c4","fff59d","fff176","ffee58","ffeb3b","fdd835","fbc02d","f9a825","f57f17","ffff8d","ffff00","ffea00","ffd600","fff8e1","ffecb3","ffe082","ffd54f","ffca28","ffc107","ffb300","ffa000","ff8f00","ff6f00","ffe57f","ffd740","ffc400","ffab00","fff3e0","ffe0b2","ffcc80","ffb74d","ffa726","ff9800","fb8c00","f57c00","ef6c00","e65100","ffd180","ffab40","ff9100","ff6d00","fbe9e7","ffccbc","ffab91","ff8a65","ff7043","ff5722","f4511e","e64a19","d84315","bf360c","ff9e80","ff6e40","ff3d00","dd2c00","efebe9","d7ccc8","bcaaa4","a1887f","8d6e63","795548","6d4c41","5d4037","4e342e","3e2723","fafafa","f5f5f5","eeeeee","e0e0e0","bdbdbd","9e9e9e","757575","616161","424242","212121","eceff1","cfd8dc","b0bec5","90a4ae","78909c","607d8b","546e7a","455a64","37474f","263238"],"simple":["ffffff","d4d4d4","a1a1a1","787878","545454","303030","000000","edc5c5","e68383","ff0000","de2424","ad3636","823737","592b2b","f5d2ee","eb8dd7","f700b9","bf1f97","9c277f","732761","4f2445","e2bcf7","bf79e8","9d00ff","8330ba","6d3096","502c69","351b47","c5c3f0","736feb","0905f7","2e2eb0","2d2d80","252554","090936","c7e2ed","6ac3e6","00bbff","279ac4","347c96","2d5b6b","103947","bbf0d9","6febb3","00ff88","2eb878","349166","2b694c","0c3d25","c2edc0","76ed70","0dff00","36c72c","408c3b","315c2e","144511","d6edbb","b5eb73","8cff00","89c93a","6f8f44","4b632a","2a400c","f1f2bf","eef069","ffff00","baba30","91913f","5e5e2b","3b3b09","ffdeb8","f2ae61","ff8400","c48037","85623d","573e25","3d2309","fcbbae","ff8066","ff2b00","cc553d","9c5b4e","61372e","36130b","757575"],"common":["000000","ffffff","464646","b4b4b4","990030","9c5a3c","ed1c24","ffa3b1","ff7e00","e5aa7a","ffc20e","f5e49c","fff200","fff9bd","a8e61d","d3f9bc","22b14c","00b7ef","99d9ea","4d6df3","709ad1","2f3699","546d8e","6f3198","b5a5d5","424242","242424","616161","949494","a3a3a3","563e2c","78553c","858585","a0a0a0","2b2b2b","727272","4a4a4a","393939","5d5d5d","313131","3a302a","976b4b","3b2a1e","bf8f6f","a97d5d","2c2c2c","752424","b01515","c91c1c","17331c","1bcf5a","1d9043","197b3b","848484","414141","969696"],"skin tones":["ffe0bd","ffdbac","ffcd94","eac086","e0ac69","f1c27d","ffad60","c68642","8d5524","896347","765339","613D24","4C2D17","391E0B","351606","2D1304","180A01","090300"]},"colorSelected":"common","frames":[{"name":"","speed":100,"layers":[{"id":0,"src":"data:image/pngp98kjasdnasd983/24kasdjasdbase64,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","edit":false,"name":"Layer 2","opacity":"1","active":true,"unqid":"","options":{"blend":"source-over","locked":false,"filter":{"brightness":"100%","contrast":"100%","grayscale":"0%","blur":0,"dropshadow_x":0,"dropshadow_y":0,"dropshadow_blur":0,"dropshadow_alpha":1}}}],"active":true,"selectedLayer":0,"unqid":"vbisup","preview":"data:image/pngp98kjasdnasd983/24kasdjasdbase64,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","width":"42","height":"105"}],"currentFrame":0,"speed":100,"name":"Untitled","preview":"data:image/pngp98kjasdnasd983/24kasdjasdbase64,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","previewApp":"","art_edit_id":0,"palette_id":false,"created_at":1678681854619,"updated_at":1678681854619,"isExternal":true,"id":1678681234982}


--------------------------------------------------------------------------------
/doc/notes.txt:
--------------------------------------------------------------------------------
  1 | My personal messy notes for while I'm doing things
  2 | 
  3 | Instruction numbers: 
  4 | 0110111: 7
  5 | 0010111: 9
  6 | 1101111: 1
  7 | 1100111: 3
  8 | 1100011: 0
  9 | 0000011: 10
 10 | 0100011: 4
 11 | 0010011: 11
 12 | 0110011: 5
 13 | 0001111: 8
 14 | 
 15 | Commands: 
 16 | ALU:
 17 | 0-1: Load 2
 18 | 0-2: Load 1
 19 | 0-3: exec
 20 | 6-0: funct3[0]
 21 | 6-1: funct3[1]
 22 | 6-2: funct3[2]
 23 | 6-3: dir, i1
 24 | Registers: 
 25 | 1-2: Store
 26 | 1-3: Load
 27 | Memory: 
 28 | 2-1: store address
 29 | 2-2: Execute
 30 | 2-3: Load/store, i1
 31 | PC: 
 32 | 3-0: Store
 33 | 3-1: Load 
 34 | 3-2: Load (reserved for base instruction logic)
 35 | 3-3: Increment
 36 | Decoder: 
 37 | 4-0: Write rd
 38 | 4-1: Read rs2
 39 | 4-2: Read rs1
 40 | 5-2: Load immediate
 41 | 5-3: Load instr
 42 | Control unit: 
 43 | 7-0: Clock
 44 | 7-1: Instruction finished
 45 | Aligner:
 46 | 1-0: Align load
 47 | 1-1: Store 2 least significant bits
 48 | 7-3: Store funct3, WARNING: no sync
 49 | 8-1: Store data to store
 50 | 8-2: Align store
 51 | Misc: 
 52 | 0-0: Increment data bus
 53 | 4-3: Store add to funct3, WARNING: no sync
 54 | 8-0: Load tmp
 55 | 8-3: Store tmp
 56 | 
 57 | Registers:
 58 | 0x1E1FC (write only):
 59 | 0: Write screen
 60 | 
 61 | 0x1E1F8 (read only):
 62 | 0: Down
 63 | 1: Left
 64 | 2: Right
 65 | 3: Up
 66 | 
 67 | Notes on registers: 
 68 | - Use 32 bit binary tree multiplexer
 69 | - Two logic gates per bit, 1 for loading and the other for storing
 70 | - Duplicated binary tree to allow a read and write in one iteration
 71 | - Can't easily allow two reads in one iteration, so instructions with rs1 and rs2 aren't allowed
 72 | 
 73 | Notes on memory: 
 74 | - Massive binary tree structure for selection, bottom layer is load/store select
 75 | - Address is cached both to deal with colour problems and because reads need two data bus inputs
 76 | - Same memory structure as registers with 2 gates for each bit, although much more compact
 77 | 
 78 | Notes on adder: 
 79 | - Could just use a 3 to 8 multiplexer for 1 bit adders, but I'd like something nicer
 80 | - Output of adder is xor of all three inputs A, B and C which is implicit with wiring, carry is harder
 81 | - Carry is determined with following equation: C_out = (A&B)^(A^B if C) which is easy to implement in faulty logic
 82 | - To get subtraction simply invert B's bits to and set first carry for two's complement
 83 | - In my implementation B is toggled back after operation, although since operands aren't expected to be reused strictly speaking this is unnecessary
 84 | 
 85 | Notes on comparator: 
 86 | - Was lazy and didn't think through things myself: http://lumetta.web.engr.illinois.edu/120-S17/slide-copies/053-2's-complement-comparator.pdf
 87 | - If dir is 1 then actually less than or equal, useful for conditional branches
 88 | 
 89 | Notes on AND/OR/XOR:
 90 | - Went for a super compact design
 91 | - xor xors, and zeros then ands, or xors then ands
 92 | 
 93 | Notes on equalitator: 
 94 | - Definitely not a word
 95 | - Not part of original ALU requirements but is required for BEQ/BNE
 96 | - Encoded as funct3=001, dir=1 since that's only free combination
 97 | - Doesn't bother to zero other bits, so sets last bit 0 if neq and 1 if eq
 98 | 
 99 | Notes on decoder:
100 | - Multiplexes opcodes out
101 | - Immediate loading is done as efficiently as possible by reusing common overlap
102 | - Load instr signal tells decoder to cache registers, functX, etc. so that data bas can be reused
103 | 
104 | Notes on PC: 
105 | - Increment loads as well to enable one clock cycle jumps
106 | - Wire colour scheme for increment has convoluted colour sharer circuit for previous design that tried to increment and load in one iteration
107 | - A bit of a mess, leaving as is for now since I might realize I've made a mistake in terms of pc loading timing
108 | 
109 | Notes on aligner: 
110 | - Not the best put together, kinda hacky
111 | - Completely undefined behavior for misaligned reads, be careful!!!
112 | 
113 | Notes on control unit: 
114 | - Instructions are responsible for incrementing pc since some instructions want to do that later or earlier
115 | 
116 | Instruction programming
117 | Prelude (common to all instructions)
118 | Load PC
119 | Store address and set mem to read
120 | Mem exec
121 | Load instr
122 | 
123 | OP-IMM
124 | Load imm
125 | ALU store 1
126 | Load rs1
127 | ALU store 2
128 | ALU exec
129 | Incr pc
130 | 
131 | LUI
132 | Load imm
133 | Store rd
134 | Incr pc
135 | 
136 | AUIPC
137 | Load imm
138 | ALU store 2
139 | Read pc
140 | ALU store 1
141 | ALU exec
142 | Store rd
143 | Incr pc
144 | 
145 | JAL
146 | Load imm
147 | ALU store 2
148 | Read pc
149 | Incr db
150 | Store rd
151 | Delay
152 | Read pc
153 | ALU store 1
154 | ALU exec
155 | Store pc
156 | 
157 | JALR
158 | Load imm
159 | ALU store 2
160 | Read rs1
161 | ALU store 1
162 | Load PC
163 | Incr db
164 | Store rd
165 | ALU exec
166 | Set lsb of db to 0
167 | Store pc
168 | 
169 | OP
170 | Load rs2
171 | ALU store 2
172 | Delay
173 | Load rs1
174 | ALU store 1
175 | ALU exec
176 | Store rd
177 | Incr PC
178 | 
179 | LOAD
180 | Load imm and store funct3 to align
181 | ALU store 2
182 | Load rs1 and store add to funct3
183 | ALU store 1
184 | ALU exec
185 | Store 2 lsbs
186 | Delay
187 | Mem store addr
188 | Mem exec
189 | Align load
190 | Write rd
191 | Incr pc
192 | 
193 | STORE
194 | Load imm and store funct3 to align
195 | ALU store 2
196 | Load rs1
197 | ALU store 1
198 | ALU exec
199 | Store 2 lsbs
200 | Delay
201 | If funct3[1]==1 
202 |     Mem store address
203 |     Load rs2
204 |     goto last delay
205 | Mem store addr
206 | Load rs2
207 | Store store data
208 | Mem exec
209 | Put store onto db
210 | Delay
211 | Mem exec and set mem to write
212 | Incr pc
213 | 
214 | BRANCH
215 | Load imm
216 | Store tmp
217 | Load rs1
218 | Store ALU 1/2
219 | Delay
220 | Load rs2
221 | Store ALU 2/1
222 | Load proper funct3
223 | ALU exec
224 | If db[0]==0
225 |     Incr pc
226 |     finish
227 | Load tmp
228 | Delay
229 | Store ALU 2
230 | Load pc
231 | Store ALU 1 and set ALU to add
232 | ALU exec
233 | Store pc
234 | 
235 | 
236 | # RAM/ROM Overhaul Notes
237 | 
238 | RAM/ROM
239 | 47 rows
240 | 24 rom, 23 ram
241 | 
242 | Screen: 176x96
243 | 
244 | ROM: 0x0-0xC0000, i.e. 768kb
245 | RAM: 0x100000-0x15BFFF, i.e. 368kb
246 | Peripherals: starting at 0x200000
247 | Color screen: 0x200000
248 | Color update: 0x203FFC (end of of 0x204000 region)
249 | Old screen: 0x20E000
250 | Old screen update: 0x20E1FC
251 | Old screen input: 0x20E1F8
252 | 
253 | 
254 | 
255 | 


--------------------------------------------------------------------------------
/doc/old-worlds/blank.wld:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/misprit7/computerraria/7d761296af5a3f8764ccb2af44a171e0a57e0e6b/doc/old-worlds/blank.wld


--------------------------------------------------------------------------------
/doc/old-worlds/computer.wld:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/misprit7/computerraria/7d761296af5a3f8764ccb2af44a171e0a57e0e6b/doc/old-worlds/computer.wld


--------------------------------------------------------------------------------
/doc/reference/computer-old.wld:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/misprit7/computerraria/7d761296af5a3f8764ccb2af44a171e0a57e0e6b/doc/reference/computer-old.wld


--------------------------------------------------------------------------------
/doc/riscv.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/misprit7/computerraria/7d761296af5a3f8764ccb2af44a171e0a57e0e6b/doc/riscv.pdf


--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------
  1 | # syntax = docker/dockerfile:1.2
  2 | 
  3 | ################################################################################
  4 | # CI dockerfile
  5 | ################################################################################
  6 | # This dockerfile contains everything required to run a full CI test suite
  7 | #
  8 | # One could potentially also use this for development, as long as another
  9 | # computer with a Terraria client installed can connect
 10 | 
 11 | 
 12 | ################################################################################
 13 | # Base
 14 | ################################################################################
 15 | # Probably should have used this in hindsight:
 16 | # https://github.com/tModLoader/tModLoader/tree/1.4/patches/tModLoader/Terraria/release_extras/DedicatedServerUtils
 17 | FROM steamcmd/steamcmd@sha256:0d3d8716fb0ac76f02bd9d850334b892d1caf92632fcce362bb52592d63211c3
 18 | 
 19 | 
 20 | ################################################################################
 21 | # Base
 22 | ################################################################################
 23 | # Yeah I'm not supposed to install user applications (vim), but it helps when 
 24 | # debugging and is trivially lightweight
 25 | RUN apt-get update && apt-get install -y \
 26 |     bsdmainutils \
 27 |     curl \
 28 |     gcc \
 29 |     git \
 30 |     libsdl2-2.0-0 \
 31 |     python3 \
 32 |     python3-pip \
 33 |     python3-tqdm \
 34 |     make \
 35 |     vim \
 36 |     wget
 37 | 
 38 | # libicu70 \
 39 | 
 40 | 
 41 | ################################################################################
 42 | # tModLoader
 43 | ################################################################################
 44 | RUN --mount=type=secret,id=_env,dst=/etc/secrets/.env \
 45 |     echo exit | steamcmd \
 46 |         "+login $(sed -n 1p /etc/secrets/.env) $(sed -n 2p /etc/secrets/.env)" \
 47 |         "+app_update 1281930 validate" &&\
 48 |     mkdir -p /root/.local/share/Terraria/tModLoader/ModSources &&\
 49 |     mkdir -p /root/.local/share/Terraria/tModLoader/Mods
 50 | # ln -s /root/Steam/steamapps/ /root/.local/share/Steam/ &&\
 51 | COPY tModLoader.targets /root/.local/share/Terraria/tModLoader/ModSources
 52 | 
 53 | 
 54 | ################################################################################
 55 | # RISCV Toolchain
 56 | ################################################################################
 57 | # These are kind of sketchy prebuilt binaries, but building from scratch takes 
 58 | # forever
 59 | WORKDIR /opt
 60 | RUN mkdir /opt/riscv &&\
 61 |     wget https://github.com/stnolting/riscv-gcc-prebuilt/releases/download/rv32i-4.0.0/riscv32-unknown-elf.gcc-12.1.0.tar.gz &&\
 62 |     tar -xzf riscv32-unknown-elf.gcc-12.1.0.tar.gz -C /opt/riscv/ &&\
 63 |     rm riscv32-unknown-elf.gcc-12.1.0.tar.gz
 64 | WORKDIR /root
 65 | 
 66 | 
 67 | ################################################################################
 68 | # Rust
 69 | ################################################################################
 70 | RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup.sh &&\
 71 |     sh rustup.sh -y --profile minimal &&\
 72 |     source "$HOME/.cargo/env" &&\
 73 |     rustup target add riscv32i-unknown-none-elf &&\
 74 |     rustup component add llvm-tools-preview &&\
 75 |     cargo install cargo-binutils &&\
 76 |     rm -rf /root/.cargo/registry &&\
 77 |     rustup target remove x86_64-unknown-linux-gnu
 78 | ENV PATH "$PATH:/opt/riscv/bin"
 79 | 
 80 | 
 81 | ################################################################################
 82 | # Dotnet
 83 | ################################################################################
 84 | RUN wget https://dot.net/v1/dotnet-install.sh &&\
 85 |     bash ./dotnet-install.sh --install-dir /usr/local/bin -channel 8.0 &&\
 86 |     dotnet --list-sdks
 87 | 
 88 | 
 89 | ################################################################################
 90 | # Riscof
 91 | ################################################################################
 92 | # RUN pip3 install git+https://github.com/riscv/riscof.git
 93 | RUN pip3 install --break-system-packages git+https://github.com/riscv/riscof.git
 94 | # I should set this up to be built, right now it relies on host machine
 95 | # already having it installed
 96 | # This would require setting up ocaml as well as other build dependencies
 97 | COPY riscv_sim_RV32 /usr/local/bin
 98 | 
 99 | 
100 | ################################################################################
101 | # Entry point
102 | ################################################################################
103 | # Override default entrypoint/cmd from base image
104 | ENTRYPOINT ["/usr/bin/env"]
105 | CMD ["/bin/bash"]
106 | 
107 | 


--------------------------------------------------------------------------------
/docker/build.sh:
--------------------------------------------------------------------------------
1 | #/usr/bin/sh
2 | 
3 | #################################################
4 | # Script to build docker image
5 | #################################################
6 | 
7 | cp /usr/local/bin/riscv_sim_RV32 .
8 | DOCKER_BUILDKIT=1 docker build --secret id=_env,src=./.env -t computerraria .
9 | 


--------------------------------------------------------------------------------
/docker/push.sh:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/sh
 2 | 
 3 | #################################################
 4 | # Script to push docker image to docker hub
 5 | #################################################
 6 | 
 7 | docker tag computerraria:latest misprit7/computerraria:latest
 8 | docker push misprit7/computerraria:latest
 9 | 
10 | 


--------------------------------------------------------------------------------
/docker/run.sh:
--------------------------------------------------------------------------------
1 | #/usr/bin/sh
2 | 
3 | #################################################
4 | # Script to run docker container ephemerally
5 | #################################################
6 | 
7 | # --rm is important, otherwise you end up with a million extraneous containers
8 | docker run -it --rm computerraria
9 | 


--------------------------------------------------------------------------------
/docker/tModLoader.targets:
--------------------------------------------------------------------------------
1 | <Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2 |   <Import Project="/root/.local/share/Steam/steamapps/common/tModLoader/tMLMod.targets" />
3 | </Project>
4 | 


--------------------------------------------------------------------------------
/run-tests.sh:
--------------------------------------------------------------------------------
 1 | #!/bin/sh
 2 | 
 3 | #################################################
 4 | # Runs all riscof tests
 5 | #################################################
 6 | 
 7 | cd test
 8 | # Why all this junk isn't specified in the config is weird, hate having to make little wrapper scripts like this
 9 | riscof run --config=config.ini --suite=riscv-arch-test/riscv-test-suite/ --env=riscv-arch-test/riscv-test-suite/env
10 | 


--------------------------------------------------------------------------------
/test/.gitignore:
--------------------------------------------------------------------------------
1 | riscof_work/
2 | 


--------------------------------------------------------------------------------
/test/computerraria/computerraria_isa.yaml:
--------------------------------------------------------------------------------
 1 | hart_ids: [0]
 2 | hart0:
 3 |   ISA: RV32I
 4 |   physical_addr_sz: 32
 5 |   User_Spec_Version: '2.3'
 6 |   supported_xlen: [32]
 7 |   misa:
 8 |    # reset-val: 0x40001104
 9 |    rv32:
10 |      accessible: true
11 |      mxl:
12 |        implemented: true
13 |        type:
14 |            warl:
15 |               dependency_fields: []
16 |               legal:
17 |                 - mxl[1:0] in [0x1]
18 |               wr_illegal:
19 |                 - Unchanged
20 |      extensions:
21 |        implemented: true
22 |        type:
23 |            warl:
24 |               dependency_fields: []
25 |               legal:
26 |                 - extensions[25:0] bitmask [0x0001104, 0x0000000]
27 |               wr_illegal:
28 |                 - Unchanged
29 |  
30 | 


--------------------------------------------------------------------------------
/test/computerraria/computerraria_platform.yaml:
--------------------------------------------------------------------------------
 1 | mtime:
 2 |   implemented: false
 3 |   address: 0xbff8
 4 | mtimecmp:
 5 |   implemented: false
 6 |   address: 0x4000
 7 | nmi:
 8 |   label: nmi_vector
 9 | reset:
10 |   label: reset_vector
11 | 


--------------------------------------------------------------------------------
/test/computerraria/env/link.ld:
--------------------------------------------------------------------------------
 1 | OUTPUT_ARCH( "riscv" )
 2 | ENTRY(rvtest_entry_point)
 3 | 
 4 | SECTIONS
 5 | {
 6 |   . = 0x00000000;
 7 |   .text.init : { *(.text.init) }
 8 |   . = ALIGN(0x1000);
 9 |   .tohost : { *(.tohost) }
10 |   . = ALIGN(0x1000);
11 |   .text : { *(.text) }
12 |   /* . = ALIGN(0x1000); */
13 |   . = 0x10000;
14 |   .data : { *(.data) }
15 |   .data.string : { *(.data.string)}
16 |   .bss : { *(.bss) }
17 |   _end = .;
18 | }
19 | 
20 | 


--------------------------------------------------------------------------------
/test/computerraria/env/model_test.h:
--------------------------------------------------------------------------------
 1 | #ifndef _COMPLIANCE_MODEL_H
 2 | #define _COMPLIANCE_MODEL_H
 3 | #define RVMODEL_DATA_SECTION \
 4 |         .pushsection .tohost,"aw",@progbits;                            \
 5 |         .align 8; .global tohost; tohost: .dword 0;                     \
 6 |         .align 8; .global fromhost; fromhost: .dword 0;                 \
 7 |         .popsection;                                                    \
 8 |         .align 8; .global begin_regstate; begin_regstate:               \
 9 |         .word 128;                                                      \
10 |         .align 8; .global end_regstate; end_regstate:                   \
11 |         .word 4;
12 | 
13 | //RV_COMPLIANCE_HALT
14 | #define RVMODEL_HALT                                              \
15 |   li x1, 1;                                                                   \
16 |   write_tohost:                                                               \
17 |     sw x1, tohost, t5;                                                        \
18 |     j write_tohost;
19 | 
20 | #define RVMODEL_BOOT
21 | 
22 | //RV_COMPLIANCE_DATA_BEGIN
23 | #define RVMODEL_DATA_BEGIN                                              \
24 |   RVMODEL_DATA_SECTION                                                        \
25 |   .align 4;\
26 |   .global begin_signature; begin_signature:
27 | 
28 | //RV_COMPLIANCE_DATA_END
29 | #define RVMODEL_DATA_END                                                      \
30 |   .align 4;\
31 |   .global end_signature; end_signature:  
32 | 
33 | //RVTEST_IO_INIT
34 | #define RVMODEL_IO_INIT
35 | //RVTEST_IO_WRITE_STR
36 | #define RVMODEL_IO_WRITE_STR(_R, _STR)
37 | //RVTEST_IO_CHECK
38 | #define RVMODEL_IO_CHECK()
39 | //RVTEST_IO_ASSERT_GPR_EQ
40 | #define RVMODEL_IO_ASSERT_GPR_EQ(_S, _R, _I)
41 | //RVTEST_IO_ASSERT_SFPR_EQ
42 | #define RVMODEL_IO_ASSERT_SFPR_EQ(_F, _R, _I)
43 | //RVTEST_IO_ASSERT_DFPR_EQ
44 | #define RVMODEL_IO_ASSERT_DFPR_EQ(_D, _R, _I)
45 | 
46 | #define RVMODEL_SET_MSW_INT       \
47 |  li t1, 1;                         \
48 |  li t2, 0x2000000;                 \
49 |  sw t1, 0(t2);
50 | 
51 | #define RVMODEL_CLEAR_MSW_INT     \
52 |  li t2, 0x2000000;                 \
53 |  sw x0, 0(t2);
54 | 
55 | #define RVMODEL_CLEAR_MTIMER_INT
56 | 
57 | #define RVMODEL_CLEAR_MEXT_INT
58 | 
59 | 
60 | #endif // _COMPLIANCE_MODEL_H
61 | 


--------------------------------------------------------------------------------
/test/computerraria/riscof_computerraria.py:
--------------------------------------------------------------------------------
  1 | import os
  2 | import logging
  3 | import tinterface
  4 | 
  5 | 
  6 | import riscof.utils as utils
  7 | import riscof.constants as constants
  8 | from riscof.pluginTemplate import pluginTemplate
  9 | 
 10 | logger = logging.getLogger()
 11 | 
 12 | class computerraria(pluginTemplate):
 13 |   __model__ = "computerraria"
 14 | 
 15 |   __version__ = "2.0"
 16 | 
 17 |   def __init__(self, *args, **kwargs):
 18 |     super().__init__(*args, **kwargs)
 19 | 
 20 |     config = kwargs.get('config')
 21 | 
 22 |     if config is None:
 23 |       print("Please enter input file paths in configuration.")
 24 |       raise SystemExit(1)
 25 |     logger.info(config)
 26 | 
 27 |     # self.dut_exe = os.path.join(config['PATH'] if 'PATH' in config else \
 28 |     #                             "~/.local/share/Steam/steamapps/common/tModLoader","start-tModLoaderServer.sh")
 29 |     self.dut_exe = os.path.join(config['PATH'] if 'PATH' in config else \
 30 |                                 "echo","start-tModLoaderServer.sh")
 31 | 
 32 | 
 33 |     self.num_jobs = str(config['jobs'] if 'jobs' in config else 1)
 34 |     self.pluginpath=os.path.abspath(config['pluginpath'])
 35 |     self.isa_spec = os.path.abspath(config['ispec'])
 36 |     self.platform_spec = os.path.abspath(config['pspec'])
 37 |     if 'target_run' in config and config['target_run']=='0':
 38 |       self.target_run = False
 39 |     else:
 40 |       self.target_run = True
 41 | 
 42 |   def initialise(self, suite, work_dir, archtest_env):
 43 | 
 44 |     self.work_dir = work_dir
 45 |     self.suite_dir = suite
 46 |     self.compile_cmd = 'riscv{1}-unknown-elf-gcc -march={0} \
 47 |       -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles -g\
 48 |       -T '+self.pluginpath+'/env/link.ld\
 49 |       -I '+self.pluginpath+'/env/\
 50 |       -I ' + archtest_env + ' {2} -o {3} {4}'
 51 | 
 52 |   def build(self, isa_yaml, platform_yaml):
 53 | 
 54 |     # load the isa yaml as a dictionary in python.
 55 |     ispec = utils.load_yaml(isa_yaml)['hart0']
 56 | 
 57 |     self.xlen = '32'
 58 |     self.isa = 'rv32I'
 59 |     self.compile_cmd = self.compile_cmd+' -mabi=ilp32'
 60 | 
 61 |   def runTests(self, testList):
 62 | 
 63 |     logger.info('Starting server')
 64 |     tserver = tinterface.TServer(terracc=False)
 65 |     tserver.start()
 66 |     logger.info('Server loaded')
 67 |     for testname in testList:
 68 |       logger.info('Running Test: {0} on DUT'.format(testname))
 69 | 
 70 |       # for each testname we get all its fields (as described by the testList format)
 71 |       testentry = testList[testname]
 72 |       test = testentry['test_path']
 73 |       test_dir = testentry['work_dir']
 74 | 
 75 |       elf = 'dut.elf'
 76 |       out = 'dut-out.txt'
 77 | 
 78 |       # name of the signature file as per requirement of RISCOF. RISCOF expects the signature to
 79 |       # be named as DUT-<dut-name>.signature. The below variable creates an absolute path of
 80 |       # signature file.
 81 |       sig_file = os.path.join(test_dir, self.name[:-1] + ".signature")
 82 |       elf_file = os.path.join(test_dir, elf)
 83 |       out_file = os.path.join(test_dir, out)
 84 |       compile_macros= ' -D' + " -D".join(testentry['macros'])
 85 | 
 86 |       cmd = self.compile_cmd.format(testentry['isa'].lower(), self.xlen, test, elf_file, compile_macros)
 87 | 
 88 |       logger.info('Compile command: ' + cmd)
 89 |       utils.shellCommand(cmd).run(cwd=test_dir)
 90 | 
 91 |       if not self.target_run:
 92 |         continue
 93 | 
 94 |       logger.info('Starting test')
 95 | 
 96 |       try:
 97 |         tserver.run(elf_file, out_file, clock_cycles=50000)
 98 |         # Don't love hardcoding this but riscof has made it difficult enough as it is for me
 99 |         # Seriously why don't they pass this as a parameter to runTests
100 |         tinterface.gen_signature(out_file, sig_file, 0x11110)
101 |       except Exception as e:
102 |         logger.error(e)
103 |         logger.error('An error occured, dropping into interactive mode to debug')
104 |         tserver.process.interact()
105 |         raise SystemExit
106 | 
107 |       logger.info('Test complete')
108 | 
109 | 
110 | 
111 | 


--------------------------------------------------------------------------------
/test/config.ini:
--------------------------------------------------------------------------------
 1 | [RISCOF]
 2 | ReferencePlugin=sail_cSim
 3 | ReferencePluginPath=./sail_cSim
 4 | DUTPlugin=computerraria
 5 | DUTPluginPath=./computerraria
 6 | 
 7 | [computerraria]
 8 | pluginpath=./computerraria
 9 | ispec=./computerraria/computerraria_isa.yaml
10 | pspec=./computerraria/computerraria_platform.yaml
11 | target_run=1
12 | 
13 | [sail_cSim]
14 | pluginpath=./sail_cSim
15 | 


--------------------------------------------------------------------------------
/test/manual/inf.s:
--------------------------------------------------------------------------------
1 | jal x0, 4
2 | jal x0, -4
3 | 


--------------------------------------------------------------------------------
/test/manual/inf.txt:
--------------------------------------------------------------------------------
1 | 6f 00 40 00 6f f0 df ff
2 | 


--------------------------------------------------------------------------------
/test/manual/loop.s:
--------------------------------------------------------------------------------
 1 | .global _start
 2 | .text
 3 | # bin read /home/xander/dev/terraria/computerraria/test/manual/loop.txt
 4 | 
 5 | _start:      
 6 | xor x1, x1, x1
 7 | xor x2, x2, x2
 8 | xor x3, x3, x3
 9 | xor x4, x4, x4
10 | addi x1, x1, 1
11 | addi x2, x2, 3
12 | addi x4, x4, 5
13 | loop:
14 | add x1, x1, x2
15 | addi x3, x3, 1
16 | blt x3, x4, loop
17 | sw x1, 100(x0)
18 | lui x5, 0x1
19 | addi x5, x5, 2046
20 | addi x5, x5, 2046
21 | sw x2, 0(x5)
22 | 


--------------------------------------------------------------------------------
/test/manual/loop.txt:
--------------------------------------------------------------------------------
1 | b3 c0 10 00 33 41 21 00 b3 c1 31 00 33 42 42 00 93 80 10 00 13 01 31 00 13 02 52 00 b3 80 20 00 93 81 11 00 e3 cc 41 fe 23 22 10 06 b7 12 00 00 93 82 e2 7f 93 82 e2 7f 23 a0 22 00
2 | 


--------------------------------------------------------------------------------
/test/sail_cSim/__init__.py:
--------------------------------------------------------------------------------
1 | from pkgutil import extend_path
2 | __path__ = extend_path(__path__, __name__)


--------------------------------------------------------------------------------
/test/sail_cSim/env/link.ld:
--------------------------------------------------------------------------------
 1 | OUTPUT_ARCH( "riscv" )
 2 | ENTRY(rvtest_entry_point)
 3 | 
 4 | SECTIONS
 5 | {
 6 |   . = 0x80000000;
 7 |   .text.init : { *(.text.init) }
 8 |   . = ALIGN(0x1000);
 9 |   .tohost : { *(.tohost) }
10 |   . = ALIGN(0x1000);
11 |   .text : { *(.text) }
12 |   . = ALIGN(0x1000);
13 |   .data : { *(.data) }
14 |   .data.string : { *(.data.string)}
15 |   .bss : { *(.bss) }
16 |   _end = .;
17 | }
18 | 
19 | 


--------------------------------------------------------------------------------
/test/sail_cSim/env/model_test.h:
--------------------------------------------------------------------------------
 1 | #ifndef _COMPLIANCE_MODEL_H
 2 | #define _COMPLIANCE_MODEL_H
 3 | 
 4 | #define RVMODEL_DATA_SECTION \
 5 |         .pushsection .tohost,"aw",@progbits;                            \
 6 |         .align 8; .global tohost; tohost: .dword 0;                     \
 7 |         .align 8; .global fromhost; fromhost: .dword 0;                 \
 8 |         .popsection;                                                    \
 9 |         .align 8; .global begin_regstate; begin_regstate:               \
10 |         .word 128;                                                      \
11 |         .align 8; .global end_regstate; end_regstate:                   \
12 |         .word 4;
13 | 
14 | //RV_COMPLIANCE_HALT
15 | #define RVMODEL_HALT                                              \
16 |   li x1, 1;                                                                   \
17 |   write_tohost:                                                               \
18 |     sw x1, tohost, t5;                                                        \
19 |     j write_tohost;
20 | 
21 | #define RVMODEL_BOOT
22 | 
23 | //RV_COMPLIANCE_DATA_BEGIN
24 | #define RVMODEL_DATA_BEGIN                                              \
25 |   RVMODEL_DATA_SECTION                                                        \
26 |   .align 4;\
27 |   .global begin_signature; begin_signature:
28 | 
29 | //RV_COMPLIANCE_DATA_END
30 | #define RVMODEL_DATA_END                                                      \
31 |   .align 4; .global end_signature; end_signature:  
32 | 
33 | //RVTEST_IO_INIT
34 | #define RVMODEL_IO_INIT
35 | //RVTEST_IO_WRITE_STR
36 | #define RVMODEL_IO_WRITE_STR(_R, _STR)
37 | //RVTEST_IO_CHECK
38 | #define RVMODEL_IO_CHECK()
39 | //RVTEST_IO_ASSERT_GPR_EQ
40 | #define RVMODEL_IO_ASSERT_GPR_EQ(_S, _R, _I)
41 | //RVTEST_IO_ASSERT_SFPR_EQ
42 | #define RVMODEL_IO_ASSERT_SFPR_EQ(_F, _R, _I)
43 | //RVTEST_IO_ASSERT_DFPR_EQ
44 | #define RVMODEL_IO_ASSERT_DFPR_EQ(_D, _R, _I)
45 | 
46 | #define RVMODEL_SET_MSW_INT
47 | 
48 | #define RVMODEL_CLEAR_MSW_INT
49 | 
50 | #define RVMODEL_CLEAR_MTIMER_INT
51 | 
52 | #define RVMODEL_CLEAR_MEXT_INT
53 | 
54 | 
55 | #endif // _COMPLIANCE_MODEL_H
56 | 


--------------------------------------------------------------------------------
/test/sail_cSim/riscof_sail_cSim.py:
--------------------------------------------------------------------------------
  1 | import os
  2 | import re
  3 | import shutil
  4 | import subprocess
  5 | import shlex
  6 | import logging
  7 | import random
  8 | import string
  9 | from string import Template
 10 | 
 11 | import riscof.utils as utils
 12 | from riscof.pluginTemplate import pluginTemplate
 13 | import riscof.constants as constants
 14 | from riscv_isac.isac import isac
 15 | 
 16 | logger = logging.getLogger()
 17 | 
 18 | class sail_cSim(pluginTemplate):
 19 |     __model__ = "sail_c_simulator"
 20 |     __version__ = "0.5.0"
 21 | 
 22 |     def __init__(self, *args, **kwargs):
 23 |         sclass = super().__init__(*args, **kwargs)
 24 | 
 25 |         config = kwargs.get('config')
 26 |         if config is None:
 27 |             logger.error("Config node for sail_cSim missing.")
 28 |             raise SystemExit(1)
 29 |         self.num_jobs = str(config['jobs'] if 'jobs' in config else 1)
 30 |         self.pluginpath = os.path.abspath(config['pluginpath'])
 31 |         self.sail_exe = { '32' : os.path.join(config['PATH'] if 'PATH' in config else "","riscv_sim_RV32"),
 32 |                 '64' : os.path.join(config['PATH'] if 'PATH' in config else "","riscv_sim_RV64")}
 33 |         self.isa_spec = os.path.abspath(config['ispec']) if 'ispec' in config else ''
 34 |         self.platform_spec = os.path.abspath(config['pspec']) if 'ispec' in config else ''
 35 |         self.make = config['make'] if 'make' in config else 'make'
 36 |         logger.debug("SAIL CSim plugin initialised using the following configuration.")
 37 |         for entry in config:
 38 |             logger.debug(entry+' : '+config[entry])
 39 |         return sclass
 40 | 
 41 |     def initialise(self, suite, work_dir, archtest_env):
 42 |         self.suite = suite
 43 |         self.work_dir = work_dir
 44 |         self.objdump_cmd = 'riscv{1}-unknown-elf-objdump -D {0} > {2};'
 45 |         self.compile_cmd = 'riscv{1}-unknown-elf-gcc -march={0} \
 46 |          -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles\
 47 |          -T '+self.pluginpath+'/env/link.ld\
 48 |          -I '+self.pluginpath+'/env/\
 49 |          -I ' + archtest_env
 50 | 
 51 |     def build(self, isa_yaml, platform_yaml):
 52 |         ispec = utils.load_yaml(isa_yaml)['hart0']
 53 |         self.xlen = ('64' if 64 in ispec['supported_xlen'] else '32')
 54 |         self.isa = 'rv' + self.xlen
 55 |         self.compile_cmd = self.compile_cmd+' -mabi='+('lp64 ' if 64 in ispec['supported_xlen'] else 'ilp32 ')
 56 |         if "I" in ispec["ISA"]:
 57 |             self.isa += 'i'
 58 |         if "M" in ispec["ISA"]:
 59 |             self.isa += 'm'
 60 |         if "C" in ispec["ISA"]:
 61 |             self.isa += 'c'
 62 |         if "F" in ispec["ISA"]:
 63 |             self.isa += 'f'
 64 |         if "D" in ispec["ISA"]:
 65 |             self.isa += 'd'
 66 |         objdump = "riscv{0}-unknown-elf-objdump".format(self.xlen)
 67 |         if shutil.which(objdump) is None:
 68 |             logger.error(objdump+": executable not found. Please check environment setup.")
 69 |             raise SystemExit(1)
 70 |         compiler = "riscv{0}-unknown-elf-gcc".format(self.xlen)
 71 |         if shutil.which(compiler) is None:
 72 |             logger.error(compiler+": executable not found. Please check environment setup.")
 73 |             raise SystemExit(1)
 74 |         if shutil.which(self.sail_exe[self.xlen]) is None:
 75 |             logger.error(self.sail_exe[self.xlen]+ ": executable not found. Please check environment setup.")
 76 |             raise SystemExit(1)
 77 |         if shutil.which(self.make) is None:
 78 |             logger.error(self.make+": executable not found. Please check environment setup.")
 79 |             raise SystemExit(1)
 80 | 
 81 | 
 82 |     def runTests(self, testList, cgf_file=None):
 83 |         if os.path.exists(self.work_dir+ "/Makefile." + self.name[:-1]):
 84 |             os.remove(self.work_dir+ "/Makefile." + self.name[:-1])
 85 |         make = utils.makeUtil(makefilePath=os.path.join(self.work_dir, "Makefile." + self.name[:-1]))
 86 |         make.makeCommand = self.make + ' -j' + self.num_jobs
 87 |         for file in testList:
 88 |             testentry = testList[file]
 89 |             test = testentry['test_path']
 90 |             test_dir = testentry['work_dir']
 91 |             test_name = test.rsplit('/',1)[1][:-2]
 92 | 
 93 |             elf = 'ref.elf'
 94 | 
 95 |             execute = "@cd "+testentry['work_dir']+";"
 96 | 
 97 |             cmd = self.compile_cmd.format(testentry['isa'].lower(), self.xlen) + ' ' + test + ' -o ' + elf
 98 |             compile_cmd = cmd + ' -D' + " -D".join(testentry['macros'])
 99 |             execute+=compile_cmd+";"
100 | 
101 |             execute += self.objdump_cmd.format(elf, self.xlen, 'ref.disass')
102 |             sig_file = os.path.join(test_dir, self.name[:-1] + ".signature")
103 | 
104 |             execute += self.sail_exe[self.xlen] + ' --test-signature={0} {1} > {2}.log 2>&1;'.format(sig_file, elf, test_name)
105 | 
106 |             cov_str = ' '
107 |             for label in testentry['coverage_labels']:
108 |                 cov_str+=' -l '+label
109 | 
110 |             if cgf_file is not None:
111 |                 coverage_cmd = 'riscv_isac --verbose info coverage -d \
112 |                         -t {0}.log --parser-name c_sail -o coverage.rpt  \
113 |                         --sig-label begin_signature  end_signature \
114 |                         --test-label rvtest_code_begin rvtest_code_end \
115 |                         -e ref.elf -c {1} -x{2} {3};'.format(\
116 |                         test_name, ' -c '.join(cgf_file), self.xlen, cov_str)
117 |             else:
118 |                 coverage_cmd = ''
119 | 
120 | 
121 |             execute+=coverage_cmd
122 | 
123 |             make.add_target(execute)
124 |         make.execute_all(self.work_dir)
125 | 


--------------------------------------------------------------------------------
/tinterface/bin/tcli:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/python3
 2 | 
 3 | import argparse
 4 | import tinterface
 5 | 
 6 | # pyright: reportOptionalMemberAccess=false
 7 | 
 8 | parser = argparse.ArgumentParser(
 9 |     prog = 'tinterfacecli',
10 |     description = 'A command line interface to interact with terraria server for computerraria',
11 | )
12 | 
13 | parser.add_argument(
14 |     '-p',
15 |     '--path',
16 |     type=str,
17 |     help='path to Terraria server executable',
18 | )
19 | parser.add_argument(
20 |     '-w',
21 |     '--world',
22 |     type=str,
23 |     help='path to .wld world file',
24 | )
25 | parser.add_argument(
26 |     '-r',
27 |     '--run',
28 |     type=str,
29 |     help='run the given program and write the results to the output file',
30 | )
31 | parser.add_argument(
32 |     '-o',
33 |     '--output',
34 |     type=str,
35 |     help='output file of run',
36 | )
37 | parser.add_argument(
38 |     '-c',
39 |     '--cycles',
40 |     type=int,
41 |     help='number of cycles to let program run for',
42 |     default=50000
43 | )
44 | parser.add_argument(
45 |     '-i',
46 |     '--interactive',
47 |     action='store_true',
48 |     help='leave the server in interactive mode after other operations finish',
49 | )
50 | 
51 |     
52 | 
53 | args = parser.parse_args()
54 | 
55 | t = tinterface.TServer(path=args.path, world=args.world, verbose=True)
56 | t.start()
57 | 
58 | if args.run is not None:
59 |     try:
60 |         t.run(args.run, args.output, clock_cycles=args.cycles)
61 |     except Exception as e:
62 |         print(e)
63 |         print('An error occured, starting interactive mode to let you debug')
64 |         args.interactive = True
65 | 
66 | if args.interactive:
67 |     t.process.interact()
68 | 
69 | 
70 | 


--------------------------------------------------------------------------------
/tinterface/setup.py:
--------------------------------------------------------------------------------
 1 | from setuptools import setup
 2 | 
 3 | setup(
 4 |     name='tinterface',
 5 |     version='0.1',
 6 |     description='Terraria server python/cli interface',
 7 |     url='https://github.com/misprit7/computerraria',
 8 |     author='Xander Naumenko',
 9 |     author_email='xandernaumenko@gmail.com',
10 |     license='MIT',
11 |     packages=['tinterface'],
12 |     zip_safe=False,
13 |     scripts=['bin/tcli'],
14 |     install_requires=[
15 |         "pexpect"
16 |     ],
17 | )
18 | 


--------------------------------------------------------------------------------