diff --git a/targets/mega65/configdb.c b/targets/mega65/configdb.c index 68aab4fc..47d4f709 100644 --- a/targets/mega65/configdb.c +++ b/targets/mega65/configdb.c @@ -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 }, @@ -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 }, diff --git a/targets/mega65/configdb.h b/targets/mega65/configdb.h index ac42c825..843f0b05 100644 --- a/targets/mega65/configdb.h +++ b/targets/mega65/configdb.h @@ -50,6 +50,7 @@ struct configdb_st { char *prg; char *sdimg; char *dumpmem; + char *dumpscreen; #ifdef XEMU_SNAPSHOT_SUPPORT char *snapload; char *snapsave; diff --git a/targets/mega65/inject.c b/targets/mega65/inject.c index c3231e64..18dd6424 100644 --- a/targets/mega65/inject.c +++ b/targets/mega65/inject.c @@ -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) + Copyright (C)2016-2022 LGB (Gábor Lénárt) 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 @@ -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" @@ -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) { @@ -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) { @@ -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! @@ -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; @@ -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 diff --git a/targets/mega65/inject.h b/targets/mega65/inject.h index dc92c5d8..2744cf44 100644 --- a/targets/mega65/inject.h +++ b/targets/mega65/inject.h @@ -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) + Copyright (C)2016-2022 LGB (Gábor Lénárt) 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 diff --git a/targets/mega65/mega65.c b/targets/mega65/mega65.c index b4e9b6ef..d8356d7c 100644 --- a/targets/mega65/mega65.c +++ b/targets/mega65/mega65.c @@ -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! @@ -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(); diff --git a/targets/mega65/mega65.h b/targets/mega65/mega65.h index ae47ac0e..2ec75c30 100644 --- a/targets/mega65/mega65.h +++ b/targets/mega65/mega65.h @@ -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; diff --git a/targets/mega65/ui.c b/targets/mega65/ui.c index 3002962d..899717f3 100644 --- a/targets/mega65/ui.c +++ b/targets/mega65/ui.c @@ -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" @@ -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)) @@ -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 ) @@ -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: @@ -687,6 +688,7 @@ static const struct menu_st menu_display[] = { { "Screenshot", XEMUGUI_MENUID_CALLABLE, xemugui_cb_set_integer_to_one, ®istered_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 } }; diff --git a/targets/mega65/vic4.c b/targets/mega65/vic4.c index 77a0e779..673a76a5 100644 --- a/targets/mega65/vic4.c +++ b/targets/mega65/vic4.c @@ -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 @@ -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 --- */ diff --git a/targets/mega65/vic4.h b/targets/mega65/vic4.h index da40e330..e16afc05 100644 --- a/targets/mega65/vic4.h +++ b/targets/mega65/vic4.h @@ -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" diff --git a/xemu/emutools.c b/xemu/emutools.c index 21bda34e..b144c930 100644 --- a/xemu/emutools.c +++ b/xemu/emutools.c @@ -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; @@ -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 @@ -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); @@ -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 @@ -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) @@ -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() @@ -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); @@ -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; } diff --git a/xemu/emutools.h b/xemu/emutools.h index 0b98666d..6dfd02b7 100644 --- a/xemu/emutools.h +++ b/xemu/emutools.h @@ -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