1
0
Fork 0
forked from Miroirs/x49gp

Compare commits

...

3 commits

Author SHA1 Message Date
Gwenhael Le Moine
347d61ced9
missing includes 2024-10-23 14:26:32 +02:00
Gwenhael Le Moine
f30edab58c
new is a reserved word 2024-10-23 14:26:15 +02:00
Gwenhael Le Moine
b5f6fbe716
select faceplate and name thru args instead of config file
Added --50g --50g-newrpl --49gp --49gp-newrpl and --name= args
Remove [gui] section from config file
2024-10-23 14:24:46 +02:00
8 changed files with 276 additions and 219 deletions

View file

@ -143,7 +143,8 @@ SRCS = ./src/main.c \
./src/tiny_font.c \
./src/symbol.c \
./src/gdbstub.c \
./src/block.c
./src/block.c \
./src/options.c
OBJS = $(SRCS:.c=.o)

41
dist/x49gpng.man.in vendored
View file

@ -142,10 +142,7 @@ 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.
.Sh OPTIONS
.Bl -tag -width indent
.It Fl d Ns Oo Ns = Ns Ar port Oc , Fl Fl debug Ns Oo Ns = Ns Ar port Oc
Enable the GDB remote debugging interface on the specified port (default 1234) and start the interface immediately. When used multiple times, the last explicitly specified port wins. If the connection is closed before
.Nm
is shut down, then the interface can be restarted from the popup menu.
.It Fl D Ns Oo Ns = Ns Ar port Oc , Fl Fl enable-debug Ns Oo Ns = Ns Ar port Oc
Same as
.Fl d ,
@ -155,6 +152,12 @@ the last explicitly specified port will still win, and the GDB interface will be
.Do Nm
.Fl D Dc
when the possibility for spontaneous debug sessions exists.
.It Fl d , Fl Fl debug
Enable the GDB remote debugging interface on the specified port (default 1234) and start the interface immediately. When used multiple times, the last explicitly specified port wins. If the connection is closed before
.Nm
is shut down, then the interface can be restarted from the popup menu.
.It Fl f Ns Oo Ns = Ns Ar firmware Oc , Fl Fl reflash Ns Oo Ns = Ns Ar firmware Oc
Rebuild the flash. If the firmware is not specified,
.Nm
@ -163,15 +166,30 @@ will ask for one through a file selection dialog window like on the first launch
for safety reasons: the firmware may have changed, so the code at the location where
.Nm
was stopped previously could be entirely different from the code at that location afterwards; a reboot ensures an orderly reinitialization of the operating system.
.It Fl F Ns Oo Ns = Ns Ar firmware Oc , Fl Fl reflash-full Ns Oo Ns = Ns Ar firmware Oc
.It Fl F , Fl Fl reflash-full
Same as
.Fl f ,
but erase the area beyond the firmware too. This has the same effect as deleting the flash, but with the added benefit of being able to specify the firmware on the command-line for automation in scripts.
.It Fl r , Fl Fl reboot
Reboot the calculator instead of starting from the state saved in the configuration file.
.It Fl h , Fl Fl help
Print a compact help message and exit.
.It Ar config
.It Fl Fl 50g
show HP 50g faceplate (default)
.It Fl Fl 50g-newrpl
show HP 50g faceplate with newRPL labels
.It Fl Fl 49gp
show HP 49g+ faceplate
.It Fl Fl 49gp-newrpl
show HP 49g+ faceplate with newRPL labels
.It Fl c Ns Oo Ns = Ns Ar config Oc , Fl Fl config Ns Oo Ns = Ns Ar config Oc
Use
.Ar config
as the configuration file instead of the default one. See below for details on the format; if the file does not exist, it will be created with default values.
@ -195,17 +213,6 @@ in the sections
which allow changing the filename of the files where the state of the respective memory is held. These can be absolute paths, or paths relative to the location of the configuration file (in the simplest case, only a filename). Any files that do not exist will be created with appropriate size and placeholder content. For
.Em s3c2410-sdi ,
the empty string is accepted as a special value for no inserted SD card.
.Pp
Finally, the
.Em gui
section contains the keys
.Em name ,
which specifies the window title (possibly useful when multiple different instances are present), and
.Em type ,
which specifies the type of the calculator (accepted values are
.Sy hp49g+
and
.Sy hp50g ) .
.It Sy flash
The default name of the file backing the flash memory; required size: 2 MiB. If this file does not exist or is too small, the calculator type's appropriate bootloader will be copied into the first 16 KiB. Do NOT simply put a firmware file here, it will not work. Just use the builtin firmware installation mechanism instead.
.It Sy sram

