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

* 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
This commit is contained in:
circuit10
2023-05-10 17:28:18 +01:00
committed by GitHub
parent aadcd37f31
commit b44a95a9b3
77 changed files with 1617 additions and 49 deletions

View File

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

View File

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

View File

@@ -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
<br>
<details>
<summary><b>Casio fx-CG-series Port</b></summary>
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.
</details>
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).

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -1,6 +1,12 @@
PythonCommandAmpersand = "&"
PythonCommandLF = "\\n"
PythonCommandPercent = "%"
PythonCommandColon = ":"
PythonCommandSemicon = ";"
PythonCommandExclamationMark = "!"
PythonCommandLessThan = "<"
PythonCommandGreaterThan = ">"
PythonCommandQuestionMark = "?"
PythonCommandPound = "#"
PythonCommandSingleQuote = "'x'"
PythonCommandSymbolExp = "^"

View File

@@ -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),

View File

@@ -18,7 +18,13 @@ public:
* 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);

View File

@@ -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));
}
}

View File

@@ -47,10 +47,19 @@ private:
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;

View File

@@ -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),

View File

@@ -57,7 +57,7 @@ public:
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};

View File

@@ -1,5 +1,6 @@
#include "about_controller.h"
#include "../../../python/src/py/mpconfig.h"
#include "poincare/division.h"
#include <assert.h>
#include <cmath>
#include <apps/settings/main_controller.h>

View File

@@ -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);
}

View File

@@ -121,3 +121,4 @@ CatalyticActivityDimension = "Katalitikus aktivitás"
SurfaceDimension = "Felület"
VolumeDimension = "Hangerő"
SpeedDimension = "Sebesség"
Factorial = "Faktorál"

View File

@@ -121,3 +121,4 @@ CatalyticActivityDimension = "Attività catalitica"
SurfaceDimension = "Superficie"
VolumeDimension = "Volume"
SpeedDimension = "Velocità"
Factorial = "Fattoriale"

View File

@@ -121,3 +121,4 @@ CatalyticActivityDimension = "Katalytische activiteit"
SurfaceDimension = "Oppervlak"
VolumeDimension = "Volume"
SpeedDimension = "Snelheid"
Factorial = "Faculteit"

View File

@@ -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)"

View File

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

View File

@@ -65,7 +65,11 @@ void ContinuousFunctionCache::ComputeNonCartesianSteps(float * tStep, float * tC
const int numberOfWholeSteps = static_cast<int>(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

View File

@@ -49,7 +49,12 @@ protected:
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;

View File

@@ -87,7 +87,7 @@ private:
// 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;

View File

@@ -511,3 +511,4 @@ MagneticFluxQuantumTag = "Magnetisches Fluss-Quantum"
ConductanceQuantumTag = "Leitwertquantum"
CirculationQuantumTag = "Auflage-Quantum"
MatricesAndVectors = "Matrizen und Vektoren"
Factorial = "Fakultät"

View File

@@ -511,3 +511,4 @@ HartreeConstantTag = "Hartree Constant"
MagneticFluxQuantumTag = "Magnetic Flux Quantum"
ConductanceQuantumTag = "Conductance Quantum"
CirculationQuantumTag = "Circulation Quantum"
Factorial = "Factorial"

View File

@@ -511,3 +511,4 @@ MagneticFluxQuantumTag = "Flujo Magnético Cuántico"
ConductanceQuantumTag = "Conductancia Quantum"
CirculationQuantumTag = "Circulación Quantum"
MatricesAndVectors = "Matrices y vectores"
Factorial = "Factorial"

View File

@@ -515,3 +515,4 @@ MagneticFluxQuantumTag = "Quantum de Flux Magnétique"
ConductanceQuantumTag = "Quantum de Conductance"
CirculationQuantumTag = "Quantum de Circulation"
MatricesAndVectors = "Matrices et vecteurs"
Factorial = "Factorielle"

View File

@@ -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"

View File

@@ -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))

View File

@@ -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 $@

View File

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

View File

@@ -1,6 +1,7 @@
#include <escher/icon_view.h>
extern "C" {
#include <assert.h>
#include <stdint.h>
}
#include <ion.h>
#include <kandinsky.h>
@@ -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);

View File

@@ -1,6 +1,7 @@
#include <escher/image_view.h>
extern "C" {
#include <assert.h>
#include <stdint.h>
}
#include <ion.h>
@@ -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);
}

