mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
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:
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
2
ion/src/simulator/external/config.fxcg.mak
vendored
Normal file
2
ion/src/simulator/external/config.fxcg.mak
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
undefine sdl_src
|
||||
undefine ion_simulator_sdl_src
|
||||
66
ion/src/simulator/fxcg/Makefile
Normal file
66
ion/src/simulator/fxcg/Makefile
Normal 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
|
||||
BIN
ion/src/simulator/fxcg/assets/icon-sel.png
Normal file
BIN
ion/src/simulator/fxcg/assets/icon-sel.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.5 KiB |
BIN
ion/src/simulator/fxcg/assets/icon-uns.png
Normal file
BIN
ion/src/simulator/fxcg/assets/icon-uns.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
67
ion/src/simulator/fxcg/backlight.cpp
Normal file
67
ion/src/simulator/fxcg/backlight.cpp
Normal 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() {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
18
ion/src/simulator/fxcg/clipboard.cpp
Normal file
18
ion/src/simulator/fxcg/clipboard.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
24
ion/src/simulator/fxcg/console.cpp
Normal file
24
ion/src/simulator/fxcg/console.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
30
ion/src/simulator/fxcg/display.cpp
Normal file
30
ion/src/simulator/fxcg/display.cpp
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
19
ion/src/simulator/fxcg/display.h
Normal file
19
ion/src/simulator/fxcg/display.h
Normal 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
|
||||
23
ion/src/simulator/fxcg/events.cpp
Normal file
23
ion/src/simulator/fxcg/events.cpp
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
24
ion/src/simulator/fxcg/events.h
Normal file
24
ion/src/simulator/fxcg/events.h
Normal 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
|
||||
15
ion/src/simulator/fxcg/events_keyboard.cpp
Normal file
15
ion/src/simulator/fxcg/events_keyboard.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#include <ion/events.h>
|
||||
|
||||
namespace Ion {
|
||||
namespace Events {
|
||||
|
||||
|
||||
Event getPlatformEvent() {
|
||||
Event result = None;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
56
ion/src/simulator/fxcg/framebuffer.cpp
Normal file
56
ion/src/simulator/fxcg/framebuffer.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
17
ion/src/simulator/fxcg/framebuffer.h
Normal file
17
ion/src/simulator/fxcg/framebuffer.h
Normal 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
|
||||
262
ion/src/simulator/fxcg/keyboard.cpp
Normal file
262
ion/src/simulator/fxcg/keyboard.cpp
Normal 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 {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
15
ion/src/simulator/fxcg/keyboard.h
Normal file
15
ion/src/simulator/fxcg/keyboard.h
Normal 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
|
||||
114
ion/src/simulator/fxcg/main.cpp
Normal file
114
ion/src/simulator/fxcg/main.cpp
Normal 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));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
20
ion/src/simulator/fxcg/main.h
Normal file
20
ion/src/simulator/fxcg/main.h
Normal 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
|
||||
97
ion/src/simulator/fxcg/menuHandler.cpp
Normal file
97
ion/src/simulator/fxcg/menuHandler.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
14
ion/src/simulator/fxcg/menuHandler.h
Normal file
14
ion/src/simulator/fxcg/menuHandler.h
Normal 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
|
||||
23
ion/src/simulator/fxcg/platform.h
Normal file
23
ion/src/simulator/fxcg/platform.h
Normal 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
|
||||
42
ion/src/simulator/fxcg/power.cpp
Normal file
42
ion/src/simulator/fxcg/power.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
15
ion/src/simulator/fxcg/telemetry_init.cpp
Normal file
15
ion/src/simulator/fxcg/telemetry_init.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "platform.h"
|
||||
|
||||
namespace Ion {
|
||||
namespace Simulator {
|
||||
namespace Telemetry {
|
||||
|
||||
void init() {
|
||||
}
|
||||
|
||||
void shutdown() {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
27
ion/src/simulator/fxcg/timing.cpp
Normal file
27
ion/src/simulator/fxcg/timing.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user