View file

@ -47,33 +47,33 @@ struct list_head {
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add( struct list_head* new, struct list_head* prev, struct list_head* next )
static inline void __list_add( struct list_head* new_entry, struct list_head* prev, struct list_head* next )
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
next->prev = new_entry;
new_entry->next = next;
new_entry->prev = prev;
prev->next = new_entry;
}
/**
* list_add - add a new entry
* @new: new entry to be added
* @new_entry: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void list_add( struct list_head* new, struct list_head* head ) { __list_add( new, head, head->next ); }
static inline void list_add( struct list_head* new_entry, struct list_head* head ) { __list_add( new_entry, head, head->next ); }
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @new_entry: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail( struct list_head* new, struct list_head* head ) { __list_add( new, head->prev, head ); }
static inline void list_add_tail( struct list_head* new_entry, struct list_head* head ) { __list_add( new_entry, head->prev, head ); }
/*
* Delete a list entry by making the prev/next entries

View file

@ -24,18 +24,10 @@
#include "x49gp_ui.h"
#include "s3c2410.h"
#include "x49gp_timer.h"
#include "gdbstub.h"
#include "options.h"
#ifndef VERSION_MAJOR
# define VERSION_MAJOR 0
#endif
#ifndef VERSION_MINOR
# define VERSION_MINOR 0
#endif
#ifndef PATCHLEVEL
# define PATCHLEVEL 0
#endif
extern struct options opt;
static x49gp_t* x49gp;
@ -48,7 +40,7 @@ uint8_t* phys_ram_base;
int phys_ram_size;
ram_addr_t ram_size = 0x80000; // LD ???
/* vl.c */
/* for qemu-git */
int singlestep;
#if !( defined( __APPLE__ ) || defined( _POSIX_C_SOURCE ) && !defined( __sun__ ) )
@ -125,11 +117,11 @@ void* qemu_vmalloc( size_t size )
uint32_t do_arm_semihosting( CPUState* env )
{
uint32_t number;
if ( env->thumb ) {
if ( env->thumb )
number = lduw_code( env->regs[ 15 ] - 2 ) & 0xff;
} else {
else
number = ldl_code( env->regs[ 15 ] - 4 ) & 0xffffff;
}
switch ( number ) {
case SWI_Breakpoint:
break;
@ -181,9 +173,9 @@ void x49gp_set_idle( x49gp_t* x49gp, x49gp_arm_idle_t idle )
x49gp->arm_idle = idle;
if ( x49gp->arm_idle == X49GP_ARM_RUN ) {
if ( x49gp->arm_idle == X49GP_ARM_RUN )
x49gp->env->halted = 0;
} else {
else {
x49gp->env->halted = 1;
cpu_exit( x49gp->env );
}
@ -228,131 +220,6 @@ void x49gp_lcd_timer( void* data )
x49gp_mod_timer( x49gp->lcd_timer, expires );
}
/***********/
/* OPTIONS */
/***********/
struct options {
char* config;
int debug_port;
int start_debugger;
char* firmware;
x49gp_reinit_t reinit;
int more_options;
};
struct options opt;
static void config_init( char* progname, int argc, char* argv[] )
{
int option_index;
int c = '?';
opt.config = NULL;
opt.debug_port = 0;
opt.start_debugger = false;
opt.reinit = X49GP_REINIT_NONE;
opt.firmware = NULL;
const char* optstring = "hrc:D:df:F";
struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
{"config", required_argument, NULL, 'c'},
{"enable-debug", required_argument, NULL, 'D'},
{"debug", no_argument, NULL, 'd'},
{"reflash", required_argument, NULL, 'f'},
{"reflash-full", no_argument, NULL, 'F'},
{"reboot", no_argument, NULL, 'r'},
{0, 0, 0, 0 }
};
while ( c != EOF ) {
c = getopt_long( argc, argv, optstring, long_options, &option_index );
switch ( c ) {
case 'h':
fprintf( stderr,
"%s %i.%i.%i Emulator for HP 49G+ / 50G calculators\n"
"Usage: %s [<options>]\n"
"Valid options:\n"
" -c --config[=<filename>] alternate config file\n"
" -D --enable-debug[=<port>] enable the debugger interface\n"
" (default port: %u)\n"
" -d --debug use along -D to also start the debugger immediately\n"
" -f --reflash[=firmware] rebuild the flash using the supplied firmware\n"
" (default: select one interactively)\n"
" (implies -r for safety reasons)\n"
" -F --reflash-full use along -f to drop the flash contents\n"
" in the area beyond the firmware\n"
" -r --reboot reboot on startup instead of continuing from the\n"
" saved state in the config file\n"
" -h --help print this message and exit\n"
"The config file is formatted as INI file and contains the settings for which\n"
" persistence makes sense, like calculator model, CPU registers, etc.\n"
"If the config file is omitted, ~/.config/%s/config is used.\n"
"Please consult the manual for more details on config file settings.\n",
progname, VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL, progname, DEFAULT_GDBSTUB_PORT, progname );
exit( EXIT_SUCCESS );
break;
case 'r':
if ( opt.reinit < X49GP_REINIT_REBOOT_ONLY )
opt.reinit = X49GP_REINIT_REBOOT_ONLY;
break;
case 'c':
opt.config = strdup( optarg );
break;
case 'D':
{
char* end;
int port;
if ( optarg == NULL && opt.debug_port == 0 )
opt.debug_port = DEFAULT_GDBSTUB_PORT;
port = strtoul( optarg, &end, 0 );
if ( ( end == optarg ) || ( *end != '\0' ) ) {
fprintf( stderr, "Invalid port \"%s\", using default\n", optarg );
if ( opt.debug_port == 0 )
opt.debug_port = DEFAULT_GDBSTUB_PORT;
}
if ( opt.debug_port != 0 && opt.debug_port != DEFAULT_GDBSTUB_PORT )
fprintf( stderr,
"Additional debug port \"%s\" specified, overriding\n",
optarg );
opt.debug_port = port;
}
break;
case 'd':
opt.start_debugger = true;
break;
case 'F':
opt.reinit = X49GP_REINIT_FLASH_FULL;
break;
case 'f':
if ( opt.reinit < X49GP_REINIT_FLASH )
opt.reinit = X49GP_REINIT_FLASH;
if ( opt.firmware != NULL )
fprintf( stderr,
"Additional firmware file \"%s\" specified,"
" overriding\n",
optarg );
opt.firmware = optarg;
break;
default:
break;
}
}
}
/************/
/* \OPTIONS */
/************/
void ui_sighnd( int sig )
{
switch ( sig ) {
@ -367,12 +234,8 @@ void ui_sighnd( int sig )
int main( int argc, char** argv )
{
char *progname, *progpath;
int error;
const char* home;
progname = g_path_get_basename( argv[ 0 ] );
progpath = g_path_get_dirname( argv[ 0 ] );
char* progname = g_path_get_basename( argv[ 0 ] );
char* progpath = g_path_get_dirname( argv[ 0 ] );
gtk_init( &argc, &argv );
@ -396,7 +259,6 @@ int main( int argc, char** argv )
x49gp->progname = progname;
x49gp->progpath = progpath;
x49gp->clk_tck = sysconf( _SC_CLK_TCK );
x49gp->emulator_fclk = 75000000;
x49gp->PCLK_ratio = 4;
x49gp->PCLK = 75000000 / 4;
@ -416,34 +278,23 @@ int main( int argc, char** argv )
x49gp_ui_init( x49gp );
x49gp_s3c2410_arm_init( x49gp );
x49gp_flash_init( x49gp );
x49gp_sram_init( x49gp );
x49gp_s3c2410_init( x49gp );
if ( x49gp_modules_init( x49gp ) ) {
if ( x49gp_modules_init( x49gp ) )
exit( EXIT_FAILURE );
}
if ( opt.config == NULL ) {
char config_dir[ strlen( progname ) + 9 ];
home = g_get_home_dir();
sprintf( config_dir, ".config/%s", progname );
opt.config = g_build_filename( home, config_dir, "config", NULL );
}
x49gp->basename = g_path_get_dirname( opt.config );
x49gp->debug_port = opt.debug_port;
x49gp->startup_reinit = opt.reinit;
x49gp->firmware = opt.firmware;
error = x49gp_modules_load( x49gp, opt.config );
int error = x49gp_modules_load( x49gp, opt.config );
if ( error || opt.reinit >= X49GP_REINIT_REBOOT_ONLY ) {
if ( error && error != -EAGAIN ) {
if ( error && error != -EAGAIN )
exit( EXIT_FAILURE );
}
x49gp_modules_reset( x49gp, X49GP_RESET_POWER_ON );
}
// x49gp_modules_reset(x49gp, X49GP_RESET_POWER_ON);
@ -471,7 +322,7 @@ int main( int argc, char** argv )
x49gp_modules_save( x49gp, opt.config );
x49gp_modules_exit( x49gp );
#if 0
#if false
printf("ClkTicks: %lu\n", ARMul_Time(x49gp->arm));
printf("D TLB: hit0 %lu, hit1 %lu, search %lu (%lu), walk %lu\n",
x49gp->mmu->dTLB.hit0, x49gp->mmu->dTLB.hit1,

170
src/options.c Normal file
View file

@ -0,0 +1,170 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <getopt.h>
#include <glib.h>
#include "options.h"
#include "gdbstub.h"
struct options opt;
void config_init( char* progname, int argc, char* argv[] )
{
int option_index;
int c = '?';
bool do_enable_debugger = false;
bool do_start_debugger = false;
bool do_reflash = false;
bool do_reflash_full = false;
opt.config = NULL;
opt.debug_port = 0;
opt.start_debugger = false;
opt.reinit = X49GP_REINIT_NONE;
opt.firmware = NULL;
opt.model = MODEL_50G;
opt.name = NULL;
const char* optstring = "hrc:D:df:Fn:";
struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
{"config", required_argument, NULL, 'c'},
{"enable-debug", required_argument, NULL, 'D'},
{"debug", no_argument, NULL, 'd'},
{"reflash", required_argument, NULL, 'f'},
{"reflash-full", no_argument, NULL, 'F'},
{"reboot", no_argument, NULL, 'r'},
{"50g", no_argument, NULL, 506},
{"50g-newrpl", no_argument, NULL, 507},
{"49gp", no_argument, NULL, 496},
{"49gp-newrpl", no_argument, NULL, 497},
{"name", required_argument, NULL, 'n'},
{0, 0, 0, 0 }
};
while ( c != EOF ) {
c = getopt_long( argc, argv, optstring, long_options, &option_index );
switch ( c ) {
case 'h':
fprintf( stderr,
"%s %i.%i.%i Emulator for HP 49G+ / 50G calculators\n"
"Usage: %s [<options>]\n"
"Valid options:\n"
" -h --help print this message and exit\n"
" -c --config[=<filename>] alternate config file\n"
" --50g show HP 50g faceplate (default)\n"
" --50g-newrpl show HP 50g faceplate with newRPL labels\n"
" --49gp show HP 49g+ faceplate\n"
" --49gp-newrpl show HP 49g+ faceplate with newRPL labels\n"
" -n --name[=<name>] set alternate UI name\n"
" -D --enable-debug[=<port>] enable the debugger interface\n"
" (default port: %u)\n"
" -d --debug use along -D to also start the debugger immediately\n"
" -f --reflash[=firmware] rebuild the flash using the supplied firmware\n"
" (default: select one interactively)\n"
" (implies -r for safety reasons)\n"
" -F --reflash-full use along -f to drop the flash contents\n"
" in the area beyond the firmware\n"
" -r --reboot reboot on startup instead of continuing from the\n"
" saved state in the config file\n"
"The config file is formatted as INI file and contains the settings for which\n"
" persistence makes sense, like calculator model, CPU registers, etc.\n"
"If the config file is omitted, ~/.config/%s/config is used.\n"
"Please consult the manual for more details on config file settings.\n",
progname, VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL, progname, DEFAULT_GDBSTUB_PORT, progname );
exit( EXIT_SUCCESS );
break;
case 'r':
if ( opt.reinit < X49GP_REINIT_REBOOT_ONLY )
opt.reinit = X49GP_REINIT_REBOOT_ONLY;
break;
case 'c':
opt.config = strdup( optarg );
break;
case 'D':
do_enable_debugger = true;
break;
case 'd':
do_start_debugger = true;
break;
case 'f':
do_reflash = true;
break;
case 'F':
do_reflash_full = true;
break;
case 496:
opt.model = MODEL_49GP;
break;
case 497:
opt.model = MODEL_49GP_NEWRPL;
break;
case 506:
opt.model = MODEL_50G;
break;
case 507:
opt.model = MODEL_50G_NEWRPL;
break;
case 'n':
opt.name = strdup( optarg );
break;
default:
break;
}
}
if ( do_enable_debugger ) {
char* end;
int port;
if ( optarg == NULL && opt.debug_port == 0 )
opt.debug_port = DEFAULT_GDBSTUB_PORT;
port = strtoul( optarg, &end, 0 );
if ( ( end == optarg ) || ( *end != '\0' ) ) {
fprintf( stderr, "Invalid port \"%s\", using default\n", optarg );
if ( opt.debug_port == 0 )
opt.debug_port = DEFAULT_GDBSTUB_PORT;
}
if ( opt.debug_port != 0 && opt.debug_port != DEFAULT_GDBSTUB_PORT )
fprintf( stderr,
"Additional debug port \"%s\" specified, overriding\n",
optarg );
opt.debug_port = port;
opt.start_debugger = do_start_debugger;
}
if ( do_reflash ) {
if ( opt.reinit < X49GP_REINIT_FLASH )
opt.reinit = X49GP_REINIT_FLASH;
if ( opt.firmware != NULL )
fprintf( stderr,
"Additional firmware file \"%s\" specified,"
" overriding\n",
optarg );
opt.firmware = optarg;
if ( do_reflash_full )
opt.reinit = X49GP_REINIT_FLASH_FULL;
}
if ( opt.config == NULL ) {
char config_dir[ strlen( progname ) + 9 ];
const char* home = g_get_home_dir();
sprintf( config_dir, ".config/%s", progname );
opt.config = g_build_filename( home, config_dir, "config", NULL );
}
}

36
src/options.h Normal file
View file

@ -0,0 +1,36 @@
#ifndef _CONFIG_H
#define _CONFIG_H 1
#include "x49gp.h"
#ifndef VERSION_MAJOR
# define VERSION_MAJOR 0
#endif
#ifndef VERSION_MINOR
# define VERSION_MINOR 0
#endif
#ifndef PATCHLEVEL
# define PATCHLEVEL 0
#endif
typedef enum { MODEL_49GP = 0, MODEL_49GP_NEWRPL, MODEL_50G, MODEL_50G_NEWRPL } x49gpng_model_t;
struct options {
char* config;
int debug_port;
int start_debugger;
char* firmware;
x49gp_reinit_t reinit;
x49gpng_model_t model;
char* name;
};
extern struct options opt;
/*************/
/* functions */
/*************/
extern void config_init( char* progname, int argc, char* argv[] );
#endif /* !_CONFIG_H */

View file

@ -19,6 +19,7 @@
#include <cairo.h>
#include <gdk/gdkkeysyms.h>
#include "options.h"
#include "x49gp.h"
#include "x49gp_ui.h"
#include "s3c2410.h"
@ -3273,31 +3274,29 @@ static int gui_load( x49gp_module_t* module, GKeyFile* keyfile )
GtkWidget *menu_debug, *menu_reset, *menu_quit;
GError* gerror = NULL;
GdkBitmap* shape;
char* typestr;
char* imagefile;
int fd;
x49gp_module_get_string( module, keyfile, "type", "hp50g", &typestr );
if ( !strcmp( typestr, "hp49g+" ) )
ui->calculator = UI_CALCULATOR_HP49GP;
else if ( !strcmp( typestr, "hp49g+/newrpl" ) )
ui->calculator = UI_CALCULATOR_HP49GP_NEWRPL;
else if ( !strcmp( typestr, "hp50g" ) )
ui->calculator = UI_CALCULATOR_HP50G;
else if ( !strcmp( typestr, "hp50g/newrpl" ) )
switch ( opt.model ) {
case MODEL_50G_NEWRPL:
ui->calculator = UI_CALCULATOR_HP50G_NEWRPL;
else {
fprintf( stderr, "Invalid calculator type, reverting to default\n" );
ui->name = opt.name != NULL ? opt.name : "HP 50g / newRPL";
break;
case MODEL_49GP:
ui->calculator = UI_CALCULATOR_HP49GP;
ui->name = opt.name != NULL ? opt.name : "HP 49g+";
break;
case MODEL_49GP_NEWRPL:
ui->calculator = UI_CALCULATOR_HP49GP_NEWRPL;
ui->name = "opt.name != NULL ? opt.name : HP 49g+ / newRPL";
break;
case MODEL_50G:
default:
ui->calculator = UI_CALCULATOR_HP50G;
ui->name = opt.name != NULL ? opt.name : "HP 50g";
break;
}
x49gp_module_get_string( module, keyfile, "name",
ui->calculator == UI_CALCULATOR_HP49GP ? "HP 49g+"
: ui->calculator == UI_CALCULATOR_HP49GP_NEWRPL ? "HP 49g+ / newRPL"
: ui->calculator == UI_CALCULATOR_HP50G ? "HP 50g"
: "HP 50g / newRPL",
&( ui->name ) );
fd = x49gp_module_open_rodata( module,
ui->calculator == UI_CALCULATOR_HP49GP || ui->calculator == UI_CALCULATOR_HP49GP_NEWRPL
? "hp49g+-cropped.png"
@ -3508,15 +3507,6 @@ static int gui_load( x49gp_module_t* module, GKeyFile* keyfile )
static int gui_save( x49gp_module_t* module, GKeyFile* keyfile )
{
x49gp_ui_t* ui = module->user_data;
x49gp_module_set_string( module, keyfile, "type",
ui->calculator == UI_CALCULATOR_HP49GP ? "hp49g+"
: ui->calculator == UI_CALCULATOR_HP49GP_NEWRPL ? "hp49g+/newrpl"
: ui->calculator == UI_CALCULATOR_HP50G ? "hp50g"
: "hp50g/newrpl" );
x49gp_module_set_string( module, keyfile, "name", ui->name );
return 0;
}

View file

@ -4,9 +4,11 @@
#ifndef _X49GP_TIMER_H
#define _X49GP_TIMER_H 1
#include <stdint.h>
#include <time.h>
#include "list.h"
# include "list.h"
#include "x49gp_types.h"
#define X49GP_TIMER_VIRTUAL 0
#define X49GP_TIMER_REALTIME 1