1
0
Fork 0
forked from Miroirs/x49gp

Merge branch 'main' of ssh://src.le-moine.org:38172/gwh/x50ng

This commit is contained in:
Gwenhael Le Moine 2024-11-22 16:12:07 +01:00
commit 4f731b9cf4
No known key found for this signature in database
GPG key ID: FDFE3669426707A7
6 changed files with 244 additions and 35 deletions

View file

@ -3,7 +3,7 @@ TARGET_ALLCAPS = X50NG
VERSION_MAJOR = 1 VERSION_MAJOR = 1
VERSION_MINOR = 5 VERSION_MINOR = 5
PATCHLEVEL = 0 PATCHLEVEL = 1
INSTALL_PREFIX = /usr/local INSTALL_PREFIX = /usr/local
INSTALL_BINARY_DIR = "$(INSTALL_PREFIX)"/bin INSTALL_BINARY_DIR = "$(INSTALL_PREFIX)"/bin

View file

@ -1,6 +1,11 @@
Quick Start Guide (2024-10-24) Quick Start Guide (2024-10-24)
Taken over by gwh, originally by Egan Ford <egan@sense.net> Taken over by gwh
![screenshot of x50ng](./screenshot.png?raw=true "screenshot of x50ng") ![screenshot of x50ng running newRPL](./screenshot-newRPL.png?raw=true "screenshot of x50ng running newRPL")
== originally by Egan Ford <egan@sense.net> ====================================
NOTE: READ ALL INSTRUCTIONS NOTE: READ ALL INSTRUCTIONS
@ -41,10 +46,10 @@ Start up X11 and use xterm
------------------------------------------------------------------------ ------------------------------------------------------------------------
Download x49gpng source: Download x50ng source:
``` ```
git clone https://github.com/gwenhael-le-moine/x49gpng.git git clone https://github.com/gwenhael-le-moine/x50ng.git
``` ```
------------------------------------------------------------------------ ------------------------------------------------------------------------
@ -52,7 +57,7 @@ git clone https://github.com/gwenhael-le-moine/x49gpng.git
Build: Build:
``` ```
cd x49gpng cd x50ng
make make
``` ```
@ -69,14 +74,14 @@ make install
Run: Run:
``` ```
./dist/x49gpng ./dist/x50ng
``` ```
When installed, there should be an applications menu entry to run x49gpng. When installed, there should be an applications menu entry to run x50ng.
Installing also enables running it from the terminal in any directory: Installing also enables running it from the terminal in any directory:
``` ```
x49gpng x50ng
``` ```
------------------------------------------------------------------------ ------------------------------------------------------------------------
@ -87,7 +92,7 @@ On the first launch, the calculator will be missing a firmware, forcing
the bootloader to complain and demand a fresh one. the bootloader to complain and demand a fresh one.
HP's official firmwares can be found at e.g.: HP's official firmwares can be found at e.g.:
https://www.hpcalc.org/hp49/pc/rom/ https://www.hpcalc.org/hp49/pc/rom/
Some of the most popular of these are also included in x49gpng's source Some of the most popular of these are also included in x50ng's source
directory. directory.
Alternatively, the most up-to-date version of NewRPL can be found at: Alternatively, the most up-to-date version of NewRPL can be found at:
https://hpgcc3.org/downloads/newrplfw.bin https://hpgcc3.org/downloads/newrplfw.bin
@ -156,22 +161,22 @@ Start Over:
* clean slate? * clean slate?
``` ```
rm -r ~/.config/x49gpng/ rm -r ~/.config/x50ng/
``` ```
* soft reset only? * soft reset only?
With x49gpng running, press F12, or right click on the screen and select With x50ng running, press F12, or right click on the screen and select
"Reset" from the menu. "Reset" from the menu.
------------------------------------------------------------------------ ------------------------------------------------------------------------
Debugging with x49gpng Debugging with x50ng
There is a GDB interface for debugging ARM programs, e.g. HPGCC2/3 There is a GDB interface for debugging ARM programs, e.g. HPGCC2/3
applications or replacement firmwares. To use it, start x49gpng from a applications or replacement firmwares. To use it, start x50ng from a
terminal with the -d option, and start arm-none-eabi-gdb with an terminal with the -d option, and start arm-none-eabi-gdb with an
appropriate ELF file in another terminal. To connect to x49gpng, type in appropriate ELF file in another terminal. To connect to x50ng, type in
the GDB console: the GDB console:
``` ```

