Skip to content

Commit

Permalink
CORE,M65: ability to use Xemu as tester tool #352
Browse files Browse the repository at this point in the history
CORE: added headless and sleepless mode to run Xemu without any output,
and to run at max speed without trying to sync to emulated target speed.
MEGA65: added -headless and -sleepless CLI options to expose these
features in the MEGA65 emulator.

MEGA65: added -dumpscreen CLI option to dump text screen in form of
ASCII values at exit time. Also an UI menu option to use this promptly.

MEGA65: inject framework (made for -prg etc) is re-worked to use more
precise VIC-IV values of the current screen memory etc.
  • Loading branch information
lgblgblgb committed Jul 16, 2022
1 parent 7f13d77 commit 7ba911b
Show file tree
Hide file tree
Showing 11 changed files with 128 additions and 46 deletions.
3 changes: 3 additions & 0 deletions targets/mega65/configdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ static const struct xemutools_configdef_str_st str_options[] = {
{ "prg", NULL, "Load a PRG file directly into the memory (/w C64/65 auto-detection on load address)", &configdb.prg },
{ "sdimg", SDCARD_NAME, "Override path of SD-image to be used (also see the -virtsd option!)", &configdb.sdimg },
{ "dumpmem", NULL, "Save memory content on exit", &configdb.dumpmem },
{ "dumpscreen", NULL, "Save screen content (ASCII) on exit", &configdb.dumpscreen },
#ifdef XEMU_SNAPSHOT_SUPPORT
{ "snapload", NULL, "Load a snapshot from the given file", &configdb.snapload },
{ "snapsave", NULL, "Save a snapshot into the given file before Xemu would exit", &configdb.snapsave },
Expand All @@ -75,6 +76,8 @@ static const struct xemutools_configdef_str_st str_options[] = {
};

static const struct xemutools_configdef_switch_st switch_options[] = {
{ "headless", "Run in headless mode (for testing!)", &emu_is_headless },
{ "sleepless", "Use maximum emulation speed (for testing!)", &emu_is_sleepless },
{ "cpusinglestep", "Force CPU emulation to do single step emulation (slower!)", &configdb.cpusinglestep },
{ "hdosvirt", "Virtualize HDOS file access functions, but via only traps", &configdb.hdosvirt },
{ "driveled", "Render drive LED at the top right corner of the screen", &configdb.show_drive_led },
Expand Down
1 change: 1 addition & 0 deletions targets/mega65/configdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ struct configdb_st {
char *prg;
char *sdimg;
char *dumpmem;
char *dumpscreen;
#ifdef XEMU_SNAPSHOT_SUPPORT
char *snapload;
char *snapsave;
Expand Down
30 changes: 9 additions & 21 deletions targets/mega65/inject.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* A work-in-progess MEGA65 (Commodore 65 clone origins) emulator
Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
Copyright (C)2016-2021 LGB (Gábor Lénárt) <[email protected]>
Copyright (C)2016-2022 LGB (Gábor Lénárt) <[email protected]>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand All @@ -16,7 +16,6 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */


#include "xemu/emutools.h"
#include "inject.h"
#include "xemu/emutools_files.h"
Expand All @@ -42,16 +41,6 @@ static struct {
static Uint8 *under_ready_p;


static XEMU_INLINE int get_screen_width ( void )
{
// C65 $D031.7 VIC-III:H640 Enable C64 640 horizontal pixels / 80 column mode
// Used to determine if C64 or C65 "power-on" screen
// TODO: this should be revised in the future, as MEGA65 can other means have
// different screens!!!
return (vic_registers[0x31] & 0x80) ? 80 : 40;
}


static void _cbm_screen_write ( Uint8 *p, const char *s )
{
while (*s) {
Expand Down Expand Up @@ -81,7 +70,7 @@ static void prg_inject_callback ( void *unused )
fdc_allow_disk_access(FDC_ALLOW_DISK_ACCESS);
memcpy(main_ram + prg.load_addr, prg.stream, prg.size);
clear_emu_events(); // clear keyboard & co state, ie for C64 mode, probably had MEGA key pressed still
CBM_SCREEN_PRINTF(under_ready_p - get_screen_width() + 7, "<$%04X-$%04X,%d bytes>", prg.load_addr, prg.load_addr + prg.size - 1, prg.size);
CBM_SCREEN_PRINTF(under_ready_p - vic4_query_screen_width() + 7, "<$%04X-$%04X,%d bytes>", prg.load_addr, prg.load_addr + prg.size - 1, prg.size);
if (prg.run_it) {
// We must modify BASIC pointers ... Important to know the C64/C65 differences!
if (prg.c64_mode) {
Expand All @@ -96,7 +85,7 @@ static void prg_inject_callback ( void *unused )
// If program was detected as BASIC (by load-addr) we want to auto-RUN it
CBM_SCREEN_PRINTF(under_ready_p, " ?\"@\":RUN:");
KBD_PRESS_KEY(0x01); // press RETURN
under_ready_p[get_screen_width()] = 0x20; // be sure no "@" (screen code 0) at the trigger position
under_ready_p[vic4_query_screen_width()] = 0x20; // be sure no "@" (screen code 0) at the trigger position
inject_ready_check_status = 100; // go into special mode, to see "@" character printed by PRINT, to release RETURN by that trigger
} else {
// In this case we DO NOT press RETURN for user, as maybe the SYS addr is different, or user does not want this at all!
Expand Down Expand Up @@ -214,15 +203,14 @@ static const Uint8 ready_msg[] = { 0x12, 0x05, 0x01, 0x04, 0x19, 0x2E }; // "REA

static int is_ready_on_screen ( void )
{
int width = get_screen_width();
// TODO: this should be revised in the future, as MEGA65 can other means have
// different screen starting addresses, and not even dependent on the 40/80 column mode!!!
int start = (width == 80) ? 2048 : 1024;
const int width = vic4_query_screen_width();
const int height = vic4_query_screen_height();
Uint8 *start = vic4_query_screen_memory();
// Check every lines of the screen (not the "0th" line, because we need "READY." in the previous line!)
// NOTE: I cannot rely on exact position as different ROMs can have different line position for the "READY." text!
for (int i = 1; i < 23; i++) {
for (int i = 1; i < height - 2; i++) {
// We need this pointer later, to "fake" a command on the screen
under_ready_p = main_ram + start + i * width;
under_ready_p = start + i * width;
// 0XA0 -> cursor is shown, and the READY. in the previous line
if (*under_ready_p == 0xA0 && !memcmp(under_ready_p - width, ready_msg, sizeof ready_msg))
return 1;
Expand All @@ -242,7 +230,7 @@ void inject_ready_check_do ( void )
// This is used to check the @ char printed by our tricky RUN line to see it's time to release RETURN (or just simply clear all the keyboard)
// Also check for 'READY.' if it's still there, run program running maybe cleared the screen and we'll miss '@'!
// TODO: this logic is too error-proon! Consider for some timing only, ie wait some frames after virtually pressing RETURN then release it.
int width = get_screen_width();
int width = vic4_query_screen_width();
if (under_ready_p[width] == 0x00 || memcmp(under_ready_p - width, ready_msg, sizeof ready_msg)) {
inject_ready_check_status = 0;
clear_emu_events(); // reset keyboard state & co
Expand Down
2 changes: 1 addition & 1 deletion targets/mega65/inject.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* A work-in-progess MEGA65 (Commodore-65 clone origins) emulator
Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
Copyright (C)2016-2021 LGB (Gábor Lénárt) <[email protected]>
Copyright (C)2016-2022 LGB (Gábor Lénárt) <[email protected]>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down
18 changes: 18 additions & 0 deletions targets/mega65/mega65.c
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,23 @@ int dump_memory ( const char *fn )
}


int dump_screen ( const char *fn )
{
if (!fn || !*fn)
return 0;
char *text = vic4_textshot();
int retcode = 1;
if (text) {
if (*text)
retcode = xemu_save_file(fn, text, strlen(text), "Cannot dump ASCII screen content into file");
else
retcode = 0;
}
free(text);
return retcode;
}


static void shutdown_callback ( void )
{
// Write out NVRAM if changed!
Expand All @@ -454,6 +471,7 @@ static void shutdown_callback ( void )
cia_dump_state (&cia2);
#if !defined(XEMU_ARCH_HTML)
(void)dump_memory(configdb.dumpmem);
(void)dump_screen(configdb.dumpscreen);
#endif
#ifdef HAS_UARTMON_SUPPORT
uartmon_close();
Expand Down
1 change: 1 addition & 0 deletions targets/mega65/mega65.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ extern int reset_mega65_asked( void );
extern void reset_mega65_cpu_only ( void );

extern int dump_memory ( const char *fn );
extern int dump_screen ( const char *fn );

extern int registered_screenshot_request;
extern Uint8 last_dd00_bits;
Expand Down
38 changes: 20 additions & 18 deletions targets/mega65/ui.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
//#include "xemu/f011_core.h"
#include "dma65.h"
#include "memory_mapper.h"
#include "xemu/basic_text.h"
#include "audio65.h"
#include "vic4.h"
#include "configdb.h"
Expand Down Expand Up @@ -533,16 +532,8 @@ static void ui_emu_info ( void )

static void ui_put_screen_text_into_paste_buffer ( void )
{
char text[8192];
char *result = xemu_cbm_screen_to_text(
text,
sizeof text,
main_ram + ((vic_registers[0x31] & 0x80) ? (vic_registers[0x18] & 0xE0) << 6 : (vic_registers[0x18] & 0xF0) << 6), // pointer to screen RAM, try to audo-tected: FIXME: works only in bank0!
(vic_registers[0x31] & 0x80) ? 80 : 40, // number of columns, try to auto-detect it
25, // number of rows
(vic_registers[0x18] & 2) // lowercase font? try to auto-detect by checking selected address chargen addr, LSB
);
if (result == NULL)
char *result = vic4_textshot();
if (!result)
return;
if (*result) {
if (SDL_SetClipboardText(result))
Expand All @@ -551,6 +542,22 @@ static void ui_put_screen_text_into_paste_buffer ( void )
OSD(-1, -1, "Copied to OS paste buffer.");
} else
INFO_WINDOW("Screen is empty, nothing to capture.");
free(result);
}

static void ui_put_screen_text_into_file ( void )
{
char fnbuf[PATH_MAX + 1];
_check_file_selection_default_override(last_used_dump_directory);
if (!xemugui_file_selector(
XEMUGUI_FSEL_SAVE | XEMUGUI_FSEL_FLAG_STORE_DIR,
"Dump screen ASCII content into file",
last_used_dump_directory,
fnbuf,
sizeof fnbuf
)) {
dump_screen(fnbuf);
}
}

static void ui_put_paste_buffer_into_screen_text ( void )
Expand All @@ -563,13 +570,7 @@ static void ui_put_paste_buffer_into_screen_text ( void )
t2++;
if (!*t2)
goto no_clipboard;
xemu_cbm_text_to_screen(
main_ram + ((vic_registers[0x31] & 0x80) ? (vic_registers[0x18] & 0xE0) << 6 : (vic_registers[0x18] & 0xF0) << 6), // pointer to screen RAM, try to audo-tected: FIXME: works only in bank0!
(vic_registers[0x31] & 0x80) ? 80 : 40, // number of columns, try to auto-detect it
25, // number of rows
t2, // text buffer as input
(vic_registers[0x18] & 2) // lowercase font? try to auto-detect by checking selected address chargen addr, LSB
);
vic4_textinsert(t2);
SDL_free(t);
return;
no_clipboard:
Expand Down Expand Up @@ -687,6 +688,7 @@ static const struct menu_st menu_display[] = {
{ "Screenshot", XEMUGUI_MENUID_CALLABLE, xemugui_cb_set_integer_to_one, &registered_screenshot_request },
#endif
{ "Screen to OS paste buffer", XEMUGUI_MENUID_CALLABLE, xemugui_cb_call_user_data, ui_put_screen_text_into_paste_buffer },
{ "Screen to ASCII file", XEMUGUI_MENUID_CALLABLE, xemugui_cb_call_user_data, ui_put_screen_text_into_file },
{ "OS paste buffer to screen", XEMUGUI_MENUID_CALLABLE, xemugui_cb_call_user_data, ui_put_paste_buffer_into_screen_text },
{ NULL }
};
Expand Down
49 changes: 49 additions & 0 deletions targets/mega65/vic4.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "xemu/f011_core.h"
#include "xemu/emutools_files.h"
#include "io_mapper.h"
#include "xemu/basic_text.h"


#define SPRITE_SPRITE_COLLISION
Expand Down Expand Up @@ -1570,6 +1571,54 @@ int vic4_render_scanline ( void )
}


/* --- AUX FUNCTIONS FOR NON-ESSENTIAL THINGS (query current text screen parameters for other components, put/get screen content as ASCII) --- */


int vic4_query_screen_width ( void )
{
return REG_H640 ? 80 : 40;
}


int vic4_query_screen_height ( void )
{
return EFFECTIVE_V400 ? 50 : 25;
}


Uint8 *vic4_query_screen_memory ( void )
{
return main_ram + (SCREEN_ADDR & 0x7FFFF);
}


char *vic4_textshot ( void )
{
char text[8192];
char *result = xemu_cbm_screen_to_text(
text,
sizeof text,
vic4_query_screen_memory(),
vic4_query_screen_width(),
vic4_query_screen_height(),
(vic_registers[0x18] & 2) // lowercase font? try to auto-detect by checking selected address chargen addr, LSB
);
return result ? xemu_strdup(result) : NULL;
}


int vic4_textinsert ( const char *text )
{
return xemu_cbm_text_to_screen(
vic4_query_screen_memory(),
vic4_query_screen_width(),
vic4_query_screen_height(),
text, // text buffer as input
(vic_registers[0x18] & 2) // lowercase font? try to auto-detect by checking selected address chargen addr, LSB
);
}


/* --- SNAPSHOT RELATED --- */


Expand Down
8 changes: 7 additions & 1 deletion targets/mega65/vic4.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,13 @@ extern void vic_write_reg ( unsigned int addr, Uint8 data );
extern Uint8 vic_read_reg ( unsigned int addr );
extern int vic4_render_scanline ( void );
extern void vic4_open_frame_access ( void );
extern void vic4_close_frame_access (void );
extern void vic4_close_frame_access ( void );

extern Uint8*vic4_query_screen_memory ( void );
extern int vic4_query_screen_width ( void );
extern int vic4_query_screen_height ( void );
extern char *vic4_textshot ( void );
extern int vic4_textinsert ( const char *text );

#ifdef XEMU_SNAPSHOT_SUPPORT
#include "xemu/emutools_snapshot.h"
Expand Down
22 changes: 17 additions & 5 deletions xemu/emutools.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ Uint32 *sdl_pixel_buffer = NULL;
Uint32 *xemu_frame_pixel_access_p = NULL;
int texture_x_size_in_bytes;
int emu_is_fullscreen = 0;
int emu_is_headless = 0;
int emu_is_sleepless = 0;
static int win_xsize, win_ysize;
char *sdl_pref_dir = NULL, *sdl_base_dir = NULL, *sdl_inst_dir = NULL;
Uint32 sdl_winid;
Expand Down Expand Up @@ -374,6 +376,8 @@ void xemu_set_screen_mode ( int setting )

static inline void do_sleep ( int td )
{
if (XEMU_UNLIKELY(emu_is_sleepless))
return;
#ifdef XEMU_ARCH_HTML
#define __SLEEP_METHOD_DESC "emscripten_set_main_loop_timing"
// Note: even if td is zero (or negative ...) give at least a little time for the browser
Expand Down Expand Up @@ -582,7 +586,6 @@ static void shutdown_emulator ( void )
sdl_win = NULL;
}
atexit_callback_for_console();
//SDL_Quit();
if (td_stat_counter) {
char td_stat_str[XEMU_CPU_STAT_INFO_BUFFER_SIZE];
xemu_get_timing_stat_string(td_stat_str, sizeof td_stat_str);
Expand All @@ -594,6 +597,7 @@ static void shutdown_emulator ( void )
}
// It seems, calling SQL_Quit() at least on Windows causes "segfault".
// Not sure why, but to be safe, I just skip calling it :(
//SDL_Quit();
#ifndef XEMU_ARCH_WIN
SDL_Quit();
#endif
Expand Down Expand Up @@ -1008,9 +1012,6 @@ int xemu_post_init (
void (*shutdown_callback)(void) // callback function called on exit (can be nULL to not have any emulator specific stuff)
) {
srand((unsigned int)time(NULL));
# include "build/xemu-48x48.xpm"
SDL_RendererInfo ren_info;
int a;
if (!debug_fp)
xemu_init_debug(getenv("XEMU_DEBUG_FILE"));
if (!debug_fp && chatty_xemu)
Expand All @@ -1021,6 +1022,15 @@ int xemu_post_init (
ERROR_WINDOW("Byte order test failed!!");
return 1;
}
#ifndef XEMU_ARCH_HTML
if (emu_is_headless) {
static char *dummies[] = { "SDL_VIDEODRIVER=dummy", "SDL_AUDIODRIVER=dummy", NULL };
for (char **p = dummies; *p; p++) {
DEBUGPRINT("SDL: headless mode env-var setup: %s" NL, *p);
putenv(*p);
}
}
#endif
#ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR
// Disallow disabling compositing (of KDE, for example)
// Maybe needed before SDL_Init(), so it's here before calling xemu_init_sdl()
Expand Down Expand Up @@ -1098,7 +1108,8 @@ int xemu_post_init (
strcpy(window_title_buffer, window_title);
window_title_buffer_end = window_title_buffer + strlen(window_title);
//SDL_SetWindowMinimumSize(sdl_win, SCREEN_WIDTH, SCREEN_HEIGHT * 2);
a = SDL_GetNumRenderDrivers();
int a = SDL_GetNumRenderDrivers();
SDL_RendererInfo ren_info;
while (--a >= 0) {
if (!SDL_GetRenderDriverInfo(a, &ren_info)) {
DEBUGPRINT("SDL renderer driver #%d: \"%s\"" NL, a, ren_info.name);
Expand Down Expand Up @@ -1146,6 +1157,7 @@ int xemu_post_init (
xemu_render_dummy_frame(black_colour, texture_x_size, texture_y_size);
if (chatty_xemu)
printf(NL);
# include "build/xemu-48x48.xpm"
xemu_set_icon_from_xpm(favicon_xpm);
return 0;
}
Expand Down
2 changes: 2 additions & 0 deletions xemu/emutools.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ extern int sdl_default_win_x_size, sdl_default_win_y_size;
extern int register_new_texture_creation;
extern SDL_version sdlver_compiled, sdlver_linked;
extern Uint32 *xemu_frame_pixel_access_p;
extern int emu_is_headless;
extern int emu_is_sleepless;

#define XEMU_VIEWPORT_ADJUST_LOGICAL_SIZE 1
//#define XEMU_VIEWPORT_WIN_SIZE_FOLLOW_LOGICAL 2
Expand Down

0 comments on commit 7ba911b

Please sign in to comment.