View File

@@ -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;

View File

@@ -195,7 +195,7 @@ public:
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 @@ public:
#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

View File

@@ -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 @@ public:
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();

View File

@@ -1,3 +1,4 @@
#include <ion/keyboard.h>
#include <ion/events.h>
#include <ion/timing.h>
#include <assert.h>
@@ -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

View File

@@ -0,0 +1,2 @@
undefine sdl_src
undefine ion_simulator_sdl_src

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,67 @@
#include <ion/backlight.h>
#include <gint/drivers/r61524.h>
#include <gint/defs/util.h>
// 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() {
}
}
}

View File

@@ -0,0 +1,18 @@
#include <ion/clipboard.h>
#include <ion.h>
#include <string.h>
namespace Ion {
namespace Clipboard {
uint32_t localClipboardVersion;
void write(const char * text) {
}
const char * read() {
return nullptr;
}
}
}

View File

@@ -0,0 +1,24 @@
#include <ion/console.h>
#include "main.h"
#include <kandinsky/ion_context.h>
#include <stdio.h>
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;
}
}
}

View File

@@ -0,0 +1,30 @@
#include "display.h"
#include "framebuffer.h"
#include <kandinsky/color.h>
#include <stdint.h>
#include <gint/display-cg.h>
#include <ion/display.h>
#include <string.h>
#include <stdio.h>
#include <gint/display.h>
#include <gint/keyboard.h>
namespace Ion {
namespace Simulator {
namespace Display {
void init() {
}
void quit() {
}
void draw() {
dupdate();
}
}
}
}

View File

@@ -0,0 +1,19 @@
#ifndef ION_SIMULATOR_DISPLAY_H
#define ION_SIMULATOR_DISPLAY_H
#include <kandinsky.h>
namespace Ion {
namespace Simulator {
namespace Display {
void init();
void quit();
void draw();
}
}
}
#endif

View File

@@ -0,0 +1,23 @@
#include "events.h"
#include <ion/events.h>
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<const char *>(sharedExternalTextBuffer());
}
return defaultText();
}
}
}

View File

@@ -0,0 +1,24 @@
#ifndef ION_SIMULATOR_EVENTS_H
#define ION_SIMULATOR_EVENTS_H
#include <ion/events.h>
namespace Ion {
namespace Simulator {
namespace Events {
void dumpEventCount(int i);
void logAfter(int numberOfEvents);
}
}
namespace Events {
static constexpr int sharedExternalTextBufferSize = 2;
char * sharedExternalTextBuffer();
}
}
#endif

View File

@@ -0,0 +1,15 @@
#include <ion/events.h>
namespace Ion {
namespace Events {
Event getPlatformEvent() {
Event result = None;
return result;
}
}
}

View File

@@ -0,0 +1,56 @@
#include "framebuffer.h"
#include <gint/display-cg.h>
#include <ion/display.h>
#include "main.h"
#include <stdio.h>
#include <gint/display.h>
// 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;
}
}
}
}

View File

@@ -0,0 +1,17 @@
#ifndef ION_SIMULATOR_FRAMEBUFFER_H
#define ION_SIMULATOR_FRAMEBUFFER_H
#include <kandinsky.h>
namespace Ion {
namespace Simulator {
namespace Framebuffer {
const KDColor * address();
void setActive(bool enabled);
}
}
}
#endif

View File

@@ -0,0 +1,262 @@
#include <stdlib.h>
#include <unistd.h>
#include <gint/display-cg.h>
#include <gint/display.h>
#include <gint/keycodes.h>
#include <gint/keyboard.h>
#include <gint/gint.h>
#include <gint/clock.h>
#include <ion/keyboard.h>
#include <ion/events.h>
#include <ion/power.h>
#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 {
}
}
}

View File

@@ -0,0 +1,15 @@
#ifndef ION_SIMULATOR_KEYBOARD_H
#define ION_SIMULATOR_KEYBOARD_H
#include <ion/keyboard.h>
// #include <libndls.h>
namespace Ion {
namespace Simulator {
namespace Keyboard {
}
}
}
#endif

View File

@@ -0,0 +1,114 @@
#include "main.h"
#include "display.h"
#include "platform.h"
#include <gint/display-cg.h>
#include <gint/gint.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <ion.h>
#include <ion/events.h>
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));
}
}
}
}

