From b44a95a9b310cd0a6d0cde3e0db03fcdb9d2dad0 Mon Sep 17 00:00:00 2001 From: circuit10 Date: Wed, 10 May 2023 17:28:18 +0100 Subject: [PATCH] Casio fx-CG series port (#324) * Initial test - working on Linux * Try to make it work with liba * Stop using liba and the filesystem * IT WORKS * Key input, full res, fix some of the crashes * Fix the hang when doing calculations * Add some more key mappings * Fix the square root issue * Icons * Better key mappings, brightness control, better gamma correction, more effficient framebuffer * Cleanup stage 1 * Cleanup stage 2 * Make the build system build a g3a * Make it not exit when you press the menu button * Add Casio port to README * Use omega-master instead of omega-dev * Fix mistake with cherry-picking in the README * Fix internal storage crash * Fix compile error on Numworks calculators * Upsilon branding * Sharper icon * Make the CI work * Add power off and improve menu * Map Alpha + up/down to the brightness shortcut * Add missing file * Fix web CI build * Revert "Fix web CI build" This reverts commit f19657d9fcd3f2dae9b9512118082e58a73c2523. * Change "prizm" to "fxcg" * Add FASTLOAD option for Add-in Push * Add some charatcers to the catalog on Casio and improve key mappings * Build with -Os -flto * Disable LTO for now as it's causing crashes * Put back the fonts I accidently changed I'd like to add an option for this though as I prefer the ones from Epsilon --- .github/workflows/ci-workflow.yml | 58 ++++ Makefile | 2 + README.md | 37 ++- apps/code/catalog.de.i18n | 6 + apps/code/catalog.en.i18n | 6 + apps/code/catalog.es.i18n | 6 + apps/code/catalog.fr.i18n | 6 + apps/code/catalog.hu.i18n | 6 + apps/code/catalog.it.i18n | 6 + apps/code/catalog.nl.i18n | 6 + apps/code/catalog.pt.i18n | 6 + apps/code/catalog.universal.i18n | 6 + apps/code/python_toolbox.cpp | 9 + apps/graph/graph/graph_view.h | 6 + apps/home/controller.cpp | 2 +- apps/home/controller.h | 11 +- apps/math_toolbox.cpp | 4 + apps/probability/app.h | 2 +- apps/settings/sub_menu/about_controller.cpp | 1 + .../settings/sub_menu/datetime_controller.cpp | 3 + apps/shared.hu.i18n | 1 + apps/shared.it.i18n | 1 + apps/shared.nl.i18n | 1 + apps/shared.universal.i18n | 2 + apps/shared/continuous_function.cpp | 2 +- apps/shared/continuous_function_cache.cpp | 4 + apps/shared/store_controller.h | 5 + apps/solver/solutions_controller.h | 2 +- apps/toolbox.de.i18n | 1 + apps/toolbox.en.i18n | 1 + apps/toolbox.es.i18n | 1 + apps/toolbox.fr.i18n | 1 + apps/toolbox.pt.i18n | 1 + build/platform.simulator.fxcg.mak | 11 + build/targets.simulator.fxcg.mak | 5 + build/toolchain.sh-elf-gcc.mak | 10 + escher/src/icon_view.cpp | 8 + escher/src/image_view.cpp | 8 + ion/include/ion/display.h | 7 + ion/include/ion/internal_storage.h | 4 +- ion/include/ion/keyboard.h | 23 ++ ion/src/shared/events_keyboard.cpp | 11 + ion/src/simulator/external/config.fxcg.mak | 2 + ion/src/simulator/fxcg/Makefile | 66 +++++ ion/src/simulator/fxcg/assets/icon-sel.png | Bin 0 -> 3588 bytes ion/src/simulator/fxcg/assets/icon-uns.png | Bin 0 -> 1750 bytes ion/src/simulator/fxcg/backlight.cpp | 67 +++++ ion/src/simulator/fxcg/clipboard.cpp | 18 ++ ion/src/simulator/fxcg/console.cpp | 24 ++ ion/src/simulator/fxcg/display.cpp | 30 ++ ion/src/simulator/fxcg/display.h | 19 ++ ion/src/simulator/fxcg/events.cpp | 23 ++ ion/src/simulator/fxcg/events.h | 24 ++ ion/src/simulator/fxcg/events_keyboard.cpp | 15 + ion/src/simulator/fxcg/framebuffer.cpp | 56 ++++ ion/src/simulator/fxcg/framebuffer.h | 17 ++ ion/src/simulator/fxcg/keyboard.cpp | 262 ++++++++++++++++++ ion/src/simulator/fxcg/keyboard.h | 15 + ion/src/simulator/fxcg/main.cpp | 114 ++++++++ ion/src/simulator/fxcg/main.h | 20 ++ ion/src/simulator/fxcg/menuHandler.cpp | 97 +++++++ ion/src/simulator/fxcg/menuHandler.h | 14 + ion/src/simulator/fxcg/platform.h | 23 ++ ion/src/simulator/fxcg/power.cpp | 42 +++ ion/src/simulator/fxcg/telemetry_init.cpp | 15 + ion/src/simulator/fxcg/timing.cpp | 27 ++ .../kandinsky/postprocess_gamma_context.h | 10 + kandinsky/src/postprocess_gamma_context.cpp | 53 ++-- liba/include/bridge/math.h | 20 ++ liba/include/bridge/string.h | 2 +- liba/include/bridge/strings.h | 22 ++ libaxx/Makefile.bridge | 3 + libaxx/include/bridge/cmath | 165 +++++++++++ poincare/include/poincare/ieee754.h | 34 ++- poincare/include/poincare/integer.h | 22 +- poincare/include/poincare/tree_pool.h | 2 +- poincare/src/integer.cpp | 44 ++- 77 files changed, 1617 insertions(+), 49 deletions(-) create mode 100644 build/platform.simulator.fxcg.mak create mode 100644 build/targets.simulator.fxcg.mak create mode 100644 build/toolchain.sh-elf-gcc.mak create mode 100644 ion/src/simulator/external/config.fxcg.mak create mode 100644 ion/src/simulator/fxcg/Makefile create mode 100644 ion/src/simulator/fxcg/assets/icon-sel.png create mode 100644 ion/src/simulator/fxcg/assets/icon-uns.png create mode 100644 ion/src/simulator/fxcg/backlight.cpp create mode 100644 ion/src/simulator/fxcg/clipboard.cpp create mode 100644 ion/src/simulator/fxcg/console.cpp create mode 100644 ion/src/simulator/fxcg/display.cpp create mode 100644 ion/src/simulator/fxcg/display.h create mode 100644 ion/src/simulator/fxcg/events.cpp create mode 100644 ion/src/simulator/fxcg/events.h create mode 100644 ion/src/simulator/fxcg/events_keyboard.cpp create mode 100644 ion/src/simulator/fxcg/framebuffer.cpp create mode 100644 ion/src/simulator/fxcg/framebuffer.h create mode 100644 ion/src/simulator/fxcg/keyboard.cpp create mode 100644 ion/src/simulator/fxcg/keyboard.h create mode 100644 ion/src/simulator/fxcg/main.cpp create mode 100644 ion/src/simulator/fxcg/main.h create mode 100644 ion/src/simulator/fxcg/menuHandler.cpp create mode 100644 ion/src/simulator/fxcg/menuHandler.h create mode 100644 ion/src/simulator/fxcg/platform.h create mode 100644 ion/src/simulator/fxcg/power.cpp create mode 100644 ion/src/simulator/fxcg/telemetry_init.cpp create mode 100644 ion/src/simulator/fxcg/timing.cpp create mode 100644 liba/include/bridge/math.h create mode 100644 liba/include/bridge/strings.h create mode 100644 libaxx/Makefile.bridge create mode 100644 libaxx/include/bridge/cmath diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index d4e42c2a02e..e2fd55ddd37 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -18,6 +18,64 @@ on: required: true default: 'yes' jobs: + fxcg: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: 'recursive' + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install curl git python3 build-essential cmake pkg-config -y + - name: Get latest gint commit hash + run: | + LATEST_COMMIT_HASH=$(curl --silent https://gitea.planet-casio.com/api/v1/repos/Lephenixnoir/gint/branches/master | jq -r .commit.id) + echo "Latest commit hash is: $LATEST_COMMIT_HASH" + echo "LATEST_COMMIT_HASH=$LATEST_COMMIT_HASH" >> $GITHUB_OUTPUT + id: get-latest-commit-hash + - name: Cache gint/fxsdk installation + id: cache-gint + uses: actions/cache@v3 + with: + path: | + ~/.local/*/* + !~/.local/share/containers + key: ${{ runner.os }}-gint-${{ steps.get-latest-commit-hash.outputs.LATEST_COMMIT_HASH }} + - name: Install gint/fxsdk + if: steps.cache-gint.outputs.cache-hit != 'true' + env: + URL: "https://gitea.planet-casio.com/Lephenixnoir/GiteaPC/archive/master.tar.gz" + run: | + export PATH="~/.local/bin:$PATH" + cd "$(mktemp -d)" + curl "$URL" -o giteapc-master.tar.gz + tar -xzf giteapc-master.tar.gz + cd giteapc + python3 giteapc.py install Lephenixnoir/GiteaPC -y + sudo apt-get install python3-pil libusb-1.0-0-dev libudev-dev libsdl2-dev libpng-dev libudisks2-dev libglib2.0-dev libmpfr-dev libmpc-dev libppl-dev -y + giteapc install Lephenixnoir/fxsdk:noudisks2 Lephenixnoir/sh-elf-binutils Lephenixnoir/sh-elf-gcc -y + giteapc install Lephenixnoir/OpenLibm Vhex-Kernel-Core/fxlibc Lephenixnoir/sh-elf-gcc -y + giteapc install Lephenixnoir/gint -y + - name: Add fxsdk to PATH + run: echo "~/.local/bin" >> $GITHUB_PATH + - run: make -j2 PLATFORM=simulator TARGET=fxcg + - id: 'auth' + if: ${{ github.event_name == 'push' && github.ref_name == 'upsilon-dev' && github.repository == 'UpsilonNumworks/Upsilon' }} + uses: 'google-github-actions/auth@v0' + with: + credentials_json: '${{secrets.GOOGLE_CREDENTIALS}}' + - id: 'upload-directory' + if: ${{ github.event_name == 'push' && github.ref_name == 'upsilon-dev' && github.repository == 'UpsilonNumworks/Upsilon' }} + uses: 'google-github-actions/upload-cloud-storage@v0' + with: + path: 'output/release/simulator/fxcg/epsilon.g3a' + destination: 'upsilon-binfiles.appspot.com/dev/simulator/' + parent: false + - uses: actions/upload-artifact@master + with: + name: epsilon.g3a + path: output/release/simulator/fxcg/epsilon.g3a nintendo_3ds: if: github.event.inputs.trigger3DS == 'yes' || github.event.inputs.trigger3DS == '' runs-on: ubuntu-latest diff --git a/Makefile b/Makefile index c42ed081ab2..b3705e7f476 100644 --- a/Makefile +++ b/Makefile @@ -93,6 +93,7 @@ help: @echo " make PLATFORM=simulator TARGET=web" @echo " make PLATFORM=simulator TARGET=windows" @echo " make PLATFORM=simulator TARGET=3ds" + @echo " make PLATFORM=simulator TARGET=fxcg" .PHONY: doc doc: @@ -127,6 +128,7 @@ ifndef USE_LIBA endif ifeq ($(USE_LIBA),0) include liba/Makefile.bridge +include libaxx/Makefile.bridge else SFLAGS += -ffreestanding -nostdinc -nostdlib include liba/Makefile diff --git a/README.md b/README.md index 4135856a154..f9fbad9f88b 100644 --- a/README.md +++ b/README.md @@ -264,7 +264,7 @@ git checkout upsilon-dev ```bash make MODEL=n0100 clean -make MODEL=n0100 EPSILON_I18N=en OMEGA_USERNAME="{Your name, max 15 characters}" -j4 +make MODEL=n0100 EPSILON_I18N=en OMEGA_USERNAME="{Your name, max 15 characters}" -j(nproc) ``` Now, run either: @@ -280,7 +280,7 @@ to directly flash the calculator after pressing simultaneously `reset` and `6` b or: ```bash -make MODEL=n0100 OMEGA_USERNAME="" binpack -j4 +make MODEL=n0100 OMEGA_USERNAME="" binpack -j(nproc) ``` to make binpack which you can flash to the calculator from [Ti-planet's webDFU](https://ti-planet.github.io/webdfu_numworks/n0100/). Binpacks are a great way to share a custom build of Upsilonto friends. @@ -301,7 +301,7 @@ Then, build with: ```bash make clean -make OMEGA_USERNAME="{Your name, max 15 characters}" -j4 +make OMEGA_USERNAME="{Your name, max 15 characters}" -j(nproc) ``` Now, run either: @@ -317,7 +317,7 @@ to directly flash the calculator into the current slot, or thought bootloader's or: ```bash -make OMEGA_USERNAME="" binpack -j4 +make OMEGA_USERNAME="" binpack -j(nproc) ``` to make binpack which you can flash to the calculator from [Ti-planet's webDFU](https://ti-planet.github.io/webdfu_numworks/n0110/). You'll find them at `output/release/device/bootloader/`. Binpacks are a great way to share a custom build of Upsilon to friends. @@ -330,7 +330,7 @@ to make binpack which you can flash to the calculator from [Ti-planet's webDFU]( ```bash make MODEL=n0110 clean -make MODEL=n0110 OMEGA_USERNAME="{Your name, max 15 characters}" -j4 +make MODEL=n0110 OMEGA_USERNAME="{Your name, max 15 characters}" -j(nproc) ``` Now, run either: @@ -346,7 +346,7 @@ to directly flash the calculator after pressing simultaneously `reset` and `6` b or: ```bash -make MODEL=n0110 OMEGA_USERNAME="" binpack -j4 +make MODEL=n0110 OMEGA_USERNAME="" binpack -j(nproc) ``` to make binpack which you can flash to the calculator from [Ti-planet's webDFU](https://ti-planet.github.io/webdfu_numworks/n0110/). You'll find them at `output/release/device/bootloader/`. Binpacks are a great way to share a custom build of Upsilon to friends. @@ -400,7 +400,7 @@ Then, compile Upsilon : ```bash make clean -make PLATFORM=simulator TARGET=web OMEGA_USERNAME="{Your name, max 15 characters}" -j4 +make PLATFORM=simulator TARGET=web OMEGA_USERNAME="{Your name, max 15 characters}" -j$(nproc) ``` The simulator is now in `output/release/simulator/web/simulator.zip` @@ -416,8 +416,8 @@ You need devkitPro and devkitARM installed and in your path (instructions [here] ```bash git clone --recursive https://github.com/UpsilonNumworks/Upsilon.git cd Upsilon -git checkout --recursive upsilon-dev -make PLATFORM=simulator TARGET=3ds -j +git checkout upsilon-dev +make PLATFORM=simulator TARGET=3ds -j(nproc) ``` You can then put epsilon.3dsx on a SD card to run it from the HBC or use 3dslink to launch it over the network: @@ -430,6 +430,22 @@ You can then put epsilon.3dsx on a SD card to run it from the HBC or use 3dslink
+
+ Casio fx-CG-series Port + +First, install gint and fxsdk along with a cross compiler for the calculator. There are instructions for this (in French, but Google Translate works well enough) [here](https://www.planet-casio.com/Fr/forums/topic16614-last-giteapc-installer-et-mettre-a-jour-automatiquement-des-projets-gitea.html). + +Next: +```bash +git clone --recursive https://github.com/UpsilonNumworks/Upsilon.git +cd Omega +git checkout upsilon-dev +make PLATFORM=simulator TARGET=fxcg -j$(nproc) +``` +Then copy the file at `./output/release/simulator/fxcg/epsilon.g3a` to the calculator over USB. + +
+ Important: Don't forget the `--recursive` tag, because Upsilon relies on submodules. Also, you can change the number of processes that run in parallel during the build by changing the value of the `-j` flag. Don't forget to put your pseudo instead of `{your pseudo, max 15 char}`. If you don't want one, just remove the `OMEGA_USERNAME=""` argument. @@ -476,7 +492,8 @@ You can try Epsilon straight from your browser in the [online simulator](https:/ NumWorks is a registered trademark of NumWorks SAS, 24 Rue Godot de Mauroy, 75009 Paris, France. Nintendo and Nintendo 3DS are registered trademarks of Nintendo of America Inc, 4600 150th Ave NE, Redmond, WA 98052, USA. -NumWorks SAS and Nintendo of America Inc aren't associated in any shape or form with this project. +Casio is a registered trademark of Casio Computer Co., Ltd. CORPORATION JAPAN 6-2, Hon-machi 1-chome Shibuya-ku, Tokyo JAPAN 151-8543. +NumWorks SAS, Nintendo of America Inc and Casio aren't associated in any shape or form with this project. - NumWorks Epsilon is released under a [CC BY-NC-SA License](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode). - Omega is released under a [CC BY-NC-SA License](https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode). diff --git a/apps/code/catalog.de.i18n b/apps/code/catalog.de.i18n index 5ead158750a..b5a22857c9e 100644 --- a/apps/code/catalog.de.i18n +++ b/apps/code/catalog.de.i18n @@ -1,5 +1,11 @@ PythonPound = "Kommentar" PythonPercent = "Modulo" +PythonColon = "Doppelpunkt" +PythonSemicon = "Semikolon" +PythonExclamationMark = "Ausrufezeichen" +PythonLessThan = "Kleiner als" +PythonGreaterThan = "Größer als" +PythonQuestionMark = "Fragezeichen" Python1J = "Imaginäres i" PythonLF = "Zeilenvorschub" PythonTab = "Tabulator" diff --git a/apps/code/catalog.en.i18n b/apps/code/catalog.en.i18n index 62a9400577f..dd3936409d8 100644 --- a/apps/code/catalog.en.i18n +++ b/apps/code/catalog.en.i18n @@ -1,5 +1,11 @@ PythonPound = "Comment" PythonPercent = "Modulo" +PythonColon = "Colon" +PythonSemicon = "Semicolon" +PythonExclamationMark = "Exclamation mark" +PythonLessThan = "Less than" +PythonGreaterThan = "Greater than" +PythonQuestionMark = "Question mark" Python1J = "Imaginary i" PythonLF = "Line feed" PythonTab = "Tabulation" diff --git a/apps/code/catalog.es.i18n b/apps/code/catalog.es.i18n index 883b47cf481..62d5bf2c991 100644 --- a/apps/code/catalog.es.i18n +++ b/apps/code/catalog.es.i18n @@ -1,5 +1,11 @@ PythonPound = "Comment" PythonPercent = "Modulo" +PythonColon = "Colon" +PythonSemicon = "Semicolon" +PythonExclamationMark = "Exclamation mark" +PythonLessThan = "Less than" +PythonGreaterThan = "Greater than" +PythonQuestionMark = "Question mark" Python1J = "Imaginary i" PythonLF = "Line feed" PythonTab = "Tabulation" diff --git a/apps/code/catalog.fr.i18n b/apps/code/catalog.fr.i18n index 99377015773..3185c5ce5a8 100644 --- a/apps/code/catalog.fr.i18n +++ b/apps/code/catalog.fr.i18n @@ -1,5 +1,11 @@ PythonPound = "Commentaire" PythonPercent = "Modulo" +PythonColon = "Deux-points" +PythonSemicon = "Point-virgule" +PythonExclamationMark = "Point d'exclamation" +PythonLessThan = "Inférieur à" +PythonGreaterThan = "Supérieur à" +PythonQuestionMark = "Point d'interrogation" Python1J = "i complexe" PythonLF = "Saut à la ligne" PythonTab = "Tabulation" diff --git a/apps/code/catalog.hu.i18n b/apps/code/catalog.hu.i18n index 6242e4dc35a..7dd162659e9 100644 --- a/apps/code/catalog.hu.i18n +++ b/apps/code/catalog.hu.i18n @@ -1,5 +1,11 @@ PythonPound = "Megjegyzés" PythonPercent = "Modulo" +PythonColon = "Kettőspont" +PythonSemicon = "Pontosvessző" +PythonExclamationMark = "Felkiáltójel" +PythonLessThan = "Kisebb mint" +PythonGreaterThan = "Nagyobb mint" +PythonQuestionMark = "Kérdőjel" Python1J = "Képzeletbeli i" PythonLF = "Enter" PythonTab = "Táblázat" diff --git a/apps/code/catalog.it.i18n b/apps/code/catalog.it.i18n index d8a24f355b9..cb17c6bb21b 100644 --- a/apps/code/catalog.it.i18n +++ b/apps/code/catalog.it.i18n @@ -1,5 +1,11 @@ PythonPound = "Commento" PythonPercent = "Modulo" +PythonColon = "Due punti" +PythonSemicon = "Punto e virgola" +PythonExclamationMark = "Punto esclamativo" +PythonLessThan = "Minore di" +PythonGreaterThan = "Maggiore di" +PythonQuestionMark = "Punto interrogativo" Python1J = "Unità immaginaria" PythonLF = "Nuova riga" PythonTab = "Tabulazione" diff --git a/apps/code/catalog.nl.i18n b/apps/code/catalog.nl.i18n index 876073d95b9..4ba8d9906c5 100644 --- a/apps/code/catalog.nl.i18n +++ b/apps/code/catalog.nl.i18n @@ -1,5 +1,11 @@ PythonPound = "Opmerkingen" PythonPercent = "Modulo" +PythonColon = "Dubbele punt" +PythonSemicon = "Puntkomma" +PythonExclamationMark = "Uitroepteken" +PythonLessThan = "Kleiner dan" +PythonGreaterThan = "Groter dan" +PythonQuestionMark = "Vraagteken" Python1J = "Imaginaire i" PythonLF = "Nieuwe regel" PythonTab = "Tabulatie" diff --git a/apps/code/catalog.pt.i18n b/apps/code/catalog.pt.i18n index 155aa785f56..bc740acdf7f 100644 --- a/apps/code/catalog.pt.i18n +++ b/apps/code/catalog.pt.i18n @@ -1,5 +1,11 @@ PythonPound = "Comentário" PythonPercent = "Módulo" +PythonColon = "Dois pontos" +PythonSemicon = "Ponto e vírgula" +PythonExclamationMark = "Ponto de exclamação" +PythonLessThan = "Menor que" +PythonGreaterThan = "Maior que" +PythonQuestionMark = "Ponto de interrogação" Python1J = "i Complexo" PythonLF = "Nova linha" PythonTab = "Tabulação" diff --git a/apps/code/catalog.universal.i18n b/apps/code/catalog.universal.i18n index ca6e19c4576..09d292f7c25 100644 --- a/apps/code/catalog.universal.i18n +++ b/apps/code/catalog.universal.i18n @@ -1,6 +1,12 @@ PythonCommandAmpersand = "&" PythonCommandLF = "\\n" PythonCommandPercent = "%" +PythonCommandColon = ":" +PythonCommandSemicon = ";" +PythonCommandExclamationMark = "!" +PythonCommandLessThan = "<" +PythonCommandGreaterThan = ">" +PythonCommandQuestionMark = "?" PythonCommandPound = "#" PythonCommandSingleQuote = "'x'" PythonCommandSymbolExp = "^" diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp index 1f75378d332..f8a74902223 100644 --- a/apps/code/python_toolbox.cpp +++ b/apps/code/python_toolbox.cpp @@ -503,6 +503,15 @@ const ToolboxMessageTree modulesChildren[] = { const ToolboxMessageTree catalogChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPound, I18n::Message::PythonPound, false), + #ifdef _FXCG + // There is no question mark button on the fx-CG calculators + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColon, I18n::Message::PythonColon, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandSemicon, I18n::Message::PythonSemicon, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandExclamationMark, I18n::Message::PythonExclamationMark, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLessThan, I18n::Message::PythonLessThan, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandGreaterThan, I18n::Message::PythonGreaterThan, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandQuestionMark, I18n::Message::PythonQuestionMark, false), + #endif ToolboxMessageTree::Leaf(I18n::Message::PythonCommandPercent, I18n::Message::PythonPercent, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommand1J, I18n::Message::Python1J, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandLF, I18n::Message::PythonLF, false), diff --git a/apps/graph/graph/graph_view.h b/apps/graph/graph/graph_view.h index ded212f6db3..87688114037 100644 --- a/apps/graph/graph/graph_view.h +++ b/apps/graph/graph/graph_view.h @@ -18,7 +18,13 @@ class GraphView : public Shared::FunctionGraphView { * 10.0938275501223 which are hopefully rare enough. * TODO: The drawCurve algorithm should use the derivative function to know * how fast the function moves... */ + #ifndef _FXCG static constexpr float k_graphStepDenominator = 10.0938275501223f; + #else + // This value rounded down has to be a factor of the horizontal resolution / 2 + // On the Casio calculator the resolution is 396 pixels, so 11 is close but works + static constexpr float k_graphStepDenominator = 11.0938275501223f; + #endif GraphView(Shared::InteractiveCurveViewRange * graphRange, Shared::CurveViewCursor * cursor, Shared::BannerView * bannerView, Shared::CursorView * cursorView); diff --git a/apps/home/controller.cpp b/apps/home/controller.cpp index da3a147d43d..1936b47eff7 100644 --- a/apps/home/controller.cpp +++ b/apps/home/controller.cpp @@ -276,7 +276,7 @@ void Controller::tableViewDidChangeSelection(SelectableTableView * t, int previo * (so the previous one is always visible). */ int appIndex = (t->selectedColumn()+t->selectedRow()*k_numberOfColumns)+1; if (appIndex >= this->numberOfIcons()+1) { - t->selectCellAtLocation((this->numberOfIcons()%3)-1, (this->numberOfIcons() / k_numberOfColumns)); + t->selectCellAtLocation((this->numberOfIcons()%k_numberOfColumns)-1, (this->numberOfIcons() / k_numberOfColumns)); } } diff --git a/apps/home/controller.h b/apps/home/controller.h index 3301fac78fb..a330a75641c 100644 --- a/apps/home/controller.h +++ b/apps/home/controller.h @@ -47,10 +47,19 @@ class Controller : public ViewController, public SimpleTableViewDataSource, publ static constexpr KDCoordinate k_sideMargin = 4; static constexpr KDCoordinate k_bottomMargin = 14; static constexpr KDCoordinate k_indicatorMargin = 61; + + #ifndef _FXCG static constexpr int k_numberOfColumns = 3; - static constexpr int k_maxNumberOfCells = 16; static constexpr int k_cellHeight = 104; static constexpr int k_cellWidth = 104; + #else + // A different screen resolution so different dimensions + static constexpr int k_numberOfColumns = 4; + static constexpr int k_cellHeight = 96; + static constexpr int k_cellWidth = 97; + #endif + + static constexpr int k_maxNumberOfCells = 16; ContentView m_view; AppCell m_cells[k_maxNumberOfCells]; App * m_app; diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index 30af1e1bd32..1d4900c9785 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -854,6 +854,10 @@ const ToolboxMessageTree Physics[] = { const ToolboxMessageTree menu[] = { + #ifdef _FXCG + // There is no factorial button on the fx-CG calculators + ToolboxMessageTree::Leaf(I18n::Message::FactorialCommandWithArg, I18n::Message::Factorial, false, I18n::Message::FactorialCommand), + #endif ToolboxMessageTree::Leaf(I18n::Message::AbsCommandWithArg, I18n::Message::AbsoluteValue), ToolboxMessageTree::Leaf(I18n::Message::RootCommandWithArg, I18n::Message::NthRoot), ToolboxMessageTree::Leaf(I18n::Message::LogCommandWithArg, I18n::Message::BasedLogarithm), diff --git a/apps/probability/app.h b/apps/probability/app.h index d93905c4690..2e8e3fddfd4 100644 --- a/apps/probability/app.h +++ b/apps/probability/app.h @@ -57,7 +57,7 @@ class App : public Shared::TextFieldDelegateApp { void deleteDistributionAndCalculation(); void initializeDistributionAndCalculation(); -#if __EMSCRIPTEN__ +#if (defined __EMSCRIPTEN__) || (defined _FXCG) constexpr static int k_distributionAlignments[] = {alignof(BinomialDistribution),alignof(ExponentialDistribution), alignof(NormalDistribution), alignof(PoissonDistribution), alignof(UniformDistribution), 0}; constexpr static size_t k_distributionAlignment = max(k_distributionAlignments); constexpr static int k_calculationAlignments[] = {alignof(LeftIntegralCalculation),alignof(FiniteIntegralCalculation), alignof(RightIntegralCalculation), 0}; diff --git a/apps/settings/sub_menu/about_controller.cpp b/apps/settings/sub_menu/about_controller.cpp index a022c48f0e4..dcae3211a61 100644 --- a/apps/settings/sub_menu/about_controller.cpp +++ b/apps/settings/sub_menu/about_controller.cpp @@ -1,5 +1,6 @@ #include "about_controller.h" #include "../../../python/src/py/mpconfig.h" +#include "poincare/division.h" #include #include #include diff --git a/apps/settings/sub_menu/datetime_controller.cpp b/apps/settings/sub_menu/datetime_controller.cpp index 1f9e801b922..35fb8c99455 100644 --- a/apps/settings/sub_menu/datetime_controller.cpp +++ b/apps/settings/sub_menu/datetime_controller.cpp @@ -30,7 +30,10 @@ bool DateTimeController::handleEvent(Ion::Events::Event event) { if (selectedRow() == 0) { clockEnabled = !clockEnabled; if (clockEnabled) { + #ifndef _FXCG + // This doesn't apply on Casio calculators Container::activeApp()->displayWarning(I18n::Message::RTCWarning1, I18n::Message::RTCWarning2); + #endif } Ion::RTC::setMode(clockEnabled ? Ion::RTC::Mode::HSE : Ion::RTC::Mode::Disabled); } diff --git a/apps/shared.hu.i18n b/apps/shared.hu.i18n index a916a2e7629..91e45f3d154 100644 --- a/apps/shared.hu.i18n +++ b/apps/shared.hu.i18n @@ -121,3 +121,4 @@ CatalyticActivityDimension = "Katalitikus aktivitás" SurfaceDimension = "Felület" VolumeDimension = "Hangerő" SpeedDimension = "Sebesség" +Factorial = "Faktorál" diff --git a/apps/shared.it.i18n b/apps/shared.it.i18n index 0e078c3011f..d1932fbd34b 100644 --- a/apps/shared.it.i18n +++ b/apps/shared.it.i18n @@ -121,3 +121,4 @@ CatalyticActivityDimension = "Attività catalitica" SurfaceDimension = "Superficie" VolumeDimension = "Volume" SpeedDimension = "Velocità" +Factorial = "Fattoriale" diff --git a/apps/shared.nl.i18n b/apps/shared.nl.i18n index d8a4b076f31..e63e98605c5 100644 --- a/apps/shared.nl.i18n +++ b/apps/shared.nl.i18n @@ -121,3 +121,4 @@ CatalyticActivityDimension = "Katalytische activiteit" SurfaceDimension = "Oppervlak" VolumeDimension = "Volume" SpeedDimension = "Snelheid" +Factorial = "Faculteit" diff --git a/apps/shared.universal.i18n b/apps/shared.universal.i18n index cad61ea9b97..f38ad608540 100644 --- a/apps/shared.universal.i18n +++ b/apps/shared.universal.i18n @@ -125,6 +125,8 @@ DotCommandWithArg = "dot(u,v)" E = "e" Equal = "=" FactorCommandWithArg = "factor(n)" +FactorialCommand = "!" +FactorialCommandWithArg = "n!" FccId = "FCC ID" FloorCommandWithArg = "floor(x)" FracCommandWithArg = "frac(x)" diff --git a/apps/shared/continuous_function.cpp b/apps/shared/continuous_function.cpp index e127feed520..39c705ecd08 100644 --- a/apps/shared/continuous_function.cpp +++ b/apps/shared/continuous_function.cpp @@ -270,7 +270,7 @@ void ContinuousFunction::rangeForDisplay(float * xMin, float * xMax, float * yMi } if (!basedOnCostlyAlgorithms(context)) { - Zoom::ValueAtAbscissa evaluation = [](float x, Context * context, const void * auxiliary) { + Zoom::ValueAtAbscissa evaluation = [](float x, Context * context, const void * auxiliary) -> float { /* When evaluating sin(x)/x close to zero using the standard sine function, * one can detect small variations, while the cardinal sine is supposed to be * locally monotonous. To smooth our such variations, we round the result of diff --git a/apps/shared/continuous_function_cache.cpp b/apps/shared/continuous_function_cache.cpp index 00a8cd687d3..5ff498052b8 100644 --- a/apps/shared/continuous_function_cache.cpp +++ b/apps/shared/continuous_function_cache.cpp @@ -65,7 +65,11 @@ void ContinuousFunctionCache::ComputeNonCartesianSteps(float * tStep, float * tC const int numberOfWholeSteps = static_cast(Graph::GraphView::k_graphStepDenominator); static_assert(numberOfCacheablePoints % numberOfWholeSteps == 0, "numberOfCacheablePoints should be a multiple of numberOfWholeSteps for optimal caching"); const int multiple = numberOfCacheablePoints / numberOfWholeSteps; + // Ignore this on Casio calculators for now, as the screen resolution breaks this + // TODO: fix this. if it's possible + #ifndef _FXCG static_assert(multiple && !(multiple & (multiple - 1)), "multiple should be a power of 2 for optimal caching"); + #endif /* Define cacheStep such that every whole graph steps are equally divided * For instance, with : * graphStepDenominator = 10.1 diff --git a/apps/shared/store_controller.h b/apps/shared/store_controller.h index 1083f8201f5..d0eebb316cb 100644 --- a/apps/shared/store_controller.h +++ b/apps/shared/store_controller.h @@ -49,7 +49,12 @@ class StoreController : public EditableCellTableViewController, public ButtonRow static constexpr KDCoordinate k_cellWidth = Poincare::PrintFloat::glyphLengthForFloatWithPrecision(Poincare::Preferences::LargeNumberOfSignificantDigits) * 7 + 2*Metric::CellMargin + Metric::TableSeparatorThickness; // KDFont::SmallFont->glyphSize().width() = 7 constexpr static int k_maxNumberOfEditableCells = (Ion::Display::Width/k_cellWidth+2) * ((Ion::Display::Height - Metric::TitleBarHeight - Metric::TabHeight)/k_cellHeight+2); + #ifndef _FXCG constexpr static int k_numberOfTitleCells = 4; + #else + // This is different here due to the changed screen resolution + constexpr static int k_numberOfTitleCells = 5; + #endif static constexpr int k_titleCellType = 0; static constexpr int k_editableCellType = 1; diff --git a/apps/solver/solutions_controller.h b/apps/solver/solutions_controller.h index 4fac929a191..2bf90d04bf9 100644 --- a/apps/solver/solutions_controller.h +++ b/apps/solver/solutions_controller.h @@ -87,7 +87,7 @@ class SolutionsController : public ViewController, public AlternateEmptyViewDefa // Number of cells constexpr static int k_maxNumberOfVisibleCells = (Ion::Display::Height - 3 * Metric::TitleBarHeight) / k_defaultCellHeight + 1; // When displaying approximate solutions for cos(x) = 0 between 0 and 1800 and scrolling down - static_assert(k_maxNumberOfVisibleCells == 10, "k_maxNumberOfVisibleCells has changed"); //This assert is just for information purposes + // static_assert(k_maxNumberOfVisibleCells == 10, "k_maxNumberOfVisibleCells has changed"); //This assert is just for information purposes static_assert(k_maxNumberOfVisibleCells <= EquationStore::k_maxNumberOfSolutions + Poincare::Expression::k_maxNumberOfVariables, "We can reduce the number of cells in Solver:SolutionsController."); constexpr static int k_maxNumberOfSymbols = EquationStore::k_maxNumberOfSolutions + Poincare::Expression::k_maxNumberOfVariables; constexpr static int k_numberOfSymbolCells = k_maxNumberOfVisibleCells < k_maxNumberOfSymbols ? k_maxNumberOfVisibleCells : k_maxNumberOfSymbols; diff --git a/apps/toolbox.de.i18n b/apps/toolbox.de.i18n index 02cc172e35c..2582f6d1bf4 100644 --- a/apps/toolbox.de.i18n +++ b/apps/toolbox.de.i18n @@ -511,3 +511,4 @@ MagneticFluxQuantumTag = "Magnetisches Fluss-Quantum" ConductanceQuantumTag = "Leitwertquantum" CirculationQuantumTag = "Auflage-Quantum" MatricesAndVectors = "Matrizen und Vektoren" +Factorial = "Fakultät" diff --git a/apps/toolbox.en.i18n b/apps/toolbox.en.i18n index fd5aaafc814..e6781e868c8 100644 --- a/apps/toolbox.en.i18n +++ b/apps/toolbox.en.i18n @@ -511,3 +511,4 @@ HartreeConstantTag = "Hartree Constant" MagneticFluxQuantumTag = "Magnetic Flux Quantum" ConductanceQuantumTag = "Conductance Quantum" CirculationQuantumTag = "Circulation Quantum" +Factorial = "Factorial" \ No newline at end of file diff --git a/apps/toolbox.es.i18n b/apps/toolbox.es.i18n index 841d37d7e7c..ddb8dcf1c55 100644 --- a/apps/toolbox.es.i18n +++ b/apps/toolbox.es.i18n @@ -511,3 +511,4 @@ MagneticFluxQuantumTag = "Flujo Magnético Cuántico" ConductanceQuantumTag = "Conductancia Quantum" CirculationQuantumTag = "Circulación Quantum" MatricesAndVectors = "Matrices y vectores" +Factorial = "Factorial" diff --git a/apps/toolbox.fr.i18n b/apps/toolbox.fr.i18n index 283f2bc28ef..ac0f40b36d3 100644 --- a/apps/toolbox.fr.i18n +++ b/apps/toolbox.fr.i18n @@ -515,3 +515,4 @@ MagneticFluxQuantumTag = "Quantum de Flux Magnétique" ConductanceQuantumTag = "Quantum de Conductance" CirculationQuantumTag = "Quantum de Circulation" MatricesAndVectors = "Matrices et vecteurs" +Factorial = "Factorielle" diff --git a/apps/toolbox.pt.i18n b/apps/toolbox.pt.i18n index 219680ae90e..8ba7d55f8cd 100644 --- a/apps/toolbox.pt.i18n +++ b/apps/toolbox.pt.i18n @@ -511,3 +511,4 @@ MagneticFluxQuantumTag = "Fluxo Magnético Quântico" ConductanceQuantumTag = "Quantum de Conduta" CirculationQuantumTag = "Quantum de Circulação" MatricesAndVectors = "Matrizes e vetores" +Factorial = "Fatorial" diff --git a/build/platform.simulator.fxcg.mak b/build/platform.simulator.fxcg.mak new file mode 100644 index 00000000000..fc30c12e842 --- /dev/null +++ b/build/platform.simulator.fxcg.mak @@ -0,0 +1,11 @@ +TOOLCHAIN = sh-elf-gcc +EXE = elf + +EPSILON_TELEMETRY ?= 0 + +HANDY_TARGETS_EXTENSIONS = g3a bin + +USE_LIBA = 0 +POINCARE_TREE_LOG = 0 + +SFLAGS := $(filter-out -fPIE, $(SFLAGS)) diff --git a/build/targets.simulator.fxcg.mak b/build/targets.simulator.fxcg.mak new file mode 100644 index 00000000000..ec26dcc8174 --- /dev/null +++ b/build/targets.simulator.fxcg.mak @@ -0,0 +1,5 @@ +$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf + $(OBJCOPY) -O binary -R .bss -R .gint_bss $< $@ + +$(BUILD_DIR)/%.g3a: $(BUILD_DIR)/%.bin ion/src/simulator/fxcg/assets/icon-uns.png ion/src/simulator/fxcg/assets/icon-sel.png + $(FXGXA) --g3a --icon-uns=ion/src/simulator/fxcg/assets/icon-uns.png --icon-sel=ion/src/simulator/fxcg/assets/icon-sel.png -n Upsilon $< -o $@ diff --git a/build/toolchain.sh-elf-gcc.mak b/build/toolchain.sh-elf-gcc.mak new file mode 100644 index 00000000000..54290ffcec9 --- /dev/null +++ b/build/toolchain.sh-elf-gcc.mak @@ -0,0 +1,10 @@ +CC = sh-elf-gcc +CXX = sh-elf-g++ +LD = sh-elf-g++ +GDB = gdb +OBJCOPY = sh-elf-objcopy +SIZE = sh-elf-size +AS = sh-elf-as +FXGXA = fxgxa + +SFLAGS += -D_FXCG -D_BIG_ENDIAN diff --git a/escher/src/icon_view.cpp b/escher/src/icon_view.cpp index 7a5453d2a4c..1c1db37fecc 100644 --- a/escher/src/icon_view.cpp +++ b/escher/src/icon_view.cpp @@ -1,6 +1,7 @@ #include extern "C" { #include +#include } #include #include @@ -43,6 +44,13 @@ void IconView::drawRect(KDContext * ctx, KDRect rect) const { iconBufferSize * sizeof(KDColor) ); + // If we are on a big-endian CPU, we need to swap the bytes + #if _BIG_ENDIAN + for (uint32_t i = 0; i < iconBufferSize; i++) { + pixelBuffer[i] = KDColor::RGB16(__builtin_bswap16(pixelBuffer[i])); + } + #endif + //We push the first 6 lines of the image so that they are truncated on the sides ctx->fillRectWithPixels(KDRect(6, 0, m_frame.width()-12, 1),pixelBuffer+6, nullptr); ctx->fillRectWithPixels(KDRect(4, 1, m_frame.width()-8, 1),pixelBuffer+4+55, nullptr); diff --git a/escher/src/image_view.cpp b/escher/src/image_view.cpp index 7cb4ee39e1c..5062ef3f7a9 100644 --- a/escher/src/image_view.cpp +++ b/escher/src/image_view.cpp @@ -1,6 +1,7 @@ #include extern "C" { #include +#include } #include @@ -50,6 +51,13 @@ void ImageView::drawRect(KDContext * ctx, KDRect rect) const { pixelBufferSize * sizeof(KDColor) ); + // If we are on a big-endian CPU, we need to swap the bytes + #if _BIG_ENDIAN + for (uint32_t i = 0; i < pixelBufferSize; i++) { + pixelBuffer[i] = KDColor::RGB16(__builtin_bswap16(pixelBuffer[i])); + } + #endif + ctx->fillRectWithPixels(bounds(), pixelBuffer, nullptr); } diff --git a/ion/include/ion/display.h b/ion/include/ion/display.h index 1b7f32508c5..0abd90c1673 100644 --- a/ion/include/ion/display.h +++ b/ion/include/ion/display.h @@ -23,8 +23,15 @@ void pullRect(KDRect r, KDColor * pixels); bool waitForVBlank(); +#ifndef _FXCG constexpr int Width = 320; constexpr int Height = 240; +#else +constexpr int Width = 396; +constexpr int Height = 224; +#endif + +// TODO: Adjust this on the Casio calculator constexpr int WidthInTenthOfMillimeter = 576; constexpr int HeightInTenthOfMillimeter = 432; diff --git a/ion/include/ion/internal_storage.h b/ion/include/ion/internal_storage.h index 257d243ce3c..fcad00c90d8 100644 --- a/ion/include/ion/internal_storage.h +++ b/ion/include/ion/internal_storage.h @@ -195,7 +195,7 @@ class StorageDelegate { class StorageHelper { public: static uint16_t unalignedShort(char * address) { -#if __EMSCRIPTEN__ +#if (defined __EMSCRIPTEN__) || (defined _FXCG) uint8_t f1 = *(address); uint8_t f2 = *(address+1); uint16_t f = (uint16_t)f1 + (((uint16_t)f2)<<8); @@ -205,7 +205,7 @@ class StorageHelper { #endif } static void writeUnalignedShort(uint16_t value, char * address) { -#if __EMSCRIPTEN__ +#if (defined __EMSCRIPTEN__) || (defined _FXCG) *((uint8_t *)address) = (uint8_t)(value & ((1 << 8) - 1)); *((uint8_t *)address+1) = (uint8_t)(value >> 8); #else diff --git a/ion/include/ion/keyboard.h b/ion/include/ion/keyboard.h index ba056ffd2a5..7d448991c7e 100644 --- a/ion/include/ion/keyboard.h +++ b/ion/include/ion/keyboard.h @@ -26,6 +26,12 @@ constexpr Key ValidKeys[] = { constexpr int NumberOfKeys = 54; constexpr int NumberOfValidKeys = 46; +enum class ModSimState : uint8_t { + None, + ForceOn, + ForceOff, +}; + class State { public: constexpr State(uint64_t s = 0) : @@ -50,8 +56,25 @@ class State { void clearKey(Key k) { m_bitField &= ~((uint64_t)1 << (uint8_t)k); } + void setSimulatedShift(ModSimState s) { + m_simulateShiftState = s; + } + ModSimState simulatedShift() const { + return m_simulateShiftState; + } + void setSimulatedAlpha(ModSimState s) { + m_simulateAlphaState = s; + } + ModSimState simulatedAlpha() const { + return m_simulateAlphaState; + } private: uint64_t m_bitField; + + // Simulated key states + // These override the real key states and are used to map keys to keys under modifiers + ModSimState m_simulateShiftState = ModSimState::None; + ModSimState m_simulateAlphaState = ModSimState::None; }; State scan(); diff --git a/ion/src/shared/events_keyboard.cpp b/ion/src/shared/events_keyboard.cpp index 73038b619cc..6d281c482a6 100644 --- a/ion/src/shared/events_keyboard.cpp +++ b/ion/src/shared/events_keyboard.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -84,6 +85,16 @@ static inline Event innerGetEvent(int * timeout) { Keyboard::Key key = (Keyboard::Key)(63-__builtin_clzll(keysSeenTransitioningFromUpToDown)); bool shift = isShiftActive() || state.keyDown(Keyboard::Key::Shift); bool alpha = isAlphaActive() || state.keyDown(Keyboard::Key::Alpha); + + // Allow the detected states to be overriden by the simulated states + // This is used for key mapping + if (state.simulatedShift() != Keyboard::ModSimState::None) { + shift = state.simulatedShift() == Keyboard::ModSimState::ForceOn; + } + if (state.simulatedAlpha() != Keyboard::ModSimState::None) { + alpha = state.simulatedAlpha() == Keyboard::ModSimState::ForceOn; + } + bool lock = isLockActive(); if ( key == Keyboard::Key::Left diff --git a/ion/src/simulator/external/config.fxcg.mak b/ion/src/simulator/external/config.fxcg.mak new file mode 100644 index 00000000000..5c9e873ab47 --- /dev/null +++ b/ion/src/simulator/external/config.fxcg.mak @@ -0,0 +1,2 @@ +undefine sdl_src +undefine ion_simulator_sdl_src diff --git a/ion/src/simulator/fxcg/Makefile b/ion/src/simulator/fxcg/Makefile new file mode 100644 index 00000000000..02a9ed71776 --- /dev/null +++ b/ion/src/simulator/fxcg/Makefile @@ -0,0 +1,66 @@ + +ion_src += $(addprefix ion/src/simulator/fxcg/, \ + main.cpp \ + clipboard.cpp \ + display.cpp \ + framebuffer.cpp \ + telemetry_init.cpp \ + keyboard.cpp \ + events_keyboard.cpp \ + events.cpp \ + timing.cpp \ + console.cpp \ + backlight.cpp \ + power.cpp \ + menuHandler.cpp \ +) + +liba_src += $(addprefix liba/src/, \ + strlcat.c \ + strlcpy.c \ +) + +ion_src += ion/src/shared/collect_registers.cpp + +sdl_simu_needs_to_be_removed += $(addprefix ion/src/simulator/shared/, \ + main.cpp \ + clipboard.cpp \ + display.cpp \ + framebuffer.cpp \ + keyboard.cpp \ + events_keyboard.cpp \ + events_platform.cpp \ + events.cpp \ + layout.cpp \ + actions.cpp \ + window.cpp \ + timing.cpp \ + console.cpp \ +) + +sdl_simu_needs_to_be_removed += $(addprefix ion/src/shared/dummy/, \ + backlight.cpp \ + power.cpp \ +) + +#sdl_simu_needs_to_be_removed += $(addprefix ion/src/simulator/shared/dummy/, \ +# display.cpp \ +# led.cpp \ +# usb.cpp \ +# battery.cpp \ +# store_script.cpp \ +#) + +# Remove the dummy diaplay (re-implemented) and the SDL simulator stuff. +ion_src := $(filter-out $(sdl_simu_needs_to_be_removed),$(ion_src)) + +SFLAGS := $(filter-out -Iion/src/simulator/external/sdl/include,$(SFLAGS)) + +SFLAGS += -DFXCG50 -DTARGET_FXCG50 -m4-nofpu -mb -ffreestanding -nostdlib -Wa,--dsp -fstrict-volatile-bitfields -g -Os +LDFLAGS += -nostdlib -Wl,--no-warn-rwx-segments -lgint-cg -lc -lgint-cg -lc -lgcc -lopenlibm -lstdc++ -lgcc + +ifdef FASTLOAD + LDFLAGS += -T fxcg50_fastload.ld +else + LDFLAGS += -T fxcg50.ld +endif diff --git a/ion/src/simulator/fxcg/assets/icon-sel.png b/ion/src/simulator/fxcg/assets/icon-sel.png new file mode 100644 index 0000000000000000000000000000000000000000..a016c36b39d406e9d21390432635d2daceff1552 GIT binary patch literal 3588 zcmV+f4*T(mP) z62R|084ld5RI=Bjg;0K7Si<6>@l=#1-&?3fz<9@um_qclp z`0Hh+njLXK)hr{OObFTBiV%855S{473`Qkp>a(Jlg6H_UhmWs!F`ngp?$6PqZd&xywjx*+i**JYRAI2RrE^UR2mNzV~Sh=pPs%Wcd` zhDtn1992|}^8Hzt70z3n)pC_J@5x^n&TGp{T&FpNBo?p;5dvgXv4Juy#Aww>F_EVI zgol67@r&e=$+ZDSj(Jp|LUR1zfAG6ovoJC4CWR9~@Wr-2hJny7(5Tt=_pxm^PJqBO zaHX~Ul{zr}NqViNMUQ~KZQ$a%rOA81@v!VI{OH$nv+5knoDlvN0yHvo`VAiQ}r7v8OmpRnJ#nf8FkJV!HvC zWcRqI-QD%-^{ZE3*H@9X*4{9{)kR=(5x8wos%QWS+ls{iMga(ow$3_K$3K~!A-i)Wv*B1n$p3pz9;Lz#3*oS40v)Bh~CuJUcL?7SaiS` zc`IGT*P~1Wr1wD^K&X-bj_&6TMCz0aLV9ns0R*;~gj~<cDMA?q)xs`DMyRZCHL7#^8zy>7(VS9!p381tC*nw{}p!m~3 zwxz%pZs@fJ@ca}IPcD*5`3fThTS>JuVdbQ!HX|(v&t)K=Qz_C=s@DL#c3hP*6bAv@ z0Uz9?+p46uU%@p%&aru5D~VmST28j(MH5!a_)2nMkUe{PFDe8b63dB<_@@W1VQCF~ zBWLs;p`=LC65yQ>Lc5#O021~%8ZRx5*(S-+%p|Gtx<9jyHR zDmt^%ICJ&_aMEC>tY6wg3Ujklu+eXD=lld(d-sQ3lmcQ1on+_w6zoz1`|C%5<__3p z%V5i3{NNGnzSqFP+fzNsM9(J1ULz^!cJ>yAhxY-UwH*}uEOBQIdq?)6K7T9K5sJg9#XJ$~yR+Qo3Xu4Q05uU`p)(wOQaB0}L1jw%JC8 zTWfJ__%6Qq*-rx2?TmmgeCx$h|NqTrKj_Z{Ai{SpzlzsyHny)qWE`VXhUbjjx1%gC z&iC*FU?cKJnFdRLqDpB>py6OK6SGZ->-%>x_pj^!b5cSTqwB+o9o()?v(?nNJv9ky zJ5EL{dL%8+)~JGj(>~Dvhz*Hnq!GL=ENiQ6%-;AL)>hk0&pm*)kF#~fB(fD_IeJ0B z*hdM|PID_e$xa8i|M?o)O$^dcT6A?zYHl@|? z-^JYY>$%@g&&>gc#5cIU8k6?>>j6xdnXb>p#To+(OrRM9zdn zKtz0YM6Pvnei`3>{x7(<(yFcxS88)Q%_6T|woK2=W)y^qr-()#th*OgHfHa5}W#La+V*QoKwnAq zd+m*IJPL+9_^)BPQNV!W4y6x@KP<1^Px;7azLI|4y>CCpj-NvmRU3To!IhVkjdYru z;kElIyOI$+di3p;2HO}Zma+j!*=(=9UKtqNh4GW;5!Y(fmJ*d^xj45lN``^K!EN)} zg$f?mFn;np1_pOk7U;EsL9})aXS{e2Eu^4F$BrNx8Uo_lws`HLGIsndb|oW~1-ld1 zuv!~J47v92S^|x(XWrp|EF;YL6n!+lU z#r@-G4Jqi|`w%Y<;*C}EVqQ79{`@s-!KN$wG`Do*DWqvb0ou3>JOw1Ax7DIA5;BNs z?1pC}(>zg@tI4P26?OD!`nS8WAQjx-tWStVFO9I!;-UXE@ZLxh+3CuLk37j+A(|wa zrZAfBJ!*uhjr^JN9fu*;ks6Y}(B`?CN{Ul(p#8l$fPGS|cH1=3)hERIJWQ6GNw-CL zn)xH1a6*tcT{&eo13ic&vgFu={78S(j)R_G6)-$)C?VySvRtY(ZFI_T%4+Byz?9*N zWgq+F(_2k?bEd>hWR}27@e{MyQjmGbR!G54N@!bxFfc~X&(pf;Js6Xp`Yk=q!Nf5w zGyqSRX3RBYm5EH{XzI5+Mp|TnKhY`p>AVzn!+eng@X;r!sYV~60Jf+>9>eLi6^c{8 z3*Sy9WI+Rj8lLXZgwc|A>tab!D3SiHxDTf+X8&y@DIsi2(Cs);lI00{jI9Hxd-k#( zNC_)UWNyBMh$acUzHbEG`@W9eDiY!&OB%xKJpWvjXU_=|D@jraBcZYY(6b~Z39iZU zb$5=2ai1N6et$i0CV@d_u7^}xX-=xvJ;&mIv=*4mfhT`^od@L4o+f2I zbp{(`HwBwYkOwvcHno7{zRJ!hpdbdal7vie@D5ZL*qxjOY9MJiXE(u5jHU2FiORWx zE(w5U;A;XjXL~)zYZ=4bNSrKVed5Q04ErDs2odZ z`jZvT_=XAfT+~1*(W?aT^+c8y>RcKcXds8-Y&4oyTW3d`0lSUtP%;e9TklHold#Gr zB_*&391naTDTY}>$gD3KRdZ(3Ro;?B9^7Oqkq9<0kwKUBrGVkmdRIp3in$kGXQapf z&ed)z9}wos^L%R5qkgIJHBE;n)Pd^76*!-aT$;Y!Pfg=wXLL=X?pc@39&I|X@!NEi1F zm`-0nc%bRZoIWPbmO?d&?8U|Yg!%Au32^BI5M`FLMwk(Sbu3z1Cl!u7Iq-(Py$0=& zRsIV@lXp$UV(TTGiq7i{+3-E1=K_n$PMjJ~fDeoU7f%3BD&RlZzy#XZl#w6+0000< KMNUMnLSTYlXV&ci literal 0 HcmV?d00001 diff --git a/ion/src/simulator/fxcg/assets/icon-uns.png b/ion/src/simulator/fxcg/assets/icon-uns.png new file mode 100644 index 0000000000000000000000000000000000000000..c2f71847222784736677a5fa53f067fc9611d68d GIT binary patch literal 1750 zcmV;{1}XW8P) z62R|084ld5RI=Bjg;0K7Si<6>@l=#1-&?3fz<9@um_qclp z`0Hh+njLXK)hr{OObFTBiV%855S{473`Qkp>a(Jlg6H_UhmWs!F`ngp?$6PqZd&xywjx*+i**JYRAI2RrE^UR2mNzV~Sh=pPs%Wcd` zhDtn1992|}^8Hzt70z3n)pC_J@5x^n&TGp{T&FpNBo?p;5dvgXv4Juy#Aww>F_EVI zgol67@r&e=$+ZDSj(Jp|LUR1zfAG6ovoJC4CWR9~@Wr-2hJny7(5Tt=_pxm^PJqBO zaHX~Ul{zr}NqViNMUQ~KZQ$a%rOA81&OpJhmGjI+AuiKc5Z3xE{%)9(Zk-%SbUM6KAM~Av$7KD2bw!?0- z7W^Ag$WoSrQJnwjIzll8&ZRKIF@IHOEXR^cmi-Z zR~U8$3C9#ToGV!H1aN7_X}rUyXFUi;RU}hsrdVN;sWgI771OgG;~nntg&>(NOs~qs zl_a9EI9m#9A#35zhKO*mC4yI9dIre4lK@_M_oAWKzjOAn?4AG!ynpU0=G?bT3K7BQ`3G_=To9bN zn*#_C&veKi>-hF5kXdy3|v`_z~`DPy4|(t0}!zVCgS{QCI5l>ts0uziF@(Lln?aPXpm}!?$yBCs zfhSZM-kXkf`d27lU;JHP^F(g(JNZyQUO06>4(zu<05A!luWL76e(D&;@9WXv3%!Ym zaQSa{<627Awb$!k;as?U6;GTP#b9rjMiB%dfTQ>u0Eeh>TCC9F2M6Q_8i= zWziSJYj1r5uP>;XhtMTNXiMYT(;^~*+aJSwUrr+$Pc$CzQm$<@u0=o2zVRW>efKjI zH30~1zuAQ`i#@I+@$GLn@b(vf;#N$p>1!!l*5RdGyOP8e6(3Jd;j?dk#PerP;OWQ5 zvh4u^aQ?~yewc9~QG-UZZ4+M3wW|UztN7^i?*Re`1k!8f!XM7MfxRWbjkxxPs!C`- zM4f);cT+1Rp~_e?=-SmrpuV$dz$Kld-;_jdDt#Iv1($s82XYb*< zf?YN6t#<9QZ%a!Px(7yJlBBz%Qrhh;P}15pik)!nk_~Q>&^<5$v!$tKp|)5puu2x= z6FxfJgNz)8#Vi$c?S#5>A6<3z9YIsGt!80c%n~wk7^A~I#(_^9@5ew-8`2R^?p~Gc zbnRlWTH9(Cw%uk$I^w}VPa7tV_ZNPL7P}KU98)m))f9gD^$M=tSVlDDhZ>LU z*gs?4wFfr)zM5VnM+Q1DKK2NnJ9DzKo2oc9ernHQ;0&C@z!^9L=P+;v&SBsToWsBw sI0NS}a0bp{;0&C@z!^9L=WJ2_2erpLmnTxXoB#j-07*qoM6N<$f^eoc-v9sr literal 0 HcmV?d00001 diff --git a/ion/src/simulator/fxcg/backlight.cpp b/ion/src/simulator/fxcg/backlight.cpp new file mode 100644 index 00000000000..18360bc0bfc --- /dev/null +++ b/ion/src/simulator/fxcg/backlight.cpp @@ -0,0 +1,67 @@ +#include + +#include +#include + +// From gint: +/* Interface with the controller */ +static volatile uint16_t *intf = (uint16_t *)0xb4000000; +/* Bit 4 of Port R controls the RS bit of the display driver */ +static volatile uint8_t *PRDR = (uint8_t *)0xa405013c; + +GINLINE static void select(uint16_t reg) +{ + /* Clear RS and write the register number */ + *PRDR &= ~0x10; + synco(); + *intf = reg; + synco(); + + /* Set RS back. We don't do this in read()/write() because the display + driver is optimized for consecutive GRAM access. LCD-transfers will + be faster when executing select() followed by several calls to + write(). (Although most applications should use the DMA instead.) */ + *PRDR |= 0x10; + synco(); +} + +// From Utilities addin: +// START OF POWER MANAGEMENT CODE +#define LCDC *(unsigned int*)(0xB4000000) +int getRawBacklightSubLevel() +{ + // Bdisp_DDRegisterSelect(0x5a1); + select(0x5a1); + return (LCDC & 0xFF) - 6; +} +void setRawBacklightSubLevel(int level) +{ + // Bdisp_DDRegisterSelect(0x5a1); + select(0x5a1); + LCDC = (level & 0xFF) + 6; +} +// END OF POWER MANAGEMENT CODE + +namespace Ion { +namespace Backlight { + +uint8_t brightness() { + return getRawBacklightSubLevel(); +} + +void setBrightness(uint8_t b) { + setRawBacklightSubLevel(b); +} + +void init() { +} + +bool isInitialized() { + return true; +} + +void shutdown() { +} + +} +} diff --git a/ion/src/simulator/fxcg/clipboard.cpp b/ion/src/simulator/fxcg/clipboard.cpp new file mode 100644 index 00000000000..c3ce45627c9 --- /dev/null +++ b/ion/src/simulator/fxcg/clipboard.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + +namespace Ion { +namespace Clipboard { + +uint32_t localClipboardVersion; + +void write(const char * text) { +} + +const char * read() { + return nullptr; +} + +} +} diff --git a/ion/src/simulator/fxcg/console.cpp b/ion/src/simulator/fxcg/console.cpp new file mode 100644 index 00000000000..d8957c6e6ca --- /dev/null +++ b/ion/src/simulator/fxcg/console.cpp @@ -0,0 +1,24 @@ +#include +#include "main.h" +#include +#include + +namespace Ion { +namespace Console { + +char readChar() { + return 0; +} + +void writeChar(char c) { + // fxlibc conflicts with this + #undef putchar + KDIonContext::putchar(c); +} + +bool transmissionDone() { + return true; +} + +} +} diff --git a/ion/src/simulator/fxcg/display.cpp b/ion/src/simulator/fxcg/display.cpp new file mode 100644 index 00000000000..27e896beef9 --- /dev/null +++ b/ion/src/simulator/fxcg/display.cpp @@ -0,0 +1,30 @@ +#include "display.h" +#include "framebuffer.h" +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace Ion { +namespace Simulator { +namespace Display { + +void init() { +} + +void quit() { +} + +void draw() { + dupdate(); +} + +} +} +} diff --git a/ion/src/simulator/fxcg/display.h b/ion/src/simulator/fxcg/display.h new file mode 100644 index 00000000000..ab524fd3c55 --- /dev/null +++ b/ion/src/simulator/fxcg/display.h @@ -0,0 +1,19 @@ +#ifndef ION_SIMULATOR_DISPLAY_H +#define ION_SIMULATOR_DISPLAY_H + +#include + +namespace Ion { +namespace Simulator { +namespace Display { + +void init(); +void quit(); + +void draw(); + +} +} +} + +#endif diff --git a/ion/src/simulator/fxcg/events.cpp b/ion/src/simulator/fxcg/events.cpp new file mode 100644 index 00000000000..9b8d0055751 --- /dev/null +++ b/ion/src/simulator/fxcg/events.cpp @@ -0,0 +1,23 @@ +#include "events.h" +#include + +namespace Ion { +namespace Events { + +void didPressNewKey() { +} + +char * sharedExternalTextBuffer() { + static char buffer[sharedExternalTextBufferSize]; + return buffer; +} + +const char * Event::text() const { + if (*this == ExternalText) { + return const_cast(sharedExternalTextBuffer()); + } + return defaultText(); +} + +} +} diff --git a/ion/src/simulator/fxcg/events.h b/ion/src/simulator/fxcg/events.h new file mode 100644 index 00000000000..b012a43c5e5 --- /dev/null +++ b/ion/src/simulator/fxcg/events.h @@ -0,0 +1,24 @@ +#ifndef ION_SIMULATOR_EVENTS_H +#define ION_SIMULATOR_EVENTS_H + +#include + +namespace Ion { +namespace Simulator { +namespace Events { + +void dumpEventCount(int i); +void logAfter(int numberOfEvents); + +} +} + +namespace Events { + +static constexpr int sharedExternalTextBufferSize = 2; +char * sharedExternalTextBuffer(); + +} +} + +#endif diff --git a/ion/src/simulator/fxcg/events_keyboard.cpp b/ion/src/simulator/fxcg/events_keyboard.cpp new file mode 100644 index 00000000000..615c327d54c --- /dev/null +++ b/ion/src/simulator/fxcg/events_keyboard.cpp @@ -0,0 +1,15 @@ +#include + +namespace Ion { +namespace Events { + + +Event getPlatformEvent() { + Event result = None; + + return result; +} + + +} +} diff --git a/ion/src/simulator/fxcg/framebuffer.cpp b/ion/src/simulator/fxcg/framebuffer.cpp new file mode 100644 index 00000000000..d680467c129 --- /dev/null +++ b/ion/src/simulator/fxcg/framebuffer.cpp @@ -0,0 +1,56 @@ +#include "framebuffer.h" +#include +#include +#include "main.h" + +#include +#include + +// static KDColor sPixels[Ion::Display::Width * Ion::Display::Height]; +static_assert(sizeof(KDColor) == sizeof(uint16_t), "KDColor is not 16 bits"); +static KDColor* sPixels = (KDColor*) gint_vram; +static bool sFrameBufferActive = true; + +namespace Ion { +namespace Display { + +static KDFrameBuffer sFrameBuffer = KDFrameBuffer(sPixels, KDSize(Ion::Display::Width, Ion::Display::Height)); + +void pushRect(KDRect r, const KDColor * pixels) { + if (sFrameBufferActive) { + Simulator::Main::setNeedsRefresh(); + sFrameBuffer.pushRect(r, pixels); + } +} + +void pushRectUniform(KDRect r, KDColor c) { + if (sFrameBufferActive) { + Simulator::Main::setNeedsRefresh(); + sFrameBuffer.pushRectUniform(r, c); + } +} + +void pullRect(KDRect r, KDColor * pixels) { + if (sFrameBufferActive) { + sFrameBuffer.pullRect(r, pixels); + } +} + +} +} + +namespace Ion { +namespace Simulator { +namespace Framebuffer { + +const KDColor * address() { + return sPixels; +} + +void setActive(bool enabled) { + sFrameBufferActive = enabled; +} + +} +} +} \ No newline at end of file diff --git a/ion/src/simulator/fxcg/framebuffer.h b/ion/src/simulator/fxcg/framebuffer.h new file mode 100644 index 00000000000..dba4dbd3278 --- /dev/null +++ b/ion/src/simulator/fxcg/framebuffer.h @@ -0,0 +1,17 @@ +#ifndef ION_SIMULATOR_FRAMEBUFFER_H +#define ION_SIMULATOR_FRAMEBUFFER_H + +#include + +namespace Ion { +namespace Simulator { +namespace Framebuffer { + +const KDColor * address(); +void setActive(bool enabled); + +} +} +} + +#endif \ No newline at end of file diff --git a/ion/src/simulator/fxcg/keyboard.cpp b/ion/src/simulator/fxcg/keyboard.cpp new file mode 100644 index 00000000000..735b72e1f5c --- /dev/null +++ b/ion/src/simulator/fxcg/keyboard.cpp @@ -0,0 +1,262 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "keyboard.h" +#include "layout_keyboard.h" +#include "main.h" +#include "menuHandler.h" + + +using namespace Ion::Keyboard; + +class KeyPair { +public: + constexpr KeyPair(Key key, bool numworksShift, bool numworksAlpha, int gintKey, bool gintShift, bool gintAlpha, bool ignoreShiftAlpha = false) : + m_key(key), + m_numworksShift(numworksShift), + m_numworksAlpha(numworksAlpha), + m_gintKey(gintKey), + m_gintShift(gintShift), + m_gintAlpha(gintAlpha), + m_ignoreShiftAlpha(ignoreShiftAlpha) + {} + Key key() const { return m_key; } + bool numworksShift() const { return m_numworksShift; } + bool numworksAlpha() const { return m_numworksAlpha; } + int gintKey() const { return m_gintKey; } + bool gintShift() const { return m_gintShift; } + bool gintAlpha() const { return m_gintAlpha; } + bool ignoreShiftAlpha() const { return m_ignoreShiftAlpha; } +private: + Key m_key; + bool m_numworksShift; + bool m_numworksAlpha; + int m_gintKey; + bool m_gintShift; + bool m_gintAlpha; + bool m_ignoreShiftAlpha; +}; + +constexpr static KeyPair sKeyPairs[] = { + KeyPair(Key::Down, false, false, KEY_DOWN, false, false, true), + KeyPair(Key::Left, false, false, KEY_LEFT, false, false, true), + KeyPair(Key::Right, false, false, KEY_RIGHT, false, false, true), + KeyPair(Key::Up, false, false, KEY_UP, false, false, true), + KeyPair(Key::Back, false, false, KEY_EXIT, false, false), + KeyPair(Key::Home, false, false, KEY_MENU, false, false), + KeyPair(Key::Shift, false, false, KEY_SHIFT, false, false, true), + KeyPair(Key::Alpha, false, false, KEY_ALPHA, false, false, true), + KeyPair(Key::XNT, false, false, KEY_XOT, false, false), + KeyPair(Key::Var, false, false, KEY_VARS, false, false), + KeyPair(Key::Toolbox, false, false, KEY_OPTN, false, false), + KeyPair(Key::Backspace, false, false, KEY_DEL, false, false), + KeyPair(Key::Exp, false, false, KEY_LN, true, false), + KeyPair(Key::Ln, false, false, KEY_LN, false, false), + KeyPair(Key::Log, false, false, KEY_LOG, false, false), + KeyPair(Key::Imaginary, false, false, KEY_0, true, false), + KeyPair(Key::Comma, false, false, KEY_COMMA, false, false), + KeyPair(Key::Power, false, false, KEY_POWER, false, false), + KeyPair(Key::Sine, false, false, KEY_SIN, false, false), + KeyPair(Key::Cosine, false, false, KEY_COS, false, false), + KeyPair(Key::Tangent, false, false, KEY_TAN, false, false), + KeyPair(Key::Pi, false, false, KEY_EXP, true, false), + KeyPair(Key::Sqrt, false, false, KEY_SQUARE, true, false), + KeyPair(Key::Square, false, false, KEY_SQUARE, false, false), + KeyPair(Key::Seven, false, false, KEY_7, false, false), + KeyPair(Key::Eight, false, false, KEY_8, false, false), + KeyPair(Key::Nine, false, false, KEY_9, false, false), + KeyPair(Key::LeftParenthesis, false, false, KEY_LEFTP, false, false), + KeyPair(Key::RightParenthesis, false, false, KEY_RIGHTP, false, false), + KeyPair(Key::Four, false, false, KEY_4, false, false), + KeyPair(Key::Five, false, false, KEY_5, false, false), + KeyPair(Key::Six, false, false, KEY_6, false, false), + KeyPair(Key::Multiplication, false, false, KEY_MUL, false, false), + KeyPair(Key::Division, false, false, KEY_DIV, false, false), + KeyPair(Key::Division, false, false, KEY_FRAC, false, false), + KeyPair(Key::One, false, false, KEY_1, false, false), + KeyPair(Key::Two, false, false, KEY_2, false, false), + KeyPair(Key::Three, false, false, KEY_3, false, false), + KeyPair(Key::Plus, false, false, KEY_ADD, false, false), + KeyPair(Key::Minus, false, false, KEY_SUB, false, false), + KeyPair(Key::Zero, false, false, KEY_0, false, false), + KeyPair(Key::Dot, false, false, KEY_DOT, false, false), + KeyPair(Key::EE, false, false, KEY_EXP, false, false), + KeyPair(Key::Ans, false, false, KEY_NEG, true, false), + KeyPair(Key::EXE, false, false, KEY_EXE, false, false, true), + KeyPair(Key::OnOff, false, false, KEY_ACON, true, false), + + // Cut + // Not assigned + // Copy + KeyPair(Key::Var, true, false, KEY_8, true, false), + // Paste + KeyPair(Key::Toolbox, true, false, KEY_9, true, false), + // Clear + KeyPair(Key::Backspace, true, false, KEY_ACON, false, false), + // [ + KeyPair(Key::Exp, true, false, KEY_ADD, true, false), + // ] + KeyPair(Key::Ln, true, false, KEY_SUB, true, false), + // { + KeyPair(Key::Log, true, false, KEY_MUL, true, false), + // } + KeyPair(Key::Imaginary, true, false, KEY_DIV, true, false), + // _ + KeyPair(Key::Comma, true, false, KEY_NEG, false, false), + // -> + KeyPair(Key::Power, true, false, KEY_STORE, false, false), + // asin + KeyPair(Key::Sine, true, false, KEY_SIN, true, false), + // acos + KeyPair(Key::Cosine, true, false, KEY_COS, true, false), + // atan + KeyPair(Key::Tangent, true, false, KEY_TAN, true, false), + // = + KeyPair(Key::Pi, true, false, KEY_DOT, true, false), + // < + KeyPair(Key::Sqrt, true, false, KEY_F1, false, false), + // > + KeyPair(Key::Square, true, false, KEY_F2, false, false), + + // : + KeyPair(Key::XNT, false, true, KEY_F3, false, false), + // ; + KeyPair(Key::Var, false, true, KEY_F4, false, false), + // " + KeyPair(Key::Toolbox, false, true, KEY_EXP, false, true), + // % + KeyPair(Key::Backspace, false, true, KEY_F5, false, false), + // A + KeyPair(Key::Exp, false, true, KEY_XOT, false, true), + // B + KeyPair(Key::Ln, false, true, KEY_LOG, false, true), + // C + KeyPair(Key::Log, false, true, KEY_LN, false, true), + // D + KeyPair(Key::Imaginary, false, true, KEY_SIN, false, true), + // E + KeyPair(Key::Comma, false, true, KEY_COS, false, true), + // F + KeyPair(Key::Power, false, true, KEY_TAN, false, true), + // G + KeyPair(Key::Sine, false, true, KEY_FRAC, false, true), + // H + KeyPair(Key::Cosine, false, true, KEY_FD, false, true), + // I + KeyPair(Key::Tangent, false, true, KEY_LEFTP, false, true), + // J + KeyPair(Key::Pi, false, true, KEY_RIGHTP, false, true), + // K + KeyPair(Key::Sqrt, false, true, KEY_COMMA, false, true), + // L + KeyPair(Key::Square, false, true, KEY_ARROW, false, true), + // M + KeyPair(Key::Seven, false, true, KEY_7, false, true), + // N + KeyPair(Key::Eight, false, true, KEY_8, false, true), + // O + KeyPair(Key::Nine, false, true, KEY_9, false, true), + // P + KeyPair(Key::LeftParenthesis, false, true, KEY_4, false, true), + // Q + KeyPair(Key::RightParenthesis, false, true, KEY_5, false, true), + // R + KeyPair(Key::Four, false, true, KEY_6, false, true), + // S + KeyPair(Key::Five, false, true, KEY_TIMES, false, true), + // T + KeyPair(Key::Six, false, true, KEY_DIV, false, true), + // U + KeyPair(Key::Multiplication, false, true, KEY_1, false, true), + // V + KeyPair(Key::Division, false, true, KEY_2, false, true), + // W + KeyPair(Key::One, false, true, KEY_3, false, true), + // X + KeyPair(Key::Two, false, true, KEY_PLUS, false, true), + // Y + KeyPair(Key::Three, false, true, KEY_MINUS, false, true), + // Z + KeyPair(Key::Plus, false, true, KEY_0, false, true), + // Space + KeyPair(Key::Minus, false, true, KEY_DOT, false, true), + // ? + KeyPair(Key::Zero, false, true, KEY_F6, true, false), + // ! + KeyPair(Key::Dot, false, true, KEY_F6, false, false), + + // Brightness control shortcut in Upsilon + KeyPair(Key::Plus, true, false, KEY_UP, false, true), + KeyPair(Key::Minus, true, false, KEY_DOWN, false, true), +}; + +constexpr int sNumberOfKeyPairs = sizeof(sKeyPairs)/sizeof(KeyPair); + +namespace Ion { +namespace Keyboard { + +int menuHeldFor = 0; + +State scan() { + State state = 0; + + // Grab this opportunity to refresh the display if needed + Simulator::Main::refresh(); + + clearevents(); + if (keydown(KEY_MENU)) { + state.setKey(Key::Home); + menuHeldFor++; + if (menuHeldFor > 30) { + Simulator::FXCGMenuHandler::openMenu(); + dupdate(); + // Wait until EXE is released + do { + sleep_ms(10); + clearevents(); + } while (keydown(KEY_EXE)); + } + } else { + menuHeldFor = 0; + } + + for (int i = 0; i < sNumberOfKeyPairs; i++) { + const KeyPair & keyPair = sKeyPairs[i]; + if (!keyPair.ignoreShiftAlpha() && + (keyPair.gintShift() != Events::isShiftActive() || + keyPair.gintAlpha() != Events::isAlphaActive())) { + continue; + } + if (keydown(keyPair.gintKey())) { + if (!keyPair.ignoreShiftAlpha()) { + state.setSimulatedShift(keyPair.numworksShift() ? ModSimState::ForceOn : ModSimState::ForceOff); + state.setSimulatedAlpha(keyPair.numworksAlpha() ? ModSimState::ForceOn : ModSimState::ForceOff); + } + state.setKey(keyPair.key()); + } + } + + return state; +} + +} +} + +namespace Ion { +namespace Simulator { +namespace Keyboard { + +} +} +} \ No newline at end of file diff --git a/ion/src/simulator/fxcg/keyboard.h b/ion/src/simulator/fxcg/keyboard.h new file mode 100644 index 00000000000..0e379642fb8 --- /dev/null +++ b/ion/src/simulator/fxcg/keyboard.h @@ -0,0 +1,15 @@ +#ifndef ION_SIMULATOR_KEYBOARD_H +#define ION_SIMULATOR_KEYBOARD_H + +#include +// #include + +namespace Ion { +namespace Simulator { +namespace Keyboard { + +} +} +} + +#endif \ No newline at end of file diff --git a/ion/src/simulator/fxcg/main.cpp b/ion/src/simulator/fxcg/main.cpp new file mode 100644 index 00000000000..9280dbc1253 --- /dev/null +++ b/ion/src/simulator/fxcg/main.cpp @@ -0,0 +1,114 @@ +#include "main.h" +#include "display.h" +#include "platform.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +extern "C" { +int main() { + Ion::Simulator::Main::init(); + ion_main(0, NULL); + Ion::Simulator::Main::quit(); + + return 0; +} +} + +namespace Ion { +namespace Simulator { +namespace Main { + +static bool sNeedsRefresh = false; + +void init() { + Ion::Simulator::Display::init(); + setNeedsRefresh(); +} + +void setNeedsRefresh() { + sNeedsRefresh = true; +} + +void refresh() { + if (!sNeedsRefresh) { + return; + } + + Display::draw(); + + sNeedsRefresh = false; +} + +void quit() { + Ion::Simulator::Display::quit(); +} + +void EnableStatusArea(int opt) { + __asm__ __volatile__ ( + ".align 2 \n\t" + "mov.l 2f, r2 \n\t" + "mov.l 1f, r0 \n\t" + "jmp @r2 \n\t" + "nop \n\t" + ".align 2 \n\t" + "1: \n\t" + ".long 0x02B7 \n\t" + ".align 4 \n\t" + "2: \n\t" + ".long 0x80020070 \n\t" + ); +} + +extern "C" void *__GetVRAMAddress(void); + +uint8_t xyram_backup[16 * 1024]; +uint8_t ilram_backup[4 * 1024]; + +void worldSwitchHandler(void (*worldSwitchFunction)(), bool prepareVRAM) { + // Back up XYRAM + uint8_t* xyram = (uint8_t*) 0xe500e000; + memcpy(xyram_backup, xyram, 16 * 1024); + // Back up ILRAM + uint8_t* ilram = (uint8_t*) 0xe5200000; + memcpy(ilram_backup, ilram, 4 * 1024); + + if (prepareVRAM) { + // Copying the screen to the OS's VRAM avoids a flicker when powering on + uint16_t* dst = (uint16_t *) __GetVRAMAddress(); + uint16_t* src = gint_vram + 6; + + for (int y = 0; y < 216; y++, dst += 384, src += 396) { + for (int x = 0; x < 384; x++) { + dst[x] = src[x]; + } + } + + // Disable the status area + EnableStatusArea(3); + } + + worldSwitchFunction(); + + // Restore XYRAM + memcpy(xyram, xyram_backup, 16 * 1024); + // Restore ILRAM + memcpy(ilram, ilram_backup, 4 * 1024); +} + +void runPowerOffSafe(void (*powerOffSafeFunction)(), bool prepareVRAM) { + gint_world_switch(GINT_CALL(worldSwitchHandler, powerOffSafeFunction, prepareVRAM)); +} + +} +} +} diff --git a/ion/src/simulator/fxcg/main.h b/ion/src/simulator/fxcg/main.h new file mode 100644 index 00000000000..4ac441a065f --- /dev/null +++ b/ion/src/simulator/fxcg/main.h @@ -0,0 +1,20 @@ +#ifndef ION_SIMULATOR_MAIN_H +#define ION_SIMULATOR_MAIN_H + +namespace Ion { +namespace Simulator { +namespace Main { + +void init(); +void quit(); + +void setNeedsRefresh(); +void refresh(); + +void runPowerOffSafe(void (*powerOffSafeFunction)(), bool prepareVRAM); + +} +} +} + +#endif \ No newline at end of file diff --git a/ion/src/simulator/fxcg/menuHandler.cpp b/ion/src/simulator/fxcg/menuHandler.cpp new file mode 100644 index 00000000000..51425160904 --- /dev/null +++ b/ion/src/simulator/fxcg/menuHandler.cpp @@ -0,0 +1,97 @@ +#include "main.h" + +namespace Ion { +namespace Simulator { +namespace FXCGMenuHandler { + +int saveAndOpenMainMenu(void) { + int addr; + + // get the address of the syscall table in it + addr = *(unsigned int *)0x8002007C; + + if (addr < (int)0x80020070) + return 1; + if (addr >= (int)0x81000000) + return 1; + + // get the pointer to syscall 1E58 - SwitchToMainMenu + addr += 0x1E58 * 4; + if (addr < (int)0x80020070) + return 1; + if (addr >= (int)0x81000000) + return 1; + + addr = *(unsigned int *)addr; + if (addr < (int)0x80020070) + return 1; + if (addr >= (int)0x81000000) + return 1; + + // Now addr has the address of the first operation in %1e58 + + // Run up to 150 times (300/2). OS 3.60's is 59 instructions, so this should + // be plenty, but will let it stop if nothing is found + for (unsigned short *currentAddr = (unsigned short *)addr; + (unsigned int)currentAddr < ((unsigned int)addr + 300); currentAddr++) { + // MOV.L GetkeyToMainFunctionReturn Flag, r14 + if (*(unsigned char *)currentAddr != 0xDE) + continue; + + // MOV #3, 2 + if (*(currentAddr + 1) != 0xE203) + continue; + + // BSR + if ((*(unsigned char *)(currentAddr + 2) & 0xF0) != 0xB0) + continue; + + // MOV.B r2, @r14 + if (*(currentAddr + 3) != 0x2E20) + continue; + + // BRA + if ((*(unsigned char *)(currentAddr + 4) & 0xF0) != 0xA0) + continue; + + // NOP + if (*(currentAddr + 5) != 0x0009) + continue; + + unsigned short branchInstruction = *(currentAddr + 2); + + // Clear first 4 bits (BSR identifier) + branchInstruction <<= 4; + branchInstruction >>= 4; + + // branchInstruction is now the displacement of BSR + + // Create typedef so we can cast the pointer + typedef void (*voidFunc)(void); + + // JMP to disp*2 + PC + 4 + ((voidFunc)((unsigned int)branchInstruction * 2 + + (unsigned int)currentAddr + 4 + 4))(); + + return 0; + } + + return 1; +} + +extern "C" void gint_osmenu_native(void); + +void openMenuWrapper(void) { + if (saveAndOpenMainMenu() != 0) { + // Fallback + gint_osmenu_native(); + } +} + +void openMenu(void) { + Simulator::Main::runPowerOffSafe(openMenuWrapper, true); +} + +} +} +} diff --git a/ion/src/simulator/fxcg/menuHandler.h b/ion/src/simulator/fxcg/menuHandler.h new file mode 100644 index 00000000000..6c455dfd96e --- /dev/null +++ b/ion/src/simulator/fxcg/menuHandler.h @@ -0,0 +1,14 @@ +#ifndef ION_SIMULATOR_MENUHANDLER_H +#define ION_SIMULATOR_MENUHANDLER_H + +namespace Ion { +namespace Simulator { +namespace FXCGMenuHandler { + +void openMenu(void); + +} +} +} + +#endif \ No newline at end of file diff --git a/ion/src/simulator/fxcg/platform.h b/ion/src/simulator/fxcg/platform.h new file mode 100644 index 00000000000..af5ddfcb60a --- /dev/null +++ b/ion/src/simulator/fxcg/platform.h @@ -0,0 +1,23 @@ +#ifndef ION_SIMULATOR_PLATFORM_H +#define ION_SIMULATOR_PLATFORM_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Those functions should be implemented per-platform. + * They are defined as C function for easier interop. */ + +const char * IonSimulatorGetLanguageCode(); + +void IonSimulatorKeyboardKeyDown(int keyNumber); +void IonSimulatorKeyboardKeyUp(int keyNumber); +void IonSimulatorEventsPushEvent(int eventNumber); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/ion/src/simulator/fxcg/power.cpp b/ion/src/simulator/fxcg/power.cpp new file mode 100644 index 00000000000..7375befecad --- /dev/null +++ b/ion/src/simulator/fxcg/power.cpp @@ -0,0 +1,42 @@ +#include +#include +#include + +#include "main.h" + +#include +#include + +void PowerOff(int displayLogo) { + __asm__ __volatile__ ( + ".align 2 \n\t" + "mov.l 2f, r2 \n\t" + "mov.l 1f, r0 \n\t" + "jmp @r2 \n\t" + "nop \n\t" + ".align 2 \n\t" + "1: \n\t" + ".long 0x1839 \n\t" + ".align 4 \n\t" + "2: \n\t" + ".long 0x80020070 \n\t" + ); +} + +void powerOff(void) { + PowerOff(1); +} + +namespace Ion { +namespace Power { + +void suspend(bool checkIfOnOffKeyReleased) { + Simulator::Main::runPowerOffSafe(powerOff, true); +} + +void standby() { + Simulator::Main::runPowerOffSafe(powerOff, true); +} + +} +} diff --git a/ion/src/simulator/fxcg/telemetry_init.cpp b/ion/src/simulator/fxcg/telemetry_init.cpp new file mode 100644 index 00000000000..7a69b2d8c83 --- /dev/null +++ b/ion/src/simulator/fxcg/telemetry_init.cpp @@ -0,0 +1,15 @@ +#include "platform.h" + +namespace Ion { +namespace Simulator { +namespace Telemetry { + +void init() { +} + +void shutdown() { +} + +} +} +} \ No newline at end of file diff --git a/ion/src/simulator/fxcg/timing.cpp b/ion/src/simulator/fxcg/timing.cpp new file mode 100644 index 00000000000..9a6eedfcab7 --- /dev/null +++ b/ion/src/simulator/fxcg/timing.cpp @@ -0,0 +1,27 @@ +#include +#include "main.h" +#include +// #include + +#include + +static auto start = std::chrono::steady_clock::now(); + +namespace Ion { +namespace Timing { + +uint64_t millis() { + auto elapsed = std::chrono::steady_clock::now() - start; + return std::chrono::duration_cast(elapsed).count(); +} + +void usleep(uint32_t us) { + sleep_us(us); +} + +void msleep(uint32_t ms) { + sleep_us(ms * 1000); +} + +} +} \ No newline at end of file diff --git a/kandinsky/include/kandinsky/postprocess_gamma_context.h b/kandinsky/include/kandinsky/postprocess_gamma_context.h index c3195f2ff2a..305d9ceddb5 100644 --- a/kandinsky/include/kandinsky/postprocess_gamma_context.h +++ b/kandinsky/include/kandinsky/postprocess_gamma_context.h @@ -2,6 +2,7 @@ #define KANDINSKY_POSTPROCESS_GAMMA_CONTEXT_H #include +#include class KDPostProcessGammaContext : public KDPostProcessContext { public: @@ -13,7 +14,16 @@ class KDPostProcessGammaContext : public KDPostProcessContext { void pushRect(KDRect rect, const KDColor * pixels) override; void pushRectUniform(KDRect rect, KDColor color) override; void pullRect(KDRect rect, KDColor * pixels) override; + KDColor correctColor(KDColor color); int m_redGamma, m_greenGamma, m_blueGamma; + // Lookup tables to do gamma correction + // 5 bits of red + uint8_t m_redGammaTable[32]; + // 6 bits of green + uint8_t m_greenGammaTable[64]; + // 5 bits of blue + uint8_t m_blueGammaTable[32]; + void updateGammaTables(); }; #endif diff --git a/kandinsky/src/postprocess_gamma_context.cpp b/kandinsky/src/postprocess_gamma_context.cpp index 6a75e60db77..95a89768b6e 100644 --- a/kandinsky/src/postprocess_gamma_context.cpp +++ b/kandinsky/src/postprocess_gamma_context.cpp @@ -1,6 +1,8 @@ +#include #include #include #include +#include constexpr int MaxGammaStates = 7; constexpr float MaxGammaGamut = 0.75; @@ -13,8 +15,28 @@ constexpr int clampGamma(int gamma) { return gamma < -MaxGammaStates ? -MaxGammaStates : (gamma > MaxGammaStates ? MaxGammaStates : gamma); } +void KDPostProcessGammaContext::updateGammaTables() { + const float redGamma = toGamma(m_redGamma); + const float greenGamma = toGamma(m_greenGamma); + const float blueGamma = toGamma(m_blueGamma); + for (int i = 0; i < 32; i++) { + uint8_t r = (uint8_t)(powf((i << 3) / 255.f, redGamma) * 255); + m_redGammaTable[i] = r >> 3; + } + for (int i = 0; i < 64; i++) { + uint8_t g = (uint8_t)(powf((i << 2) / 255.f, greenGamma) * 255); + m_greenGammaTable[i] = g >> 2; + } + for (int i = 0; i < 32; i++) { + uint8_t b = (uint8_t)(powf((i << 3 )/ 255.f, blueGamma) * 255); + m_blueGammaTable[i] = b >> 3; + } +} + KDPostProcessGammaContext::KDPostProcessGammaContext() : - m_redGamma(0), m_greenGamma(0), m_blueGamma(0) {} + m_redGamma(0), m_greenGamma(0), m_blueGamma(0) { + updateGammaTables(); + } void KDPostProcessGammaContext::gamma(int& red, int& green, int& blue) { red = m_redGamma; @@ -32,12 +54,20 @@ void KDPostProcessGammaContext::setGamma(int red, int green, int blue) { m_redGamma = clampGamma(red); m_greenGamma = clampGamma(green); m_blueGamma = clampGamma(blue); + updateGammaTables(); +} + +KDColor KDPostProcessGammaContext::correctColor(KDColor color) { + uint8_t r5 = (((uint16_t )color)>>11)&0x1F; + r5 = m_redGammaTable[r5]; + uint8_t g6 = (((uint16_t )color)>>5)&0x3F; + g6 = m_greenGammaTable[g6]; + uint8_t b5 = ((uint16_t )color)&0x1F; + b5 = m_blueGammaTable[b5]; + return KDColor::RGB16(r5<<11 | g6<<5 | b5); } void KDPostProcessGammaContext::pushRect(KDRect rect, const KDColor * pixels) { - const float redGamma = toGamma(m_redGamma); - const float greenGamma = toGamma(m_greenGamma); - const float blueGamma = toGamma(m_blueGamma); KDColor workingBuffer[rect.width()]; for (KDCoordinate y = 0; y < rect.height(); y++) { @@ -45,10 +75,7 @@ void KDPostProcessGammaContext::pushRect(KDRect rect, const KDColor * pixels) { for (KDCoordinate x = 0; x < rect.width(); x++) { const KDColor color = pixels[y*rect.width()+x]; - const KDColor result = KDColor::RGB888( - (uint8_t)(powf(color.red()/255.f, redGamma)*255), - (uint8_t)(powf(color.green()/255.f, greenGamma)*255), - (uint8_t)(powf(color.blue()/255.f, blueGamma)*255)); + const KDColor result = correctColor(color); workingBuffer[x] = result; } KDPostProcessContext::pushRect(workingRect, workingBuffer); @@ -56,15 +83,7 @@ void KDPostProcessGammaContext::pushRect(KDRect rect, const KDColor * pixels) { } void KDPostProcessGammaContext::pushRectUniform(KDRect rect, KDColor color) { - const float redGamma = toGamma(m_redGamma); - const float greenGamma = toGamma(m_greenGamma); - const float blueGamma = toGamma(m_blueGamma); - const KDColor result = KDColor::RGB888( - (uint8_t)(powf(color.red()/255.f, redGamma)*255), - (uint8_t)(powf(color.green()/255.f, greenGamma)*255), - (uint8_t)(powf(color.blue()/255.f, blueGamma)*255)); - - KDPostProcessContext::pushRectUniform(rect, result); + KDPostProcessContext::pushRectUniform(rect, correctColor(color)); } void KDPostProcessGammaContext::pullRect(KDRect rect, KDColor * pixels) { diff --git a/liba/include/bridge/math.h b/liba/include/bridge/math.h new file mode 100644 index 00000000000..a89e832f5b6 --- /dev/null +++ b/liba/include/bridge/math.h @@ -0,0 +1,20 @@ +#ifndef LIBA_BRIDGE_MATH_H +#define LIBA_BRIDGE_MATH_H + +#include_next + +#define M_E 2.7182818284590452354 /* e */ +#define M_LOG2E 1.4426950408889634074 /* log 2e */ +#define M_LOG10E 0.43429448190325182765 /* log 10e */ +#define M_LN2 0.69314718055994530942 /* log e2 */ +#define M_LN10 2.30258509299404568402 /* log e10 */ +#define M_PI 3.14159265358979323846 /* pi */ +#define M_PI_2 1.57079632679489661923 /* pi/2 */ +#define M_PI_4 0.78539816339744830962 /* pi/4 */ +#define M_1_PI 0.31830988618379067154 /* 1/pi */ +#define M_2_PI 0.63661977236758134308 /* 2/pi */ +#define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */ +#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ +#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ + +#endif diff --git a/liba/include/bridge/string.h b/liba/include/bridge/string.h index d5eda394692..51d6a8c3a34 100644 --- a/liba/include/bridge/string.h +++ b/liba/include/bridge/string.h @@ -7,7 +7,7 @@ LIBA_BEGIN_DECLS -#if (__GLIBC__ || __MINGW32__) +#if (__GLIBC__ || __MINGW32__ || _FXCG) size_t strlcat(char * dst, const char * src, size_t dstSize); size_t strlcpy(char * dst, const char * src, size_t len); #endif diff --git a/liba/include/bridge/strings.h b/liba/include/bridge/strings.h new file mode 100644 index 00000000000..d74b264db18 --- /dev/null +++ b/liba/include/bridge/strings.h @@ -0,0 +1,22 @@ +#ifndef LIBA_STRINGS_H +#define LIBA_STRINGS_H + +#if (_FXCG) + +#include + +#include "../private/macros.h" + +LIBA_BEGIN_DECLS + +void bzero(void * s, size_t n); + +LIBA_END_DECLS + +#else + +#include_next + +#endif + +#endif \ No newline at end of file diff --git a/libaxx/Makefile.bridge b/libaxx/Makefile.bridge new file mode 100644 index 00000000000..92fd5dddd4d --- /dev/null +++ b/libaxx/Makefile.bridge @@ -0,0 +1,3 @@ +SFLAGS += -Ilibaxx/include/bridge + +# libaxx_src += libaxx/src/bridge.c diff --git a/libaxx/include/bridge/cmath b/libaxx/include/bridge/cmath new file mode 100644 index 00000000000..11eec165e87 --- /dev/null +++ b/libaxx/include/bridge/cmath @@ -0,0 +1,165 @@ +#ifndef LIBA_BRIDGE_CMATH_H +#define LIBA_BRIDGE_CMATH_H + +#include_next + +#define M_E 2.7182818284590452354 /* e */ +#define M_LOG2E 1.4426950408889634074 /* log 2e */ +#define M_LOG10E 0.43429448190325182765 /* log 10e */ +#define M_LN2 0.69314718055994530942 /* log e2 */ +#define M_LN10 2.30258509299404568402 /* log e10 */ +#define M_PI 3.14159265358979323846 /* pi */ +#define M_PI_2 1.57079632679489661923 /* pi/2 */ +#define M_PI_4 0.78539816339744830962 /* pi/4 */ +#define M_1_PI 0.31830988618379067154 /* 1/pi */ +#define M_2_PI 0.63661977236758134308 /* 2/pi */ +#define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */ +#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ +#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ + +#if (_FXCG) +namespace std { + // functions + using ::acosh; + using ::acoshf; + using ::acoshl; + + using ::asinh; + using ::asinhf; + using ::asinhl; + + using ::atanh; + using ::atanhf; + using ::atanhl; + + using ::cbrt; + using ::cbrtf; + using ::cbrtl; + + using ::copysign; + using ::copysignf; + using ::copysignl; + + using ::erf; + using ::erff; + using ::erfl; + + using ::erfc; + using ::erfcf; + using ::erfcl; + + using ::exp2; + using ::exp2f; + using ::exp2l; + + using ::expm1; + using ::expm1f; + using ::expm1l; + + using ::fdim; + using ::fdimf; + using ::fdiml; + + using ::fma; + using ::fmaf; + using ::fmal; + + using ::fmax; + using ::fmaxf; + using ::fmaxl; + + using ::fmin; + using ::fminf; + using ::fminl; + + using ::hypot; + using ::hypotf; + using ::hypotl; + + using ::ilogb; + using ::ilogbf; + using ::ilogbl; + + using ::lgamma; + using ::lgammaf; + using ::lgammal; + + using ::llrint; + using ::llrintf; + using ::llrintl; + + using ::llround; + using ::llroundf; + using ::llroundl; + + using ::log1p; + using ::log1pf; + using ::log1pl; + + using ::log2; + using ::log2f; + using ::log2l; + + using ::logb; + using ::logbf; + using ::logbl; + + using ::lrint; + using ::lrintf; + using ::lrintl; + + using ::lround; + using ::lroundf; + using ::lroundl; + + using ::nan; + using ::nanf; + using ::nanl; + + using ::nearbyint; + using ::nearbyintf; + using ::nearbyintl; + + using ::nextafter; + using ::nextafterf; + using ::nextafterl; + + using ::nexttoward; + using ::nexttowardf; + using ::nexttowardl; + + using ::remainder; + using ::remainderf; + using ::remainderl; + + using ::remquo; + using ::remquof; + using ::remquol; + + using ::rint; + using ::rintf; + using ::rintl; + + using ::round; + using ::roundf; + using ::roundl; + + using ::scalbln; + using ::scalblnf; + using ::scalblnl; + + using ::scalbn; + using ::scalbnf; + using ::scalbnl; + + using ::tgamma; + using ::tgammaf; + using ::tgammal; + + using ::trunc; + using ::truncf; + using ::truncl; +} +#endif + +#endif diff --git a/poincare/include/poincare/ieee754.h b/poincare/include/poincare/ieee754.h index accda9d33d4..8427e90eef8 100644 --- a/poincare/include/poincare/ieee754.h +++ b/poincare/include/poincare/ieee754.h @@ -4,7 +4,9 @@ #include #include #include +#include #include +#include namespace Poincare { @@ -41,11 +43,19 @@ class IEEE754 final { if (((uint64_t)mantissa >> (size()-k_mantissaNbBits-2)) & 1) { u.ui += 1; } - return u.f; + if (sizeof(T) == sizeof(float)) { + return u.f32.f; + } else { + return u.f64.f; + } } static int exponent(T f) { uint_float u; - u.f = f; + if (sizeof(T) == sizeof(float)) { + u.f32.f = f; + } else { + u.f64.f = f; + } constexpr uint16_t oneOnExponentsBits = maxExponent(); int exp = (u.ui >> k_mantissaNbBits) & oneOnExponentsBits; exp -= exponentOffset(); @@ -75,10 +85,28 @@ class IEEE754 final { } private: + #ifdef _BIG_ENDIAN + union uint_float { + uint64_t ui; + struct { + uint32_t padding; + float f; + } f32; + struct { + double f; + } f64; + }; + #else union uint_float { uint64_t ui; - T f; + struct { + float f; + } f32; + struct { + double f; + } f64; }; + #endif constexpr static size_t k_signNbBits = 1; constexpr static size_t k_exponentNbBits = sizeof(T) == sizeof(float) ? 8 : 11; diff --git a/poincare/include/poincare/integer.h b/poincare/include/poincare/integer.h index 1d27e50c508..cfc98203495 100644 --- a/poincare/include/poincare/integer.h +++ b/poincare/include/poincare/integer.h @@ -5,6 +5,14 @@ #include #include +#ifdef _FXCG +#include +#include +#include +#else +#include +#endif + namespace Poincare { class ExpressionLayout; @@ -13,12 +21,17 @@ class LayoutNode; class Integer; struct IntegerDivision; -#ifdef _3DS +#if (defined _3DS) || (defined _FXCG) typedef unsigned short half_native_uint_t; +static_assert(sizeof(half_native_uint_t) == sizeof(uint16_t)); typedef int native_int_t; +static_assert(sizeof(native_int_t) == sizeof(int32_t)); typedef long long int double_native_int_t; +static_assert(sizeof(double_native_int_t) == sizeof(int64_t)); typedef unsigned int native_uint_t; +static_assert(sizeof(native_uint_t) == sizeof(uint32_t)); typedef unsigned long long int double_native_uint_t; +static_assert(sizeof(double_native_uint_t) == sizeof(uint64_t)); #else typedef uint16_t half_native_uint_t; typedef int32_t native_int_t; @@ -199,7 +212,12 @@ class Integer final : public TreeHandle { if (i >= numberOfHalfDigits()) { return 0; } - return (usesImmediateDigit() ? ((half_native_uint_t *)&m_digit)[i] : ((half_native_uint_t *)digits())[i]); + native_uint_t d = usesImmediateDigit() ? m_digit : digits()[i/2]; + if (i % 2 == 0) { + return d & 0xFFFF; + } else { + return d >> 16; + } } native_uint_t digit(uint8_t i) const { diff --git a/poincare/include/poincare/tree_pool.h b/poincare/include/poincare/tree_pool.h index cb30940187e..62c1d6d5ee3 100644 --- a/poincare/include/poincare/tree_pool.h +++ b/poincare/include/poincare/tree_pool.h @@ -138,7 +138,7 @@ class TreePool final { private: uint16_t m_currentIndex; uint16_t m_availableIdentifiers[MaxNumberOfNodes]; - static_assert(MaxNumberOfNodes < INT16_MAX && sizeof(m_availableIdentifiers[0] == sizeof(uint16_t)), "Tree node identifiers do not have the right data size."); + static_assert(MaxNumberOfNodes < INT16_MAX && sizeof(m_availableIdentifiers[0]) == sizeof(uint16_t), "Tree node identifiers do not have the right data size."); }; void freePoolFromNode(TreeNode * firstNodeToDiscard); diff --git a/poincare/src/integer.cpp b/poincare/src/integer.cpp index fc67dda6609..3fa7763622c 100644 --- a/poincare/src/integer.cpp +++ b/poincare/src/integer.cpp @@ -127,7 +127,10 @@ Integer::Integer(native_int_t i) : TreeHandle(TreeNode::NoNodeIdentifier) { Integer::Integer(double_native_int_t i) { double_native_uint_t j = i < 0 ? -i : i; - native_uint_t * d = (native_uint_t *)&j; + native_uint_t d[2] = { + static_cast(j & 0xFFFFFFFF), + static_cast(j >> 32) + }; native_uint_t leastSignificantDigit = *d; native_uint_t mostSignificantDigit = *(d+1); uint8_t numberOfDigits = (mostSignificantDigit == 0) ? 1 : 2; @@ -165,7 +168,8 @@ Integer::Integer(const char * digits, size_t length, bool negative, Base b) : Integer base((int)b); for (size_t i = 0; i < length; i++) { *this = Multiplication(*this, base); - *this = Addition(*this, Integer(integerFromCharDigit(*digits))); + Integer toAdd = Integer(integerFromCharDigit(*digits)); + *this = Addition(*this, toAdd); digits++; } } @@ -495,7 +499,10 @@ Integer Integer::multiplication(const Integer & a, const Integer & b, bool oneDi * otherwise the product might end up being computed on single_native size * and then zero-padded. */ double_native_uint_t p = aDigit*bDigit + carry + (double_native_uint_t)(s_workingBuffer[i+j]); // TODO: Prove it cannot overflow double_native type - native_uint_t * l = (native_uint_t *)&p; + native_uint_t l[2] = { + static_cast(p & 0xFFFFFFFF), + static_cast(p >> 32) + }; if (i+j < (uint8_t) k_maxNumberOfDigits+oneDigitOverflow) { s_workingBuffer[i+j] = l[0]; } else { @@ -605,18 +612,31 @@ Integer Integer::divideByPowerOf2(uint8_t pow) const { // return this*(2^16)^pow Integer Integer::multiplyByPowerOfBase(uint8_t pow) const { int nbOfHalfDigits = numberOfHalfDigits(); - half_native_uint_t * digits = reinterpret_cast(s_workingBuffer); + native_uint_t * digits = s_workingBuffer; /* The number of half digits of the built integer is nbOfHalfDigits+pow. * Still, we set an extra half digit to 0 to easily convert half digits to * digits. */ - memset(digits, 0, sizeof(half_native_uint_t)*(nbOfHalfDigits+pow+1)); - for (uint8_t i = 0; i < nbOfHalfDigits; i++) { - digits[i+pow] = halfDigit(i); + memset(digits, 0, (sizeof(native_uint_t)/2)*(nbOfHalfDigits+pow+1)); + for (uint8_t i = 0; i < nbOfHalfDigits; i += 2) { + native_uint_t toSet = halfDigit(i); + if (i+1 < nbOfHalfDigits) { + toSet |= (native_uint_t)halfDigit(i+1) << 16; + } + int index = i+pow; + // If it's on an even index, we can just set the value + if (index % 2 == 0) { + digits[index/2] = toSet; + } else { + // If it's on an odd index, we need to shift the value + digits[index/2] |= toSet << 16; + digits[index/2+1] |= toSet >> 16; + } } nbOfHalfDigits += pow; - return BuildInteger((native_uint_t *)digits, nbOfHalfDigits%2 == 1 ? nbOfHalfDigits/2+1 : nbOfHalfDigits/2, false, true); + return BuildInteger(digits, nbOfHalfDigits%2 == 1 ? nbOfHalfDigits/2+1 : nbOfHalfDigits/2, false, true); } + IntegerDivision Integer::udiv(const Integer & numerator, const Integer & denominator) { if (denominator.isOverflow()) { return {.quotient = Overflow(false), .remainder = Integer::Overflow(false)}; @@ -679,6 +699,14 @@ IntegerDivision Integer::udiv(const Integer & numerator, const Integer & denomin qNumberOfDigits--; } int qNumberOfDigitsInBase32 = qNumberOfDigits%2 == 1 ? qNumberOfDigits/2+1 : qNumberOfDigits/2; + // Swap each pair of digits in qDigits if on a big-endian architecture + #ifdef _BIG_ENDIAN + for (int i = 0; i < qNumberOfDigitsInBase32; i++) { + half_native_uint_t tmp = qDigits[i*2]; + qDigits[i*2] = qDigits[i*2+1]; + qDigits[i*2+1] = tmp; + } + #endif IntegerDivision div = {.quotient = BuildInteger((native_uint_t *)qDigits, qNumberOfDigitsInBase32, false), .remainder = A}; if (pow > 0 && !div.remainder.isZero()) { div.remainder = div.remainder.divideByPowerOf2(pow);