32
dist/x50ng.scd vendored
View file

@ -1,22 +1,22 @@
X49GPNG(1) X50NG(1)
# NAME # NAME
x49gpng — Emulator for HP 49g+ / 50g calculators x50ng — Emulator for HP 49g+ / 50g calculators
# SYNOPSIS # SYNOPSIS
*x49gpng* <options> *x50ng* <options>
# DESCRIPTION # DESCRIPTION
*x49gpng* is an emulator capable of running any software written for the HP 49g+ and HP 50g calculators, including ARM programs or even custom firmware. It achieves this by using a modified version of QEMU to emulate the ARM hardware based around the Samsung S3C2410 chip. *x50ng* is an emulator capable of running any software written for the HP 49g+ and HP 50g calculators, including ARM programs or even custom firmware. It achieves this by using a modified version of QEMU to emulate the ARM hardware based around the Samsung S3C2410 chip.
## Input ## Input
For mouse input, the keys shown in the window can be interacted with; left-clicking on one holds it down for as long as the mouse button is down, right-clicking on one holds it down until any key is left-clicked. For mouse input, the keys shown in the window can be interacted with; left-clicking on one holds it down for as long as the mouse button is down, right-clicking on one holds it down until any key is left-clicked.
Another method of interacting with the calculator is through a physical keyboard. _A-Z_, _0-9_, _F1-F6_, _cursor keys_, _'_, _Backspace_, _^_, _+_, _-_, _\*_, _/_, _._, _Space_, _Enter_ correspond to their sensible calculator counterparts. In addition, _Delete_ acts as extra Backspace key, _,_ acts as extra decimal separator key, _Shift_ presses the Leftshift key (green on the 49g+, white on the 50g), _Control_ presses the Rightshift key (red on the 49g+, orange on the 50g), _Tab+ presses the Alpha key (yellow on the 49g+ and 50g), and _Escape_ presses the On key. Note that in order to allow multiple-key combinations involving e.g. _Shift+ without surprises, such as pressing _Shift-8_ on a US QWERTY keyboard producing the key sequence “Leftshift-hold multiply”, *x49gpng* ignores all keyboard modifier states except NumLock. Because that may make certain virtual keys inaccessible to a laptop keyboard without a numpad, there are certain additional key definitions to support at least some common keyboard layouts: Another method of interacting with the calculator is through a physical keyboard. _A-Z_, _0-9_, _F1-F6_, _cursor keys_, _'_, _Backspace_, _^_, _+_, _-_, _\*_, _/_, _._, _Space_, _Enter_ correspond to their sensible calculator counterparts. In addition, _Delete_ acts as extra Backspace key, _,_ acts as extra decimal separator key, _Shift_ presses the Leftshift key (green on the 49g+, white on the 50g), _Control_ presses the Rightshift key (red on the 49g+, orange on the 50g), _Tab+ presses the Alpha key (yellow on the 49g+ and 50g), and _Escape_ presses the On key. Note that in order to allow multiple-key combinations involving e.g. _Shift+ without surprises, such as pressing _Shift-8_ on a US QWERTY keyboard producing the key sequence “Leftshift-hold multiply”, *x50ng* ignores all keyboard modifier states except NumLock. Because that may make certain virtual keys inaccessible to a laptop keyboard without a numpad, there are certain additional key definitions to support at least some common keyboard layouts:
US, UK, International QWERTY: _\\_ acts as \* key, _=_ acts as + key. US, UK, International QWERTY: _\\_ acts as \* key, _=_ acts as + key.
@ -24,26 +24,26 @@ German QWERTZ: _#_ acts as \* key, _ß_ acts as / key.
(Further suggestions are welcome.) These additional key definitions do not need their respective layouts to work, so e.g. _\\_ will act as \* on any keyboard that has it as an unshifted key. (Further suggestions are welcome.) These additional key definitions do not need their respective layouts to work, so e.g. _\\_ will act as \* on any keyboard that has it as an unshifted key.
Pressing physical keys and clicking on virtual ones can be freely combined. Right-clicked keys are released when no keys are held down by the left mouse button or physical keys anymore. To avoid stuck keys, *x49gpng* forcibly releases all keys when losing focus. Pressing physical keys and clicking on virtual ones can be freely combined. Right-clicked keys are released when no keys are held down by the left mouse button or physical keys anymore. To avoid stuck keys, *x50ng* forcibly releases all keys when losing focus.
There are more remaining miscellaneous key definitions: There are more remaining miscellaneous key definitions:
- _F7_ or _F10_ closes *x49gpng* and saves the configuration, CPU registers, hardware registers, and memory contents to their respective files; - _F7_ or _F10_ closes *x50ng* and saves the configuration, CPU registers, hardware registers, and memory contents to their respective files;
- _F12_ resets the calculator, like inserting a paperclip into the tiny hole at the back of the real device or removing all of its power sources (batteries, USB) would; - _F12_ resets the calculator, like inserting a paperclip into the tiny hole at the back of the real device or removing all of its power sources (batteries, USB) would;
- _Menu_ opens a popup menu granting access to several emulator control items. This popup menu can also be opened by right-clicking on the screen area. - _Menu_ opens a popup menu granting access to several emulator control items. This popup menu can also be opened by right-clicking on the screen area.
## The popup menu ## The popup menu
The first group of items in the popup menu deals with the calculator's SD card. The SD card can either be backed by a directory on the host system (item *Mount SD folder...*; *x49gpng* will simulate a FAT-formatted file system on the fly), or by an image file (item *Mount SD image...*). The former is more convenient for general use, but when debugging a hypothetical replacement firmware's SD driver, the latter variant's accuracy (it allows corrupting the filesystem, for instance) might be more desirable. The virtual SD card can be absent entirely, too (item *Unmount SD*). The first group of items in the popup menu deals with the calculator's SD card. The SD card can either be backed by a directory on the host system (item *Mount SD folder...*; *x50ng* will simulate a FAT-formatted file system on the fly), or by an image file (item *Mount SD image...*). The former is more convenient for general use, but when debugging a hypothetical replacement firmware's SD driver, the latter variant's accuracy (it allows corrupting the filesystem, for instance) might be more desirable. The virtual SD card can be absent entirely, too (item *Unmount SD*).
The second group consists of only one item, and it is only visible when one of the debug options has been used while starting *x49gpng*. Named *Start debugger*, it (re-)starts the GDB remote debugging interface. This is hidden by default because accidental clicks will seemingly freeze the emulator while it waits for an incoming connection. The second group consists of only one item, and it is only visible when one of the debug options has been used while starting *x50ng*. Named *Start debugger*, it (re-)starts the GDB remote debugging interface. This is hidden by default because accidental clicks will seemingly freeze the emulator while it waits for an incoming connection.
The third and final group contains two items: *Reset*, which resets the calculator just like the _F12_ key, and *Quit*, which closes *x49gpng* and saves the configuration, CPU registers, hardware registers, and memory contents to their respective files. This saving step is also performed when *x49gpng* is closed in another way, e.g. pressing _Control-C_ in the controlling terminal. The third and final group contains two items: *Reset*, which resets the calculator just like the _F12_ key, and *Quit*, which closes *x50ng* and saves the configuration, CPU registers, hardware registers, and memory contents to their respective files. This saving step is also performed when *x50ng* is closed in another way, e.g. pressing _Control-C_ in the controlling terminal.
## First launch ## First launch
During the first launch, *x49gpng* generates a new configuration with default values and empty memory. *x49gpng* does not ship with a default firmware, only with the bootloaders for the supported calculators. Hence, the user is required to select a firmware to load into the flash. *x49gpng* will show a file selection window for that task. For the stock firmware HP has always used the file extension “.bin”, any other files (including the update.scp files that typically come with them!) are generally not actual firmware files. During the first launch, *x50ng* generates a new configuration with default values and empty memory. *x50ng* does not ship with a default firmware, only with the bootloaders for the supported calculators. Hence, the user is required to select a firmware to load into the flash. *x50ng* will show a file selection window for that task. For the stock firmware HP has always used the file extension “.bin”, any other files (including the update.scp files that typically come with them!) are generally not actual firmware files.
When the file selection dialog is cancelled or the file could not be read, *x49gpng* creates a flash without firmware; the bootloader will complain and offer ways to correct the situation just like it would on a real device, which include receiving a firmware via USB (currently not available in *x49gpng*, see _Caveats_ below) or loading one from the SD card. Apart from these options, it's also possible to recover from this by exiting *x49gpng* and either delet ing the flash file or using one of the options *-f* and *-F*, causing *x49gpng* to rebuild the flash and ask for a firmware again. When the file selection dialog is cancelled or the file could not be read, *x50ng* creates a flash without firmware; the bootloader will complain and offer ways to correct the situation just like it would on a real device, which include receiving a firmware via USB (currently not available in *x50ng*, see _Caveats_ below) or loading one from the SD card. Apart from these options, it's also possible to recover from this by exiting *x50ng* and either delet ing the flash file or using one of the options *-f* and *-F*, causing *x50ng* to rebuild the flash and ask for a firmware again.
Please consult HP's manual (for their official firmware) or the documentation of the custom firmware (if using one) for an explanation of using the calculator. Please consult HP's manual (for their official firmware) or the documentation of the custom firmware (if using one) for an explanation of using the calculator.
@ -51,7 +51,7 @@ Please consult HP's manual (for their official firmware) or the documentation of
- *-h* *--help* print this message and exit - *-h* *--help* print this message and exit
- *--verbose* print out more information - *--verbose* print out more information
- *--datadir*[=_absolute path_] alternate datadir (default: $XDG_CONFIG_HOME/x49gpng/) - *--datadir*[=_absolute path_] alternate datadir (default: $XDG_CONFIG_HOME/x50ng/)
- *--overwrite-config* force writing <datadir>/config.lua even if it exists - *--overwrite-config* force writing <datadir>/config.lua even if it exists
- *--50g* emulate an HP 50g (default) - *--50g* emulate an HP 50g (default)
- *--49gp* emulate an HP 49g+ - *--49gp* emulate an HP 49g+
@ -67,15 +67,15 @@ Please consult HP's manual (for their official firmware) or the documentation of
# FILES # FILES
All files are located under ~/.config/x49gpng/ All files are located under ~/.config/x50ng/
- *config.lua* - *config.lua*
The general configuration file of *x49gpng*. Content reflecting default values (as printed by running *x49gpng --print-config*): The general configuration file of *x50ng*. Content reflecting default values (as printed by running *x50ng --print-config*):
``` ```
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- Configuration file for x49gpng -- Configuration file for x50ng
-- This is a comment -- This is a comment
name = "HP 50g" -- this customize the title of the window name = "HP 50g" -- this customize the title of the window
model = "50g" -- possible values: "49gp", "50g". Changes the colors and the bootloader looked for when (re-)flashing model = "50g" -- possible values: "49gp", "50g". Changes the colors and the bootloader looked for when (re-)flashing