View File

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

View File

@@ -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 <SaveAndOpenMainMenu>
if ((*(unsigned char *)(currentAddr + 2) & 0xF0) != 0xB0)
continue;
// MOV.B r2, @r14
if (*(currentAddr + 3) != 0x2E20)
continue;
// BRA <some addr>
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);
}
}
}
}

View File

@@ -0,0 +1,14 @@
#ifndef ION_SIMULATOR_MENUHANDLER_H
#define ION_SIMULATOR_MENUHANDLER_H
namespace Ion {
namespace Simulator {
namespace FXCGMenuHandler {
void openMenu(void);
}
}
}
#endif

View File

@@ -0,0 +1,23 @@
#ifndef ION_SIMULATOR_PLATFORM_H
#define ION_SIMULATOR_PLATFORM_H
#include <stdbool.h>
#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

View File

@@ -0,0 +1,42 @@
#include <ion/power.h>
#include <stdint.h>
#include <string.h>
#include "main.h"
#include <gint/gint.h>
#include <gint/display.h>
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);
}
}
}

View File

@@ -0,0 +1,15 @@
#include "platform.h"
namespace Ion {
namespace Simulator {
namespace Telemetry {
void init() {
}
void shutdown() {
}
}
}
}

View File

@@ -0,0 +1,27 @@
#include <ion/timing.h>
#include "main.h"
#include <chrono>
// #include <libndls.h>
#include <gint/clock.h>
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<std::chrono::milliseconds>(elapsed).count();
}
void usleep(uint32_t us) {
sleep_us(us);
}
void msleep(uint32_t ms) {
sleep_us(ms * 1000);
}
}
}

View File

@@ -2,6 +2,7 @@
#define KANDINSKY_POSTPROCESS_GAMMA_CONTEXT_H
#include <kandinsky/postprocess_context.h>
#include <stdint.h>
class KDPostProcessGammaContext : public KDPostProcessContext {
public:
@@ -13,7 +14,16 @@ private:
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

View File

@@ -1,6 +1,8 @@
#include <kandinsky/color.h>
#include <kandinsky/postprocess_gamma_context.h>
#include <ion.h>
#include <math.h>
#include <stdint.h>
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) {

View File

@@ -0,0 +1,20 @@
#ifndef LIBA_BRIDGE_MATH_H
#define LIBA_BRIDGE_MATH_H
#include_next <math.h>
#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

View File

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

View File

@@ -0,0 +1,22 @@
#ifndef LIBA_STRINGS_H
#define LIBA_STRINGS_H
#if (_FXCG)
#include <stdlib.h>
#include "../private/macros.h"
LIBA_BEGIN_DECLS
void bzero(void * s, size_t n);
LIBA_END_DECLS
#else
#include_next <strings.h>
#endif
#endif

3
libaxx/Makefile.bridge Normal file
View File

@@ -0,0 +1,3 @@
SFLAGS += -Ilibaxx/include/bridge
# libaxx_src += libaxx/src/bridge.c

165
libaxx/include/bridge/cmath Normal file
View File

@@ -0,0 +1,165 @@
#ifndef LIBA_BRIDGE_CMATH_H
#define LIBA_BRIDGE_CMATH_H
#include_next <cmath>
#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

View File

@@ -4,7 +4,9 @@
#include <assert.h>
#include <stdint.h>
#include <stddef.h>
#include <stdint.h>
#include <cmath>
#include <type_traits>
namespace Poincare {
@@ -41,11 +43,19 @@ public:
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 @@ public:
}
private:
#ifdef _BIG_ENDIAN
union uint_float {
uint64_t ui;
T f;
struct {
uint32_t padding;
float f;
} f32;
struct {
double f;
} f64;
};
#else
union uint_float {
uint64_t ui;
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;

View File

@@ -5,6 +5,14 @@
#include <assert.h>
#include <poincare/horizontal_layout.h>
#ifdef _FXCG
#include <gint/display.h>
#include <gint/keyboard.h>
#include <stdio.h>
#else
#include <stdio.h>
#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 @@ private:
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 {

View File

@@ -138,7 +138,7 @@ private:
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);

View File

@@ -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<native_uint_t>(j & 0xFFFFFFFF),
static_cast<native_uint_t>(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<native_uint_t>(p & 0xFFFFFFFF),
static_cast<native_uint_t>(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<half_native_uint_t *>(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);