BIN
screenshot-newRPL.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View file

@ -609,8 +609,8 @@ static inline void x50ng_set_key_state( x49gp_t* x49gp, const x49gp_ui_key_t* ke
else else
s3c2410_io_port_f_set_bit( x49gp, key->eint, state ); s3c2410_io_port_f_set_bit( x49gp, key->eint, state );
} }
#define X49GPNG_PRESS_KEY( x49gp, key ) x50ng_set_key_state( x49gp, key, true ) #define X50NG_PRESS_KEY( x49gp, key ) x50ng_set_key_state( x49gp, key, true )
#define X49GPNG_RELEASE_KEY( x49gp, key ) x50ng_set_key_state( x49gp, key, false ) #define X50NG_RELEASE_KEY( x49gp, key ) x50ng_set_key_state( x49gp, key, false )
static void ui_release_button( x49gp_ui_button_t* button ) static void ui_release_button( x49gp_ui_button_t* button )
{ {
@ -629,7 +629,7 @@ static void ui_release_button( x49gp_ui_button_t* button )
gtk_style_context_remove_class( gtk_widget_get_style_context( button->button ), "key-down" ); gtk_style_context_remove_class( gtk_widget_get_style_context( button->button ), "key-down" );
#endif #endif
X49GPNG_RELEASE_KEY( x49gp, key ); X50NG_RELEASE_KEY( x49gp, key );
} }
static bool ui_press_button( x49gp_ui_button_t* button, bool hold ) static bool ui_press_button( x49gp_ui_button_t* button, bool hold )
@ -654,7 +654,7 @@ static bool ui_press_button( x49gp_ui_button_t* button, bool hold )
gtk_style_context_add_class( gtk_widget_get_style_context( button->button ), "key-down" ); gtk_style_context_add_class( gtk_widget_get_style_context( button->button ), "key-down" );
#endif #endif
X49GPNG_RELEASE_KEY( x49gp, key ); X50NG_RELEASE_KEY( x49gp, key );
return GDK_EVENT_STOP; return GDK_EVENT_STOP;
} }
@ -671,7 +671,7 @@ static bool react_to_button_press( GtkWidget* widget, GdkEventButton* event, gpo
if ( !ui_press_button( button, event->button == 3 ) ) if ( !ui_press_button( button, event->button == 3 ) )
return GDK_EVENT_PROPAGATE; return GDK_EVENT_PROPAGATE;
X49GPNG_PRESS_KEY( x49gp, key ); X50NG_PRESS_KEY( x49gp, key );
return GDK_EVENT_STOP; return GDK_EVENT_STOP;
} }
@ -1036,6 +1036,207 @@ static bool react_to_key_event( GtkWidget* widget, GdkEventKey* event, gpointer
return GDK_EVENT_STOP; return GDK_EVENT_STOP;
} }
static void x50g_string_to_keys_sequence( const char* input )
{
for ( int i = 0; i < strlen( input ); i++ ) {
switch ( input[ i ] ) {
case '0':
fprintf( stderr, "%c", '0' );
break;
case '1':
fprintf( stderr, "%c", '1' );
break;
case '2':
fprintf( stderr, "%c", '2' );
break;
case '3':
fprintf( stderr, "%c", '3' );
break;
case '4':
fprintf( stderr, "%c", '4' );
break;
case '5':
fprintf( stderr, "%c", '5' );
break;
case '6':
fprintf( stderr, "%c", '6' );
break;
case '7':
fprintf( stderr, "%c", '7' );
break;
case '8':
fprintf( stderr, "%c", '8' );
break;
case '9':
fprintf( stderr, "%c", '9' );
break;
case 'a':
fprintf( stderr, "%c", 'a' );
break;
case 'b':
fprintf( stderr, "%c", 'b' );
break;
case 'c':
fprintf( stderr, "%c", 'c' );
break;
case 'd':
fprintf( stderr, "%c", 'd' );
break;
case 'e':
fprintf( stderr, "%c", 'e' );
break;
case 'f':
fprintf( stderr, "%c", 'f' );
break;
case 'g':
fprintf( stderr, "%c", 'g' );
break;
case 'h':
fprintf( stderr, "%c", 'h' );
break;
case 'i':
fprintf( stderr, "%c", 'i' );
break;
case 'j':
fprintf( stderr, "%c", 'j' );
break;
case 'k':
fprintf( stderr, "%c", 'k' );
break;
case 'l':
fprintf( stderr, "%c", 'l' );
break;
case 'm':
fprintf( stderr, "%c", 'm' );
break;
case 'n':
fprintf( stderr, "%c", 'n' );
break;
case 'o':
fprintf( stderr, "%c", 'o' );
break;
case 'p':
fprintf( stderr, "%c", 'p' );
break;
case 'q':
fprintf( stderr, "%c", 'q' );
break;
case 'r':
fprintf( stderr, "%c", 'r' );
break;
case 's':
fprintf( stderr, "%c", 's' );
break;
case 't':
fprintf( stderr, "%c", 't' );
break;
case 'u':
fprintf( stderr, "%c", 'u' );
break;
case 'v':
fprintf( stderr, "%c", 'v' );
break;
case 'w':
fprintf( stderr, "%c", 'w' );
break;
case 'x':
fprintf( stderr, "%c", 'x' );
break;
case 'y':
fprintf( stderr, "%c", 'y' );
break;
case 'z':
fprintf( stderr, "%c", 'z' );
break;
case 'A':
fprintf( stderr, "%c", 'A' );
break;
case 'B':
fprintf( stderr, "%c", 'B' );
break;
case 'C':
fprintf( stderr, "%c", 'C' );
break;
case 'D':
fprintf( stderr, "%c", 'D' );
break;
case 'E':
fprintf( stderr, "%c", 'E' );
break;
case 'F':
fprintf( stderr, "%c", 'F' );
break;
case 'G':
fprintf( stderr, "%c", 'G' );
break;
case 'H':
fprintf( stderr, "%c", 'H' );
break;
case 'I':
fprintf( stderr, "%c", 'I' );
break;
case 'J':
fprintf( stderr, "%c", 'J' );
break;
case 'K':
fprintf( stderr, "%c", 'K' );
break;
case 'L':
fprintf( stderr, "%c", 'L' );
break;
case 'M':
fprintf( stderr, "%c", 'M' );
break;
case 'N':
fprintf( stderr, "%c", 'N' );
break;
case 'O':
fprintf( stderr, "%c", 'O' );
break;
case 'P':
fprintf( stderr, "%c", 'P' );
break;
case 'Q':
fprintf( stderr, "%c", 'Q' );
break;
case 'R':
fprintf( stderr, "%c", 'R' );
break;
case 'S':
fprintf( stderr, "%c", 'S' );
break;
case 'T':
fprintf( stderr, "%c", 'T' );
break;
case 'U':
fprintf( stderr, "%c", 'U' );
break;
case 'V':
fprintf( stderr, "%c", 'V' );
break;
case 'W':
fprintf( stderr, "%c", 'W' );
break;
case 'X':
fprintf( stderr, "%c", 'X' );
break;
case 'Y':
fprintf( stderr, "%c", 'Y' );
break;
case 'Z':
fprintf( stderr, "%c", 'Z' );
break;
default:
fprintf( stderr, "<unknown: %c>", input[ i ] );
}
}
fprintf( stderr, "\n" );
}
#if GTK_MAJOR_VERSION == 3 #if GTK_MAJOR_VERSION == 3
static bool react_to_display_click( GtkWidget* widget, GdkEventButton* event, gpointer user_data ) static bool react_to_display_click( GtkWidget* widget, GdkEventButton* event, gpointer user_data )
{ {
@ -1062,6 +1263,9 @@ static bool react_to_display_click( GtkWidget* widget, GdkEventButton* event, gp
GtkClipboard* clip = gtk_clipboard_get( GDK_SELECTION_CLIPBOARD ); GtkClipboard* clip = gtk_clipboard_get( GDK_SELECTION_CLIPBOARD );
gchar* text = gtk_clipboard_wait_for_text( clip ); gchar* text = gtk_clipboard_wait_for_text( clip );
fprintf( stderr, "clipboard: %s\n", text ); fprintf( stderr, "clipboard: %s\n", text );
x50g_string_to_keys_sequence( text );
return GDK_EVENT_STOP; return GDK_EVENT_STOP;
case 3: // right click case 3: // right click
# if GTK_MAJOR_VERSION == 3 # if GTK_MAJOR_VERSION == 3