From 9fe038c8d0e1aa4c7acffecbaeb78fcf42e49b01 Mon Sep 17 00:00:00 2001 From: Christopher Mason Date: Wed, 2 Apr 2014 21:29:34 +0000 Subject: [PATCH] Merge Imagewriter branch into trunk. --- doc/web/src/site/apt/history.apt | 2 + src/Makefile | 4 +- src/config.c | 6648 +++++++++++++++--------------- src/gsport.vcxproj | 4 + src/gsport.vcxproj.filters | 12 + src/imagewriter.cpp | 2173 ++++++++++ src/imagewriter.h | 312 ++ src/iw_charmaps.h | 60 + src/protos.h | 5 + src/scc.c | 2591 ++++++------ src/scc_imagewriter.c | 156 + src/sim65816.c | 5091 +++++++++++------------ 12 files changed, 9929 insertions(+), 7129 deletions(-) create mode 100644 src/imagewriter.cpp create mode 100644 src/imagewriter.h create mode 100644 src/iw_charmaps.h create mode 100644 src/scc_imagewriter.c diff --git a/doc/web/src/site/apt/history.apt b/doc/web/src/site/apt/history.apt index 7cdffb5..f1b8794 100644 --- a/doc/web/src/site/apt/history.apt +++ b/doc/web/src/site/apt/history.apt @@ -14,6 +14,8 @@ GSport Release History * Emulated serial ports are individually configurable as either IP or passthrough to real hardware ports + + * Added Imagewriter LQ printer emulation [] diff --git a/src/Makefile b/src/Makefile index 910e606..0eb8e81 100644 --- a/src/Makefile +++ b/src/Makefile @@ -3,7 +3,7 @@ OBJECTS1 = adb.o clock.o config.o dis.o engine_c.o scc.o iwm.o \ joystick_driver.o moremem.o paddles.o parallel.o printer.o \ sim65816.o smartport.o sound.o sound_driver.o video.o \ - scc_socket_driver.o + scc_socket_driver.o scc_imagewriter.o imagewriter.o include vars @@ -148,7 +148,9 @@ scc.o: scc.c defc.h defcomm.h iwm.h protos.h scc.h scc_socket_driver.o: scc_socket_driver.c defc.h defcomm.h iwm.h protos.h scc.h scc_windriver.o: scc_windriver.c defc.h defcomm.h iwm.h protos.h scc.h scc_macdriver.o: scc_macdriver.c defc.h defcomm.h iwm.h protos.h scc.h +scc_imagewriter.o: scc_imagewriter.c defc.h defcomm.h protos.h scc.h iwm.o: iwm.c defc.h defcomm.h iwm.h protos.h iwm_35_525.h +imagewriter.o: imagewriter.cpp joystick_driver.o: joystick_driver.c defc.h defcomm.h iwm.h protos.h moremem.o: moremem.c defc.h defcomm.h iwm.h protos.h paddles.o: paddles.c defc.h defcomm.h iwm.h protos.h diff --git a/src/config.c b/src/config.c index 99b9573..eb4cb5b 100644 --- a/src/config.c +++ b/src/config.c @@ -1,3333 +1,3367 @@ -/* - GSport - an Apple //gs Emulator - Copyright (C) 2010 - 2013 by GSport contributors - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - 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 the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - 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 "defc.h" -#include -#include "config.h" -#if defined(__OS2__) -#include "arch\os2\src\dirport.h" -#elif defined(_MSC_VER) -#include "arch\win32\dirent-win32.h" -#else -#include -#endif - -#ifdef HAVE_TFE -#include "tfe/tfesupp.h" -#include "tfe/protos_tfe.h" -#endif - -#if defined _MSC_VER -#include -#define snprintf _snprintf -typedef unsigned int mode_t; -#endif - -extern int Verbose; -extern word32 g_vbl_count; -extern Iwm iwm; - -extern int g_track_bytes_35[]; -extern int g_track_nibs_35[]; -extern int g_c031_disk35; - -extern int g_cur_a2_stat; -extern byte *g_slow_memory_ptr; -extern byte *g_rom_fc_ff_ptr; -extern byte *g_rom_cards_ptr; -extern double g_cur_dcycs; -extern int g_rom_version; -extern int g_fatal_log; - -extern word32 g_adb_repeat_vbl; - -extern int halt_sim; -extern int g_limit_speed; -extern int g_force_depth; -extern int g_serial_type[]; -extern int g_serial_out_masking; -extern int g_serial_modem[]; -extern word32 g_mem_size_base; -extern word32 g_mem_size_exp; -extern int g_video_line_update_interval; -extern int g_video_extra_check_inputs; -extern int g_user_halt_bad; -extern int g_joystick_type; -extern int g_joystick_scale_factor_x; -extern int g_joystick_scale_factor_y; -extern int g_joystick_trim_amount_x; -extern int g_joystick_trim_amount_y; -extern int g_swap_paddles; -extern int g_invert_paddles; -extern int g_ethernet; -extern int g_ethernet_interface; -extern int g_parallel; -extern int g_parallel_out_masking; -extern int g_printer; -extern int g_printer_dpi; -extern char* g_printer_output; -extern int g_printer_multipage; -extern char* g_printer_font_roman; -extern char* g_printer_font_sans; -extern char* g_printer_font_prestige; -extern char* g_printer_font_courier; -extern char* g_printer_font_script; -extern char* g_printer_font_ocra; -extern int g_printer_timeout; -#if defined(_WIN32) || defined(__CYGWIN__) -extern int g_win_show_console_request; -extern int g_win_status_debug_request; -#endif - -extern int g_screen_index[]; -extern word32 g_full_refresh_needed; -extern word32 g_a2_screen_buffer_changed; -extern int g_a2_new_all_stat[]; -extern int g_new_a2_stat_cur_line; -extern byte g_bram[2][256]; -extern byte* g_bram_ptr; -extern byte g_temp_boot_slot; -extern byte g_orig_boot_slot; - -extern int g_key_down; -extern const char g_gsport_version_str[]; -int g_config_control_panel = 0; -char g_config_gsport_name[1024]; -char g_cfg_cwd_str[CFG_PATH_MAX] = { 0 }; - -int g_config_gsport_auto_update = 1; -int g_config_gsport_update_needed = 0; - -const char *g_config_gsport_name_list[] = { - "config.txt", "config.gsport", "gsport_conf", ".config.gsport", 0 -}; - -int g_highest_smartport_unit = -1; -int g_reparse_delay = 0; -int g_user_page2_shadow = 1; - -byte g_save_text_screen_bytes[0x800]; -int g_save_cur_a2_stat = 0; -char g_cfg_printf_buf[CFG_PRINTF_BUFSIZE]; -char g_config_gsport_buf[CONF_BUF_LEN]; - -word32 g_cfg_vbl_count = 0; - -int g_cfg_curs_x = 0; -int g_cfg_curs_y = 0; -int g_cfg_curs_inv = 0; -int g_cfg_curs_mousetext = 0; - -#define CFG_MAX_OPTS 16 -#define CFG_OPT_MAXSTR 100 - -int g_cfg_opts_vals[CFG_MAX_OPTS]; -char g_cfg_opts_strs[CFG_MAX_OPTS][CFG_OPT_MAXSTR]; -char g_cfg_opts_strvals[CFG_MAX_OPTS][CFG_OPT_MAXSTR]; -char g_cfg_opt_buf[CFG_OPT_MAXSTR]; - -char *g_cfg_rom_path = "ROM"; -char *g_cfg_file_def_name = "Undefined"; -char **g_cfg_file_strptr = 0; -int g_cfg_file_min_size = 1024; -int g_cfg_file_max_size = 2047*1024*1024; - -#define MAX_PARTITION_BLK_SIZE 65536 - -extern Cfg_menu g_cfg_main_menu[]; - -#define KNMP(a) &a, #a, 0 - -Cfg_menu g_cfg_disk_menu[] = { -{ "Disk Configuration", g_cfg_disk_menu, 0, 0, CFGTYPE_MENU }, -{ "s5d1 = ", 0, 0, 0, CFGTYPE_DISK + 0x5000 }, -{ "s5d2 = ", 0, 0, 0, CFGTYPE_DISK + 0x5010 }, -{ "", 0, 0, 0, 0 }, -{ "s6d1 = ", 0, 0, 0, CFGTYPE_DISK + 0x6000 }, -{ "s6d2 = ", 0, 0, 0, CFGTYPE_DISK + 0x6010 }, -{ "", 0, 0, 0, 0 }, -{ "s7d1 = ", 0, 0, 0, CFGTYPE_DISK + 0x7000 }, -{ "s7d2 = ", 0, 0, 0, CFGTYPE_DISK + 0x7010 }, -{ "s7d3 = ", 0, 0, 0, CFGTYPE_DISK + 0x7020 }, -{ "s7d4 = ", 0, 0, 0, CFGTYPE_DISK + 0x7030 }, -{ "s7d5 = ", 0, 0, 0, CFGTYPE_DISK + 0x7040 }, -{ "s7d6 = ", 0, 0, 0, CFGTYPE_DISK + 0x7050 }, -{ "s7d7 = ", 0, 0, 0, CFGTYPE_DISK + 0x7060 }, -{ "s7d8 = ", 0, 0, 0, CFGTYPE_DISK + 0x7070 }, -{ "s7d9 = ", 0, 0, 0, CFGTYPE_DISK + 0x7080 }, -{ "s7d10 = ", 0, 0, 0, CFGTYPE_DISK + 0x7090 }, -{ "s7d11 = ", 0, 0, 0, CFGTYPE_DISK + 0x70a0 }, -{ "", 0, 0, 0, 0 }, -{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, -{ 0, 0, 0, 0, 0 }, -}; - +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2013 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + 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 the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + 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 "defc.h" +#include +#include "config.h" +#if defined(__OS2__) +#include "arch\os2\src\dirport.h" +#elif defined(_MSC_VER) +#include "arch\win32\dirent-win32.h" +#else +#include +#endif + +#ifdef HAVE_TFE +#include "tfe/tfesupp.h" +#include "tfe/protos_tfe.h" +#endif + +#if defined _MSC_VER +#include +#define snprintf _snprintf +typedef unsigned int mode_t; +#endif + +extern int Verbose; +extern word32 g_vbl_count; +extern Iwm iwm; + +extern int g_track_bytes_35[]; +extern int g_track_nibs_35[]; +extern int g_c031_disk35; + +extern int g_cur_a2_stat; +extern byte *g_slow_memory_ptr; +extern byte *g_rom_fc_ff_ptr; +extern byte *g_rom_cards_ptr; +extern double g_cur_dcycs; +extern int g_rom_version; +extern int g_fatal_log; + +extern word32 g_adb_repeat_vbl; + +extern int halt_sim; +extern int g_limit_speed; +extern int g_force_depth; +extern int g_serial_type[]; +extern int g_serial_out_masking; +extern int g_serial_modem[]; +extern word32 g_mem_size_base; +extern word32 g_mem_size_exp; +extern int g_video_line_update_interval; +extern int g_video_extra_check_inputs; +extern int g_user_halt_bad; +extern int g_joystick_type; +extern int g_joystick_scale_factor_x; +extern int g_joystick_scale_factor_y; +extern int g_joystick_trim_amount_x; +extern int g_joystick_trim_amount_y; +extern int g_swap_paddles; +extern int g_invert_paddles; +extern int g_ethernet; +extern int g_ethernet_interface; +extern int g_parallel; +extern int g_parallel_out_masking; +extern int g_printer; +extern int g_printer_dpi; +extern char* g_printer_output; +extern int g_printer_multipage; +extern char* g_printer_font_roman; +extern char* g_printer_font_sans; +extern char* g_printer_font_prestige; +extern char* g_printer_font_courier; +extern char* g_printer_font_script; +extern char* g_printer_font_ocra; +extern int g_printer_timeout; + +extern int g_imagewriter; +extern int g_imagewriter_dpi; +extern char* g_imagewriter_output; +extern int g_imagewriter_multipage; +extern int g_imagewriter_timeout; +extern char* g_imagewriter_fixed_font; +extern char* g_imagewriter_prop_font; + +#if defined(_WIN32) || defined(__CYGWIN__) +extern int g_win_show_console_request; +extern int g_win_status_debug_request; +#endif + +extern int g_screen_index[]; +extern word32 g_full_refresh_needed; +extern word32 g_a2_screen_buffer_changed; +extern int g_a2_new_all_stat[]; +extern int g_new_a2_stat_cur_line; +extern byte g_bram[2][256]; +extern byte* g_bram_ptr; +extern byte g_temp_boot_slot; +extern byte g_orig_boot_slot; + +extern int g_key_down; +extern const char g_gsport_version_str[]; +int g_config_control_panel = 0; +char g_config_gsport_name[1024]; +char g_cfg_cwd_str[CFG_PATH_MAX] = { 0 }; + +int g_config_gsport_auto_update = 1; +int g_config_gsport_update_needed = 0; + +const char *g_config_gsport_name_list[] = { + "config.txt", "config.gsport", "gsport_conf", ".config.gsport", 0 +}; + +int g_highest_smartport_unit = -1; +int g_reparse_delay = 0; +int g_user_page2_shadow = 1; + +byte g_save_text_screen_bytes[0x800]; +int g_save_cur_a2_stat = 0; +char g_cfg_printf_buf[CFG_PRINTF_BUFSIZE]; +char g_config_gsport_buf[CONF_BUF_LEN]; + +word32 g_cfg_vbl_count = 0; + +int g_cfg_curs_x = 0; +int g_cfg_curs_y = 0; +int g_cfg_curs_inv = 0; +int g_cfg_curs_mousetext = 0; + +#define CFG_MAX_OPTS 16 +#define CFG_OPT_MAXSTR 100 + +int g_cfg_opts_vals[CFG_MAX_OPTS]; +char g_cfg_opts_strs[CFG_MAX_OPTS][CFG_OPT_MAXSTR]; +char g_cfg_opts_strvals[CFG_MAX_OPTS][CFG_OPT_MAXSTR]; +char g_cfg_opt_buf[CFG_OPT_MAXSTR]; + +char *g_cfg_rom_path = "ROM"; +char *g_cfg_file_def_name = "Undefined"; +char **g_cfg_file_strptr = 0; +int g_cfg_file_min_size = 1024; +int g_cfg_file_max_size = 2047*1024*1024; + +#define MAX_PARTITION_BLK_SIZE 65536 + +extern Cfg_menu g_cfg_main_menu[]; + +#define KNMP(a) &a, #a, 0 + +Cfg_menu g_cfg_disk_menu[] = { +{ "Disk Configuration", g_cfg_disk_menu, 0, 0, CFGTYPE_MENU }, +{ "s5d1 = ", 0, 0, 0, CFGTYPE_DISK + 0x5000 }, +{ "s5d2 = ", 0, 0, 0, CFGTYPE_DISK + 0x5010 }, +{ "", 0, 0, 0, 0 }, +{ "s6d1 = ", 0, 0, 0, CFGTYPE_DISK + 0x6000 }, +{ "s6d2 = ", 0, 0, 0, CFGTYPE_DISK + 0x6010 }, +{ "", 0, 0, 0, 0 }, +{ "s7d1 = ", 0, 0, 0, CFGTYPE_DISK + 0x7000 }, +{ "s7d2 = ", 0, 0, 0, CFGTYPE_DISK + 0x7010 }, +{ "s7d3 = ", 0, 0, 0, CFGTYPE_DISK + 0x7020 }, +{ "s7d4 = ", 0, 0, 0, CFGTYPE_DISK + 0x7030 }, +{ "s7d5 = ", 0, 0, 0, CFGTYPE_DISK + 0x7040 }, +{ "s7d6 = ", 0, 0, 0, CFGTYPE_DISK + 0x7050 }, +{ "s7d7 = ", 0, 0, 0, CFGTYPE_DISK + 0x7060 }, +{ "s7d8 = ", 0, 0, 0, CFGTYPE_DISK + 0x7070 }, +{ "s7d9 = ", 0, 0, 0, CFGTYPE_DISK + 0x7080 }, +{ "s7d10 = ", 0, 0, 0, CFGTYPE_DISK + 0x7090 }, +{ "s7d11 = ", 0, 0, 0, CFGTYPE_DISK + 0x70a0 }, +{ "", 0, 0, 0, 0 }, +{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, +{ 0, 0, 0, 0, 0 }, +}; + // OG Use define instead of const for joystick_types #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) -Cfg_menu g_cfg_joystick_menu[] = { -{ "Joystick Configuration", g_cfg_joystick_menu, 0, 0, CFGTYPE_MENU }, +Cfg_menu g_cfg_joystick_menu[] = { +{ "Joystick Configuration", g_cfg_joystick_menu, 0, 0, CFGTYPE_MENU }, { "Joystick Emulation,"TOSTRING(JOYSTICK_TYPE_KEYPAD)",Keypad Joystick,"TOSTRING(JOYSTICK_TYPE_MOUSE)",Mouse Joystick,"TOSTRING(JOYSTICK_TYPE_NATIVE_1)",Native Joystick 1," TOSTRING(JOYSTICK_TYPE_NATIVE_2)",Native Joystick 2,"TOSTRING(JOYSTICK_TYPE_NONE)",No Joystick", KNMP(g_joystick_type), CFGTYPE_INT }, -{ "Joystick Scale X,0x100,Standard,0x119,+10%,0x133,+20%," - "0x150,+30%,0xb0,-30%,0xcd,-20%,0xe7,-10%", - KNMP(g_joystick_scale_factor_x), CFGTYPE_INT }, -{ "Joystick Scale Y,0x100,Standard,0x119,+10%,0x133,+20%," - "0x150,+30%,0xb0,-30%,0xcd,-20%,0xe7,-10%", - KNMP(g_joystick_scale_factor_y), CFGTYPE_INT }, -{ "Joystick Trim X", KNMP(g_joystick_trim_amount_x), CFGTYPE_INT }, -{ "Joystick Trim Y", KNMP(g_joystick_trim_amount_y), CFGTYPE_INT }, -{ "Swap Joystick X and Y,0,Normal operation,1,Paddle 1 and Paddle 0 swapped", - KNMP(g_swap_paddles), CFGTYPE_INT }, -{ "Invert Joystick,0,Normal operation,1,Left becomes right and up becomes down", - KNMP(g_invert_paddles), CFGTYPE_INT }, -{ "", 0, 0, 0, 0 }, -{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, -{ 0, 0, 0, 0, 0 }, -}; - -Cfg_menu g_cfg_rom_menu[] = { -{ "ROM File Selection", g_cfg_rom_menu, 0, 0, CFGTYPE_MENU }, -{ "ROM File", KNMP(g_cfg_rom_path), CFGTYPE_FILE }, -{ "", 0, 0, 0, 0 }, -{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, -{ 0, 0, 0, 0, 0 }, -}; - -Cfg_menu g_cfg_serial_menu[] = { -{ "Serial Port Configuration", g_cfg_serial_menu, 0, 0, CFGTYPE_MENU }, -{ "Port 0 (slot 1),0,Only use socket 6501,1,Use real port if avail", +{ "Joystick Scale X,0x100,Standard,0x119,+10%,0x133,+20%," + "0x150,+30%,0xb0,-30%,0xcd,-20%,0xe7,-10%", + KNMP(g_joystick_scale_factor_x), CFGTYPE_INT }, +{ "Joystick Scale Y,0x100,Standard,0x119,+10%,0x133,+20%," + "0x150,+30%,0xb0,-30%,0xcd,-20%,0xe7,-10%", + KNMP(g_joystick_scale_factor_y), CFGTYPE_INT }, +{ "Joystick Trim X", KNMP(g_joystick_trim_amount_x), CFGTYPE_INT }, +{ "Joystick Trim Y", KNMP(g_joystick_trim_amount_y), CFGTYPE_INT }, +{ "Swap Joystick X and Y,0,Normal operation,1,Paddle 1 and Paddle 0 swapped", + KNMP(g_swap_paddles), CFGTYPE_INT }, +{ "Invert Joystick,0,Normal operation,1,Left becomes right and up becomes down", + KNMP(g_invert_paddles), CFGTYPE_INT }, +{ "", 0, 0, 0, 0 }, +{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, +{ 0, 0, 0, 0, 0 }, +}; + +Cfg_menu g_cfg_rom_menu[] = { +{ "ROM File Selection", g_cfg_rom_menu, 0, 0, CFGTYPE_MENU }, +{ "ROM File", KNMP(g_cfg_rom_path), CFGTYPE_FILE }, +{ "", 0, 0, 0, 0 }, +{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, +{ 0, 0, 0, 0, 0 }, +}; + +Cfg_menu g_cfg_serial_menu[] = { +{ "Serial Port Configuration", g_cfg_serial_menu, 0, 0, CFGTYPE_MENU }, +{ "Port 0 (slot 1),0,Only use socket 6501,1,Use real port if avail,2,Virtual Imagewriter", KNMP(g_serial_type[0]), CFGTYPE_INT }, -{ "Port 1 (slot 2),0,Only use socket 6502,1,Use real port if avail", - KNMP(g_serial_type[1]), CFGTYPE_INT }, -{ "Serial Output,0,Send full 8-bit data,1,Mask off high bit", - KNMP(g_serial_out_masking), CFGTYPE_INT }, -{ "Modem on port 0 (slot 1),0,Simple socket emulation mode,1,Modem with " - "incoming and outgoing emulation", KNMP(g_serial_modem[0]), - CFGTYPE_INT }, -{ "Modem on port 1 (slot 2),0,Simple socket emulation mode,1,Modem with " - "incoming and outgoing emulation", KNMP(g_serial_modem[1]), - CFGTYPE_INT }, -{ "", 0, 0, 0, 0 }, -{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, -{ 0, 0, 0, 0, 0 }, -}; - -Cfg_menu g_cfg_parallel_menu[] = { -{ "Parallel Card Configuration", g_cfg_parallel_menu, 0, 0, CFGTYPE_MENU }, -{ "Parallel Card in Slot 1,0,Off,1,On", - KNMP(g_parallel), CFGTYPE_INT }, -{ "Parallel Output,0,Send full 8-bit data,1,Mask off high bit", - KNMP(g_parallel_out_masking), CFGTYPE_INT }, -{ "", 0, 0, 0, 0 }, -{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, -{ 0, 0, 0, 0, 0 }, -}; - -Cfg_menu g_cfg_ethernet_menu[] = { -{ "Ethernet Card Configuration", g_cfg_ethernet_menu, 0, 0, CFGTYPE_MENU }, -{ "Uthernet Card in Slot 3,0,Off,1,On", - KNMP(g_ethernet), CFGTYPE_INT }, -{ "Use Interface Number,0,0,1,1,2,2,3,3,4,4", - KNMP(g_ethernet_interface), CFGTYPE_INT }, -{ "", 0, 0, 0, 0 }, -{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, -{ 0, 0, 0, 0, 0 }, -}; - -Cfg_menu g_cfg_printer_menu[] = { -{ "Virtual Printer Configuration", g_cfg_ethernet_menu, 0, 0, CFGTYPE_MENU }, -{ "Virtual Printer Type,0,Epson LQ", - KNMP(g_printer), CFGTYPE_INT }, -{ "Printer DPI,60,60x60 dpi,180,180x180 dpi,360,360x360 dpi", - KNMP(g_printer_dpi), CFGTYPE_INT }, -{ "Printer Output Type,bmp,Windows Bitmap,ps,Postscript (B&W),printer,Direct to host printer,text,Text file", - KNMP(g_printer_output), CFGTYPE_STR }, +{ "Port 1 (slot 2),0,Only use socket 6502,1,Use real port if avail,2,Virtual Imagewriter", + KNMP(g_serial_type[1]), CFGTYPE_INT }, +{ "Serial Output,0,Send full 8-bit data,1,Mask off high bit", + KNMP(g_serial_out_masking), CFGTYPE_INT }, +{ "Modem on port 0 (slot 1),0,Simple socket emulation mode,1,Modem with " + "incoming and outgoing emulation", KNMP(g_serial_modem[0]), + CFGTYPE_INT }, +{ "Modem on port 1 (slot 2),0,Simple socket emulation mode,1,Modem with " + "incoming and outgoing emulation", KNMP(g_serial_modem[1]), + CFGTYPE_INT }, +{ "", 0, 0, 0, 0 }, +{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, +{ 0, 0, 0, 0, 0 }, +}; + +Cfg_menu g_cfg_parallel_menu[] = { +{ "Parallel Card Configuration", g_cfg_parallel_menu, 0, 0, CFGTYPE_MENU }, +{ "Parallel Card in Slot 1,0,Off,1,On", + KNMP(g_parallel), CFGTYPE_INT }, +{ "Parallel Output,0,Send full 8-bit data,1,Mask off high bit", + KNMP(g_parallel_out_masking), CFGTYPE_INT }, +{ "", 0, 0, 0, 0 }, +{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, +{ 0, 0, 0, 0, 0 }, +}; + +Cfg_menu g_cfg_ethernet_menu[] = { +{ "Ethernet Card Configuration", g_cfg_ethernet_menu, 0, 0, CFGTYPE_MENU }, +{ "Uthernet Card in Slot 3,0,Off,1,On", + KNMP(g_ethernet), CFGTYPE_INT }, +{ "Use Interface Number,0,0,1,1,2,2,3,3,4,4", + KNMP(g_ethernet_interface), CFGTYPE_INT }, +{ "", 0, 0, 0, 0 }, +{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, +{ 0, 0, 0, 0, 0 }, +}; + +Cfg_menu g_cfg_printer_menu[] = { +{ "Virtual Printer Configuration", g_cfg_printer_menu, 0, 0, CFGTYPE_MENU }, +{ "Virtual Printer Type,0,Epson LQ", + KNMP(g_printer), CFGTYPE_INT }, +{ "Printer DPI,60,60x60 dpi,180,180x180 dpi,360,360x360 dpi", + KNMP(g_printer_dpi), CFGTYPE_INT }, +{ "Printer Output Type,bmp,Windows Bitmap,ps,Postscript (B&W),printer,Direct to host printer,text,Text file", + KNMP(g_printer_output), CFGTYPE_STR }, +{ "Multipage Files? (PS Only),0,No,1,Yes", + KNMP(g_printer_multipage), CFGTYPE_INT }, +{ "Printer Timeout,0,Never,2,2 sec.,15,15 sec.,30,30 sec.,60, 1 min.", + KNMP(g_printer_timeout), CFGTYPE_INT }, +{ "", 0, 0, 0, 0 }, +{ "Epson LQ Fonts", 0, 0, 0, 0 }, +{ "--------------", 0, 0, 0, 0 }, +{ "", 0, 0, 0, 0 }, +{ "Roman", KNMP(g_printer_font_roman), CFGTYPE_FILE }, +{ "Sans Serif", KNMP(g_printer_font_sans), CFGTYPE_FILE }, +{ "Courier", KNMP(g_printer_font_courier), CFGTYPE_FILE }, +{ "Prestige", KNMP(g_printer_font_prestige), CFGTYPE_FILE }, +{ "Script", KNMP(g_printer_font_script), CFGTYPE_FILE }, +{ "OCR A/B", KNMP(g_printer_font_ocra), CFGTYPE_FILE }, +{ "", 0, 0, 0, 0 }, +{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, +{ 0, 0, 0, 0, 0 }, +}; + +Cfg_menu g_cfg_imagewriter_menu[] = { +{ "Virtual Imagewriter Configuration", g_cfg_imagewriter_menu, 0, 0, CFGTYPE_MENU }, +{ "Virtual Printer Type,0,Imagewriter II,1,Imagewriter LQ", + KNMP(g_imagewriter), CFGTYPE_INT }, +{ "Printer DPI,360,360x360 dpi (Best for 8-bit software),720,720x720 dpi (Best for GS/OS & IW LQ Modes),1440,1440x1440 dpi", + KNMP(g_imagewriter_dpi), CFGTYPE_INT }, +{ "Printer Output Type,bmp,Windows Bitmap,ps,Postscript (B&W),colorps,Postscript (Color),printer,Direct to host printer,text,Text file", + KNMP(g_imagewriter_output), CFGTYPE_STR }, { "Multipage Files? (PS Only),0,No,1,Yes", - KNMP(g_printer_multipage), CFGTYPE_INT }, + KNMP(g_imagewriter_multipage), CFGTYPE_INT }, { "Printer Timeout,0,Never,2,2 sec.,15,15 sec.,30,30 sec.,60, 1 min.", - KNMP(g_printer_timeout), CFGTYPE_INT }, + KNMP(g_imagewriter_timeout), CFGTYPE_INT }, { "", 0, 0, 0, 0 }, -{ "Epson LQ Fonts", 0, 0, 0, 0 }, -{ "--------------", 0, 0, 0, 0 }, +{ "Imagewriter Fonts", 0, 0, 0, 0 }, +{ "-----------------", 0, 0, 0, 0 }, { "", 0, 0, 0, 0 }, -{ "Roman", KNMP(g_printer_font_roman), CFGTYPE_FILE }, -{ "Sans Serif", KNMP(g_printer_font_sans), CFGTYPE_FILE }, -{ "Courier", KNMP(g_printer_font_courier), CFGTYPE_FILE }, -{ "Prestige", KNMP(g_printer_font_prestige), CFGTYPE_FILE }, -{ "Script", KNMP(g_printer_font_script), CFGTYPE_FILE }, -{ "OCR A/B", KNMP(g_printer_font_ocra), CFGTYPE_FILE }, +{ "Fixed Width Font", KNMP(g_imagewriter_fixed_font), CFGTYPE_FILE }, +{ "", 0, 0, 0, 0 }, +{ "Proporational Font", KNMP(g_imagewriter_prop_font), CFGTYPE_FILE }, { "", 0, 0, 0, 0 }, { "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, { 0, 0, 0, 0, 0 }, -}; - -#if defined(_WIN32) || defined(__CYGWIN__) -Cfg_menu g_cfg_debug_menu[] = { -{ "Debugging Options", g_cfg_debug_menu, 0, 0, CFGTYPE_MENU }, -{ "Status lines,0,Hide,1,Show", KNMP(g_win_status_debug_request), CFGTYPE_INT }, -{ "Console,0,Hide,1,Show", KNMP(g_win_show_console_request), CFGTYPE_INT }, -{ "", 0, 0, 0, 0 }, -{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, -{ 0, 0, 0, 0, 0 }, -}; -#endif - -Cfg_menu g_cfg_main_menu[] = { -{ "GSport Configuration", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, -{ "Disk Configuration", g_cfg_disk_menu, 0, 0, CFGTYPE_MENU }, -{ "Joystick Configuration", g_cfg_joystick_menu, 0, 0, CFGTYPE_MENU }, -{ "ROM File Selection", g_cfg_rom_menu, 0, 0, CFGTYPE_MENU }, -{ "Serial Port Configuration", g_cfg_serial_menu, 0, 0, CFGTYPE_MENU }, -{ "Ethernet Card Configuration", g_cfg_ethernet_menu, 0, 0, CFGTYPE_MENU }, -{ "Parallel Card Configuration", g_cfg_parallel_menu, 0, 0, CFGTYPE_MENU }, -{ "Virtual Printer Configuration", g_cfg_printer_menu, 0, 0, CFGTYPE_MENU }, -#ifndef _WIN32 -{ "Force X-windows display depth", KNMP(g_force_depth), CFGTYPE_INT }, -#endif -#if defined(_WIN32) || defined(__CYGWIN__) -{ "Debugging Options", g_cfg_debug_menu, 0, 0, CFGTYPE_MENU }, -#endif -{ "Auto-update configuration file,0,Manual,1,Immediately", - KNMP(g_config_gsport_auto_update), CFGTYPE_INT }, -{ "Speed,0,Unlimited,1,1.0MHz,2,2.8MHz,3,8.0MHz (Zip)", - KNMP(g_limit_speed), CFGTYPE_INT }, -{ "Expansion Mem Size,0,0MB,0x100000,1MB,0x200000,2MB,0x300000,3MB," - "0x400000,4MB,0x600000,6MB,0x800000,8MB,0xa00000,10MB,0xc00000,12MB," - "0xe00000,14MB", KNMP(g_mem_size_exp), CFGTYPE_INT }, -{ "3200 Color Enable,0,Auto (Full if fast enough),1,Full (Update every line)," - "8,Off (Update video every 8 lines)", - KNMP(g_video_line_update_interval), CFGTYPE_INT }, -{ "Keyboard and mouse poll rate,0,60 times per second,1,240 times per second", - KNMP(g_video_extra_check_inputs), CFGTYPE_INT }, -{ "Code Red Halts,0,Do not stop on bad accesses,1,Enter debugger on bad " - "accesses", KNMP(g_user_halt_bad), CFGTYPE_INT }, -{ "Enable Text Page 2 Shadow,0,Disabled on ROM 01 (matches real hardware)," - "1,Enabled on ROM 01 and 03", - KNMP(g_user_page2_shadow), CFGTYPE_INT }, -{ "Dump text screen to file", (void *)cfg_text_screen_dump, 0, 0, CFGTYPE_FUNC}, -{ "", 0, 0, 0, 0 }, -{ "Save changes to configuration file", (void *)config_write_config_gsport_file, 0, 0, - CFGTYPE_FUNC }, -{ "", 0, 0, 0, 0 }, -{ "Exit Config (or press F4)", (void *)cfg_exit, 0, 0, CFGTYPE_FUNC }, -{ 0, 0, 0, 0, 0 }, -}; - - -#define CFG_MAX_DEFVALS 128 -Cfg_defval g_cfg_defvals[CFG_MAX_DEFVALS]; -int g_cfg_defval_index = 0; - -int g_cfg_slotdrive = -1; -int g_cfg_select_partition = -1; -char g_cfg_tmp_path[CFG_PATH_MAX]; -char g_cfg_file_path[CFG_PATH_MAX]; -char g_cfg_file_cachedpath[CFG_PATH_MAX]; -char g_cfg_file_cachedreal[CFG_PATH_MAX]; -char g_cfg_file_curpath[CFG_PATH_MAX]; -char g_cfg_file_shortened[CFG_PATH_MAX]; -char g_cfg_file_match[CFG_PATH_MAX]; - -Cfg_listhdr g_cfg_dirlist = { 0 }; -Cfg_listhdr g_cfg_partitionlist = { 0 }; - -int g_cfg_file_pathfield = 0; - -const char *g_gsport_rom_names[] = { "ROM", "ROM", "ROM.01", "ROM.03", 0 }; - /* First entry is special--it will be overwritten by g_cfg_rom_path */ - -const char *g_gsport_c1rom_names[] = { "parallel.rom", 0 }; -const char *g_gsport_c2rom_names[] = { 0 }; -const char *g_gsport_c3rom_names[] = { 0 }; -const char *g_gsport_c4rom_names[] = { 0 }; -const char *g_gsport_c5rom_names[] = { 0 }; -const char *g_gsport_c6rom_names[] = { "c600.rom", "controller.rom", "disk.rom", - "DISK.ROM", "diskII.prom", 0 }; -const char *g_gsport_c7rom_names[] = { 0 }; - -const char **g_gsport_rom_card_list[8] = { - 0, g_gsport_c1rom_names, - g_gsport_c2rom_names, g_gsport_c3rom_names, - g_gsport_c4rom_names, g_gsport_c5rom_names, - g_gsport_c6rom_names, g_gsport_c7rom_names }; - -byte g_rom_c600_rom01_diffs[256] = { - 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xe2, 0x00, - 0xd0, 0x50, 0x0f, 0x77, 0x5b, 0xb9, 0xc3, 0xb1, - 0xb1, 0xf8, 0xcb, 0x4e, 0xb8, 0x60, 0xc7, 0x2e, - 0xfc, 0xe0, 0xbf, 0x1f, 0x66, 0x37, 0x4a, 0x70, - 0x55, 0x2c, 0x3c, 0xfc, 0xc2, 0xa5, 0x08, 0x29, - 0xac, 0x21, 0xcc, 0x09, 0x55, 0x03, 0x17, 0x35, - 0x4e, 0xe2, 0x0c, 0xe9, 0x3f, 0x9d, 0xc2, 0x06, - 0x18, 0x88, 0x0d, 0x58, 0x57, 0x6d, 0x83, 0x8c, - 0x22, 0xd3, 0x4f, 0x0a, 0xe5, 0xb7, 0x9f, 0x7d, - 0x2c, 0x3e, 0xae, 0x7f, 0x24, 0x78, 0xfd, 0xd0, - 0xb5, 0xd6, 0xe5, 0x26, 0x85, 0x3d, 0x8d, 0xc9, - 0x79, 0x0c, 0x75, 0xec, 0x98, 0xcc, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x39, 0x00, 0x35, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, - 0x6c, 0x44, 0xce, 0x4c, 0x01, 0x08, 0x00, 0x00 -}; - - -void -config_init_menus(Cfg_menu *menuptr) -{ - void *voidptr; - const char *name_str; - Cfg_defval *defptr; - char **str_ptr; - char *str; - int type; - int pos; - int val; - - if(menuptr[0].defptr != 0) { - return; - } - menuptr[0].defptr = (void *)1; - pos = 0; - while(pos < 100) { - type = menuptr->cfgtype; - voidptr = menuptr->ptr; - name_str = menuptr->name_str; - if(menuptr->str == 0) { - break; - } - if(name_str != 0) { - defptr = &(g_cfg_defvals[g_cfg_defval_index++]); - if(g_cfg_defval_index >= CFG_MAX_DEFVALS) { - fatal_printf("CFG_MAX_DEFVAL overflow\n"); - my_exit(5); - } - defptr->menuptr = menuptr; - defptr->intval = 0; - defptr->strval = 0; - switch(type) { - case CFGTYPE_INT: - val = *((int *)voidptr); - defptr->intval = val; - menuptr->defptr = &(defptr->intval); - break; - case CFGTYPE_STR: - str_ptr = (char **)menuptr->ptr; - str = *str_ptr; - // We need to malloc this string since all - // string values must be dynamically alloced - defptr->strval = str; // this can have a copy - *str_ptr = gsport_malloc_str(str); - menuptr->defptr = &(defptr->strval); - break; - case CFGTYPE_FILE: - str_ptr = (char **)menuptr->ptr; - str = *str_ptr; - // We need to malloc this string since all - // string values must be dynamically alloced - defptr->strval = str; // this can have a copy - *str_ptr = gsport_malloc_str(str); - menuptr->defptr = &(defptr->strval); - break; - default: - fatal_printf("name_str is %p = %s, but type: " - "%d\n", name_str, name_str, type); - my_exit(5); - } - } - if(type == CFGTYPE_MENU) { - config_init_menus((Cfg_menu *)voidptr); - } - pos++; - menuptr++; - } -} - -void -config_init() -{ - int can_create; - - config_init_menus(g_cfg_main_menu); - - // Find the configuration file - g_config_gsport_name[0] = 0; - can_create = 1; - setup_gsport_file(&g_config_gsport_name[0], sizeof(g_config_gsport_name), 0, - can_create, &g_config_gsport_name_list[0]); - - config_parse_config_gsport_file(); -} - -void -cfg_exit() -{ - /* printf("In cfg exit\n"); */ - if(g_rom_version >= 1) { - g_config_control_panel = 0; - } -} - -void -cfg_toggle_config_panel() -{ - g_config_control_panel = !g_config_control_panel; - if(g_rom_version < 0) { - g_config_control_panel = 1; /* Stay in config mode */ - } -} - -void -cfg_text_screen_dump() -{ - char buf[85]; - char *filename; - FILE *ofile; - int offset; - int c; - int pos; - int i, j; - - filename = "gsport.screen.dump"; - printf("Writing text screen to the file %s\n", filename); - ofile = fopen(filename, "w"); - if(ofile == 0) { - fatal_printf("Could not write to file %s, (%d)\n", filename, - errno); - return; - } - - for(i = 0; i < 24; i++) { - pos = 0; - for(j = 0; j < 40; j++) { - offset = g_screen_index[i] + j; - if(g_save_cur_a2_stat & ALL_STAT_VID80) { - c = g_save_text_screen_bytes[0x400+offset]; - c = c & 0x7f; - if(c < 0x20) { - c += 0x40; - } - buf[pos++] = c; - } - c = g_save_text_screen_bytes[offset] & 0x7f; - if(c < 0x20) { - c += 0x40; - } - buf[pos++] = c; - } - while((pos > 0) && (buf[pos-1] == ' ')) { - /* try to strip out trailing spaces */ - pos--; - } - buf[pos++] = '\n'; - buf[pos++] = 0; - fputs(buf, ofile); - } - fclose(ofile); -} - -#ifdef HAVE_TFE -void -cfg_get_tfe_name() -{ - int i = 0; - char *ppname = NULL; - char *ppdes = NULL; - cfg_htab_vtab(0,9); - if (tfe_enumadapter_open()) - { - cfg_printf("Interface List:\n---------------"); - while(tfe_enumadapter(&ppname,&ppdes)) - { - cfg_htab_vtab(0, 11+i); - cfg_printf("%2d: %s",i,ppdes); - i++; - lib_free(ppname); - lib_free(ppdes); - } - tfe_enumadapter_close(); - } - else - { - #if defined(_WIN32) || defined(__CYGWIN__) - cfg_printf("ERROR: Install/Enable WinPcap for Ethernet Support!!"); - #else - cfg_printf("ERROR: Install/Enable LibPcap for Ethernet Support!!"); - #endif - } - return; -} -#endif - -void -config_vbl_update(int doit_3_persec) -{ - if(doit_3_persec) { - if(g_config_gsport_auto_update && g_config_gsport_update_needed) { - config_write_config_gsport_file(); - } - } - return; -} - -void -config_parse_option(char *buf, int pos, int len, int line) -{ - Cfg_menu *menuptr; - Cfg_defval *defptr; - char *nameptr; - char **strptr; - int *iptr; - int num_equals; - int type; - int val; - int c; - int i; - -// warning: modifies buf (turns spaces to nulls) -// parse buf from pos into option, "=" and then "rest" - if(pos >= len) { - /* blank line */ - return; - } - - if(strncmp(&buf[pos], "bram", 4) == 0) { - config_parse_bram(buf, pos+4, len); - return; - } - - // find "name" as first contiguous string - printf("...parse_option: line %d, %p,%p = %s (%s) len:%d\n", line, - &buf[pos], buf, &buf[pos], buf, len); - - nameptr = &buf[pos]; - while(pos < len) { - c = buf[pos]; - if(c == 0 || c == ' ' || c == '\t' || c == '\n') { - break; - } - pos++; - } - buf[pos] = 0; - pos++; - - // Eat up all whitespace and '=' - num_equals = 0; - while(pos < len) { - c = buf[pos]; - if((c == '=') && num_equals == 0) { - pos++; - num_equals++; - } else if(c == ' ' || c == '\t') { - pos++; - } else { - break; - } - } - - /* Look up nameptr to find type */ - type = -1; - defptr = 0; - menuptr = 0; - for(i = 0; i < g_cfg_defval_index; i++) { - defptr = &(g_cfg_defvals[i]); - menuptr = defptr->menuptr; - if(strcmp(menuptr->name_str, nameptr) == 0) { - type = menuptr->cfgtype; - break; - } - } - - switch(type) { - case CFGTYPE_INT: - /* use strtol */ - val = (int)strtol(&buf[pos], 0, 0); - iptr = (int *)menuptr->ptr; - *iptr = val; - break; - case CFGTYPE_STR: - strptr = (char **)menuptr->ptr; - if(strptr && *strptr) { - free(*strptr); - } - *strptr = gsport_malloc_str(&buf[pos]); - break; - case CFGTYPE_FILE: - strptr = (char **)menuptr->ptr; - if(strptr && *strptr) { - free(*strptr); - } - *strptr = gsport_malloc_str(&buf[pos]); - break; - default: - printf("Config file variable %s is unknown type: %d\n", - nameptr, type); - } - -} - -void -config_parse_bram(char *buf, int pos, int len) -{ - int bram_num; - int offset; - int val; - - if((len < (pos+5)) || (buf[pos+1] != '[') || (buf[pos+4] != ']')) { - fatal_printf("While reading configuration file, found malformed bram " - "statement: %s\n", buf); - return; - } - bram_num = buf[pos] - '0'; - if(bram_num != 1 && bram_num != 3) { - fatal_printf("While reading configuration file, found bad bram " - "num: %s\n", buf); - return; - } - - bram_num = bram_num >> 1; // turn 3->1 and 1->0 - - offset = strtoul(&(buf[pos+2]), 0, 16); - pos += 5; - while(pos < len) { - while(buf[pos] == ' ' || buf[pos] == '\t' || buf[pos] == 0x0a || - buf[pos] == 0x0d || buf[pos] == '=') { - pos++; - } - val = strtoul(&buf[pos], 0, 16); - clk_bram_set(bram_num, offset, val); - offset++; - pos += 2; - } -} - -void -config_load_roms() -{ - struct stat stat_buf; - const char **names_ptr; - int more_than_8mb; - int changed_rom; - int len; - FILE *file; - int ret; - int i; - - g_rom_version = -1; - - /* set first entry of g_gsport_rom_names[] to g_cfg_rom_path so that */ - /* it becomes the first place searched. */ - g_gsport_rom_names[0] = g_cfg_rom_path; - setup_gsport_file(&g_cfg_tmp_path[0], CFG_PATH_MAX, -1, 0, - &g_gsport_rom_names[0]); - - if(g_cfg_tmp_path[0] == 0) { - // Just get out, let config interface select ROM - g_config_control_panel = 1; - return; - } - file = fopen(&g_cfg_tmp_path[0], "rb"); - if(!file) { - fatal_printf("Open ROM file %s failed; errno:%d\n", - &g_cfg_tmp_path[0], errno); - g_config_control_panel = 1; - return; - } - - ret = stat(&g_cfg_tmp_path[0], &stat_buf); - if(ret != 0) { - fatal_printf("stat returned %d; errno: %d\n", - ret, errno); - g_config_control_panel = 1; - return; - } - - len = stat_buf.st_size; - if(len == 128*1024) { - g_rom_version = 1; - g_mem_size_base = 256*1024; - memset(&g_rom_fc_ff_ptr[0], 0, 2*65536); - /* Clear banks fc and fd to 0 */ - ret = fread(&g_rom_fc_ff_ptr[2*65536], 1, len, file); - } else if(len == 256*1024) { - g_rom_version = 3; - g_mem_size_base = 1024*1024; - ret = fread(&g_rom_fc_ff_ptr[0], 1, len, file); - } else { - fatal_printf("The ROM size should be 128K or 256K, this file " - "is %d bytes\n", len); - g_config_control_panel = 1; - return; - } - - printf("Read: %d bytes of ROM\n", ret); - if(ret != len) { - fatal_printf("errno: %d\n", errno); - g_config_control_panel = 1; - return; - } - fclose(file); - - memset(&g_rom_cards_ptr[0], 0, 256*16); - - /* initialize c600 rom to be diffs from the real ROM, to build-in */ - /* Apple II compatibility without distributing ROMs */ - for(i = 0; i < 256; i++) { - g_rom_cards_ptr[0x600 + i] = g_rom_fc_ff_ptr[0x3c600 + i] ^ - g_rom_c600_rom01_diffs[i]; - } - if(g_rom_version >= 3) { - /* some patches */ - g_rom_cards_ptr[0x61b] ^= 0x40; - g_rom_cards_ptr[0x61c] ^= 0x33; - g_rom_cards_ptr[0x632] ^= 0xc0; - g_rom_cards_ptr[0x633] ^= 0x33; - } - - for(i = 1; i < 8; i++) { - names_ptr = g_gsport_rom_card_list[i]; - if(names_ptr == 0) { - continue; - } - if(*names_ptr == 0) { - continue; - } - setup_gsport_file(&g_cfg_tmp_path[0], CFG_PATH_MAX, 1, 0, - names_ptr); - if(g_cfg_tmp_path[0] != 0) { - file = fopen(&(g_cfg_tmp_path[0]), "rb"); - if(!file) { - fatal_printf("Open card ROM file %s failed; errno:%d\n", - &g_cfg_tmp_path[0], errno); - continue; - } - - len = 256; - ret = fread(&g_rom_cards_ptr[i*0x100], 1, len, file); - - if(ret != len) { - fatal_printf("While reading card ROM %s, file " - "is too short. (%d) Expected %d bytes, " - "read %d bytes\n", &g_cfg_tmp_path[0], errno, len, ret); - continue; - } - printf("Read: %d bytes of ROM in slot %d from file %s.\n", ret, i, &g_cfg_tmp_path[0]); - fclose(file); - } - } - more_than_8mb = (g_mem_size_exp > 0x800000); - /* Only do the patch if users wants more than 8MB of expansion mem */ - - changed_rom = 0; - if(g_rom_version == 1) { - /* make some patches to ROM 01 */ -#if 0 - /* 1: Patch ROM selftest to not do speed test */ - printf("Patching out speed test failures from ROM 01\n"); - g_rom_fc_ff_ptr[0x3785a] = 0x18; - changed_rom = 1; -#endif - -#if 0 - /* 2: Patch ROM selftests not to do tests 2,4 */ - /* 0 = skip, 1 = do it, test 1 is bit 0 of LSByte */ - g_rom_fc_ff_ptr[0x371e9] = 0xf5; - g_rom_fc_ff_ptr[0x371ea] = 0xff; - changed_rom = 1; -#endif - - if(more_than_8mb) { - /* Geoff Weiss patch to use up to 14MB of RAM */ - g_rom_fc_ff_ptr[0x30302] = 0xdf; - g_rom_fc_ff_ptr[0x30314] = 0xdf; - g_rom_fc_ff_ptr[0x3031c] = 0x00; - changed_rom = 1; - } - - /* Patch ROM selftest to not do ROM cksum if any changes*/ - if(changed_rom) { - g_rom_fc_ff_ptr[0x37a06] = 0x18; - g_rom_fc_ff_ptr[0x37a07] = 0x18; - } - } else if(g_rom_version == 3) { - /* patch ROM 03 */ - printf("Patching ROM 03 smartport bug\n"); - /* 1: Patch Smartport code to fix a stupid bug */ - /* that causes it to write the IWM status reg into c036, */ - /* which is the system speed reg...it's "safe" since */ - /* IWM status reg bit 4 must be 0 (7MHz)..., otherwise */ - /* it might have turned on shadowing in all banks! */ - g_rom_fc_ff_ptr[0x357c9] = 0x00; - changed_rom = 1; - -#if 0 - /* patch ROM 03 to not to speed test */ - /* skip fast speed test */ - g_rom_fc_ff_ptr[0x36ad7] = 0x18; - g_rom_fc_ff_ptr[0x36ad8] = 0x18; - changed_rom = 1; -#endif - -#if 0 - /* skip slow speed test */ - g_rom_fc_ff_ptr[0x36ae7] = 0x18; - g_rom_fc_ff_ptr[0x36ae8] = 0x6b; - changed_rom = 1; -#endif - -#if 0 - /* 4: Patch ROM 03 selftests not to do tests 1-4 */ - g_rom_fc_ff_ptr[0x364a9] = 0xf0; - g_rom_fc_ff_ptr[0x364aa] = 0xff; - changed_rom = 1; -#endif - - /* ROM tests are in ff/6403-642x, where 6403 = addr of */ - /* test 1, etc. */ - - if(more_than_8mb) { - /* Geoff Weiss patch to use up to 14MB of RAM */ - g_rom_fc_ff_ptr[0x30b] = 0xdf; - g_rom_fc_ff_ptr[0x31d] = 0xdf; - g_rom_fc_ff_ptr[0x325] = 0x00; - changed_rom = 1; - } - - if(changed_rom) { - /* patch ROM 03 selftest to not do ROM cksum */ - g_rom_fc_ff_ptr[0x36cb0] = 0x18; - g_rom_fc_ff_ptr[0x36cb1] = 0x18; - } - - } -} - -void -config_parse_config_gsport_file() -{ - FILE *fconf; - char *buf; - char *ptr; - char *name_ptr; - char *partition_name; - int part_num; - int ejected; - int line; - int pos; - int slot; - int drive; - int size; - int len; - int ret; - int i; - - printf("Parsing configuration file\n"); - - clk_bram_zero(); - - g_highest_smartport_unit = -1; - - cfg_get_base_path(&g_cfg_cwd_str[0], g_config_gsport_name, 0); -#ifndef __OS2__ - if(g_cfg_cwd_str[0] != 0) { - ret = chdir(&g_cfg_cwd_str[0]); - if(ret != 0) { - printf("chdir to %s, errno:%d\n", g_cfg_cwd_str, errno); - } - } - /* In any case, copy the directory path to g_cfg_cwd_str */ - (void)getcwd(&g_cfg_cwd_str[0], CFG_PATH_MAX); -#endif - - fconf = fopen(g_config_gsport_name, "r"); - if(fconf == 0) { - fatal_printf("cannot open configuration file at %s! Stopping!\n", - g_config_gsport_name); - my_exit(3); - } - - line = 0; - while(1) { - buf = &g_config_gsport_buf[0]; - ptr = fgets(buf, CONF_BUF_LEN, fconf); - if(ptr == 0) { - iwm_printf("Done reading disk_conf\n"); - break; - } - - line++; - /* strip off newline(s) */ - len = strlen(buf); - for(i = len - 1; i >= 0; i--) { - if((buf[i] != 0x0d) && (buf[i] != 0x0a)) { - break; - } - len = i; - buf[i] = 0; - } - - iwm_printf("disk_conf[%d]: %s\n", line, buf); - if(len > 0 && buf[0] == '#') { - iwm_printf("Skipping comment\n"); - continue; - } - - /* determine what this is */ - pos = 0; - - while(pos < len && (buf[pos] == ' ' || buf[pos] == '\t') ) { - pos++; - } - if((pos + 4) > len || buf[pos] != 's' || buf[pos+2] != 'd' || - buf[pos+1] > '9' || buf[pos+1] < '0') { - config_parse_option(buf, pos, len, line); - continue; - } - - slot = buf[pos+1] - '0'; - drive = buf[pos+3] - '0'; - - /* skip over slot, drive */ - pos += 4; - if(buf[pos] >= '0' && buf[pos] <= '9') { - drive = drive * 10 + buf[pos] - '0'; - pos++; - } - - /* make s6d1 mean index 0 */ - drive--; - - while(pos < len && (buf[pos] == ' ' || buf[pos] == '\t' || - buf[pos] == '=') ) { - pos++; - } - - ejected = 0; - if(buf[pos] == '#') { - /* disk is ejected, but read all the info anyway */ - ejected = 1; - pos++; - } - - size = 0; - if(buf[pos] == ',') { - /* read optional size parameter */ - pos++; - while(pos < len && buf[pos] >= '0' && buf[pos] <= '9'){ - size = size * 10 + buf[pos] - '0'; - pos++; - } - size = size * 1024; - if(buf[pos] == ',') { - pos++; /* eat trailing ',' */ - } - } - - /* see if it has a partition name */ - partition_name = 0; - part_num = -1; - if(buf[pos] == ':') { - pos++; - /* yup, it's got a partition name! */ - partition_name = &buf[pos]; - while((pos < len) && (buf[pos] != ':')) { - pos++; - } - buf[pos] = 0; /* null terminate partition name */ - pos++; - } - if(buf[pos] == ';') { - pos++; - /* it's got a partition number */ - part_num = 0; - while((pos < len) && (buf[pos] != ':')) { - part_num = (10*part_num) + buf[pos] - '0'; - pos++; - } - pos++; - } - - /* Get filename */ - name_ptr = &(buf[pos]); - if(name_ptr[0] == 0) { - continue; - } - - insert_disk(slot, drive, name_ptr, ejected, size, - partition_name, part_num); - - } - - ret = fclose(fconf); - if(ret != 0) { - fatal_printf("Closing configuration file ret: %d, errno: %d\n", ret, - errno); - my_exit(4); - } - - iwm_printf("Done parsing disk_conf file\n"); -} - - -Disk * -cfg_get_dsk_from_slot_drive(int slot, int drive) -{ - Disk *dsk; - int max_drive; - - /* Get dsk */ - max_drive = 2; - switch(slot) { - case 5: - dsk = &(iwm.drive35[drive]); - break; - case 6: - dsk = &(iwm.drive525[drive]); - break; - default: - max_drive = MAX_C7_DISKS; - dsk = &(iwm.smartport[drive]); - } - - if(drive >= max_drive) { - dsk -= drive; /* move back to drive 0 effectively */ - } - - return dsk; -} - -void -config_generate_config_gsport_name(char *outstr, int maxlen, Disk *dsk, - int with_extras) -{ - char *str; - - str = outstr; - - if(with_extras && (!dsk->file)) { - snprintf(str, maxlen - (str - outstr), "#"); - str = &outstr[strlen(outstr)]; - } - if(with_extras && dsk->force_size > 0) { - snprintf(str, maxlen - (str - outstr), ",%d,", dsk->force_size); - str = &outstr[strlen(outstr)]; - } - if(with_extras && dsk->partition_name != 0) { - snprintf(str, maxlen - (str - outstr), ":%s:", - dsk->partition_name); - str = &outstr[strlen(outstr)]; - } else if(with_extras && dsk->partition_num >= 0) { - snprintf(str, maxlen - (str - outstr), ";%d:", - dsk->partition_num); - str = &outstr[strlen(outstr)]; - } - snprintf(str, maxlen - (str - outstr), "%s", dsk->name_ptr); -} - -void -config_write_config_gsport_file() -{ - FILE *fconf; - Disk *dsk; - Cfg_defval *defptr; - Cfg_menu *menuptr; - char *curstr, *defstr; - int defval, curval; - int type; - int slot, drive; - int i; - - printf("Writing configuration file to %s\n", g_config_gsport_name); - - fconf = fopen(g_config_gsport_name, "w+"); - if(fconf == 0) { - halt_printf("cannot open %s! Stopping!\n",g_config_gsport_name); - return; - } - - fprintf(fconf, "# GSport configuration file version %s\n", - g_gsport_version_str); - - for(i = 0; i < MAX_C7_DISKS + 4; i++) { - slot = 7; - drive = i - 4; - if(i < 4) { - slot = (i >> 1) + 5; - drive = i & 1; - } - if(drive == 0) { - fprintf(fconf, "\n"); /* an extra blank line */ - } - - dsk = cfg_get_dsk_from_slot_drive(slot, drive); - if(dsk->name_ptr == 0 && (i > 4)) { - /* No disk, not even ejected--just skip */ - continue; - } - fprintf(fconf, "s%dd%d = ", slot, drive + 1); - if(dsk->name_ptr == 0) { - fprintf(fconf, "\n"); - continue; - } - config_generate_config_gsport_name(&g_cfg_tmp_path[0], - CFG_PATH_MAX, dsk, 1); - fprintf(fconf, "%s\n", &g_cfg_tmp_path[0]); - } - - fprintf(fconf, "\n"); - - /* See if any variables are different than their default */ - for(i = 0; i < g_cfg_defval_index; i++) { - defptr = &(g_cfg_defvals[i]); - menuptr = defptr->menuptr; - defval = defptr->intval; - type = menuptr->cfgtype; - if(type == CFGTYPE_INT) { - curval = *((int *)menuptr->ptr); - if(curval != defval) { - fprintf(fconf, "%s = %d\n", menuptr->name_str, - curval); - } - } - if(type == CFGTYPE_STR) { - curstr = *((char **)menuptr->ptr); - defstr = *((char **)menuptr->defptr); - if(strcmp(curstr, defstr) != 0) { - fprintf(fconf, "%s = %s\n", menuptr->name_str, - curstr); - } - } - if(type == CFGTYPE_FILE) { - curstr = *((char **)menuptr->ptr); - defstr = *((char **)menuptr->defptr); - if(strcmp(curstr, defstr) != 0) { - fprintf(fconf, "%s = %s\n", menuptr->name_str, - curstr); - } - } - } - - fprintf(fconf, "\n"); - - /* write bram state */ - clk_write_bram(fconf); - - fclose(fconf); - - g_config_gsport_update_needed = 0; -} - -void -insert_disk(int slot, int drive, const char *name, int ejected, int force_size, - const char *partition_name, int part_num) -{ - byte buf_2img[512]; - Disk *dsk; - char *name_ptr, *uncomp_ptr, *system_str; - char *part_ptr; - int size; - int system_len; - int part_len; - int cmp_o, cmp_p, cmp_dot; - int cmp_b, cmp_i, cmp_n; - int can_write; - int len; - int nibs; - int unix_pos; - int name_len; - int image_identified; - int exp_size; - int save_track; - int ret; - int tmp; - int i; - - g_config_gsport_update_needed = 1; - - if((slot < 5) || (slot > 7)) { - fatal_printf("Invalid slot for inserting disk: %d\n", slot); - return; - } - if(drive < 0 || ((slot == 7) && (drive >= MAX_C7_DISKS)) || - ((slot < 7) && (drive > 1))) { - fatal_printf("Invalid drive for inserting disk: %d\n", drive); - return; - } - - dsk = cfg_get_dsk_from_slot_drive(slot, drive); - -#if 0 - printf("Inserting disk %s (%s or %d) in slot %d, drive: %d\n", name, - partition_name, part_num, slot, drive); -#endif - - dsk->just_ejected = 0; - dsk->force_size = force_size; - - if(!dsk->file) { - eject_disk(dsk); - } - - /* Before opening, make sure no other mounted disk has this name */ - /* If so, unmount it */ - if(!ejected) { - for(i = 0; i < 2; i++) { - eject_named_disk(&iwm.drive525[i], name,partition_name); - eject_named_disk(&iwm.drive35[i], name, partition_name); - } - for(i = 0; i < MAX_C7_DISKS; i++) { - eject_named_disk(&iwm.smartport[i],name,partition_name); - } - } - - if(dsk->name_ptr != 0) { - /* free old name_ptr */ - free(dsk->name_ptr); - } - - name_len = strlen(name); - name_ptr = (char *)malloc(name_len + 1); -#if defined(_WIN32) || defined(__CYGWIN__) - // On Windows, we need to change backslashes to forward slashes. - for (i = 0; i < name_len; i++) { - if (name[i] == '\\') { - name_ptr[i] = '/'; - } else { - name_ptr[i] = name[i]; - } - } - name_ptr[name_len] = 0; -#else - strncpy(name_ptr, name, name_len + 1); -#endif - dsk->name_ptr = name_ptr; - - dsk->partition_name = 0; - if(partition_name != 0) { - part_len = strlen(partition_name) + 1; - part_ptr = (char *)malloc(part_len); - strncpy(part_ptr, partition_name, part_len); - dsk->partition_name = part_ptr; - } - dsk->partition_num = part_num; - - iwm_printf("Opening up disk image named: %s\n", name_ptr); - - if(ejected) { - /* just get out of here */ - dsk->file = 0; - return; - } - - dsk->file = 0; - can_write = 1; - - if((name_len > 3) && (strcmp(&name_ptr[name_len - 3], ".gz") == 0)) { - - /* it's gzip'ed, try to gunzip it, then unlink the */ - /* uncompressed file */ - - can_write = 0; - - uncomp_ptr = (char *)malloc(name_len + 1); - strncpy(uncomp_ptr, name_ptr, name_len + 1); - uncomp_ptr[name_len - 3] = 0; - - system_len = 2*name_len + 100; - system_str = (char *)malloc(system_len + 1); - snprintf(system_str, system_len, - "set -o noclobber;gunzip -c %c%s%c > %c%s%c", - 0x22, name_ptr, 0x22, - 0x22, uncomp_ptr, 0x22); - /* 0x22 are " to allow spaces in filenames */ - printf("I am uncompressing %s into %s for mounting\n", - name_ptr, uncomp_ptr); - ret = system(system_str); - if(ret == 0) { - /* successfully ran */ - dsk->file = fopen(uncomp_ptr, "rb"); - iwm_printf("Opening .gz file %s\n", uncomp_ptr); - - /* and, unlink the temporary file */ - (void)unlink(uncomp_ptr); - } - free(system_str); - free(uncomp_ptr); - /* Reduce name_len by 3 so that subsequent compares for .po */ - /* look at the correct chars */ - name_len -= 3; - } - - if((!dsk->file) && can_write) { - dsk->file = fopen(name_ptr, "rb+"); - } - - if((!dsk->file) && can_write) { - printf("Trying to open %s read-only, errno: %d\n", name_ptr, - errno); - dsk->file = fopen(name_ptr, "rb"); - can_write = 0; - } - - if(!dsk->file) { - fatal_printf("Disk image %s does not exist!\n", name_ptr); - return; - } - - if(can_write != 0) { - dsk->write_prot = 0; - dsk->write_through_to_unix = 1; - } else { - dsk->write_prot = 1; - dsk->write_through_to_unix = 0; - } - - save_track = dsk->cur_qtr_track; /* save arm position */ - dsk->image_type = DSK_TYPE_PRODOS; - dsk->image_start = 0; - - /* See if it is in 2IMG format */ - ret = fread((char *)&buf_2img[0], 1, 512, dsk->file); - size = force_size; - if(size <= 0) { - size = cfg_get_fd_size(name_ptr); - } - - /* Try to guess that there is a Mac Binary header of 128 bytes */ - /* See if image size & 0xfff = 0x080 which indicates extra 128 bytes */ - if((size & 0xfff) == 0x080) { - printf("Assuming Mac Binary header on %s\n", dsk->name_ptr); - dsk->image_start += 0x80; - } - image_identified = 0; - if(buf_2img[0] == '2' && buf_2img[1] == 'I' && buf_2img[2] == 'M' && - buf_2img[3] == 'G') { - /* It's a 2IMG disk */ - printf("Image named %s is in 2IMG format\n", dsk->name_ptr); - image_identified = 1; - - if(buf_2img[12] == 0) { - printf("2IMG is in DOS 3.3 sector order\n"); - dsk->image_type = DSK_TYPE_DOS33; - } - if(buf_2img[19] & 0x80) { - /* disk is locked */ - printf("2IMG is write protected\n"); - dsk->write_prot = 1; - dsk->write_through_to_unix = 0; - } - if((buf_2img[17] & 1) && (dsk->image_type == DSK_TYPE_DOS33)) { - dsk->vol_num = buf_2img[16]; - printf("Setting DOS 3.3 vol num to %d\n", dsk->vol_num); - } - // Some 2IMG archives have the size byte reversed - size = (buf_2img[31] << 24) + (buf_2img[30] << 16) + - (buf_2img[29] << 8) + buf_2img[28]; - unix_pos = (buf_2img[27] << 24) + (buf_2img[26] << 16) + - (buf_2img[25] << 8) + buf_2img[24]; - if(size == 0x800c00) { - // Byte reversed 0x0c8000 - size = 0x0c8000; - } - dsk->image_start = unix_pos; - dsk->image_size = size; - } - exp_size = 800*1024; - if(dsk->disk_525) { - exp_size = 140*1024; - } - if(!image_identified) { - /* See if it might be the Mac diskcopy format */ - tmp = (buf_2img[0x40] << 24) + (buf_2img[0x41] << 16) + - (buf_2img[0x42] << 8) + buf_2img[0x43]; - if((size >= (exp_size + 0x54)) && (tmp == exp_size)) { - /* It's diskcopy since data size field matches */ - printf("Image named %s is in Mac diskcopy format\n", - dsk->name_ptr); - image_identified = 1; - dsk->image_start += 0x54; - dsk->image_size = exp_size; - dsk->image_type = DSK_TYPE_PRODOS; /* ProDOS */ - } - } - if(!image_identified) { - /* Assume raw image */ - dsk->image_size = size; - dsk->image_type = DSK_TYPE_PRODOS; - if(dsk->disk_525) { - dsk->image_type = DSK_TYPE_DOS33; - if(name_len >= 4) { - cmp_o = dsk->name_ptr[name_len-1]; - cmp_p = dsk->name_ptr[name_len-2]; - cmp_dot = dsk->name_ptr[name_len-3]; - if(cmp_dot == '.' && - (cmp_p == 'p' || cmp_p == 'P') && - (cmp_o == 'o' || cmp_o == 'O')) { - dsk->image_type = DSK_TYPE_PRODOS; - } - - cmp_b = dsk->name_ptr[name_len-1]; - cmp_i = dsk->name_ptr[name_len-2]; - cmp_n = dsk->name_ptr[name_len-3]; - cmp_dot = dsk->name_ptr[name_len-4]; - if(cmp_dot == '.' && - (cmp_n == 'n' || cmp_n == 'N') && - (cmp_i == 'i' || cmp_i == 'I') && - (cmp_b == 'b' || cmp_b == 'B')) { - dsk->image_type = DSK_TYPE_NIB; - dsk->write_prot = 1; - dsk->write_through_to_unix = 0; - } - } - } - } - - dsk->disk_dirty = 0; - dsk->nib_pos = 0; - dsk->trks = 0; - - if(dsk->smartport) { - g_highest_smartport_unit = MAX(dsk->drive, - g_highest_smartport_unit); - - if(partition_name != 0 || part_num >= 0) { - ret = cfg_partition_find_by_name_or_num(dsk->file, - partition_name, part_num, dsk); - printf("partition %s (num %d) mounted, wr_prot: %d\n", - partition_name, part_num, dsk->write_prot); - - if(ret < 0) { - fclose(dsk->file); - dsk->file = 0; - return; - } - } - iwm_printf("adding smartport device[%d], size:%08x, " - "img_sz:%08x\n", dsk->drive, dsk->trks[0].unix_len, - dsk->image_size); - } else if(dsk->disk_525) { - unix_pos = dsk->image_start; - size = dsk->image_size; - disk_set_num_tracks(dsk, 4*35); - len = 0x1000; - nibs = NIB_LEN_525; - if(dsk->image_type == DSK_TYPE_NIB) { - len = dsk->image_size / 35;; - nibs = len; - } - if(size != 35*len) { - fatal_printf("Disk 5.25 error: size is %d, not 140K. " - "Will try to mount anyway\n", size, 35*len); - } - for(i = 0; i < 35; i++) { - iwm_move_to_track(dsk, 4*i); - disk_unix_to_nib(dsk, 4*i, unix_pos, len, nibs); - unix_pos += len; - } - } else { - /* disk_35 */ - unix_pos = dsk->image_start; - size = dsk->image_size; - if(size != 800*1024) { - fatal_printf("Disk 3.5 error: size is %d, not 800K. " - "Will try to mount anyway\n", size); - } - disk_set_num_tracks(dsk, 2*80); - for(i = 0; i < 2*80; i++) { - iwm_move_to_track(dsk, i); - len = g_track_bytes_35[i >> 5]; - nibs = g_track_nibs_35[i >> 5]; - iwm_printf("Trk: %d.%d = unix: %08x, %04x, %04x\n", - i>>1, i & 1, unix_pos, len, nibs); - disk_unix_to_nib(dsk, i, unix_pos, len, nibs); - unix_pos += len; - - iwm_printf(" trk_len:%05x\n", dsk->trks[i].track_len); - } - } - - iwm_move_to_track(dsk, save_track); - -} - -void -eject_named_disk(Disk *dsk, const char *name, const char *partition_name) -{ - - if(!dsk->file) { - return; - } - - /* If name matches, eject the disk! */ - if(!strcmp(dsk->name_ptr, name)) { - /* It matches, eject it */ - if((partition_name != 0) && (dsk->partition_name != 0)) { - /* If both have partitions, and they differ, then */ - /* don't eject. Otherwise, eject */ - if(strcmp(dsk->partition_name, partition_name) != 0) { - /* Don't eject */ - return; - } - } - eject_disk(dsk); - } -} - -void -eject_disk_by_num(int slot, int drive) -{ - Disk *dsk; - - dsk = cfg_get_dsk_from_slot_drive(slot, drive); - - eject_disk(dsk); -} - -void -eject_disk(Disk *dsk) -{ - int motor_on; - int i; - - if(!dsk->file) { - return; - } - - g_config_gsport_update_needed = 1; - - motor_on = iwm.motor_on; - if(g_c031_disk35 & 0x40) { - motor_on = iwm.motor_on35; - } - if(motor_on) { - halt_printf("Try eject dsk:%s, but motor_on!\n", dsk->name_ptr); - } - - iwm_flush_disk_to_unix(dsk); - - printf("Ejecting disk: %s\n", dsk->name_ptr); - - /* Free all memory, close file */ - - /* free the tracks first */ - if(dsk->trks != 0) { - for(i = 0; i < dsk->num_tracks; i++) { - if(dsk->trks[i].nib_area) { - free(dsk->trks[i].nib_area); - } - dsk->trks[i].nib_area = 0; - dsk->trks[i].track_len = 0; - } - free(dsk->trks); - } - dsk->num_tracks = 0; - dsk->trks = 0; - - /* close file, clean up dsk struct */ - fclose(dsk->file); - - dsk->image_start = 0; - dsk->image_size = 0; - dsk->nib_pos = 0; - dsk->disk_dirty = 0; - dsk->write_through_to_unix = 0; - dsk->write_prot = 1; - dsk->file = 0; - dsk->just_ejected = 1; - - /* Leave name_ptr valid */ -} - -int -cfg_get_fd_size(char *filename) -{ - struct stat stat_buf; - int ret; - - ret = stat(filename, &stat_buf); - if(ret != 0) { - fprintf(stderr,"stat %s returned errno: %d\n", - filename, errno); - stat_buf.st_size = 0; - } - - return stat_buf.st_size; -} - -int -cfg_partition_read_block(FILE *file, void *buf, int blk, int blk_size) -{ - int ret; - - ret = fseek(file, blk * blk_size, SEEK_SET); - if(ret != 0) { - printf("fseek: wanted: %08x, errno: %d\n", - blk * blk_size, errno); - return 0; - } - - ret = fread((char *)buf, 1, blk_size, file); - if(ret != blk_size) { - printf("ret: %08x, wanted %08x, errno: %d\n", ret, blk_size, - errno); - return 0; - } - return ret; -} - -int -cfg_partition_find_by_name_or_num(FILE *file, const char *partnamestr, int part_num, - Disk *dsk) -{ - Cfg_dirent *direntptr; - int match; - int num_parts; - int i; - - num_parts = cfg_partition_make_list(dsk->name_ptr, file); - - if(num_parts <= 0) { - return -1; - } - - for(i = 0; i < g_cfg_partitionlist.last; i++) { - direntptr = &(g_cfg_partitionlist.direntptr[i]); - match = 0; - if((strncmp(partnamestr, direntptr->name, 32) == 0) && - (part_num < 0)) { - //printf("partition, match1, name:%s %s, part_num:%d\n", - // partnamestr, direntptr->name, part_num); - - match = 1; - } - if((partnamestr == 0) && (direntptr->part_num == part_num)) { - //printf("partition, match2, n:%s, part_num:%d == %d\n", - // direntptr->name, direntptr->part_num, part_num); - match = 1; - } - if(match) { - dsk->image_start = direntptr->image_start; - dsk->image_size = direntptr->size; - //printf("match with image_start: %08x, image_size: " - // "%08x\n", dsk->image_start, dsk->image_size); - - return i; - } - } - - return -1; -} - -int -cfg_partition_make_list(char *filename, FILE *file) -{ - Driver_desc *driver_desc_ptr; - Part_map *part_map_ptr; - word32 *blk_bufptr; - word32 start; - word32 len; - word32 data_off; - word32 data_len; - word32 sig; - int size; - int image_start, image_size; - int is_dir; - int block_size; - int map_blks; - int cur_blk; - - block_size = 512; - - cfg_free_alldirents(&g_cfg_partitionlist); - - blk_bufptr = (word32 *)malloc(MAX_PARTITION_BLK_SIZE); - - cfg_partition_read_block(file, blk_bufptr, 0, block_size); - - driver_desc_ptr = (Driver_desc *)blk_bufptr; - sig = GET_BE_WORD16(driver_desc_ptr->sig); - block_size = GET_BE_WORD16(driver_desc_ptr->blk_size); - if(block_size == 0) { - block_size = 512; - } - if(sig != 0x4552 || block_size < 0x200 || - (block_size > MAX_PARTITION_BLK_SIZE)) { - cfg_printf("Partition error: No driver descriptor map found\n"); - free(blk_bufptr); - return 0; - } - - map_blks = 1; - cur_blk = 0; - size = cfg_get_fd_size(filename); - cfg_file_add_dirent(&g_cfg_partitionlist, "None - Whole image", - is_dir=0, size, 0, -1); - - while(cur_blk < map_blks) { - cur_blk++; - cfg_partition_read_block(file, blk_bufptr, cur_blk, block_size); - part_map_ptr = (Part_map *)blk_bufptr; - sig = GET_BE_WORD16(part_map_ptr->sig); - if(cur_blk <= 1) { - map_blks = MIN(20, - GET_BE_WORD32(part_map_ptr->map_blk_cnt)); - } - if(sig != 0x504d) { - printf("Partition entry %d bad signature:%04x\n", - cur_blk, sig); - free(blk_bufptr); - return g_cfg_partitionlist.last; - } - - /* found it, check for consistency */ - start = GET_BE_WORD32(part_map_ptr->phys_part_start); - len = GET_BE_WORD32(part_map_ptr->part_blk_cnt); - data_off = GET_BE_WORD32(part_map_ptr->data_start); - data_len = GET_BE_WORD32(part_map_ptr->data_cnt); - if(data_off + data_len > len) { - printf("Poorly formed entry\n"); - continue; - } - - if(data_len < 10 || start < 1) { - printf("Poorly formed entry %d, datalen:%d, " - "start:%08x\n", cur_blk, data_len, start); - continue; - } - - image_size = data_len * block_size; - image_start = (start + data_off) * block_size; - is_dir = 2*(image_size < 800*1024); -#if 0 - printf(" partition add entry %d = %s %d %08x %08x\n", - cur_blk, part_map_ptr->part_name, is_dir, - image_size, image_start); -#endif - - cfg_file_add_dirent(&g_cfg_partitionlist, - part_map_ptr->part_name, is_dir, image_size, - image_start, cur_blk); - } - - free(blk_bufptr); - return g_cfg_partitionlist.last; -} - -int -cfg_maybe_insert_disk(int slot, int drive, const char *namestr) -{ - int num_parts; - FILE *file; - - file = fopen(namestr, "rb"); - if(!file) { - fatal_printf("Cannot open disk image: %s\n", namestr); - return 0; - } - - num_parts = cfg_partition_make_list((char*)namestr, file); - fclose(file); - - if(num_parts > 0) { - printf("Choose a partition\n"); - g_cfg_select_partition = 1; - } else { - insert_disk(slot, drive, namestr, 0, 0, 0, -1); - return 1; - } - return 0; -} - -int -cfg_stat(char *path, struct stat *sb) -{ - int removed_slash; - int len; - int ret; - - removed_slash = 0; - len = 0; - -#ifdef _WIN32 - /* Windows doesn't like to stat paths ending in a /, so remove it */ - len = strlen(path); - if((len > 1) && (path[len - 1] == '/') ) { - path[len - 1] = 0; /* remove the slash */ - removed_slash = 1; - } -#endif - - ret = stat(path, sb); - -#ifdef _WIN32 - /* put the slash back */ - if(removed_slash) { - path[len - 1] = '/'; - } -#endif - - return ret; -} - -void -cfg_htab_vtab(int x, int y) -{ - if(x > 79) { - x = 0; - } - if(y > 23) { - y = 0; - } - g_cfg_curs_x = x; - g_cfg_curs_y = y; - g_cfg_curs_inv = 0; - g_cfg_curs_mousetext = 0; -} - -void -cfg_home() -{ - int i; - - cfg_htab_vtab(0, 0); - for(i = 0; i < 24; i++) { - cfg_cleol(); - } -} - -void -cfg_cleol() -{ - g_cfg_curs_inv = 0; - g_cfg_curs_mousetext = 0; - cfg_putchar(' '); - while(g_cfg_curs_x != 0) { - cfg_putchar(' '); - } -} - -void -cfg_putchar(int c) -{ - int offset; - int x, y; - - if(c == '\n') { - cfg_cleol(); - return; - } - if(c == '\b') { - g_cfg_curs_inv = !g_cfg_curs_inv; - return; - } - if(c == '\t') { - g_cfg_curs_mousetext = !g_cfg_curs_mousetext; - return; - } - y = g_cfg_curs_y; - x = g_cfg_curs_x; - - offset = g_screen_index[g_cfg_curs_y]; - if((x & 1) == 0) { - offset += 0x10000; - } - if(g_cfg_curs_inv) { - if(c >= 0x40 && c < 0x60) { - c = c & 0x1f; - } - } else { - c = c | 0x80; - } - if(g_cfg_curs_mousetext) { - c = (c & 0x1f) | 0x40; - } - set_memory_c(0xe00400 + offset + (x >> 1), c, 0); - x++; - if(x >= 80) { - x = 0; - y++; - if(y >= 24) { - y = 0; - } - } - g_cfg_curs_y = y; - g_cfg_curs_x = x; -} - -void -cfg_printf(const char *fmt, ...) -{ - va_list ap; - int c; - int i; - - va_start(ap, fmt); - (void)vsnprintf(g_cfg_printf_buf, CFG_PRINTF_BUFSIZE, fmt, ap); - va_end(ap); - - for(i = 0; i < CFG_PRINTF_BUFSIZE; i++) { - c = g_cfg_printf_buf[i]; - if(c == 0) { - return; - } - cfg_putchar(c); - } -} - -void -cfg_print_num(int num, int max_len) -{ - char buf[64]; - char buf2[64]; - int len; - int cnt; - int c; - int i, j; - - /* Prints right-adjusted "num" in field "max_len" wide */ - snprintf(&buf[0], 64, "%d", num); - len = strlen(buf); - for(i = 0; i < 64; i++) { - buf2[i] = ' '; - } - j = max_len + 1; - buf2[j] = 0; - j--; - cnt = 0; - for(i = len - 1; (i >= 0) && (j >= 1); i--) { - c = buf[i]; - if(c >= '0' && c <= '9') { - if(cnt >= 3) { - buf2[j--] = ','; - cnt = 0; - } - cnt++; - } - buf2[j--] = c; - } - cfg_printf(&buf2[1]); -} - -void -cfg_get_disk_name(char *outstr, int maxlen, int type_ext, int with_extras) -{ - Disk *dsk; - int slot, drive; - - slot = type_ext >> 8; - drive = type_ext & 0xff; - dsk = cfg_get_dsk_from_slot_drive(slot, drive); - - outstr[0] = 0; - if(dsk->name_ptr == 0) { - return; - } - - config_generate_config_gsport_name(outstr, maxlen, dsk, with_extras); -} - -void -cfg_parse_menu(Cfg_menu *menuptr, int menu_pos, int highlight_pos, int change) -{ - char valbuf[CFG_OPT_MAXSTR]; - char **str_ptr; - const char *menustr; - char *curstr, *defstr; - char *str; - char *outstr; - int *iptr; - int val; - int num_opts; - int opt_num; - int bufpos, outpos; - int curval, defval; - int type; - int type_ext; - int opt_get_str; - int separator; - int len; - int c; - int i; - - g_cfg_opt_buf[0] = 0; - - num_opts = 0; - opt_get_str = 0; - separator = ','; - - menuptr += menu_pos; /* move forward to entry menu_pos */ - - menustr = menuptr->str; - type = menuptr->cfgtype; - type_ext = (type >> 4); - type = type & 0xf; - len = strlen(menustr) + 1; - - bufpos = 0; - outstr = &(g_cfg_opt_buf[0]); - - outstr[bufpos++] = ' '; - outstr[bufpos++] = ' '; - outstr[bufpos++] = '\t'; - outstr[bufpos++] = '\t'; - outstr[bufpos++] = ' '; - outstr[bufpos++] = ' '; - - if(menu_pos == highlight_pos) { - outstr[bufpos++] = '\b'; - } - - opt_get_str = 2; - i = -1; - outpos = bufpos; -#if 0 - printf("cfg menu_pos: %d str len: %d\n", menu_pos, len); -#endif - while(++i < len) { - c = menustr[i]; - if(c == separator) { - if(i == 0) { - continue; - } - c = 0; - } - outstr[outpos++] = c; - outstr[outpos] = 0; - if(outpos >= CFG_OPT_MAXSTR) { - fprintf(stderr, "CFG_OPT_MAXSTR exceeded\n"); - my_exit(1); - } - if(c == 0) { - if(opt_get_str == 2) { - outstr = &(valbuf[0]); - bufpos = outpos - 1; - opt_get_str = 0; - } else if(opt_get_str) { -#if 0 - if(menu_pos == highlight_pos) { - printf("menu_pos %d opt %d = %s=%d\n", - menu_pos, num_opts, - g_cfg_opts_strs[num_opts], - g_cfg_opts_vals[num_opts]); - } -#endif - num_opts++; - outstr = &(valbuf[0]); - opt_get_str = 0; - if(num_opts >= CFG_MAX_OPTS) { - fprintf(stderr, "CFG_MAX_OPTS oflow\n"); - my_exit(1); - } - } else { - if (type == CFGTYPE_INT) - { - val = strtoul(valbuf, 0, 0); - g_cfg_opts_vals[num_opts] = val; - } - - if (type == CFGTYPE_STR) - { - strncpy(&(g_cfg_opts_strvals[num_opts][0]),&(valbuf[0]),CFG_OPT_MAXSTR); - } - outstr = &(g_cfg_opts_strs[num_opts][0]); - opt_get_str = 1; - } - outpos = 0; - outstr[0] = 0; - } - } - - if(menu_pos == highlight_pos) { - g_cfg_opt_buf[bufpos++] = '\b'; - } - - g_cfg_opt_buf[bufpos] = 0; - - // Figure out if we should get a checkmark - curval = -1; - defval = -1; - curstr = 0; - if(type == CFGTYPE_INT) { +}; + +#if defined(_WIN32) || defined(__CYGWIN__) +Cfg_menu g_cfg_debug_menu[] = { +{ "Debugging Options", g_cfg_debug_menu, 0, 0, CFGTYPE_MENU }, +{ "Status lines,0,Hide,1,Show", KNMP(g_win_status_debug_request), CFGTYPE_INT }, +{ "Console,0,Hide,1,Show", KNMP(g_win_show_console_request), CFGTYPE_INT }, +{ "", 0, 0, 0, 0 }, +{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, +{ 0, 0, 0, 0, 0 }, +}; +#endif + +Cfg_menu g_cfg_main_menu[] = { +{ "GSport Configuration", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, +{ "Disk Configuration", g_cfg_disk_menu, 0, 0, CFGTYPE_MENU }, +{ "Joystick Configuration", g_cfg_joystick_menu, 0, 0, CFGTYPE_MENU }, +{ "ROM File Selection", g_cfg_rom_menu, 0, 0, CFGTYPE_MENU }, +{ "Serial Port Configuration", g_cfg_serial_menu, 0, 0, CFGTYPE_MENU }, +{ "Ethernet Card Configuration", g_cfg_ethernet_menu, 0, 0, CFGTYPE_MENU }, +{ "Parallel Card Configuration", g_cfg_parallel_menu, 0, 0, CFGTYPE_MENU }, +{ "Virtual Printer Configuration", g_cfg_printer_menu, 0, 0, CFGTYPE_MENU }, +{ "Virtual Imagewriter Configuration", g_cfg_imagewriter_menu, 0, 0, CFGTYPE_MENU }, +#ifndef _WIN32 +{ "Force X-windows display depth", KNMP(g_force_depth), CFGTYPE_INT }, +#endif +#if defined(_WIN32) || defined(__CYGWIN__) +{ "Debugging Options", g_cfg_debug_menu, 0, 0, CFGTYPE_MENU }, +#endif +{ "Auto-update configuration file,0,Manual,1,Immediately", + KNMP(g_config_gsport_auto_update), CFGTYPE_INT }, +{ "Speed,0,Unlimited,1,1.0MHz,2,2.8MHz,3,8.0MHz (Zip)", + KNMP(g_limit_speed), CFGTYPE_INT }, +{ "Expansion Mem Size,0,0MB,0x100000,1MB,0x200000,2MB,0x300000,3MB," + "0x400000,4MB,0x600000,6MB,0x800000,8MB,0xa00000,10MB,0xc00000,12MB," + "0xe00000,14MB", KNMP(g_mem_size_exp), CFGTYPE_INT }, +{ "3200 Color Enable,0,Auto (Full if fast enough),1,Full (Update every line)," + "8,Off (Update video every 8 lines)", + KNMP(g_video_line_update_interval), CFGTYPE_INT }, +{ "Keyboard and mouse poll rate,0,60 times per second,1,240 times per second", + KNMP(g_video_extra_check_inputs), CFGTYPE_INT }, +{ "Code Red Halts,0,Do not stop on bad accesses,1,Enter debugger on bad " + "accesses", KNMP(g_user_halt_bad), CFGTYPE_INT }, +{ "Enable Text Page 2 Shadow,0,Disabled on ROM 01 (matches real hardware)," + "1,Enabled on ROM 01 and 03", + KNMP(g_user_page2_shadow), CFGTYPE_INT }, +{ "Dump text screen to file", (void *)cfg_text_screen_dump, 0, 0, CFGTYPE_FUNC}, +{ "", 0, 0, 0, 0 }, +{ "Save changes to configuration file", (void *)config_write_config_gsport_file, 0, 0, + CFGTYPE_FUNC }, +{ "", 0, 0, 0, 0 }, +{ "Exit Config (or press F4)", (void *)cfg_exit, 0, 0, CFGTYPE_FUNC }, +{ 0, 0, 0, 0, 0 }, +}; + + +#define CFG_MAX_DEFVALS 128 +Cfg_defval g_cfg_defvals[CFG_MAX_DEFVALS]; +int g_cfg_defval_index = 0; + +int g_cfg_slotdrive = -1; +int g_cfg_select_partition = -1; +char g_cfg_tmp_path[CFG_PATH_MAX]; +char g_cfg_file_path[CFG_PATH_MAX]; +char g_cfg_file_cachedpath[CFG_PATH_MAX]; +char g_cfg_file_cachedreal[CFG_PATH_MAX]; +char g_cfg_file_curpath[CFG_PATH_MAX]; +char g_cfg_file_shortened[CFG_PATH_MAX]; +char g_cfg_file_match[CFG_PATH_MAX]; + +Cfg_listhdr g_cfg_dirlist = { 0 }; +Cfg_listhdr g_cfg_partitionlist = { 0 }; + +int g_cfg_file_pathfield = 0; + +const char *g_gsport_rom_names[] = { "ROM", "ROM", "ROM.01", "ROM.03", 0 }; + /* First entry is special--it will be overwritten by g_cfg_rom_path */ + +const char *g_gsport_c1rom_names[] = { "parallel.rom", 0 }; +const char *g_gsport_c2rom_names[] = { 0 }; +const char *g_gsport_c3rom_names[] = { 0 }; +const char *g_gsport_c4rom_names[] = { 0 }; +const char *g_gsport_c5rom_names[] = { 0 }; +const char *g_gsport_c6rom_names[] = { "c600.rom", "controller.rom", "disk.rom", + "DISK.ROM", "diskII.prom", 0 }; +const char *g_gsport_c7rom_names[] = { 0 }; + +const char **g_gsport_rom_card_list[8] = { + 0, g_gsport_c1rom_names, + g_gsport_c2rom_names, g_gsport_c3rom_names, + g_gsport_c4rom_names, g_gsport_c5rom_names, + g_gsport_c6rom_names, g_gsport_c7rom_names }; + +byte g_rom_c600_rom01_diffs[256] = { + 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xe2, 0x00, + 0xd0, 0x50, 0x0f, 0x77, 0x5b, 0xb9, 0xc3, 0xb1, + 0xb1, 0xf8, 0xcb, 0x4e, 0xb8, 0x60, 0xc7, 0x2e, + 0xfc, 0xe0, 0xbf, 0x1f, 0x66, 0x37, 0x4a, 0x70, + 0x55, 0x2c, 0x3c, 0xfc, 0xc2, 0xa5, 0x08, 0x29, + 0xac, 0x21, 0xcc, 0x09, 0x55, 0x03, 0x17, 0x35, + 0x4e, 0xe2, 0x0c, 0xe9, 0x3f, 0x9d, 0xc2, 0x06, + 0x18, 0x88, 0x0d, 0x58, 0x57, 0x6d, 0x83, 0x8c, + 0x22, 0xd3, 0x4f, 0x0a, 0xe5, 0xb7, 0x9f, 0x7d, + 0x2c, 0x3e, 0xae, 0x7f, 0x24, 0x78, 0xfd, 0xd0, + 0xb5, 0xd6, 0xe5, 0x26, 0x85, 0x3d, 0x8d, 0xc9, + 0x79, 0x0c, 0x75, 0xec, 0x98, 0xcc, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x39, 0x00, 0x35, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, + 0x6c, 0x44, 0xce, 0x4c, 0x01, 0x08, 0x00, 0x00 +}; + + +void +config_init_menus(Cfg_menu *menuptr) +{ + void *voidptr; + const char *name_str; + Cfg_defval *defptr; + char **str_ptr; + char *str; + int type; + int pos; + int val; + + if(menuptr[0].defptr != 0) { + return; + } + menuptr[0].defptr = (void *)1; + pos = 0; + while(pos < 100) { + type = menuptr->cfgtype; + voidptr = menuptr->ptr; + name_str = menuptr->name_str; + if(menuptr->str == 0) { + break; + } + if(name_str != 0) { + defptr = &(g_cfg_defvals[g_cfg_defval_index++]); + if(g_cfg_defval_index >= CFG_MAX_DEFVALS) { + fatal_printf("CFG_MAX_DEFVAL overflow\n"); + my_exit(5); + } + defptr->menuptr = menuptr; + defptr->intval = 0; + defptr->strval = 0; + switch(type) { + case CFGTYPE_INT: + val = *((int *)voidptr); + defptr->intval = val; + menuptr->defptr = &(defptr->intval); + break; + case CFGTYPE_STR: + str_ptr = (char **)menuptr->ptr; + str = *str_ptr; + // We need to malloc this string since all + // string values must be dynamically alloced + defptr->strval = str; // this can have a copy + *str_ptr = gsport_malloc_str(str); + menuptr->defptr = &(defptr->strval); + break; + case CFGTYPE_FILE: + str_ptr = (char **)menuptr->ptr; + str = *str_ptr; + // We need to malloc this string since all + // string values must be dynamically alloced + defptr->strval = str; // this can have a copy + *str_ptr = gsport_malloc_str(str); + menuptr->defptr = &(defptr->strval); + break; + default: + fatal_printf("name_str is %p = %s, but type: " + "%d\n", name_str, name_str, type); + my_exit(5); + } + } + if(type == CFGTYPE_MENU) { + config_init_menus((Cfg_menu *)voidptr); + } + pos++; + menuptr++; + } +} + +void +config_init() +{ + int can_create; + + config_init_menus(g_cfg_main_menu); + + // Find the configuration file + g_config_gsport_name[0] = 0; + can_create = 1; + setup_gsport_file(&g_config_gsport_name[0], sizeof(g_config_gsport_name), 0, + can_create, &g_config_gsport_name_list[0]); + + config_parse_config_gsport_file(); +} + +void +cfg_exit() +{ + /* printf("In cfg exit\n"); */ + if(g_rom_version >= 1) { + g_config_control_panel = 0; + } +} + +void +cfg_toggle_config_panel() +{ + g_config_control_panel = !g_config_control_panel; + if(g_rom_version < 0) { + g_config_control_panel = 1; /* Stay in config mode */ + } +} + +void +cfg_text_screen_dump() +{ + char buf[85]; + char *filename; + FILE *ofile; + int offset; + int c; + int pos; + int i, j; + + filename = "gsport.screen.dump"; + printf("Writing text screen to the file %s\n", filename); + ofile = fopen(filename, "w"); + if(ofile == 0) { + fatal_printf("Could not write to file %s, (%d)\n", filename, + errno); + return; + } + + for(i = 0; i < 24; i++) { + pos = 0; + for(j = 0; j < 40; j++) { + offset = g_screen_index[i] + j; + if(g_save_cur_a2_stat & ALL_STAT_VID80) { + c = g_save_text_screen_bytes[0x400+offset]; + c = c & 0x7f; + if(c < 0x20) { + c += 0x40; + } + buf[pos++] = c; + } + c = g_save_text_screen_bytes[offset] & 0x7f; + if(c < 0x20) { + c += 0x40; + } + buf[pos++] = c; + } + while((pos > 0) && (buf[pos-1] == ' ')) { + /* try to strip out trailing spaces */ + pos--; + } + buf[pos++] = '\n'; + buf[pos++] = 0; + fputs(buf, ofile); + } + fclose(ofile); +} + +#ifdef HAVE_TFE +void +cfg_get_tfe_name() +{ + int i = 0; + char *ppname = NULL; + char *ppdes = NULL; + cfg_htab_vtab(0,9); + if (tfe_enumadapter_open()) + { + cfg_printf("Interface List:\n---------------"); + while(tfe_enumadapter(&ppname,&ppdes)) + { + cfg_htab_vtab(0, 11+i); + cfg_printf("%2d: %s",i,ppdes); + i++; + lib_free(ppname); + lib_free(ppdes); + } + tfe_enumadapter_close(); + } + else + { + #if defined(_WIN32) || defined(__CYGWIN__) + cfg_printf("ERROR: Install/Enable WinPcap for Ethernet Support!!"); + #else + cfg_printf("ERROR: Install/Enable LibPcap for Ethernet Support!!"); + #endif + } + return; +} +#endif + +void +config_vbl_update(int doit_3_persec) +{ + if(doit_3_persec) { + if(g_config_gsport_auto_update && g_config_gsport_update_needed) { + config_write_config_gsport_file(); + } + } + return; +} + +void +config_parse_option(char *buf, int pos, int len, int line) +{ + Cfg_menu *menuptr; + Cfg_defval *defptr; + char *nameptr; + char **strptr; + int *iptr; + int num_equals; + int type; + int val; + int c; + int i; + +// warning: modifies buf (turns spaces to nulls) +// parse buf from pos into option, "=" and then "rest" + if(pos >= len) { + /* blank line */ + return; + } + + if(strncmp(&buf[pos], "bram", 4) == 0) { + config_parse_bram(buf, pos+4, len); + return; + } + + // find "name" as first contiguous string + printf("...parse_option: line %d, %p,%p = %s (%s) len:%d\n", line, + &buf[pos], buf, &buf[pos], buf, len); + + nameptr = &buf[pos]; + while(pos < len) { + c = buf[pos]; + if(c == 0 || c == ' ' || c == '\t' || c == '\n') { + break; + } + pos++; + } + buf[pos] = 0; + pos++; + + // Eat up all whitespace and '=' + num_equals = 0; + while(pos < len) { + c = buf[pos]; + if((c == '=') && num_equals == 0) { + pos++; + num_equals++; + } else if(c == ' ' || c == '\t') { + pos++; + } else { + break; + } + } + + /* Look up nameptr to find type */ + type = -1; + defptr = 0; + menuptr = 0; + for(i = 0; i < g_cfg_defval_index; i++) { + defptr = &(g_cfg_defvals[i]); + menuptr = defptr->menuptr; + if(strcmp(menuptr->name_str, nameptr) == 0) { + type = menuptr->cfgtype; + break; + } + } + + switch(type) { + case CFGTYPE_INT: + /* use strtol */ + val = (int)strtol(&buf[pos], 0, 0); + iptr = (int *)menuptr->ptr; + *iptr = val; + break; + case CFGTYPE_STR: + strptr = (char **)menuptr->ptr; + if(strptr && *strptr) { + free(*strptr); + } + *strptr = gsport_malloc_str(&buf[pos]); + break; + case CFGTYPE_FILE: + strptr = (char **)menuptr->ptr; + if(strptr && *strptr) { + free(*strptr); + } + *strptr = gsport_malloc_str(&buf[pos]); + break; + default: + printf("Config file variable %s is unknown type: %d\n", + nameptr, type); + } + +} + +void +config_parse_bram(char *buf, int pos, int len) +{ + int bram_num; + int offset; + int val; + + if((len < (pos+5)) || (buf[pos+1] != '[') || (buf[pos+4] != ']')) { + fatal_printf("While reading configuration file, found malformed bram " + "statement: %s\n", buf); + return; + } + bram_num = buf[pos] - '0'; + if(bram_num != 1 && bram_num != 3) { + fatal_printf("While reading configuration file, found bad bram " + "num: %s\n", buf); + return; + } + + bram_num = bram_num >> 1; // turn 3->1 and 1->0 + + offset = strtoul(&(buf[pos+2]), 0, 16); + pos += 5; + while(pos < len) { + while(buf[pos] == ' ' || buf[pos] == '\t' || buf[pos] == 0x0a || + buf[pos] == 0x0d || buf[pos] == '=') { + pos++; + } + val = strtoul(&buf[pos], 0, 16); + clk_bram_set(bram_num, offset, val); + offset++; + pos += 2; + } +} + +void +config_load_roms() +{ + struct stat stat_buf; + const char **names_ptr; + int more_than_8mb; + int changed_rom; + int len; + FILE *file; + int ret; + int i; + + g_rom_version = -1; + + /* set first entry of g_gsport_rom_names[] to g_cfg_rom_path so that */ + /* it becomes the first place searched. */ + g_gsport_rom_names[0] = g_cfg_rom_path; + setup_gsport_file(&g_cfg_tmp_path[0], CFG_PATH_MAX, -1, 0, + &g_gsport_rom_names[0]); + + if(g_cfg_tmp_path[0] == 0) { + // Just get out, let config interface select ROM + g_config_control_panel = 1; + return; + } + file = fopen(&g_cfg_tmp_path[0], "rb"); + if(!file) { + fatal_printf("Open ROM file %s failed; errno:%d\n", + &g_cfg_tmp_path[0], errno); + g_config_control_panel = 1; + return; + } + + ret = stat(&g_cfg_tmp_path[0], &stat_buf); + if(ret != 0) { + fatal_printf("stat returned %d; errno: %d\n", + ret, errno); + g_config_control_panel = 1; + return; + } + + len = stat_buf.st_size; + if(len == 128*1024) { + g_rom_version = 1; + g_mem_size_base = 256*1024; + memset(&g_rom_fc_ff_ptr[0], 0, 2*65536); + /* Clear banks fc and fd to 0 */ + ret = fread(&g_rom_fc_ff_ptr[2*65536], 1, len, file); + } else if(len == 256*1024) { + g_rom_version = 3; + g_mem_size_base = 1024*1024; + ret = fread(&g_rom_fc_ff_ptr[0], 1, len, file); + } else { + fatal_printf("The ROM size should be 128K or 256K, this file " + "is %d bytes\n", len); + g_config_control_panel = 1; + return; + } + + printf("Read: %d bytes of ROM\n", ret); + if(ret != len) { + fatal_printf("errno: %d\n", errno); + g_config_control_panel = 1; + return; + } + fclose(file); + + memset(&g_rom_cards_ptr[0], 0, 256*16); + + /* initialize c600 rom to be diffs from the real ROM, to build-in */ + /* Apple II compatibility without distributing ROMs */ + for(i = 0; i < 256; i++) { + g_rom_cards_ptr[0x600 + i] = g_rom_fc_ff_ptr[0x3c600 + i] ^ + g_rom_c600_rom01_diffs[i]; + } + if(g_rom_version >= 3) { + /* some patches */ + g_rom_cards_ptr[0x61b] ^= 0x40; + g_rom_cards_ptr[0x61c] ^= 0x33; + g_rom_cards_ptr[0x632] ^= 0xc0; + g_rom_cards_ptr[0x633] ^= 0x33; + } + + for(i = 1; i < 8; i++) { + names_ptr = g_gsport_rom_card_list[i]; + if(names_ptr == 0) { + continue; + } + if(*names_ptr == 0) { + continue; + } + setup_gsport_file(&g_cfg_tmp_path[0], CFG_PATH_MAX, 1, 0, + names_ptr); + if(g_cfg_tmp_path[0] != 0) { + file = fopen(&(g_cfg_tmp_path[0]), "rb"); + if(!file) { + fatal_printf("Open card ROM file %s failed; errno:%d\n", + &g_cfg_tmp_path[0], errno); + continue; + } + + len = 256; + ret = fread(&g_rom_cards_ptr[i*0x100], 1, len, file); + + if(ret != len) { + fatal_printf("While reading card ROM %s, file " + "is too short. (%d) Expected %d bytes, " + "read %d bytes\n", &g_cfg_tmp_path[0], errno, len, ret); + continue; + } + printf("Read: %d bytes of ROM in slot %d from file %s.\n", ret, i, &g_cfg_tmp_path[0]); + fclose(file); + } + } + more_than_8mb = (g_mem_size_exp > 0x800000); + /* Only do the patch if users wants more than 8MB of expansion mem */ + + changed_rom = 0; + if(g_rom_version == 1) { + /* make some patches to ROM 01 */ +#if 0 + /* 1: Patch ROM selftest to not do speed test */ + printf("Patching out speed test failures from ROM 01\n"); + g_rom_fc_ff_ptr[0x3785a] = 0x18; + changed_rom = 1; +#endif + +#if 0 + /* 2: Patch ROM selftests not to do tests 2,4 */ + /* 0 = skip, 1 = do it, test 1 is bit 0 of LSByte */ + g_rom_fc_ff_ptr[0x371e9] = 0xf5; + g_rom_fc_ff_ptr[0x371ea] = 0xff; + changed_rom = 1; +#endif + + if(more_than_8mb) { + /* Geoff Weiss patch to use up to 14MB of RAM */ + g_rom_fc_ff_ptr[0x30302] = 0xdf; + g_rom_fc_ff_ptr[0x30314] = 0xdf; + g_rom_fc_ff_ptr[0x3031c] = 0x00; + changed_rom = 1; + } + + /* Patch ROM selftest to not do ROM cksum if any changes*/ + if(changed_rom) { + g_rom_fc_ff_ptr[0x37a06] = 0x18; + g_rom_fc_ff_ptr[0x37a07] = 0x18; + } + } else if(g_rom_version == 3) { + /* patch ROM 03 */ + printf("Patching ROM 03 smartport bug\n"); + /* 1: Patch Smartport code to fix a stupid bug */ + /* that causes it to write the IWM status reg into c036, */ + /* which is the system speed reg...it's "safe" since */ + /* IWM status reg bit 4 must be 0 (7MHz)..., otherwise */ + /* it might have turned on shadowing in all banks! */ + g_rom_fc_ff_ptr[0x357c9] = 0x00; + changed_rom = 1; + +#if 0 + /* patch ROM 03 to not to speed test */ + /* skip fast speed test */ + g_rom_fc_ff_ptr[0x36ad7] = 0x18; + g_rom_fc_ff_ptr[0x36ad8] = 0x18; + changed_rom = 1; +#endif + +#if 0 + /* skip slow speed test */ + g_rom_fc_ff_ptr[0x36ae7] = 0x18; + g_rom_fc_ff_ptr[0x36ae8] = 0x6b; + changed_rom = 1; +#endif + +#if 0 + /* 4: Patch ROM 03 selftests not to do tests 1-4 */ + g_rom_fc_ff_ptr[0x364a9] = 0xf0; + g_rom_fc_ff_ptr[0x364aa] = 0xff; + changed_rom = 1; +#endif + + /* ROM tests are in ff/6403-642x, where 6403 = addr of */ + /* test 1, etc. */ + + if(more_than_8mb) { + /* Geoff Weiss patch to use up to 14MB of RAM */ + g_rom_fc_ff_ptr[0x30b] = 0xdf; + g_rom_fc_ff_ptr[0x31d] = 0xdf; + g_rom_fc_ff_ptr[0x325] = 0x00; + changed_rom = 1; + } + + if(changed_rom) { + /* patch ROM 03 selftest to not do ROM cksum */ + g_rom_fc_ff_ptr[0x36cb0] = 0x18; + g_rom_fc_ff_ptr[0x36cb1] = 0x18; + } + + } +} + +void +config_parse_config_gsport_file() +{ + FILE *fconf; + char *buf; + char *ptr; + char *name_ptr; + char *partition_name; + int part_num; + int ejected; + int line; + int pos; + int slot; + int drive; + int size; + int len; + int ret; + int i; + + printf("Parsing configuration file\n"); + + clk_bram_zero(); + + g_highest_smartport_unit = -1; + + cfg_get_base_path(&g_cfg_cwd_str[0], g_config_gsport_name, 0); +#ifndef __OS2__ + if(g_cfg_cwd_str[0] != 0) { + ret = chdir(&g_cfg_cwd_str[0]); + if(ret != 0) { + printf("chdir to %s, errno:%d\n", g_cfg_cwd_str, errno); + } + } + /* In any case, copy the directory path to g_cfg_cwd_str */ + (void)getcwd(&g_cfg_cwd_str[0], CFG_PATH_MAX); +#endif + + fconf = fopen(g_config_gsport_name, "r"); + if(fconf == 0) { + fatal_printf("cannot open configuration file at %s! Stopping!\n", + g_config_gsport_name); + my_exit(3); + } + + line = 0; + while(1) { + buf = &g_config_gsport_buf[0]; + ptr = fgets(buf, CONF_BUF_LEN, fconf); + if(ptr == 0) { + iwm_printf("Done reading disk_conf\n"); + break; + } + + line++; + /* strip off newline(s) */ + len = strlen(buf); + for(i = len - 1; i >= 0; i--) { + if((buf[i] != 0x0d) && (buf[i] != 0x0a)) { + break; + } + len = i; + buf[i] = 0; + } + + iwm_printf("disk_conf[%d]: %s\n", line, buf); + if(len > 0 && buf[0] == '#') { + iwm_printf("Skipping comment\n"); + continue; + } + + /* determine what this is */ + pos = 0; + + while(pos < len && (buf[pos] == ' ' || buf[pos] == '\t') ) { + pos++; + } + if((pos + 4) > len || buf[pos] != 's' || buf[pos+2] != 'd' || + buf[pos+1] > '9' || buf[pos+1] < '0') { + config_parse_option(buf, pos, len, line); + continue; + } + + slot = buf[pos+1] - '0'; + drive = buf[pos+3] - '0'; + + /* skip over slot, drive */ + pos += 4; + if(buf[pos] >= '0' && buf[pos] <= '9') { + drive = drive * 10 + buf[pos] - '0'; + pos++; + } + + /* make s6d1 mean index 0 */ + drive--; + + while(pos < len && (buf[pos] == ' ' || buf[pos] == '\t' || + buf[pos] == '=') ) { + pos++; + } + + ejected = 0; + if(buf[pos] == '#') { + /* disk is ejected, but read all the info anyway */ + ejected = 1; + pos++; + } + + size = 0; + if(buf[pos] == ',') { + /* read optional size parameter */ + pos++; + while(pos < len && buf[pos] >= '0' && buf[pos] <= '9'){ + size = size * 10 + buf[pos] - '0'; + pos++; + } + size = size * 1024; + if(buf[pos] == ',') { + pos++; /* eat trailing ',' */ + } + } + + /* see if it has a partition name */ + partition_name = 0; + part_num = -1; + if(buf[pos] == ':') { + pos++; + /* yup, it's got a partition name! */ + partition_name = &buf[pos]; + while((pos < len) && (buf[pos] != ':')) { + pos++; + } + buf[pos] = 0; /* null terminate partition name */ + pos++; + } + if(buf[pos] == ';') { + pos++; + /* it's got a partition number */ + part_num = 0; + while((pos < len) && (buf[pos] != ':')) { + part_num = (10*part_num) + buf[pos] - '0'; + pos++; + } + pos++; + } + + /* Get filename */ + name_ptr = &(buf[pos]); + if(name_ptr[0] == 0) { + continue; + } + + insert_disk(slot, drive, name_ptr, ejected, size, + partition_name, part_num); + + } + + ret = fclose(fconf); + if(ret != 0) { + fatal_printf("Closing configuration file ret: %d, errno: %d\n", ret, + errno); + my_exit(4); + } + + iwm_printf("Done parsing disk_conf file\n"); +} + + +Disk * +cfg_get_dsk_from_slot_drive(int slot, int drive) +{ + Disk *dsk; + int max_drive; + + /* Get dsk */ + max_drive = 2; + switch(slot) { + case 5: + dsk = &(iwm.drive35[drive]); + break; + case 6: + dsk = &(iwm.drive525[drive]); + break; + default: + max_drive = MAX_C7_DISKS; + dsk = &(iwm.smartport[drive]); + } + + if(drive >= max_drive) { + dsk -= drive; /* move back to drive 0 effectively */ + } + + return dsk; +} + +void +config_generate_config_gsport_name(char *outstr, int maxlen, Disk *dsk, + int with_extras) +{ + char *str; + + str = outstr; + + if(with_extras && (!dsk->file)) { + snprintf(str, maxlen - (str - outstr), "#"); + str = &outstr[strlen(outstr)]; + } + if(with_extras && dsk->force_size > 0) { + snprintf(str, maxlen - (str - outstr), ",%d,", dsk->force_size); + str = &outstr[strlen(outstr)]; + } + if(with_extras && dsk->partition_name != 0) { + snprintf(str, maxlen - (str - outstr), ":%s:", + dsk->partition_name); + str = &outstr[strlen(outstr)]; + } else if(with_extras && dsk->partition_num >= 0) { + snprintf(str, maxlen - (str - outstr), ";%d:", + dsk->partition_num); + str = &outstr[strlen(outstr)]; + } + snprintf(str, maxlen - (str - outstr), "%s", dsk->name_ptr); +} + +void +config_write_config_gsport_file() +{ + FILE *fconf; + Disk *dsk; + Cfg_defval *defptr; + Cfg_menu *menuptr; + char *curstr, *defstr; + int defval, curval; + int type; + int slot, drive; + int i; + + printf("Writing configuration file to %s\n", g_config_gsport_name); + + fconf = fopen(g_config_gsport_name, "w+"); + if(fconf == 0) { + halt_printf("cannot open %s! Stopping!\n",g_config_gsport_name); + return; + } + + fprintf(fconf, "# GSport configuration file version %s\n", + g_gsport_version_str); + + for(i = 0; i < MAX_C7_DISKS + 4; i++) { + slot = 7; + drive = i - 4; + if(i < 4) { + slot = (i >> 1) + 5; + drive = i & 1; + } + if(drive == 0) { + fprintf(fconf, "\n"); /* an extra blank line */ + } + + dsk = cfg_get_dsk_from_slot_drive(slot, drive); + if(dsk->name_ptr == 0 && (i > 4)) { + /* No disk, not even ejected--just skip */ + continue; + } + fprintf(fconf, "s%dd%d = ", slot, drive + 1); + if(dsk->name_ptr == 0) { + fprintf(fconf, "\n"); + continue; + } + config_generate_config_gsport_name(&g_cfg_tmp_path[0], + CFG_PATH_MAX, dsk, 1); + fprintf(fconf, "%s\n", &g_cfg_tmp_path[0]); + } + + fprintf(fconf, "\n"); + + /* See if any variables are different than their default */ + for(i = 0; i < g_cfg_defval_index; i++) { + defptr = &(g_cfg_defvals[i]); + menuptr = defptr->menuptr; + defval = defptr->intval; + type = menuptr->cfgtype; + if(type == CFGTYPE_INT) { + curval = *((int *)menuptr->ptr); + if(curval != defval) { + fprintf(fconf, "%s = %d\n", menuptr->name_str, + curval); + } + } + if(type == CFGTYPE_STR) { + curstr = *((char **)menuptr->ptr); + defstr = *((char **)menuptr->defptr); + if(strcmp(curstr, defstr) != 0) { + fprintf(fconf, "%s = %s\n", menuptr->name_str, + curstr); + } + } + if(type == CFGTYPE_FILE) { + curstr = *((char **)menuptr->ptr); + defstr = *((char **)menuptr->defptr); + if(strcmp(curstr, defstr) != 0) { + fprintf(fconf, "%s = %s\n", menuptr->name_str, + curstr); + } + } + } + + fprintf(fconf, "\n"); + + /* write bram state */ + clk_write_bram(fconf); + + fclose(fconf); + + g_config_gsport_update_needed = 0; +} + +void +insert_disk(int slot, int drive, const char *name, int ejected, int force_size, + const char *partition_name, int part_num) +{ + byte buf_2img[512]; + Disk *dsk; + char *name_ptr, *uncomp_ptr, *system_str; + char *part_ptr; + int size; + int system_len; + int part_len; + int cmp_o, cmp_p, cmp_dot; + int cmp_b, cmp_i, cmp_n; + int can_write; + int len; + int nibs; + int unix_pos; + int name_len; + int image_identified; + int exp_size; + int save_track; + int ret; + int tmp; + int i; + + g_config_gsport_update_needed = 1; + + if((slot < 5) || (slot > 7)) { + fatal_printf("Invalid slot for inserting disk: %d\n", slot); + return; + } + if(drive < 0 || ((slot == 7) && (drive >= MAX_C7_DISKS)) || + ((slot < 7) && (drive > 1))) { + fatal_printf("Invalid drive for inserting disk: %d\n", drive); + return; + } + + dsk = cfg_get_dsk_from_slot_drive(slot, drive); + +#if 0 + printf("Inserting disk %s (%s or %d) in slot %d, drive: %d\n", name, + partition_name, part_num, slot, drive); +#endif + + dsk->just_ejected = 0; + dsk->force_size = force_size; + + if(!dsk->file) { + eject_disk(dsk); + } + + /* Before opening, make sure no other mounted disk has this name */ + /* If so, unmount it */ + if(!ejected) { + for(i = 0; i < 2; i++) { + eject_named_disk(&iwm.drive525[i], name,partition_name); + eject_named_disk(&iwm.drive35[i], name, partition_name); + } + for(i = 0; i < MAX_C7_DISKS; i++) { + eject_named_disk(&iwm.smartport[i],name,partition_name); + } + } + + if(dsk->name_ptr != 0) { + /* free old name_ptr */ + free(dsk->name_ptr); + } + + name_len = strlen(name); + name_ptr = (char *)malloc(name_len + 1); +#if defined(_WIN32) || defined(__CYGWIN__) + // On Windows, we need to change backslashes to forward slashes. + for (i = 0; i < name_len; i++) { + if (name[i] == '\\') { + name_ptr[i] = '/'; + } else { + name_ptr[i] = name[i]; + } + } + name_ptr[name_len] = 0; +#else + strncpy(name_ptr, name, name_len + 1); +#endif + dsk->name_ptr = name_ptr; + + dsk->partition_name = 0; + if(partition_name != 0) { + part_len = strlen(partition_name) + 1; + part_ptr = (char *)malloc(part_len); + strncpy(part_ptr, partition_name, part_len); + dsk->partition_name = part_ptr; + } + dsk->partition_num = part_num; + + iwm_printf("Opening up disk image named: %s\n", name_ptr); + + if(ejected) { + /* just get out of here */ + dsk->file = 0; + return; + } + + dsk->file = 0; + can_write = 1; + + if((name_len > 3) && (strcmp(&name_ptr[name_len - 3], ".gz") == 0)) { + + /* it's gzip'ed, try to gunzip it, then unlink the */ + /* uncompressed file */ + + can_write = 0; + + uncomp_ptr = (char *)malloc(name_len + 1); + strncpy(uncomp_ptr, name_ptr, name_len + 1); + uncomp_ptr[name_len - 3] = 0; + + system_len = 2*name_len + 100; + system_str = (char *)malloc(system_len + 1); + snprintf(system_str, system_len, + "set -o noclobber;gunzip -c %c%s%c > %c%s%c", + 0x22, name_ptr, 0x22, + 0x22, uncomp_ptr, 0x22); + /* 0x22 are " to allow spaces in filenames */ + printf("I am uncompressing %s into %s for mounting\n", + name_ptr, uncomp_ptr); + ret = system(system_str); + if(ret == 0) { + /* successfully ran */ + dsk->file = fopen(uncomp_ptr, "rb"); + iwm_printf("Opening .gz file %s\n", uncomp_ptr); + + /* and, unlink the temporary file */ + (void)unlink(uncomp_ptr); + } + free(system_str); + free(uncomp_ptr); + /* Reduce name_len by 3 so that subsequent compares for .po */ + /* look at the correct chars */ + name_len -= 3; + } + + if((!dsk->file) && can_write) { + dsk->file = fopen(name_ptr, "rb+"); + } + + if((!dsk->file) && can_write) { + printf("Trying to open %s read-only, errno: %d\n", name_ptr, + errno); + dsk->file = fopen(name_ptr, "rb"); + can_write = 0; + } + + if(!dsk->file) { + fatal_printf("Disk image %s does not exist!\n", name_ptr); + return; + } + + if(can_write != 0) { + dsk->write_prot = 0; + dsk->write_through_to_unix = 1; + } else { + dsk->write_prot = 1; + dsk->write_through_to_unix = 0; + } + + save_track = dsk->cur_qtr_track; /* save arm position */ + dsk->image_type = DSK_TYPE_PRODOS; + dsk->image_start = 0; + + /* See if it is in 2IMG format */ + ret = fread((char *)&buf_2img[0], 1, 512, dsk->file); + size = force_size; + if(size <= 0) { + size = cfg_get_fd_size(name_ptr); + } + + /* Try to guess that there is a Mac Binary header of 128 bytes */ + /* See if image size & 0xfff = 0x080 which indicates extra 128 bytes */ + if((size & 0xfff) == 0x080) { + printf("Assuming Mac Binary header on %s\n", dsk->name_ptr); + dsk->image_start += 0x80; + } + image_identified = 0; + if(buf_2img[0] == '2' && buf_2img[1] == 'I' && buf_2img[2] == 'M' && + buf_2img[3] == 'G') { + /* It's a 2IMG disk */ + printf("Image named %s is in 2IMG format\n", dsk->name_ptr); + image_identified = 1; + + if(buf_2img[12] == 0) { + printf("2IMG is in DOS 3.3 sector order\n"); + dsk->image_type = DSK_TYPE_DOS33; + } + if(buf_2img[19] & 0x80) { + /* disk is locked */ + printf("2IMG is write protected\n"); + dsk->write_prot = 1; + dsk->write_through_to_unix = 0; + } + if((buf_2img[17] & 1) && (dsk->image_type == DSK_TYPE_DOS33)) { + dsk->vol_num = buf_2img[16]; + printf("Setting DOS 3.3 vol num to %d\n", dsk->vol_num); + } + // Some 2IMG archives have the size byte reversed + size = (buf_2img[31] << 24) + (buf_2img[30] << 16) + + (buf_2img[29] << 8) + buf_2img[28]; + unix_pos = (buf_2img[27] << 24) + (buf_2img[26] << 16) + + (buf_2img[25] << 8) + buf_2img[24]; + if(size == 0x800c00) { + // Byte reversed 0x0c8000 + size = 0x0c8000; + } + dsk->image_start = unix_pos; + dsk->image_size = size; + } + exp_size = 800*1024; + if(dsk->disk_525) { + exp_size = 140*1024; + } + if(!image_identified) { + /* See if it might be the Mac diskcopy format */ + tmp = (buf_2img[0x40] << 24) + (buf_2img[0x41] << 16) + + (buf_2img[0x42] << 8) + buf_2img[0x43]; + if((size >= (exp_size + 0x54)) && (tmp == exp_size)) { + /* It's diskcopy since data size field matches */ + printf("Image named %s is in Mac diskcopy format\n", + dsk->name_ptr); + image_identified = 1; + dsk->image_start += 0x54; + dsk->image_size = exp_size; + dsk->image_type = DSK_TYPE_PRODOS; /* ProDOS */ + } + } + if(!image_identified) { + /* Assume raw image */ + dsk->image_size = size; + dsk->image_type = DSK_TYPE_PRODOS; + if(dsk->disk_525) { + dsk->image_type = DSK_TYPE_DOS33; + if(name_len >= 4) { + cmp_o = dsk->name_ptr[name_len-1]; + cmp_p = dsk->name_ptr[name_len-2]; + cmp_dot = dsk->name_ptr[name_len-3]; + if(cmp_dot == '.' && + (cmp_p == 'p' || cmp_p == 'P') && + (cmp_o == 'o' || cmp_o == 'O')) { + dsk->image_type = DSK_TYPE_PRODOS; + } + + cmp_b = dsk->name_ptr[name_len-1]; + cmp_i = dsk->name_ptr[name_len-2]; + cmp_n = dsk->name_ptr[name_len-3]; + cmp_dot = dsk->name_ptr[name_len-4]; + if(cmp_dot == '.' && + (cmp_n == 'n' || cmp_n == 'N') && + (cmp_i == 'i' || cmp_i == 'I') && + (cmp_b == 'b' || cmp_b == 'B')) { + dsk->image_type = DSK_TYPE_NIB; + dsk->write_prot = 1; + dsk->write_through_to_unix = 0; + } + } + } + } + + dsk->disk_dirty = 0; + dsk->nib_pos = 0; + dsk->trks = 0; + + if(dsk->smartport) { + g_highest_smartport_unit = MAX(dsk->drive, + g_highest_smartport_unit); + + if(partition_name != 0 || part_num >= 0) { + ret = cfg_partition_find_by_name_or_num(dsk->file, + partition_name, part_num, dsk); + printf("partition %s (num %d) mounted, wr_prot: %d\n", + partition_name, part_num, dsk->write_prot); + + if(ret < 0) { + fclose(dsk->file); + dsk->file = 0; + return; + } + } + iwm_printf("adding smartport device[%d], size:%08x, " + "img_sz:%08x\n", dsk->drive, dsk->trks[0].unix_len, + dsk->image_size); + } else if(dsk->disk_525) { + unix_pos = dsk->image_start; + size = dsk->image_size; + disk_set_num_tracks(dsk, 4*35); + len = 0x1000; + nibs = NIB_LEN_525; + if(dsk->image_type == DSK_TYPE_NIB) { + len = dsk->image_size / 35;; + nibs = len; + } + if(size != 35*len) { + fatal_printf("Disk 5.25 error: size is %d, not 140K. " + "Will try to mount anyway\n", size, 35*len); + } + for(i = 0; i < 35; i++) { + iwm_move_to_track(dsk, 4*i); + disk_unix_to_nib(dsk, 4*i, unix_pos, len, nibs); + unix_pos += len; + } + } else { + /* disk_35 */ + unix_pos = dsk->image_start; + size = dsk->image_size; + if(size != 800*1024) { + fatal_printf("Disk 3.5 error: size is %d, not 800K. " + "Will try to mount anyway\n", size); + } + disk_set_num_tracks(dsk, 2*80); + for(i = 0; i < 2*80; i++) { + iwm_move_to_track(dsk, i); + len = g_track_bytes_35[i >> 5]; + nibs = g_track_nibs_35[i >> 5]; + iwm_printf("Trk: %d.%d = unix: %08x, %04x, %04x\n", + i>>1, i & 1, unix_pos, len, nibs); + disk_unix_to_nib(dsk, i, unix_pos, len, nibs); + unix_pos += len; + + iwm_printf(" trk_len:%05x\n", dsk->trks[i].track_len); + } + } + + iwm_move_to_track(dsk, save_track); + +} + +void +eject_named_disk(Disk *dsk, const char *name, const char *partition_name) +{ + + if(!dsk->file) { + return; + } + + /* If name matches, eject the disk! */ + if(!strcmp(dsk->name_ptr, name)) { + /* It matches, eject it */ + if((partition_name != 0) && (dsk->partition_name != 0)) { + /* If both have partitions, and they differ, then */ + /* don't eject. Otherwise, eject */ + if(strcmp(dsk->partition_name, partition_name) != 0) { + /* Don't eject */ + return; + } + } + eject_disk(dsk); + } +} + +void +eject_disk_by_num(int slot, int drive) +{ + Disk *dsk; + + dsk = cfg_get_dsk_from_slot_drive(slot, drive); + + eject_disk(dsk); +} + +void +eject_disk(Disk *dsk) +{ + int motor_on; + int i; + + if(!dsk->file) { + return; + } + + g_config_gsport_update_needed = 1; + + motor_on = iwm.motor_on; + if(g_c031_disk35 & 0x40) { + motor_on = iwm.motor_on35; + } + if(motor_on) { + halt_printf("Try eject dsk:%s, but motor_on!\n", dsk->name_ptr); + } + + iwm_flush_disk_to_unix(dsk); + + printf("Ejecting disk: %s\n", dsk->name_ptr); + + /* Free all memory, close file */ + + /* free the tracks first */ + if(dsk->trks != 0) { + for(i = 0; i < dsk->num_tracks; i++) { + if(dsk->trks[i].nib_area) { + free(dsk->trks[i].nib_area); + } + dsk->trks[i].nib_area = 0; + dsk->trks[i].track_len = 0; + } + free(dsk->trks); + } + dsk->num_tracks = 0; + dsk->trks = 0; + + /* close file, clean up dsk struct */ + fclose(dsk->file); + + dsk->image_start = 0; + dsk->image_size = 0; + dsk->nib_pos = 0; + dsk->disk_dirty = 0; + dsk->write_through_to_unix = 0; + dsk->write_prot = 1; + dsk->file = 0; + dsk->just_ejected = 1; + + /* Leave name_ptr valid */ +} + +int +cfg_get_fd_size(char *filename) +{ + struct stat stat_buf; + int ret; + + ret = stat(filename, &stat_buf); + if(ret != 0) { + fprintf(stderr,"stat %s returned errno: %d\n", + filename, errno); + stat_buf.st_size = 0; + } + + return stat_buf.st_size; +} + +int +cfg_partition_read_block(FILE *file, void *buf, int blk, int blk_size) +{ + int ret; + + ret = fseek(file, blk * blk_size, SEEK_SET); + if(ret != 0) { + printf("fseek: wanted: %08x, errno: %d\n", + blk * blk_size, errno); + return 0; + } + + ret = fread((char *)buf, 1, blk_size, file); + if(ret != blk_size) { + printf("ret: %08x, wanted %08x, errno: %d\n", ret, blk_size, + errno); + return 0; + } + return ret; +} + +int +cfg_partition_find_by_name_or_num(FILE *file, const char *partnamestr, int part_num, + Disk *dsk) +{ + Cfg_dirent *direntptr; + int match; + int num_parts; + int i; + + num_parts = cfg_partition_make_list(dsk->name_ptr, file); + + if(num_parts <= 0) { + return -1; + } + + for(i = 0; i < g_cfg_partitionlist.last; i++) { + direntptr = &(g_cfg_partitionlist.direntptr[i]); + match = 0; + if((strncmp(partnamestr, direntptr->name, 32) == 0) && + (part_num < 0)) { + //printf("partition, match1, name:%s %s, part_num:%d\n", + // partnamestr, direntptr->name, part_num); + + match = 1; + } + if((partnamestr == 0) && (direntptr->part_num == part_num)) { + //printf("partition, match2, n:%s, part_num:%d == %d\n", + // direntptr->name, direntptr->part_num, part_num); + match = 1; + } + if(match) { + dsk->image_start = direntptr->image_start; + dsk->image_size = direntptr->size; + //printf("match with image_start: %08x, image_size: " + // "%08x\n", dsk->image_start, dsk->image_size); + + return i; + } + } + + return -1; +} + +int +cfg_partition_make_list(char *filename, FILE *file) +{ + Driver_desc *driver_desc_ptr; + Part_map *part_map_ptr; + word32 *blk_bufptr; + word32 start; + word32 len; + word32 data_off; + word32 data_len; + word32 sig; + int size; + int image_start, image_size; + int is_dir; + int block_size; + int map_blks; + int cur_blk; + + block_size = 512; + + cfg_free_alldirents(&g_cfg_partitionlist); + + blk_bufptr = (word32 *)malloc(MAX_PARTITION_BLK_SIZE); + + cfg_partition_read_block(file, blk_bufptr, 0, block_size); + + driver_desc_ptr = (Driver_desc *)blk_bufptr; + sig = GET_BE_WORD16(driver_desc_ptr->sig); + block_size = GET_BE_WORD16(driver_desc_ptr->blk_size); + if(block_size == 0) { + block_size = 512; + } + if(sig != 0x4552 || block_size < 0x200 || + (block_size > MAX_PARTITION_BLK_SIZE)) { + cfg_printf("Partition error: No driver descriptor map found\n"); + free(blk_bufptr); + return 0; + } + + map_blks = 1; + cur_blk = 0; + size = cfg_get_fd_size(filename); + cfg_file_add_dirent(&g_cfg_partitionlist, "None - Whole image", + is_dir=0, size, 0, -1); + + while(cur_blk < map_blks) { + cur_blk++; + cfg_partition_read_block(file, blk_bufptr, cur_blk, block_size); + part_map_ptr = (Part_map *)blk_bufptr; + sig = GET_BE_WORD16(part_map_ptr->sig); + if(cur_blk <= 1) { + map_blks = MIN(20, + GET_BE_WORD32(part_map_ptr->map_blk_cnt)); + } + if(sig != 0x504d) { + printf("Partition entry %d bad signature:%04x\n", + cur_blk, sig); + free(blk_bufptr); + return g_cfg_partitionlist.last; + } + + /* found it, check for consistency */ + start = GET_BE_WORD32(part_map_ptr->phys_part_start); + len = GET_BE_WORD32(part_map_ptr->part_blk_cnt); + data_off = GET_BE_WORD32(part_map_ptr->data_start); + data_len = GET_BE_WORD32(part_map_ptr->data_cnt); + if(data_off + data_len > len) { + printf("Poorly formed entry\n"); + continue; + } + + if(data_len < 10 || start < 1) { + printf("Poorly formed entry %d, datalen:%d, " + "start:%08x\n", cur_blk, data_len, start); + continue; + } + + image_size = data_len * block_size; + image_start = (start + data_off) * block_size; + is_dir = 2*(image_size < 800*1024); +#if 0 + printf(" partition add entry %d = %s %d %08x %08x\n", + cur_blk, part_map_ptr->part_name, is_dir, + image_size, image_start); +#endif + + cfg_file_add_dirent(&g_cfg_partitionlist, + part_map_ptr->part_name, is_dir, image_size, + image_start, cur_blk); + } + + free(blk_bufptr); + return g_cfg_partitionlist.last; +} + +int +cfg_maybe_insert_disk(int slot, int drive, const char *namestr) +{ + int num_parts; + FILE *file; + + file = fopen(namestr, "rb"); + if(!file) { + fatal_printf("Cannot open disk image: %s\n", namestr); + return 0; + } + + num_parts = cfg_partition_make_list((char*)namestr, file); + fclose(file); + + if(num_parts > 0) { + printf("Choose a partition\n"); + g_cfg_select_partition = 1; + } else { + insert_disk(slot, drive, namestr, 0, 0, 0, -1); + return 1; + } + return 0; +} + +int +cfg_stat(char *path, struct stat *sb) +{ + int removed_slash; + int len; + int ret; + + removed_slash = 0; + len = 0; + +#ifdef _WIN32 + /* Windows doesn't like to stat paths ending in a /, so remove it */ + len = strlen(path); + if((len > 1) && (path[len - 1] == '/') ) { + path[len - 1] = 0; /* remove the slash */ + removed_slash = 1; + } +#endif + + ret = stat(path, sb); + +#ifdef _WIN32 + /* put the slash back */ + if(removed_slash) { + path[len - 1] = '/'; + } +#endif + + return ret; +} + +void +cfg_htab_vtab(int x, int y) +{ + if(x > 79) { + x = 0; + } + if(y > 23) { + y = 0; + } + g_cfg_curs_x = x; + g_cfg_curs_y = y; + g_cfg_curs_inv = 0; + g_cfg_curs_mousetext = 0; +} + +void +cfg_home() +{ + int i; + + cfg_htab_vtab(0, 0); + for(i = 0; i < 24; i++) { + cfg_cleol(); + } +} + +void +cfg_cleol() +{ + g_cfg_curs_inv = 0; + g_cfg_curs_mousetext = 0; + cfg_putchar(' '); + while(g_cfg_curs_x != 0) { + cfg_putchar(' '); + } +} + +void +cfg_putchar(int c) +{ + int offset; + int x, y; + + if(c == '\n') { + cfg_cleol(); + return; + } + if(c == '\b') { + g_cfg_curs_inv = !g_cfg_curs_inv; + return; + } + if(c == '\t') { + g_cfg_curs_mousetext = !g_cfg_curs_mousetext; + return; + } + y = g_cfg_curs_y; + x = g_cfg_curs_x; + + offset = g_screen_index[g_cfg_curs_y]; + if((x & 1) == 0) { + offset += 0x10000; + } + if(g_cfg_curs_inv) { + if(c >= 0x40 && c < 0x60) { + c = c & 0x1f; + } + } else { + c = c | 0x80; + } + if(g_cfg_curs_mousetext) { + c = (c & 0x1f) | 0x40; + } + set_memory_c(0xe00400 + offset + (x >> 1), c, 0); + x++; + if(x >= 80) { + x = 0; + y++; + if(y >= 24) { + y = 0; + } + } + g_cfg_curs_y = y; + g_cfg_curs_x = x; +} + +void +cfg_printf(const char *fmt, ...) +{ + va_list ap; + int c; + int i; + + va_start(ap, fmt); + (void)vsnprintf(g_cfg_printf_buf, CFG_PRINTF_BUFSIZE, fmt, ap); + va_end(ap); + + for(i = 0; i < CFG_PRINTF_BUFSIZE; i++) { + c = g_cfg_printf_buf[i]; + if(c == 0) { + return; + } + cfg_putchar(c); + } +} + +void +cfg_print_num(int num, int max_len) +{ + char buf[64]; + char buf2[64]; + int len; + int cnt; + int c; + int i, j; + + /* Prints right-adjusted "num" in field "max_len" wide */ + snprintf(&buf[0], 64, "%d", num); + len = strlen(buf); + for(i = 0; i < 64; i++) { + buf2[i] = ' '; + } + j = max_len + 1; + buf2[j] = 0; + j--; + cnt = 0; + for(i = len - 1; (i >= 0) && (j >= 1); i--) { + c = buf[i]; + if(c >= '0' && c <= '9') { + if(cnt >= 3) { + buf2[j--] = ','; + cnt = 0; + } + cnt++; + } + buf2[j--] = c; + } + cfg_printf(&buf2[1]); +} + +void +cfg_get_disk_name(char *outstr, int maxlen, int type_ext, int with_extras) +{ + Disk *dsk; + int slot, drive; + + slot = type_ext >> 8; + drive = type_ext & 0xff; + dsk = cfg_get_dsk_from_slot_drive(slot, drive); + + outstr[0] = 0; + if(dsk->name_ptr == 0) { + return; + } + + config_generate_config_gsport_name(outstr, maxlen, dsk, with_extras); +} + +void +cfg_parse_menu(Cfg_menu *menuptr, int menu_pos, int highlight_pos, int change) +{ + char valbuf[CFG_OPT_MAXSTR]; + char **str_ptr; + const char *menustr; + char *curstr, *defstr; + char *str; + char *outstr; + int *iptr; + int val; + int num_opts; + int opt_num; + int bufpos, outpos; + int curval, defval; + int type; + int type_ext; + int opt_get_str; + int separator; + int len; + int c; + int i; + + g_cfg_opt_buf[0] = 0; + + num_opts = 0; + opt_get_str = 0; + separator = ','; + + menuptr += menu_pos; /* move forward to entry menu_pos */ + + menustr = menuptr->str; + type = menuptr->cfgtype; + type_ext = (type >> 4); + type = type & 0xf; + len = strlen(menustr) + 1; + + bufpos = 0; + outstr = &(g_cfg_opt_buf[0]); + + outstr[bufpos++] = ' '; + outstr[bufpos++] = ' '; + outstr[bufpos++] = '\t'; + outstr[bufpos++] = '\t'; + outstr[bufpos++] = ' '; + outstr[bufpos++] = ' '; + + if(menu_pos == highlight_pos) { + outstr[bufpos++] = '\b'; + } + + opt_get_str = 2; + i = -1; + outpos = bufpos; +#if 0 + printf("cfg menu_pos: %d str len: %d\n", menu_pos, len); +#endif + while(++i < len) { + c = menustr[i]; + if(c == separator) { + if(i == 0) { + continue; + } + c = 0; + } + outstr[outpos++] = c; + outstr[outpos] = 0; + if(outpos >= CFG_OPT_MAXSTR) { + fprintf(stderr, "CFG_OPT_MAXSTR exceeded\n"); + my_exit(1); + } + if(c == 0) { + if(opt_get_str == 2) { + outstr = &(valbuf[0]); + bufpos = outpos - 1; + opt_get_str = 0; + } else if(opt_get_str) { +#if 0 + if(menu_pos == highlight_pos) { + printf("menu_pos %d opt %d = %s=%d\n", + menu_pos, num_opts, + g_cfg_opts_strs[num_opts], + g_cfg_opts_vals[num_opts]); + } +#endif + num_opts++; + outstr = &(valbuf[0]); + opt_get_str = 0; + if(num_opts >= CFG_MAX_OPTS) { + fprintf(stderr, "CFG_MAX_OPTS oflow\n"); + my_exit(1); + } + } else { + if (type == CFGTYPE_INT) + { + val = strtoul(valbuf, 0, 0); + g_cfg_opts_vals[num_opts] = val; + } + + if (type == CFGTYPE_STR) + { + strncpy(&(g_cfg_opts_strvals[num_opts][0]),&(valbuf[0]),CFG_OPT_MAXSTR); + } + outstr = &(g_cfg_opts_strs[num_opts][0]); + opt_get_str = 1; + } + outpos = 0; + outstr[0] = 0; + } + } + + if(menu_pos == highlight_pos) { + g_cfg_opt_buf[bufpos++] = '\b'; + } + + g_cfg_opt_buf[bufpos] = 0; + + // Figure out if we should get a checkmark + curval = -1; + defval = -1; + curstr = 0; + if(type == CFGTYPE_INT) { iptr = (int*)menuptr->ptr; // OG Added cast - curval = *iptr; + curval = *iptr; iptr = (int*)menuptr->defptr; // OG Added cast - defval = *iptr; - if(curval == defval) { - g_cfg_opt_buf[3] = 'D'; /* checkmark */ - g_cfg_opt_buf[4] = '\t'; - } - } - if(type == CFGTYPE_STR) { - str_ptr = (char **)menuptr->ptr; - curstr = *str_ptr; - str_ptr = (char **)menuptr->defptr; - defstr = *str_ptr; - if(strcmp(curstr,defstr) == 0) { - g_cfg_opt_buf[3] = 'D'; /* checkmark */ - g_cfg_opt_buf[4] = '\t'; - } - } - if(type == CFGTYPE_FILE) { - str_ptr = (char **)menuptr->ptr; - curstr = *str_ptr; - str_ptr = (char **)menuptr->defptr; - defstr = *str_ptr; - if(strcmp(curstr,defstr) == 0) { - g_cfg_opt_buf[3] = 'D'; /* checkmark */ - g_cfg_opt_buf[4] = '\t'; - } - } - - // If it's a menu, give it a special menu indicator - if(type == CFGTYPE_MENU) { - g_cfg_opt_buf[1] = '\t'; - g_cfg_opt_buf[2] = 'M'; /* return-like symbol */ - g_cfg_opt_buf[3] = '\t'; - g_cfg_opt_buf[4] = ' '; - } - - // Decide what to display on the "right" side - str = 0; - opt_num = -1; - if(type == CFGTYPE_INT || type == CFGTYPE_FILE) { - g_cfg_opt_buf[bufpos++] = ' '; - g_cfg_opt_buf[bufpos++] = '='; - g_cfg_opt_buf[bufpos++] = ' '; - g_cfg_opt_buf[bufpos] = 0; - for(i = 0; i < num_opts; i++) { - if(curval == g_cfg_opts_vals[i]) { - opt_num = i; - break; - } - } - } - if(type == CFGTYPE_STR) { - g_cfg_opt_buf[bufpos++] = ' '; - g_cfg_opt_buf[bufpos++] = '='; - g_cfg_opt_buf[bufpos++] = ' '; - g_cfg_opt_buf[bufpos] = 0; - for(i = 0; i < num_opts; i++) { - if(!strcmp(curstr,g_cfg_opts_strvals[i])) { - opt_num = i; - break; - } - } - } - - if(change != 0) { - if(type == CFGTYPE_INT) { - if(num_opts > 0) { - opt_num += change; - if(opt_num >= num_opts) { - opt_num = 0; - } - if(opt_num < 0) { - opt_num = num_opts - 1; - } - curval = g_cfg_opts_vals[opt_num]; - } else { - curval += change; - /* HACK: min_val, max_val testing here */ - } - iptr = (int *)menuptr->ptr; - *iptr = curval; - } - if(type == CFGTYPE_STR) { - if(num_opts > 0) { - opt_num += change; - if(opt_num >= num_opts) { - opt_num = 0; - } - if(opt_num < 0) { - opt_num = num_opts - 1; - } - curstr = g_cfg_opts_strvals[opt_num]; - } else { - //curstr += change; - /* HACK: min_val, max_val testing here */ - } - str_ptr = (char **)menuptr->ptr; - *str_ptr = curstr; - } - g_config_gsport_update_needed = 1; - } - -#if 0 - if(menu_pos == highlight_pos) { - printf("menu_pos %d opt_num %d\n", menu_pos, opt_num); - } -#endif - - if(opt_num >= 0) { - str = &(g_cfg_opts_strs[opt_num][0]); - } else { - if(type == CFGTYPE_INT) { - str = &(g_cfg_opts_strs[0][0]); - snprintf(str, CFG_OPT_MAXSTR, "%d", curval); - } else if (type == CFGTYPE_STR) { - str = &(g_cfg_opts_strs[0][0]); - printf("curstr is: %s str is: %s\n", curstr,str); - snprintf(str, CFG_OPT_MAXSTR, "%s", curstr); - } else if (type == CFGTYPE_DISK) { - str = &(g_cfg_opts_strs[0][0]), - cfg_get_disk_name(str, CFG_OPT_MAXSTR, type_ext, 1); - str = cfg_shorten_filename(str, 68); - } else if (type == CFGTYPE_FILE) { - str = &(g_cfg_opts_strs[0][0]); - snprintf(str, CFG_OPT_MAXSTR, "%s", curstr); - str = cfg_shorten_filename(str, 68); - } else { - str = ""; - } - } - -#if 0 - if(menu_pos == highlight_pos) { - printf("menu_pos %d buf_pos %d, str is %s, %02x, %02x, " - "%02x %02x\n", - menu_pos, bufpos, str, g_cfg_opt_buf[bufpos-1], - g_cfg_opt_buf[bufpos-2], - g_cfg_opt_buf[bufpos-3], - g_cfg_opt_buf[bufpos-4]); - } -#endif - - g_cfg_opt_buf[bufpos] = 0; - strncpy(&(g_cfg_opt_buf[bufpos]), str, CFG_OPT_MAXSTR - bufpos - 1); - g_cfg_opt_buf[CFG_OPT_MAXSTR-1] = 0; -} - -void -cfg_get_base_path(char *pathptr, const char *inptr, int go_up) -{ - const char *tmpptr; - char *slashptr; - char *outptr; - int add_dotdot, is_dotdot; - int len; - int c; - - /* Take full filename, copy it to pathptr, and truncate at last slash */ - /* inptr and pathptr can be the same */ - /* if go_up is set, then replace a blank dir with ".." */ - /* but first, see if path is currently just ../ over and over */ - /* if so, just tack .. onto the end and return */ - //printf("cfg_get_base start with %s\n", inptr); - - g_cfg_file_match[0] = 0; - tmpptr = inptr; - is_dotdot = 1; - while(1) { - if(tmpptr[0] == 0) { - break; - } - if(tmpptr[0] == '.' && tmpptr[1] == '.' && tmpptr[2] == '/') { - tmpptr += 3; - } else { - is_dotdot = 0; - break; - } - } - slashptr = 0; - outptr = pathptr; - c = -1; - while(c != 0) { - c = *inptr++; - if(c == '/') { - if(*inptr != 0) { /* if not a trailing slash... */ - slashptr = outptr; - } - } - *outptr++ = c; - } - if(!go_up) { - /* if not go_up, copy chopped part to g_cfg_file_match*/ - /* copy from slashptr+1 to end */ - tmpptr = slashptr+1; - if(slashptr == 0) { - tmpptr = pathptr; - } - strncpy(&g_cfg_file_match[0], tmpptr, CFG_PATH_MAX); - /* remove trailing / from g_cfg_file_match */ - len = strlen(&g_cfg_file_match[0]); - if((len > 1) && (len < (CFG_PATH_MAX - 1)) && - g_cfg_file_match[len - 1] == '/') { - g_cfg_file_match[len - 1] = 0; - } - //printf("set g_cfg_file_match to %s\n", &g_cfg_file_match[0]); - } - if(!is_dotdot && (slashptr != 0)) { - slashptr[0] = '/'; - slashptr[1] = 0; - outptr = slashptr + 2; - } - add_dotdot = 0; - if(pathptr[0] == 0 || is_dotdot) { - /* path was blank, or consisted of just ../ pattern */ - if(go_up) { - add_dotdot = 1; - } - } else if(slashptr == 0) { - /* no slashes found, but path was not blank--make it blank */ - if(pathptr[0] == '/') { - pathptr[1] = 0; - } else { - pathptr[0] = 0; - } - } - - if(add_dotdot) { - --outptr; - outptr[0] = '.'; - outptr[1] = '.'; - outptr[2] = '/'; - outptr[3] = 0; - } - - //printf("cfg_get_base end with %s, is_dotdot:%d, add_dotdot:%d\n", - // pathptr, is_dotdot, add_dotdot); -} - -void -cfg_file_init() -{ - int slot, drive; - int i; - - if(g_cfg_slotdrive < 0xfff) { - cfg_get_disk_name(&g_cfg_tmp_path[0], CFG_PATH_MAX, - g_cfg_slotdrive, 0); - - slot = g_cfg_slotdrive >> 8; - drive = g_cfg_slotdrive & 1; - for(i = 0; i < 6; i++) { - if(g_cfg_tmp_path[0] != 0) { - break; - } - /* try to get a starting path from some mounted drive */ - drive = !drive; - if(i & 1) { - slot++; - if(slot >= 8) { - slot = 5; - } - } - cfg_get_disk_name(&g_cfg_tmp_path[0], CFG_PATH_MAX, - (slot << 8) + drive, 0); - } - } else { - // Just use g_cfg_file_def_name - strncpy(&g_cfg_tmp_path[0], g_cfg_file_def_name, CFG_PATH_MAX); - } - - cfg_get_base_path(&g_cfg_file_curpath[0], &g_cfg_tmp_path[0], 0); - g_cfg_dirlist.invalid = 1; -} - -void -cfg_free_alldirents(Cfg_listhdr *listhdrptr) -{ - int i; - - if(listhdrptr->max > 0) { - // Free the old directory listing - for(i = 0; i < listhdrptr->last; i++) { - free(listhdrptr->direntptr[i].name); - } - free(listhdrptr->direntptr); - } - - listhdrptr->direntptr = 0; - listhdrptr->last = 0; - listhdrptr->max = 0; - listhdrptr->invalid = 0; - - listhdrptr->topent = 0; - listhdrptr->curent = 0; -} - - -void -cfg_file_add_dirent(Cfg_listhdr *listhdrptr, const char *nameptr, int is_dir, - int size, int image_start, int part_num) -{ - Cfg_dirent *direntptr; - char *ptr; - int inc_amt; - int namelen; - - namelen = strlen(nameptr); - if(listhdrptr->last >= listhdrptr->max) { - // realloc - inc_amt = MAX(64, listhdrptr->max); - inc_amt = MIN(inc_amt, 1024); - listhdrptr->max += inc_amt; + defval = *iptr; + if(curval == defval) { + g_cfg_opt_buf[3] = 'D'; /* checkmark */ + g_cfg_opt_buf[4] = '\t'; + } + } + if(type == CFGTYPE_STR) { + str_ptr = (char **)menuptr->ptr; + curstr = *str_ptr; + str_ptr = (char **)menuptr->defptr; + defstr = *str_ptr; + if(strcmp(curstr,defstr) == 0) { + g_cfg_opt_buf[3] = 'D'; /* checkmark */ + g_cfg_opt_buf[4] = '\t'; + } + } + if(type == CFGTYPE_FILE) { + str_ptr = (char **)menuptr->ptr; + curstr = *str_ptr; + str_ptr = (char **)menuptr->defptr; + defstr = *str_ptr; + if(strcmp(curstr,defstr) == 0) { + g_cfg_opt_buf[3] = 'D'; /* checkmark */ + g_cfg_opt_buf[4] = '\t'; + } + } + + // If it's a menu, give it a special menu indicator + if(type == CFGTYPE_MENU) { + g_cfg_opt_buf[1] = '\t'; + g_cfg_opt_buf[2] = 'M'; /* return-like symbol */ + g_cfg_opt_buf[3] = '\t'; + g_cfg_opt_buf[4] = ' '; + } + + // Decide what to display on the "right" side + str = 0; + opt_num = -1; + if(type == CFGTYPE_INT || type == CFGTYPE_FILE) { + g_cfg_opt_buf[bufpos++] = ' '; + g_cfg_opt_buf[bufpos++] = '='; + g_cfg_opt_buf[bufpos++] = ' '; + g_cfg_opt_buf[bufpos] = 0; + for(i = 0; i < num_opts; i++) { + if(curval == g_cfg_opts_vals[i]) { + opt_num = i; + break; + } + } + } + if(type == CFGTYPE_STR) { + g_cfg_opt_buf[bufpos++] = ' '; + g_cfg_opt_buf[bufpos++] = '='; + g_cfg_opt_buf[bufpos++] = ' '; + g_cfg_opt_buf[bufpos] = 0; + for(i = 0; i < num_opts; i++) { + if(!strcmp(curstr,g_cfg_opts_strvals[i])) { + opt_num = i; + break; + } + } + } + + if(change != 0) { + if(type == CFGTYPE_INT) { + if(num_opts > 0) { + opt_num += change; + if(opt_num >= num_opts) { + opt_num = 0; + } + if(opt_num < 0) { + opt_num = num_opts - 1; + } + curval = g_cfg_opts_vals[opt_num]; + } else { + curval += change; + /* HACK: min_val, max_val testing here */ + } + iptr = (int *)menuptr->ptr; + *iptr = curval; + } + if(type == CFGTYPE_STR) { + if(num_opts > 0) { + opt_num += change; + if(opt_num >= num_opts) { + opt_num = 0; + } + if(opt_num < 0) { + opt_num = num_opts - 1; + } + curstr = g_cfg_opts_strvals[opt_num]; + } else { + //curstr += change; + /* HACK: min_val, max_val testing here */ + } + str_ptr = (char **)menuptr->ptr; + *str_ptr = curstr; + } + g_config_gsport_update_needed = 1; + } + +#if 0 + if(menu_pos == highlight_pos) { + printf("menu_pos %d opt_num %d\n", menu_pos, opt_num); + } +#endif + + if(opt_num >= 0) { + str = &(g_cfg_opts_strs[opt_num][0]); + } else { + if(type == CFGTYPE_INT) { + str = &(g_cfg_opts_strs[0][0]); + snprintf(str, CFG_OPT_MAXSTR, "%d", curval); + } else if (type == CFGTYPE_STR) { + str = &(g_cfg_opts_strs[0][0]); + printf("curstr is: %s str is: %s\n", curstr,str); + snprintf(str, CFG_OPT_MAXSTR, "%s", curstr); + } else if (type == CFGTYPE_DISK) { + str = &(g_cfg_opts_strs[0][0]), + cfg_get_disk_name(str, CFG_OPT_MAXSTR, type_ext, 1); + str = cfg_shorten_filename(str, 68); + } else if (type == CFGTYPE_FILE) { + str = &(g_cfg_opts_strs[0][0]); + snprintf(str, CFG_OPT_MAXSTR, "%s", curstr); + str = cfg_shorten_filename(str, 68); + } else { + str = ""; + } + } + +#if 0 + if(menu_pos == highlight_pos) { + printf("menu_pos %d buf_pos %d, str is %s, %02x, %02x, " + "%02x %02x\n", + menu_pos, bufpos, str, g_cfg_opt_buf[bufpos-1], + g_cfg_opt_buf[bufpos-2], + g_cfg_opt_buf[bufpos-3], + g_cfg_opt_buf[bufpos-4]); + } +#endif + + g_cfg_opt_buf[bufpos] = 0; + strncpy(&(g_cfg_opt_buf[bufpos]), str, CFG_OPT_MAXSTR - bufpos - 1); + g_cfg_opt_buf[CFG_OPT_MAXSTR-1] = 0; +} + +void +cfg_get_base_path(char *pathptr, const char *inptr, int go_up) +{ + const char *tmpptr; + char *slashptr; + char *outptr; + int add_dotdot, is_dotdot; + int len; + int c; + + /* Take full filename, copy it to pathptr, and truncate at last slash */ + /* inptr and pathptr can be the same */ + /* if go_up is set, then replace a blank dir with ".." */ + /* but first, see if path is currently just ../ over and over */ + /* if so, just tack .. onto the end and return */ + //printf("cfg_get_base start with %s\n", inptr); + + g_cfg_file_match[0] = 0; + tmpptr = inptr; + is_dotdot = 1; + while(1) { + if(tmpptr[0] == 0) { + break; + } + if(tmpptr[0] == '.' && tmpptr[1] == '.' && tmpptr[2] == '/') { + tmpptr += 3; + } else { + is_dotdot = 0; + break; + } + } + slashptr = 0; + outptr = pathptr; + c = -1; + while(c != 0) { + c = *inptr++; + if(c == '/') { + if(*inptr != 0) { /* if not a trailing slash... */ + slashptr = outptr; + } + } + *outptr++ = c; + } + if(!go_up) { + /* if not go_up, copy chopped part to g_cfg_file_match*/ + /* copy from slashptr+1 to end */ + tmpptr = slashptr+1; + if(slashptr == 0) { + tmpptr = pathptr; + } + strncpy(&g_cfg_file_match[0], tmpptr, CFG_PATH_MAX); + /* remove trailing / from g_cfg_file_match */ + len = strlen(&g_cfg_file_match[0]); + if((len > 1) && (len < (CFG_PATH_MAX - 1)) && + g_cfg_file_match[len - 1] == '/') { + g_cfg_file_match[len - 1] = 0; + } + //printf("set g_cfg_file_match to %s\n", &g_cfg_file_match[0]); + } + if(!is_dotdot && (slashptr != 0)) { + slashptr[0] = '/'; + slashptr[1] = 0; + outptr = slashptr + 2; + } + add_dotdot = 0; + if(pathptr[0] == 0 || is_dotdot) { + /* path was blank, or consisted of just ../ pattern */ + if(go_up) { + add_dotdot = 1; + } + } else if(slashptr == 0) { + /* no slashes found, but path was not blank--make it blank */ + if(pathptr[0] == '/') { + pathptr[1] = 0; + } else { + pathptr[0] = 0; + } + } + + if(add_dotdot) { + --outptr; + outptr[0] = '.'; + outptr[1] = '.'; + outptr[2] = '/'; + outptr[3] = 0; + } + + //printf("cfg_get_base end with %s, is_dotdot:%d, add_dotdot:%d\n", + // pathptr, is_dotdot, add_dotdot); +} + +void +cfg_file_init() +{ + int slot, drive; + int i; + + if(g_cfg_slotdrive < 0xfff) { + cfg_get_disk_name(&g_cfg_tmp_path[0], CFG_PATH_MAX, + g_cfg_slotdrive, 0); + + slot = g_cfg_slotdrive >> 8; + drive = g_cfg_slotdrive & 1; + for(i = 0; i < 6; i++) { + if(g_cfg_tmp_path[0] != 0) { + break; + } + /* try to get a starting path from some mounted drive */ + drive = !drive; + if(i & 1) { + slot++; + if(slot >= 8) { + slot = 5; + } + } + cfg_get_disk_name(&g_cfg_tmp_path[0], CFG_PATH_MAX, + (slot << 8) + drive, 0); + } + } else { + // Just use g_cfg_file_def_name + strncpy(&g_cfg_tmp_path[0], g_cfg_file_def_name, CFG_PATH_MAX); + } + + cfg_get_base_path(&g_cfg_file_curpath[0], &g_cfg_tmp_path[0], 0); + g_cfg_dirlist.invalid = 1; +} + +void +cfg_free_alldirents(Cfg_listhdr *listhdrptr) +{ + int i; + + if(listhdrptr->max > 0) { + // Free the old directory listing + for(i = 0; i < listhdrptr->last; i++) { + free(listhdrptr->direntptr[i].name); + } + free(listhdrptr->direntptr); + } + + listhdrptr->direntptr = 0; + listhdrptr->last = 0; + listhdrptr->max = 0; + listhdrptr->invalid = 0; + + listhdrptr->topent = 0; + listhdrptr->curent = 0; +} + + +void +cfg_file_add_dirent(Cfg_listhdr *listhdrptr, const char *nameptr, int is_dir, + int size, int image_start, int part_num) +{ + Cfg_dirent *direntptr; + char *ptr; + int inc_amt; + int namelen; + + namelen = strlen(nameptr); + if(listhdrptr->last >= listhdrptr->max) { + // realloc + inc_amt = MAX(64, listhdrptr->max); + inc_amt = MIN(inc_amt, 1024); + listhdrptr->max += inc_amt; listhdrptr->direntptr = (Cfg_dirent*)realloc(listhdrptr->direntptr, - listhdrptr->max * sizeof(Cfg_dirent)); - } + listhdrptr->max * sizeof(Cfg_dirent)); + } ptr = (char*)malloc(namelen+1+is_dir); // OG Added cast - strncpy(ptr, nameptr, namelen+1); - if(is_dir) { - strcat(ptr, "/"); - } -#if 0 - printf("...file entry %d is %s\n", g_cfg_dirlist.last, ptr); -#endif - direntptr = &(listhdrptr->direntptr[listhdrptr->last]); - direntptr->name = ptr; - direntptr->is_dir = is_dir; - direntptr->size = size; - direntptr->image_start = image_start; - direntptr->part_num = part_num; - listhdrptr->last++; -} - -int -cfg_dirent_sortfn(const void *obj1, const void *obj2) -{ - const Cfg_dirent *direntptr1, *direntptr2; - int ret; - - /* Called by qsort to sort directory listings */ - direntptr1 = (const Cfg_dirent *)obj1; - direntptr2 = (const Cfg_dirent *)obj2; + strncpy(ptr, nameptr, namelen+1); + if(is_dir) { + strcat(ptr, "/"); + } +#if 0 + printf("...file entry %d is %s\n", g_cfg_dirlist.last, ptr); +#endif + direntptr = &(listhdrptr->direntptr[listhdrptr->last]); + direntptr->name = ptr; + direntptr->is_dir = is_dir; + direntptr->size = size; + direntptr->image_start = image_start; + direntptr->part_num = part_num; + listhdrptr->last++; +} + +int +cfg_dirent_sortfn(const void *obj1, const void *obj2) +{ + const Cfg_dirent *direntptr1, *direntptr2; + int ret; + + /* Called by qsort to sort directory listings */ + direntptr1 = (const Cfg_dirent *)obj1; + direntptr2 = (const Cfg_dirent *)obj2; #if defined(MAC) || defined(_WIN32) // OG ret = 0; // ret = strcasecmp(direntptr1->name, direntptr2->name); -#else - ret = strcmp(direntptr1->name, direntptr2->name); -#endif - return ret; -} - -int -cfg_str_match(const char *str1, const char *str2, int len) -{ - const byte *bptr1, *bptr2; - int c, c2; - int i; - - /* basically, work like strcmp, except if str1 ends first, return 0 */ - - bptr1 = (const byte *)str1; - bptr2 = (const byte *)str2; - for(i = 0; i < len; i++) { - c = *bptr1++; - c2 = *bptr2++; - if(c == 0) { - if(i > 0) { - return 0; - } else { - return c - c2; - } - } - if(c != c2) { - return c - c2; - } - } - - return 0; -} - -void -cfg_file_readdir(const char *pathptr) -{ -#ifndef __OS2__ - struct dirent *direntptr; - struct stat stat_buf; - DIR *dirptr; - mode_t fmt; - char *str; - const char *tmppathptr; - int size; - int ret; - int is_dir, is_gz; - int len; - int i; - - if(!strncmp(pathptr, &g_cfg_file_cachedpath[0], CFG_PATH_MAX) && - (g_cfg_dirlist.last > 0) && (g_cfg_dirlist.invalid==0)){ - return; - } - // No match, must read new directory - - // Free all dirents that were cached previously - cfg_free_alldirents(&g_cfg_dirlist); - - strncpy(&g_cfg_file_cachedpath[0], pathptr, CFG_PATH_MAX); - strncpy(&g_cfg_file_cachedreal[0], pathptr, CFG_PATH_MAX); - - str = &g_cfg_file_cachedreal[0]; - - for(i = 0; i < 200; i++) { - len = strlen(str); - if(len <= 0) { - break; - } else if(len < CFG_PATH_MAX-2) { - if(str[len-1] != '/') { - // append / to make various routines work - str[len] = '/'; - str[len+1] = 0; - } - } - ret = cfg_stat(str, &stat_buf); - is_dir = 0; - if(ret == 0) { - fmt = stat_buf.st_mode & S_IFMT; - if(fmt == S_IFDIR) { - /* it's a directory */ - is_dir = 1; - } - } - if(is_dir) { - break; - } else { - // user is entering more path, use base for display - cfg_get_base_path(str, str, 0); - } - } - tmppathptr = str; - if(str[0] == 0) { - tmppathptr = "."; - } - cfg_file_add_dirent(&g_cfg_dirlist, "..", 1, 0, -1, -1); - dirptr = opendir(tmppathptr); - if(dirptr == 0) { - printf("Could not open %s as a directory\n", tmppathptr); - return; - } - while(1) { - direntptr = readdir(dirptr); - if(direntptr == 0) { - break; - } - if(!strcmp(".", direntptr->d_name)) { - continue; - } - if(!strcmp("..", direntptr->d_name)) { - continue; - } - /* Else, see if it is a directory or a file */ - snprintf(&g_cfg_tmp_path[0], CFG_PATH_MAX, "%s%s", - &g_cfg_file_cachedreal[0], direntptr->d_name); - ret = cfg_stat(&g_cfg_tmp_path[0], &stat_buf); - len = strlen(g_cfg_tmp_path); - is_dir = 0; - is_gz = 0; - if((len > 3) && (strcmp(&g_cfg_tmp_path[len - 3], ".gz") == 0)){ - is_gz = 1; - } - if(ret != 0) { - printf("stat %s ret %d, errno:%d\n", &g_cfg_tmp_path[0], - ret, errno); - stat_buf.st_size = 0; - continue; /* skip it */ - } else { - fmt = stat_buf.st_mode & S_IFMT; - size = stat_buf.st_size; - if(fmt == S_IFDIR) { - /* it's a directory */ - is_dir = 1; - } else if((fmt == S_IFREG) && (is_gz == 0)) { - if(g_cfg_slotdrive < 0xfff) { - if(size < 140*1024) { - continue; /* skip it */ - } - } else { - /* see if there are size limits */ - if((size < g_cfg_file_min_size) || - (size > g_cfg_file_max_size)) { - continue; /* skip it */ - } - } - } - } - cfg_file_add_dirent(&g_cfg_dirlist, direntptr->d_name, is_dir, - stat_buf.st_size, -1, -1); - } - /* then sort the results (Mac's HFS+ is sorted, but other FS won't be)*/ - qsort(&(g_cfg_dirlist.direntptr[0]), g_cfg_dirlist.last, - sizeof(Cfg_dirent), cfg_dirent_sortfn); - g_cfg_dirlist.curent = g_cfg_dirlist.last - 1; - for(i = g_cfg_dirlist.last - 1; i >= 0; i--) { - ret = cfg_str_match(&g_cfg_file_match[0], - g_cfg_dirlist.direntptr[i].name, CFG_PATH_MAX); - if(ret <= 0) { - /* set cur ent to closest filename to the match name */ - g_cfg_dirlist.curent = i; - } - } -#endif -} - -void -cfg_inspect_maybe_insert_file(char *filename, int should_boot) -{ -/* -Take a look at a file. Based on its size, guess a slot/drive to insert it into. -Used for blind operations like dragging/dropping files. -Optionally boot from that slot. -*/ - int rc = 0; - int slot = 0; - rc = cfg_guess_image_size(filename); - switch (rc) - { - case 0: slot = 7; break; - case 1: slot = 6; break; - case 2: slot = 5; break; - case 3: slot = 7; break; - default: break; - } - if (slot > 0) - { - insert_disk(slot,0,filename,0,0,0,-1); - printf("Inserted disk in slot %d, drive 1. Filename: %s\n", slot, filename); - if (should_boot) { - g_temp_boot_slot = slot; - printf("That slot has been set to boot.\n"); - } - } - else - printf("Unable to determine appropriate place to insert file %s.\n",filename); -} - -int -cfg_guess_image_size(char *filename) -{ -/* -Guess the image size. Return values: - -1 : invalid/unknown. Can't guess. - 0 : Less than 140k; might be ram disk image. - 1 : 140k, 5.25" image. - 2 : 800k, 3.5" image. - 3 : Something bigger. -*/ - struct stat stat_buf; - int rc = -1; - int len; - rc = stat(filename, &stat_buf); - if(rc < 0) - { - printf("Can't get statistics on file %s; errno: %d\n", - filename, errno); - rc = -1; - } else { - len = stat_buf.st_size; - printf("Found file %s, size %d; guessing ", - filename, len); - if (len < 140 * 1024) { - /* Not enough for a 140k image */ - printf("small ProDOS image.\n"); - rc = 0; - } else if (len < 140 * 1024 + 256 + 1) { - /* Reasonable size for 140k image, maybe in 2mg format */ - printf("a 5-1/4\" image.\n"); - rc = 1; - } else if (len < 800 * 1024 + 256 + 1) { - /* Reasonable size for 800k image, maybe in 2mg format */ - printf("a 3-1/2\" image.\n"); - rc = 2; - } else { - /* Let's pretend it's an HDV image */ - printf("a hard drive image.\n"); - rc = 3; - } - } - return rc; -} - -char * -cfg_shorten_filename(const char *in_ptr, int maxlen) -{ - char *out_ptr; - int len; - int c; - int i; - /* Warning: uses a static string, not reentrant! */ - out_ptr = &(g_cfg_file_shortened[0]); - len = strlen(in_ptr); - maxlen = MIN(len, maxlen); - for(i = 0; i < maxlen; i++) { - c = in_ptr[i] & 0x7f; - if(c < 0x20) { - c = '*'; - } - out_ptr[i] = c; - } - out_ptr[maxlen] = 0; - if(len > maxlen) { - for(i = 0; i < (maxlen/2); i++) { - c = in_ptr[len-i-1] & 0x7f; - if(c < 0x20) { - c = '*'; - } - out_ptr[maxlen-i-1] = c; - } - out_ptr[(maxlen/2) - 1] = '.'; - out_ptr[maxlen/2] = '.'; - out_ptr[(maxlen/2) + 1] = '.'; - } - return out_ptr; -} -void -cfg_fix_topent(Cfg_listhdr *listhdrptr) -{ - int num_to_show; - num_to_show = listhdrptr->num_to_show; - /* Force curent and topent to make sense */ - if(listhdrptr->curent >= listhdrptr->last) { - listhdrptr->curent = listhdrptr->last - 1; - } - if(listhdrptr->curent < 0) { - listhdrptr->curent = 0; - } - if(abs(listhdrptr->curent - listhdrptr->topent) >= num_to_show) { - listhdrptr->topent = listhdrptr->curent - (num_to_show/2); - } - if(listhdrptr->topent > listhdrptr->curent) { - listhdrptr->topent = listhdrptr->curent - (num_to_show/2); - } - if(listhdrptr->topent < 0) { - listhdrptr->topent = 0; - } -} -void -cfg_file_draw() -{ - Cfg_listhdr *listhdrptr; - Cfg_dirent *direntptr; - char *str, *fmt; - int num_to_show; - int yoffset; - int x, y; - int i; - cfg_file_readdir(&g_cfg_file_curpath[0]); - for(y = 0; y < 21; y++) { - cfg_htab_vtab(0, y); - cfg_printf("\tZ\t"); - for(x = 1; x < 79; x++) { - cfg_htab_vtab(x, y); - cfg_putchar(' '); - } - cfg_htab_vtab(79, y); - cfg_printf("\t_\t"); - } - cfg_htab_vtab(1, 0); - cfg_putchar('\b'); - for(x = 1; x < 79; x++) { - cfg_putchar(' '); - } - if(g_cfg_slotdrive < 0xfff) { - cfg_htab_vtab(30, 0); - cfg_printf("\bSelect image for s%dd%d\b", - (g_cfg_slotdrive >> 8), (g_cfg_slotdrive & 0xff) + 1); - } else { - cfg_htab_vtab(5, 0); - cfg_printf("\bSelect file to use as %-40s\b", - cfg_shorten_filename(g_cfg_file_def_name, 40)); - } - cfg_htab_vtab(2, 1); - cfg_printf("Configuration file path: %-56s", - cfg_shorten_filename(&g_config_gsport_name[0], 56)); - cfg_htab_vtab(2, 2); - cfg_printf("Current directory: %-50s", - cfg_shorten_filename(&g_cfg_cwd_str[0], 50)); - cfg_htab_vtab(2, 3); - str = ""; - if(g_cfg_file_pathfield) { - str = "\b \b"; - } - cfg_printf("Path: %s%s", - cfg_shorten_filename(&g_cfg_file_curpath[0], 68), str); - cfg_htab_vtab(0, 4); - cfg_printf(" \t"); - for(x = 1; x < 79; x++) { - cfg_putchar('\\'); - } - cfg_printf("\t "); - - /* Force curent and topent to make sense */ - listhdrptr = &g_cfg_dirlist; - num_to_show = CFG_NUM_SHOWENTS; - yoffset = 5; - if(g_cfg_select_partition > 0) { - listhdrptr = &g_cfg_partitionlist; - num_to_show -= 2; - cfg_htab_vtab(2, yoffset); - cfg_printf("Select partition of %-50s\n", - cfg_shorten_filename(&g_cfg_file_path[0], 50), str); - yoffset += 2; - } - listhdrptr->num_to_show = num_to_show; - cfg_fix_topent(listhdrptr); - for(i = 0; i < num_to_show; i++) { - y = i + yoffset; - if(listhdrptr->last > (i + listhdrptr->topent)) { - direntptr = &(listhdrptr-> - direntptr[i + listhdrptr->topent]); - cfg_htab_vtab(2, y); - if(direntptr->is_dir) { - cfg_printf("\tXY\t "); - } else { - cfg_printf(" "); - } - if(direntptr->part_num >= 0) { - cfg_printf("%3d: ", direntptr->part_num); - } - str = cfg_shorten_filename(direntptr->name, 45); - fmt = "%-45s"; - if(i + listhdrptr->topent == listhdrptr->curent) { - if(g_cfg_file_pathfield == 0) { - fmt = "\b%-45s\b"; - } else { - fmt = "%-44s\b \b"; - } - } - cfg_printf(fmt, str); - if(!direntptr->is_dir) { - cfg_print_num(direntptr->size, 13); - } - } - } - cfg_htab_vtab(1, 5 + CFG_NUM_SHOWENTS); - cfg_putchar('\t'); - for(x = 1; x < 79; x++) { - cfg_putchar('L'); - } - cfg_putchar('\t'); -} -void -cfg_partition_selected() -{ - char *str; - const char *part_str; - char *part_str2; - int pos; - int part_num; - pos = g_cfg_partitionlist.curent; - str = g_cfg_partitionlist.direntptr[pos].name; - part_num = -2; - part_str = 0; - if(str[0] == 0 || (str[0] >= '0' && str[0] <= '9')) { - part_num = g_cfg_partitionlist.direntptr[pos].part_num; - } else { - part_str = str; - } - part_str2 = 0; - if(part_str != 0) { - part_str2 = (char *)malloc(strlen(part_str)+1); - strcpy(part_str2, part_str); - } - insert_disk(g_cfg_slotdrive >> 8, g_cfg_slotdrive & 0xff, - &(g_cfg_file_path[0]), 0, 0, part_str2, part_num); - if(part_str2 != 0) { - free(part_str2); - } - g_cfg_slotdrive = -1; - g_cfg_select_partition = -1; -} -void -cfg_file_update_ptr(char *str) -{ - char *newstr; - int len; - len = strlen(str) + 1; +#else + ret = strcmp(direntptr1->name, direntptr2->name); +#endif + return ret; +} + +int +cfg_str_match(const char *str1, const char *str2, int len) +{ + const byte *bptr1, *bptr2; + int c, c2; + int i; + + /* basically, work like strcmp, except if str1 ends first, return 0 */ + + bptr1 = (const byte *)str1; + bptr2 = (const byte *)str2; + for(i = 0; i < len; i++) { + c = *bptr1++; + c2 = *bptr2++; + if(c == 0) { + if(i > 0) { + return 0; + } else { + return c - c2; + } + } + if(c != c2) { + return c - c2; + } + } + + return 0; +} + +void +cfg_file_readdir(const char *pathptr) +{ +#ifndef __OS2__ + struct dirent *direntptr; + struct stat stat_buf; + DIR *dirptr; + mode_t fmt; + char *str; + const char *tmppathptr; + int size; + int ret; + int is_dir, is_gz; + int len; + int i; + + if(!strncmp(pathptr, &g_cfg_file_cachedpath[0], CFG_PATH_MAX) && + (g_cfg_dirlist.last > 0) && (g_cfg_dirlist.invalid==0)){ + return; + } + // No match, must read new directory + + // Free all dirents that were cached previously + cfg_free_alldirents(&g_cfg_dirlist); + + strncpy(&g_cfg_file_cachedpath[0], pathptr, CFG_PATH_MAX); + strncpy(&g_cfg_file_cachedreal[0], pathptr, CFG_PATH_MAX); + + str = &g_cfg_file_cachedreal[0]; + + for(i = 0; i < 200; i++) { + len = strlen(str); + if(len <= 0) { + break; + } else if(len < CFG_PATH_MAX-2) { + if(str[len-1] != '/') { + // append / to make various routines work + str[len] = '/'; + str[len+1] = 0; + } + } + ret = cfg_stat(str, &stat_buf); + is_dir = 0; + if(ret == 0) { + fmt = stat_buf.st_mode & S_IFMT; + if(fmt == S_IFDIR) { + /* it's a directory */ + is_dir = 1; + } + } + if(is_dir) { + break; + } else { + // user is entering more path, use base for display + cfg_get_base_path(str, str, 0); + } + } + tmppathptr = str; + if(str[0] == 0) { + tmppathptr = "."; + } + cfg_file_add_dirent(&g_cfg_dirlist, "..", 1, 0, -1, -1); + dirptr = opendir(tmppathptr); + if(dirptr == 0) { + printf("Could not open %s as a directory\n", tmppathptr); + return; + } + while(1) { + direntptr = readdir(dirptr); + if(direntptr == 0) { + break; + } + if(!strcmp(".", direntptr->d_name)) { + continue; + } + if(!strcmp("..", direntptr->d_name)) { + continue; + } + /* Else, see if it is a directory or a file */ + snprintf(&g_cfg_tmp_path[0], CFG_PATH_MAX, "%s%s", + &g_cfg_file_cachedreal[0], direntptr->d_name); + ret = cfg_stat(&g_cfg_tmp_path[0], &stat_buf); + len = strlen(g_cfg_tmp_path); + is_dir = 0; + is_gz = 0; + if((len > 3) && (strcmp(&g_cfg_tmp_path[len - 3], ".gz") == 0)){ + is_gz = 1; + } + if(ret != 0) { + printf("stat %s ret %d, errno:%d\n", &g_cfg_tmp_path[0], + ret, errno); + stat_buf.st_size = 0; + continue; /* skip it */ + } else { + fmt = stat_buf.st_mode & S_IFMT; + size = stat_buf.st_size; + if(fmt == S_IFDIR) { + /* it's a directory */ + is_dir = 1; + } else if((fmt == S_IFREG) && (is_gz == 0)) { + if(g_cfg_slotdrive < 0xfff) { + if(size < 140*1024) { + continue; /* skip it */ + } + } else { + /* see if there are size limits */ + if((size < g_cfg_file_min_size) || + (size > g_cfg_file_max_size)) { + continue; /* skip it */ + } + } + } + } + cfg_file_add_dirent(&g_cfg_dirlist, direntptr->d_name, is_dir, + stat_buf.st_size, -1, -1); + } + /* then sort the results (Mac's HFS+ is sorted, but other FS won't be)*/ + qsort(&(g_cfg_dirlist.direntptr[0]), g_cfg_dirlist.last, + sizeof(Cfg_dirent), cfg_dirent_sortfn); + g_cfg_dirlist.curent = g_cfg_dirlist.last - 1; + for(i = g_cfg_dirlist.last - 1; i >= 0; i--) { + ret = cfg_str_match(&g_cfg_file_match[0], + g_cfg_dirlist.direntptr[i].name, CFG_PATH_MAX); + if(ret <= 0) { + /* set cur ent to closest filename to the match name */ + g_cfg_dirlist.curent = i; + } + } +#endif +} + +void +cfg_inspect_maybe_insert_file(char *filename, int should_boot) +{ +/* +Take a look at a file. Based on its size, guess a slot/drive to insert it into. +Used for blind operations like dragging/dropping files. +Optionally boot from that slot. +*/ + int rc = 0; + int slot = 0; + rc = cfg_guess_image_size(filename); + switch (rc) + { + case 0: slot = 7; break; + case 1: slot = 6; break; + case 2: slot = 5; break; + case 3: slot = 7; break; + default: break; + } + if (slot > 0) + { + insert_disk(slot,0,filename,0,0,0,-1); + printf("Inserted disk in slot %d, drive 1. Filename: %s\n", slot, filename); + if (should_boot) { + g_temp_boot_slot = slot; + printf("That slot has been set to boot.\n"); + } + } + else + printf("Unable to determine appropriate place to insert file %s.\n",filename); +} + +int +cfg_guess_image_size(char *filename) +{ +/* +Guess the image size. Return values: + -1 : invalid/unknown. Can't guess. + 0 : Less than 140k; might be ram disk image. + 1 : 140k, 5.25" image. + 2 : 800k, 3.5" image. + 3 : Something bigger. +*/ + struct stat stat_buf; + int rc = -1; + int len; + rc = stat(filename, &stat_buf); + if(rc < 0) + { + printf("Can't get statistics on file %s; errno: %d\n", + filename, errno); + rc = -1; + } else { + len = stat_buf.st_size; + printf("Found file %s, size %d; guessing ", + filename, len); + if (len < 140 * 1024) { + /* Not enough for a 140k image */ + printf("small ProDOS image.\n"); + rc = 0; + } else if (len < 140 * 1024 + 256 + 1) { + /* Reasonable size for 140k image, maybe in 2mg format */ + printf("a 5-1/4\" image.\n"); + rc = 1; + } else if (len < 800 * 1024 + 256 + 1) { + /* Reasonable size for 800k image, maybe in 2mg format */ + printf("a 3-1/2\" image.\n"); + rc = 2; + } else { + /* Let's pretend it's an HDV image */ + printf("a hard drive image.\n"); + rc = 3; + } + } + return rc; +} + +char * +cfg_shorten_filename(const char *in_ptr, int maxlen) +{ + char *out_ptr; + int len; + int c; + int i; + /* Warning: uses a static string, not reentrant! */ + out_ptr = &(g_cfg_file_shortened[0]); + len = strlen(in_ptr); + maxlen = MIN(len, maxlen); + for(i = 0; i < maxlen; i++) { + c = in_ptr[i] & 0x7f; + if(c < 0x20) { + c = '*'; + } + out_ptr[i] = c; + } + out_ptr[maxlen] = 0; + if(len > maxlen) { + for(i = 0; i < (maxlen/2); i++) { + c = in_ptr[len-i-1] & 0x7f; + if(c < 0x20) { + c = '*'; + } + out_ptr[maxlen-i-1] = c; + } + out_ptr[(maxlen/2) - 1] = '.'; + out_ptr[maxlen/2] = '.'; + out_ptr[(maxlen/2) + 1] = '.'; + } + return out_ptr; +} +void +cfg_fix_topent(Cfg_listhdr *listhdrptr) +{ + int num_to_show; + num_to_show = listhdrptr->num_to_show; + /* Force curent and topent to make sense */ + if(listhdrptr->curent >= listhdrptr->last) { + listhdrptr->curent = listhdrptr->last - 1; + } + if(listhdrptr->curent < 0) { + listhdrptr->curent = 0; + } + if(abs(listhdrptr->curent - listhdrptr->topent) >= num_to_show) { + listhdrptr->topent = listhdrptr->curent - (num_to_show/2); + } + if(listhdrptr->topent > listhdrptr->curent) { + listhdrptr->topent = listhdrptr->curent - (num_to_show/2); + } + if(listhdrptr->topent < 0) { + listhdrptr->topent = 0; + } +} +void +cfg_file_draw() +{ + Cfg_listhdr *listhdrptr; + Cfg_dirent *direntptr; + char *str, *fmt; + int num_to_show; + int yoffset; + int x, y; + int i; + cfg_file_readdir(&g_cfg_file_curpath[0]); + for(y = 0; y < 21; y++) { + cfg_htab_vtab(0, y); + cfg_printf("\tZ\t"); + for(x = 1; x < 79; x++) { + cfg_htab_vtab(x, y); + cfg_putchar(' '); + } + cfg_htab_vtab(79, y); + cfg_printf("\t_\t"); + } + cfg_htab_vtab(1, 0); + cfg_putchar('\b'); + for(x = 1; x < 79; x++) { + cfg_putchar(' '); + } + if(g_cfg_slotdrive < 0xfff) { + cfg_htab_vtab(30, 0); + cfg_printf("\bSelect image for s%dd%d\b", + (g_cfg_slotdrive >> 8), (g_cfg_slotdrive & 0xff) + 1); + } else { + cfg_htab_vtab(5, 0); + cfg_printf("\bSelect file to use as %-40s\b", + cfg_shorten_filename(g_cfg_file_def_name, 40)); + } + cfg_htab_vtab(2, 1); + cfg_printf("Configuration file path: %-56s", + cfg_shorten_filename(&g_config_gsport_name[0], 56)); + cfg_htab_vtab(2, 2); + cfg_printf("Current directory: %-50s", + cfg_shorten_filename(&g_cfg_cwd_str[0], 50)); + cfg_htab_vtab(2, 3); + str = ""; + if(g_cfg_file_pathfield) { + str = "\b \b"; + } + cfg_printf("Path: %s%s", + cfg_shorten_filename(&g_cfg_file_curpath[0], 68), str); + cfg_htab_vtab(0, 4); + cfg_printf(" \t"); + for(x = 1; x < 79; x++) { + cfg_putchar('\\'); + } + cfg_printf("\t "); + + /* Force curent and topent to make sense */ + listhdrptr = &g_cfg_dirlist; + num_to_show = CFG_NUM_SHOWENTS; + yoffset = 5; + if(g_cfg_select_partition > 0) { + listhdrptr = &g_cfg_partitionlist; + num_to_show -= 2; + cfg_htab_vtab(2, yoffset); + cfg_printf("Select partition of %-50s\n", + cfg_shorten_filename(&g_cfg_file_path[0], 50), str); + yoffset += 2; + } + listhdrptr->num_to_show = num_to_show; + cfg_fix_topent(listhdrptr); + for(i = 0; i < num_to_show; i++) { + y = i + yoffset; + if(listhdrptr->last > (i + listhdrptr->topent)) { + direntptr = &(listhdrptr-> + direntptr[i + listhdrptr->topent]); + cfg_htab_vtab(2, y); + if(direntptr->is_dir) { + cfg_printf("\tXY\t "); + } else { + cfg_printf(" "); + } + if(direntptr->part_num >= 0) { + cfg_printf("%3d: ", direntptr->part_num); + } + str = cfg_shorten_filename(direntptr->name, 45); + fmt = "%-45s"; + if(i + listhdrptr->topent == listhdrptr->curent) { + if(g_cfg_file_pathfield == 0) { + fmt = "\b%-45s\b"; + } else { + fmt = "%-44s\b \b"; + } + } + cfg_printf(fmt, str); + if(!direntptr->is_dir) { + cfg_print_num(direntptr->size, 13); + } + } + } + cfg_htab_vtab(1, 5 + CFG_NUM_SHOWENTS); + cfg_putchar('\t'); + for(x = 1; x < 79; x++) { + cfg_putchar('L'); + } + cfg_putchar('\t'); +} +void +cfg_partition_selected() +{ + char *str; + const char *part_str; + char *part_str2; + int pos; + int part_num; + pos = g_cfg_partitionlist.curent; + str = g_cfg_partitionlist.direntptr[pos].name; + part_num = -2; + part_str = 0; + if(str[0] == 0 || (str[0] >= '0' && str[0] <= '9')) { + part_num = g_cfg_partitionlist.direntptr[pos].part_num; + } else { + part_str = str; + } + part_str2 = 0; + if(part_str != 0) { + part_str2 = (char *)malloc(strlen(part_str)+1); + strcpy(part_str2, part_str); + } + insert_disk(g_cfg_slotdrive >> 8, g_cfg_slotdrive & 0xff, + &(g_cfg_file_path[0]), 0, 0, part_str2, part_num); + if(part_str2 != 0) { + free(part_str2); + } + g_cfg_slotdrive = -1; + g_cfg_select_partition = -1; +} +void +cfg_file_update_ptr(char *str) +{ + char *newstr; + int len; + len = strlen(str) + 1; newstr = (char*)malloc(len); - memcpy(newstr, str, len); - if(g_cfg_file_strptr) { - if(*g_cfg_file_strptr) { - free(*g_cfg_file_strptr); - } - } - *g_cfg_file_strptr = newstr; - if(g_cfg_file_strptr == &(g_cfg_rom_path)) { - printf("Updated ROM file\n"); - load_roms_init_memory(); - } - g_config_gsport_update_needed = 1; -} -void -cfg_file_selected() -{ -#ifndef __OS2__ - struct stat stat_buf; - char *str; - int fmt; - int ret; - if(g_cfg_select_partition > 0) { - cfg_partition_selected(); - return; - } - if(g_cfg_file_pathfield == 0) { - // in file section area of window - str = g_cfg_dirlist.direntptr[g_cfg_dirlist.curent].name; - if(!strcmp(str, "../")) { - /* go up one directory */ - cfg_get_base_path(&g_cfg_file_curpath[0], - &g_cfg_file_curpath[0], 1); - return; - } - snprintf(&g_cfg_file_path[0], CFG_PATH_MAX, "%s%s", - &g_cfg_file_cachedreal[0], str); - } else { - // just use cfg_file_curpath directly - strncpy(&g_cfg_file_path[0], &g_cfg_file_curpath[0], - CFG_PATH_MAX); - } - ret = cfg_stat(&g_cfg_file_path[0], &stat_buf); - fmt = stat_buf.st_mode & S_IFMT; - cfg_printf("Stat'ing %s, st_mode is: %08x\n", &g_cfg_file_path[0], - (int)stat_buf.st_mode); - if(ret != 0) { - printf("stat %s returned %d, errno: %d\n", &g_cfg_file_path[0], - ret, errno); - } else { - if(fmt == S_IFDIR) { - /* it's a directory */ - strncpy(&g_cfg_file_curpath[0], &g_cfg_file_path[0], - CFG_PATH_MAX); - } else { - /* select it */ - if(g_cfg_slotdrive < 0xfff) { - ret = cfg_maybe_insert_disk(g_cfg_slotdrive>>8, - g_cfg_slotdrive & 0xff, - &g_cfg_file_path[0]); - if(ret > 0) { - g_cfg_slotdrive = -1; - } - } else { - cfg_file_update_ptr(&g_cfg_file_path[0]); - g_cfg_slotdrive = -1; - } - } - } -#endif -} - -void -cfg_file_handle_key(int key) -{ - Cfg_listhdr *listhdrptr; - int len; - if(g_cfg_file_pathfield) { - if(key >= 0x20 && key < 0x7f) { - len = strlen(&g_cfg_file_curpath[0]); - if(len < CFG_PATH_MAX-4) { - g_cfg_file_curpath[len] = key; - g_cfg_file_curpath[len+1] = 0; - } - return; - } - } - listhdrptr = &g_cfg_dirlist; - if(g_cfg_select_partition > 0) { - listhdrptr = &g_cfg_partitionlist; - } - if( (g_cfg_file_pathfield == 0) && - ((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z')) ) { - /* jump to file starting with this letter */ - g_cfg_file_match[0] = key; - g_cfg_file_match[1] = 0; - g_cfg_dirlist.invalid = 1; /* re-read directory */ - } - switch(key) { - case 0x1b: - if(g_cfg_slotdrive < 0xfff) { - eject_disk_by_num(g_cfg_slotdrive >> 8, - g_cfg_slotdrive & 0xff); - } - g_cfg_slotdrive = -1; - g_cfg_select_partition = -1; - g_cfg_dirlist.invalid = 1; - break; - case 0x0a: /* down arrow */ - if(g_cfg_file_pathfield == 0) { - listhdrptr->curent++; - cfg_fix_topent(listhdrptr); - } - break; - case 0x0b: /* up arrow */ - if(g_cfg_file_pathfield == 0) { - listhdrptr->curent--; - cfg_fix_topent(listhdrptr); - } - break; - case 0x0d: /* return */ - printf("handling return press\n"); - cfg_file_selected(); - break; - case 0x09: /* tab */ - g_cfg_file_pathfield = !g_cfg_file_pathfield; - break; - case 0x08: /* left arrow */ - case 0x7f: /* delete key */ - if(g_cfg_file_pathfield) { - // printf("left arrow/delete\n"); - len = strlen(&g_cfg_file_curpath[0]) - 1; - if(len >= 0) { - g_cfg_file_curpath[len] = 0; - } - } - break; - default: - printf("key: %02x\n", key); - } -#if 0 - printf("curent: %d, topent: %d, last: %d\n", - g_cfg_dirlist.curent, g_cfg_dirlist.topent, g_cfg_dirlist.last); -#endif -} -void -config_control_panel() -{ - void (*fn_ptr)(); - const char *str; - Cfg_menu *menuptr; - void *ptr; - int print_eject_help; - int line; - int type; - int match_found; - int menu_line; - int menu_inc; - int max_line; - int key; - int i, j; - // First, save important text screen state - g_save_cur_a2_stat = g_cur_a2_stat; - for(i = 0; i < 0x400; i++) { - g_save_text_screen_bytes[i] = g_slow_memory_ptr[0x400+i]; - g_save_text_screen_bytes[0x400+i] =g_slow_memory_ptr[0x10400+i]; - } - g_cur_a2_stat = ALL_STAT_TEXT | ALL_STAT_VID80 | ALL_STAT_ANNUNC3 | - (0xf << BIT_ALL_STAT_TEXT_COLOR) | ALL_STAT_ALTCHARSET; - g_a2_new_all_stat[0] = g_cur_a2_stat; - g_new_a2_stat_cur_line = 0; - cfg_printf("In config_control_panel\n"); - for(i = 0; i < 20; i++) { - // Toss any queued-up keypresses - if(adb_read_c000() & 0x80) { - (void)adb_access_c010(); - } - } - g_adb_repeat_vbl = 0; - g_cfg_vbl_count = 0; - // HACK: Force adb keyboard (and probably mouse) to "normal"... - g_full_refresh_needed = -1; - g_a2_screen_buffer_changed = -1; - cfg_home(); - j = 0; - menuptr = g_cfg_main_menu; - if(g_rom_version < 0) { - /* Must select ROM file */ - menuptr = g_cfg_rom_menu; - } - menu_line = 1; - menu_inc = 1; - g_cfg_slotdrive = -1; - g_cfg_select_partition = -1; - while(g_config_control_panel & !(halt_sim&HALT_WANTTOQUIT)) { - if(g_fatal_log > 0) { - x_show_alert(0, 0); - } - cfg_home(); - line = 1; - max_line = 1; - match_found = 0; - print_eject_help = 0; - cfg_printf("%s\n\n", menuptr[0].str); - while(line < 24) { - str = menuptr[line].str; - type = menuptr[line].cfgtype; - ptr = menuptr[line].ptr; - if(str == 0) { - break; - } - if((type & 0xf) == CFGTYPE_DISK) { - print_eject_help = 1; - } - cfg_parse_menu(menuptr, line, menu_line, 0); - if(line == menu_line) { - if(type != 0) { - match_found = 1; - } else if(menu_inc) { - menu_line++; - } else { - menu_line--; - } - } - if(line > max_line) { - max_line = line; - } - cfg_printf("%s\n", g_cfg_opt_buf); - line++; - } - if((menu_line < 1) && !match_found) { - menu_line = 1; - } - if((menu_line >= max_line) && !match_found) { - menu_line = max_line; - } - if(g_rom_version < 0) { - cfg_htab_vtab(0, 21); - cfg_printf("\bYOU MUST SELECT A VALID ROM FILE\b\n"); - } - cfg_htab_vtab(0, 23); - cfg_printf("Move: \tJ\t \tK\t Change: \tH\t \tU\t \tM\t"); - if(print_eject_help) { - cfg_printf(" Eject: "); - if(g_cfg_slotdrive >= 0) { - cfg_printf("\bESC\b"); - } else { - cfg_printf("E"); - } - } -#if 0 - cfg_htab_vtab(0, 22); - cfg_printf("menu_line: %d line: %d, vbl:%d, adb:%d key_dn:%d\n", - menu_line, line, g_cfg_vbl_count, g_adb_repeat_vbl, - g_key_down); -#endif - if(g_cfg_slotdrive >= 0) { - cfg_file_draw(); - } -#ifdef HAVE_TFE - /*HACK eh, at least I think it is. Display the available ethernet interfaces - when in the ethernet control panel. This is the only way one can customize a menu pane. - Kent did it with the directory browser, so why not.*/ - if(menuptr == g_cfg_ethernet_menu) - { - cfg_get_tfe_name(); - } -#endif - key = -1; - while(g_config_control_panel & !(halt_sim&HALT_WANTTOQUIT)) { - video_update(); - key = adb_read_c000(); - if(key & 0x80) { - key = key & 0x7f; - (void)adb_access_c010(); - break; - } else { - key = -1; - } - micro_sleep(1.0/60.0); - g_cfg_vbl_count++; - if(!match_found) { - break; - } - } - if((key >= 0) && (g_cfg_slotdrive < 0)) { - // Normal menu system - switch(key) { - case 0x0a: /* down arrow */ - menu_line++; - menu_inc = 1; - break; - case 0x0b: /* up arrow */ - menu_line--; - menu_inc = 0; - if(menu_line < 1) { - menu_line = 1; - } - break; - case 0x15: /* right arrow */ - cfg_parse_menu(menuptr, menu_line,menu_line,1); - break; - case 0x08: /* left arrow */ - cfg_parse_menu(menuptr,menu_line,menu_line,-1); - break; - case 0x0d: - type = menuptr[menu_line].cfgtype; - ptr = menuptr[menu_line].ptr; - switch(type & 0xf) { - case CFGTYPE_MENU: - menuptr = (Cfg_menu *)ptr; - menu_line = 1; - break; - case CFGTYPE_DISK: - g_cfg_slotdrive = type >> 4; - cfg_file_init(); - break; - case CFGTYPE_FUNC: - fn_ptr = (void (*)())ptr; - (*fn_ptr)(); - break; - case CFGTYPE_FILE: - g_cfg_slotdrive = 0xfff; - g_cfg_file_def_name = *((char **)ptr); - g_cfg_file_strptr = (char **)ptr; - cfg_file_init(); - } - break; - case 0x1b: - // Jump to last menu entry - menu_line = max_line; - break; - case 'e': - case 'E': - type = menuptr[menu_line].cfgtype; - if((type & 0xf) == CFGTYPE_DISK) { - eject_disk_by_num(type >> 12, - (type >> 4) & 0xff); - } - break; - default: - printf("key: %02x\n", key); - } - } else if(key >= 0) { - cfg_file_handle_key(key); - } - } - for(i = 0; i < 0x400; i++) { - set_memory_c(0xe00400+i, g_save_text_screen_bytes[i], 0); - set_memory_c(0xe10400+i, g_save_text_screen_bytes[0x400+i], 0); - } - // And quit - g_config_control_panel = 0; - g_adb_repeat_vbl = g_vbl_count + 60; - g_cur_a2_stat = g_save_cur_a2_stat; - change_display_mode(g_cur_dcycs); - g_full_refresh_needed = -1; - g_a2_screen_buffer_changed = -1; -} + memcpy(newstr, str, len); + if(g_cfg_file_strptr) { + if(*g_cfg_file_strptr) { + free(*g_cfg_file_strptr); + } + } + *g_cfg_file_strptr = newstr; + if(g_cfg_file_strptr == &(g_cfg_rom_path)) { + printf("Updated ROM file\n"); + load_roms_init_memory(); + } + g_config_gsport_update_needed = 1; +} +void +cfg_file_selected() +{ +#ifndef __OS2__ + struct stat stat_buf; + char *str; + int fmt; + int ret; + if(g_cfg_select_partition > 0) { + cfg_partition_selected(); + return; + } + if(g_cfg_file_pathfield == 0) { + // in file section area of window + str = g_cfg_dirlist.direntptr[g_cfg_dirlist.curent].name; + if(!strcmp(str, "../")) { + /* go up one directory */ + cfg_get_base_path(&g_cfg_file_curpath[0], + &g_cfg_file_curpath[0], 1); + return; + } + snprintf(&g_cfg_file_path[0], CFG_PATH_MAX, "%s%s", + &g_cfg_file_cachedreal[0], str); + } else { + // just use cfg_file_curpath directly + strncpy(&g_cfg_file_path[0], &g_cfg_file_curpath[0], + CFG_PATH_MAX); + } + ret = cfg_stat(&g_cfg_file_path[0], &stat_buf); + fmt = stat_buf.st_mode & S_IFMT; + cfg_printf("Stat'ing %s, st_mode is: %08x\n", &g_cfg_file_path[0], + (int)stat_buf.st_mode); + if(ret != 0) { + printf("stat %s returned %d, errno: %d\n", &g_cfg_file_path[0], + ret, errno); + } else { + if(fmt == S_IFDIR) { + /* it's a directory */ + strncpy(&g_cfg_file_curpath[0], &g_cfg_file_path[0], + CFG_PATH_MAX); + } else { + /* select it */ + if(g_cfg_slotdrive < 0xfff) { + ret = cfg_maybe_insert_disk(g_cfg_slotdrive>>8, + g_cfg_slotdrive & 0xff, + &g_cfg_file_path[0]); + if(ret > 0) { + g_cfg_slotdrive = -1; + } + } else { + cfg_file_update_ptr(&g_cfg_file_path[0]); + g_cfg_slotdrive = -1; + } + } + } +#endif +} + +void +cfg_file_handle_key(int key) +{ + Cfg_listhdr *listhdrptr; + int len; + if(g_cfg_file_pathfield) { + if(key >= 0x20 && key < 0x7f) { + len = strlen(&g_cfg_file_curpath[0]); + if(len < CFG_PATH_MAX-4) { + g_cfg_file_curpath[len] = key; + g_cfg_file_curpath[len+1] = 0; + } + return; + } + } + listhdrptr = &g_cfg_dirlist; + if(g_cfg_select_partition > 0) { + listhdrptr = &g_cfg_partitionlist; + } + if( (g_cfg_file_pathfield == 0) && + ((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z')) ) { + /* jump to file starting with this letter */ + g_cfg_file_match[0] = key; + g_cfg_file_match[1] = 0; + g_cfg_dirlist.invalid = 1; /* re-read directory */ + } + switch(key) { + case 0x1b: + if(g_cfg_slotdrive < 0xfff) { + eject_disk_by_num(g_cfg_slotdrive >> 8, + g_cfg_slotdrive & 0xff); + } + g_cfg_slotdrive = -1; + g_cfg_select_partition = -1; + g_cfg_dirlist.invalid = 1; + break; + case 0x0a: /* down arrow */ + if(g_cfg_file_pathfield == 0) { + listhdrptr->curent++; + cfg_fix_topent(listhdrptr); + } + break; + case 0x0b: /* up arrow */ + if(g_cfg_file_pathfield == 0) { + listhdrptr->curent--; + cfg_fix_topent(listhdrptr); + } + break; + case 0x0d: /* return */ + printf("handling return press\n"); + cfg_file_selected(); + break; + case 0x09: /* tab */ + g_cfg_file_pathfield = !g_cfg_file_pathfield; + break; + case 0x08: /* left arrow */ + case 0x7f: /* delete key */ + if(g_cfg_file_pathfield) { + // printf("left arrow/delete\n"); + len = strlen(&g_cfg_file_curpath[0]) - 1; + if(len >= 0) { + g_cfg_file_curpath[len] = 0; + } + } + break; + default: + printf("key: %02x\n", key); + } +#if 0 + printf("curent: %d, topent: %d, last: %d\n", + g_cfg_dirlist.curent, g_cfg_dirlist.topent, g_cfg_dirlist.last); +#endif +} +void +config_control_panel() +{ + void (*fn_ptr)(); + const char *str; + Cfg_menu *menuptr; + void *ptr; + int print_eject_help; + int line; + int type; + int match_found; + int menu_line; + int menu_inc; + int max_line; + int key; + int i, j; + // First, save important text screen state + g_save_cur_a2_stat = g_cur_a2_stat; + for(i = 0; i < 0x400; i++) { + g_save_text_screen_bytes[i] = g_slow_memory_ptr[0x400+i]; + g_save_text_screen_bytes[0x400+i] =g_slow_memory_ptr[0x10400+i]; + } + g_cur_a2_stat = ALL_STAT_TEXT | ALL_STAT_VID80 | ALL_STAT_ANNUNC3 | + (0xf << BIT_ALL_STAT_TEXT_COLOR) | ALL_STAT_ALTCHARSET; + g_a2_new_all_stat[0] = g_cur_a2_stat; + g_new_a2_stat_cur_line = 0; + cfg_printf("In config_control_panel\n"); + for(i = 0; i < 20; i++) { + // Toss any queued-up keypresses + if(adb_read_c000() & 0x80) { + (void)adb_access_c010(); + } + } + g_adb_repeat_vbl = 0; + g_cfg_vbl_count = 0; + // HACK: Force adb keyboard (and probably mouse) to "normal"... + g_full_refresh_needed = -1; + g_a2_screen_buffer_changed = -1; + cfg_home(); + j = 0; + menuptr = g_cfg_main_menu; + if(g_rom_version < 0) { + /* Must select ROM file */ + menuptr = g_cfg_rom_menu; + } + menu_line = 1; + menu_inc = 1; + g_cfg_slotdrive = -1; + g_cfg_select_partition = -1; + while(g_config_control_panel & !(halt_sim&HALT_WANTTOQUIT)) { + if(g_fatal_log > 0) { + x_show_alert(0, 0); + } + cfg_home(); + line = 1; + max_line = 1; + match_found = 0; + print_eject_help = 0; + cfg_printf("%s\n\n", menuptr[0].str); + while(line < 24) { + str = menuptr[line].str; + type = menuptr[line].cfgtype; + ptr = menuptr[line].ptr; + if(str == 0) { + break; + } + if((type & 0xf) == CFGTYPE_DISK) { + print_eject_help = 1; + } + cfg_parse_menu(menuptr, line, menu_line, 0); + if(line == menu_line) { + if(type != 0) { + match_found = 1; + } else if(menu_inc) { + menu_line++; + } else { + menu_line--; + } + } + if(line > max_line) { + max_line = line; + } + cfg_printf("%s\n", g_cfg_opt_buf); + line++; + } + if((menu_line < 1) && !match_found) { + menu_line = 1; + } + if((menu_line >= max_line) && !match_found) { + menu_line = max_line; + } + if(g_rom_version < 0) { + cfg_htab_vtab(0, 21); + cfg_printf("\bYOU MUST SELECT A VALID ROM FILE\b\n"); + } + cfg_htab_vtab(0, 23); + cfg_printf("Move: \tJ\t \tK\t Change: \tH\t \tU\t \tM\t"); + if(print_eject_help) { + cfg_printf(" Eject: "); + if(g_cfg_slotdrive >= 0) { + cfg_printf("\bESC\b"); + } else { + cfg_printf("E"); + } + } +#if 0 + cfg_htab_vtab(0, 22); + cfg_printf("menu_line: %d line: %d, vbl:%d, adb:%d key_dn:%d\n", + menu_line, line, g_cfg_vbl_count, g_adb_repeat_vbl, + g_key_down); +#endif + if(g_cfg_slotdrive >= 0) { + cfg_file_draw(); + } +#ifdef HAVE_TFE + /*HACK eh, at least I think it is. Display the available ethernet interfaces + when in the ethernet control panel. This is the only way one can customize a menu pane. + Kent did it with the directory browser, so why not.*/ + if(menuptr == g_cfg_ethernet_menu) + { + cfg_get_tfe_name(); + } +#endif + key = -1; + while(g_config_control_panel & !(halt_sim&HALT_WANTTOQUIT)) { + video_update(); + key = adb_read_c000(); + if(key & 0x80) { + key = key & 0x7f; + (void)adb_access_c010(); + break; + } else { + key = -1; + } + micro_sleep(1.0/60.0); + g_cfg_vbl_count++; + if(!match_found) { + break; + } + } + if((key >= 0) && (g_cfg_slotdrive < 0)) { + // Normal menu system + switch(key) { + case 0x0a: /* down arrow */ + menu_line++; + menu_inc = 1; + break; + case 0x0b: /* up arrow */ + menu_line--; + menu_inc = 0; + if(menu_line < 1) { + menu_line = 1; + } + break; + case 0x15: /* right arrow */ + cfg_parse_menu(menuptr, menu_line,menu_line,1); + break; + case 0x08: /* left arrow */ + cfg_parse_menu(menuptr,menu_line,menu_line,-1); + break; + case 0x0d: + type = menuptr[menu_line].cfgtype; + ptr = menuptr[menu_line].ptr; + switch(type & 0xf) { + case CFGTYPE_MENU: + menuptr = (Cfg_menu *)ptr; + menu_line = 1; + break; + case CFGTYPE_DISK: + g_cfg_slotdrive = type >> 4; + cfg_file_init(); + break; + case CFGTYPE_FUNC: + fn_ptr = (void (*)())ptr; + (*fn_ptr)(); + break; + case CFGTYPE_FILE: + g_cfg_slotdrive = 0xfff; + g_cfg_file_def_name = *((char **)ptr); + g_cfg_file_strptr = (char **)ptr; + cfg_file_init(); + } + break; + case 0x1b: + // Jump to last menu entry + menu_line = max_line; + break; + case 'e': + case 'E': + type = menuptr[menu_line].cfgtype; + if((type & 0xf) == CFGTYPE_DISK) { + eject_disk_by_num(type >> 12, + (type >> 4) & 0xff); + } + break; + default: + printf("key: %02x\n", key); + } + } else if(key >= 0) { + cfg_file_handle_key(key); + } + } + for(i = 0; i < 0x400; i++) { + set_memory_c(0xe00400+i, g_save_text_screen_bytes[i], 0); + set_memory_c(0xe10400+i, g_save_text_screen_bytes[0x400+i], 0); + } + // And quit + g_config_control_panel = 0; + g_adb_repeat_vbl = g_vbl_count + 60; + g_cur_a2_stat = g_save_cur_a2_stat; + change_display_mode(g_cur_dcycs); + g_full_refresh_needed = -1; + g_a2_screen_buffer_changed = -1; +} void x_clk_setup_bram_version() { diff --git a/src/gsport.vcxproj b/src/gsport.vcxproj index 247ced7..8d98eec 100644 --- a/src/gsport.vcxproj +++ b/src/gsport.vcxproj @@ -124,6 +124,8 @@ perl make_inst s 16 instable.h > 16inst_s.h + + @@ -170,6 +172,8 @@ perl make_size c size_tab.h > size_c.h + + diff --git a/src/gsport.vcxproj.filters b/src/gsport.vcxproj.filters index 40311e0..734b40e 100644 --- a/src/gsport.vcxproj.filters +++ b/src/gsport.vcxproj.filters @@ -60,6 +60,12 @@ Header Files + + Header Files + + + Header Files + Header Files @@ -182,6 +188,12 @@ Source Files + + Source Files + + + Source Files + diff --git a/src/imagewriter.cpp b/src/imagewriter.cpp new file mode 100644 index 0000000..3f4c6d3 --- /dev/null +++ b/src/imagewriter.cpp @@ -0,0 +1,2173 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2011 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + 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 the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + 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 +*/ + +/* + * Copyright (C) 2002-2004 The DOSBox Team + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * 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. + */ + +/* + Modified for the GSport emulator by Christopher G. Mason 03/2014 + Extensively rewritten to provide full emulation of the Apple ImageWriter II + and LQ printers. + + Information used to write this emulator was provided by + Apple's "ImageWriter II Technical Reference Manual" + ISBN# 0-201-17766-8 + and + Apple's "ImageWriter LQ Reference Manual" + ISBN# 0-201-17751-X + */ + +#include "imagewriter.h" +#include +#include "support.h" + +//#include "png.h" +//#pragma comment( lib, "libpng.lib" ) +//#pragma comment (lib, "zdll.lib" ) + +static Imagewriter* defaultImagewriter = NULL; + +static FILE *textPrinterFile = NULL; +#ifdef WIN32 +const char* const textPrinterFileName = ".\\printer.txt"; +#else +const char* const textPrinterFileName = "./printer.txt"; +#endif + +#define PARAM16(I) (params[I+1]*256+params[I]) +#define PIXX ((Bitu)floor(curX*dpi+0.5)) +#define PIXY ((Bitu)floor(curY*dpi+0.5)) +//These ugly defines are so we can convert multibyte parameters from strings into some nice ints. +#define paramc(I) (params[I]-'0') +#define PARAM2(I) (paramc(I)*10+paramc(I+1)) +#define PARAM3(I) (paramc(I)*100+paramc(I+1)*10+paramc(I+2)) +#define PARAM4(I) (paramc(I)*1000+paramc(I+1)*100+paramc(I+2)*10+paramc(I+3)) + +static Bitu printer_timout; +static bool timeout_dirty; +static const char* document_path; +extern "C" char* g_imagewriter_fixed_font; +extern "C" char* g_imagewriter_prop_font; +extern "C" int iw_scc_write; +#include "iw_charmaps.h" + +#ifdef HAVE_SDL +void Imagewriter::FillPalette(Bit8u redmax, Bit8u greenmax, Bit8u bluemax, Bit8u colorID, SDL_Palette* pal) +{ + float red=redmax/30.9; + float green=greenmax/30.9; + float blue=bluemax/30.9; + + Bit8u colormask=colorID<<=5; + + for(int i = 0; i < 32;i++) { + pal->colors[i+colormask].r=255-(red*(float)i); + pal->colors[i+colormask].g=255-(green*(float)i); + pal->colors[i+colormask].b=255-(blue*(float)i); + } +} +#endif // HAVE_SDL + +Imagewriter::Imagewriter(Bit16u dpi, Bit16u width, Bit16u height, char* output, bool multipageOutput, int port) +{ +#ifdef HAVE_SDL + if (FT_Init_FreeType(&FTlib)) + { + page = NULL; + } + else + { + SDL_Init(SDL_INIT_EVERYTHING); + this->dpi = dpi; + this->output = output; + this->multipageOutput = multipageOutput; + this->port = port; + + defaultPageWidth = (Real64)width/(Real64)10; + defaultPageHeight = (Real64)height/(Real64)10; + + // Create page + page = SDL_CreateRGBSurface( + SDL_SWSURFACE, + (Bitu)(defaultPageWidth*dpi), + (Bitu)(defaultPageHeight*dpi), + 8, + 0, + 0, + 0, + 0); + + // Set a grey palette + SDL_Palette* palette = page->format->palette; + + for (Bitu i=0; i<32; i++) + { + palette->colors[i].r =255; + palette->colors[i].g =255; + palette->colors[i].b =255; + } + + // 0 = all white needed for logic 000 + FillPalette( 0, 0, 0, 1, palette); + // 1 = magenta* 001 + FillPalette( 0, 255, 0, 1, palette); + // 2 = cyan* 010 + FillPalette(255, 0, 0, 2, palette); + // 3 = "violet" 011 + FillPalette(255, 255, 0, 3, palette); + // 4 = yellow* 100 + FillPalette( 0, 0, 255, 4, palette); + // 5 = red 101 + FillPalette( 0, 255, 255, 5, palette); + // 6 = green 110 + FillPalette(255, 0, 255, 6, palette); + // 7 = black 111 + FillPalette(255, 255, 255, 7, palette); + + // 0 = all white needed for logic 000 + /*FillPalette( 0, 0, 0, 1, palette); + // 1 = yellow* 100 IW + FillPalette( 0, 0, 255, 1, palette); + // 2 = magenta* 001 IW + FillPalette( 0, 255, 0, 2, palette); + // 3 = cyan* 010 IW + FillPalette(255, 0, 0, 3, palette); + // 4 = red 101 IW + FillPalette( 0, 255, 255, 4, palette); + // 5 = green 110 IW + FillPalette(255, 0, 255, 5, palette); + // 6 = "violet" 011 IW + FillPalette(255, 255, 0, 6, palette); + // 7 = black 111 + FillPalette(255, 255, 255, 7, palette);*/ + + // yyyxxxxx bit pattern: yyy=color xxxxx = intensity: 31=max + // Printing colors on top of each other ORs them and gets the + // correct resulting color. + // i.e. magenta on blank page yyy=001 + // then yellow on magenta 001 | 100 = 101 = red + + color=COLOR_BLACK; + + curFont = NULL; + charRead = false; + autoFeed = false; + outputHandle = NULL; + + resetPrinter(); + + if (strcasecmp(output, "printer") == 0) + { +#if defined (WIN32) + // Show Print dialog to obtain a printer device context + + PRINTDLG pd; + pd.lStructSize = sizeof(PRINTDLG); + pd.hDevMode = (HANDLE) NULL; + pd.hDevNames = (HANDLE) NULL; + pd.Flags = PD_RETURNDC; + pd.hwndOwner = NULL; + pd.hDC = (HDC) NULL; + pd.nFromPage = 1; + pd.nToPage = 1; + pd.nMinPage = 0; + pd.nMaxPage = 0; + pd.nCopies = 1; + pd.hInstance = NULL; + pd.lCustData = 0L; + pd.lpfnPrintHook = (LPPRINTHOOKPROC) NULL; + pd.lpfnSetupHook = (LPSETUPHOOKPROC) NULL; + pd.lpPrintTemplateName = (LPCSTR) NULL; + pd.lpSetupTemplateName = (LPCSTR) NULL; + pd.hPrintTemplate = (HANDLE) NULL; + pd.hSetupTemplate = (HANDLE) NULL; + PrintDlg(&pd); + // TODO: what if user presses cancel? + printerDC = pd.hDC; +#endif // WIN32 + } + } +#endif // HAVE_SDL +#ifndef HAVE_SDL + this->output = output; + this->multipageOutput = multipageOutput; +#endif // !HAVE_SDL +}; + +void Imagewriter::resetPrinterHard() +{ +#ifdef HAVE_SDL + charRead = false; + resetPrinter(); +#endif // HAVE_SDL +} + +void Imagewriter::resetPrinter() +{ +#ifdef HAVE_SDL + printRes = 0; + color=COLOR_BLACK; + curX = curY = 0.0; + ESCSeen = false; + FSSeen = false; + ESCCmd = 0; + numParam = neededParam = 0; + topMargin = 0.0; + leftMargin = 0.0; + rightMargin = pageWidth = defaultPageWidth; + bottomMargin = pageHeight = defaultPageHeight; + lineSpacing = (Real64)1/6; + cpi = 12.0; + printRes = 2; + style &= (0xffff - STYLE_PROP); + definedUnit = 96; + curCharTable = 1; + style = 0; + extraIntraSpace = 0.0; + printUpperContr = true; + bitGraph.remBytes = 0; + densk = 0; + densl = 1; + densy = 2; + densz = 3; + charTables[0] = 0; // Italics + charTables[1] = charTables[2] = charTables[3] = 437; + multipoint = false; + multiPointSize = 0.0; + multicpi = 0.0; + hmi = -1.0; + switcha = 0; + switchb = ' '; + numPrintAsChar = 0; + LQtypeFace = fixed; + verticalDot = 0; + selectCodepage(charTables[curCharTable]); + + updateFont(); + updateSwitch(); + +#endif // HAVE_SDL + newPage(false,true); +#ifdef HAVE_SDL + + // Default tabs => Each eight characters + /*for (Bitu i=0;i<32;i++) + horiztabs[i] = i*8*(1/(Real64)cpi);*/ + numHorizTabs = 0; + + numVertTabs = 0; +#endif // HAVE_SDL +} + + +Imagewriter::~Imagewriter(void) +{ +#ifdef HAVE_SDL + finishMultipage(); + if (page != NULL) + { + SDL_FreeSurface(page); + page = NULL; + FT_Done_FreeType(FTlib); + } +#if defined (WIN32) + DeleteDC(printerDC); +#endif +#endif // HAVE_SDL +}; + +#ifdef HAVE_SDL +void Imagewriter::selectCodepage(Bit16u cp) +{ + Bit16u *mapToUse = NULL; + + switch(cp) + { + case 0: // Italics, use cp437 + case 437: + mapToUse = (Bit16u*)&cp437Map; + break; + default: + //LOG(LOG_MISC,LOG_WARN)("Unsupported codepage %i. Using CP437 instead.", cp); + mapToUse = (Bit16u*)&cp437Map; + } + + for (int i=0; i<256; i++) + curMap[i] = mapToUse[i]; +} +#endif // HAVE_SDL + +#ifdef HAVE_SDL +void Imagewriter::updateFont() +{ + // char buffer[1000]; + if (curFont != NULL) + FT_Done_Face(curFont); + + char* fontName; + + switch (LQtypeFace) + { + case fixed: + fontName = g_imagewriter_fixed_font; + break; + case prop: + fontName = g_imagewriter_prop_font; + break; + default: + fontName = g_imagewriter_fixed_font; + } + + if (FT_New_Face(FTlib, fontName, 0, &curFont)) + { + + printf("Unable to load font %s\n"); + //LOG_MSG("Unable to load font %s", fontName); + curFont = NULL; + } + + Real64 horizPoints = 10; + Real64 vertPoints = 10; + if (!multipoint) + { + actcpi = cpi; + + if (!(style & STYLE_CONDENSED)) { + horizPoints *= 10.0/cpi; + //vertPoints *= 10.0/cpi; + } + + if (!(style & STYLE_PROP)) { + if ((cpi == 10.0) && (style & STYLE_CONDENSED)) { + actcpi = 17.14; + horizPoints *= 10.0/17.14; + } + if ((cpi == 12.0) && (style & STYLE_CONDENSED)) { + actcpi = 20.0; + horizPoints *= 10.0/20.0; + vertPoints *= 10.0/12.0; + } + } else if (style & STYLE_CONDENSED) horizPoints /= 2.0; + + + if ((style & STYLE_DOUBLEWIDTH)) { + actcpi /= 2.0; + horizPoints *= 2.0; + } + } else { // multipoint true + actcpi = multicpi; + horizPoints = vertPoints = multiPointSize; + } + + if (style & STYLE_SUPERSCRIPT || style & STYLE_SUBSCRIPT || style & STYLE_HALFHEIGHT) { + //horizPoints *= 2.0/3.0; + vertPoints *= 2.0/3.0; + //actcpi /= 2.0/3.0; + } + + FT_Set_Char_Size(curFont, (Bit16u)horizPoints*64, (Bit16u)vertPoints*64, dpi, dpi); + + if (style & STYLE_ITALICS || charTables[curCharTable] == 0) + { + FT_Matrix matrix; + matrix.xx = 0x10000L; + matrix.xy = (FT_Fixed)(0.20 * 0x10000L); + matrix.yx = 0; + matrix.yy = 0x10000L; + FT_Set_Transform(curFont, &matrix, 0); + } +} +#endif // HAVE_SDL + +void Imagewriter::updateSwitch() +{ + //Set international character mappping (Switches A-1 to A3) + int charmap = switcha &= 7; + curMap[0x23] = intCharSets[charmap][0]; + curMap[0x40] = intCharSets[charmap][1]; + curMap[0x5b] = intCharSets[charmap][2]; + curMap[0x5c] = intCharSets[charmap][3]; + curMap[0x5d] = intCharSets[charmap][4]; + curMap[0x60] = intCharSets[charmap][5]; + curMap[0x7b] = intCharSets[charmap][6]; + curMap[0x7c] = intCharSets[charmap][7]; + curMap[0x7d] = intCharSets[charmap][8]; + curMap[0x7e] = intCharSets[charmap][9]; + //MSB control (Switch B-6) + if (!(switchb&32)) + { + msb = 255; + } + else msb = 0; +} +void Imagewriter::slashzero(Bit16u penX, Bit16u penY) +{ + FT_Face slashFont = curFont; + FT_UInt slashindex = FT_Get_Char_Index(slashFont, curMap[0x2f]); + FT_Load_Glyph(slashFont, slashindex, FT_LOAD_DEFAULT); + FT_Render_Glyph(slashFont->glyph, FT_RENDER_MODE_NORMAL); + blitGlyph(slashFont->glyph->bitmap, penX, penY, false); + blitGlyph(slashFont->glyph->bitmap, penX+1, penY, true); + if (style & STYLE_BOLD) { + blitGlyph(slashFont->glyph->bitmap, penX+1, penY, true); + blitGlyph(slashFont->glyph->bitmap, penX+2, penY, true); + blitGlyph(slashFont->glyph->bitmap, penX+3, penY, true); + } +} +#ifdef HAVE_SDL +bool Imagewriter::processCommandChar(Bit8u ch) +{ + if (ESCSeen || FSSeen) + { + ESCCmd = ch; + if(FSSeen) ESCCmd |= 0x800; + ESCSeen = FSSeen = false; + numParam = 0; + + switch (ESCCmd) { + case 0x21: // Select bold font (ESC !) IW + case 0x22: // Cancel bold font (ESC ") IW + case 0x24: // Cancel MSB control and Mousetext (ESC $) IW + case 0x2b: // custom char width is 8 dots (ESC -) IW + case 0x2e: // custom char width is 8 dots (ESC +) IW + case 0x30: // Clear all tabs (ESC 0) IW + case 0x31: // Insert 1 intercharacter spaces (ESC 1) IW + case 0x32: // Insert 2 intercharacter spaces (ESC 2) IW + case 0x33: // Insert 3 intercharacter spaces (ESC 3) IW + case 0x34: // Insert 4 intercharacter spaces (ESC 4) IW + case 0x35: // Insert 5 intercharacter spaces (ESC 5) IW + case 0x36: // Insert 6 intercharacter spaces (ESC 6) IW + case 0x3c: // bidirectional mode (one line) (ESC <) IW + case 0x3e: // Unidirectional mode (one line) (ESC >) IW + case 0x3f: // Send ID string (ESC ?) IW + case 0x41: // Select 1/6-inch line spacing (ESC A) IW + case 0x42: // Select 1/8-inch line spacing (ESC B) IW + case 0x45: // 12 cpi, 96 dpi graphics (ESC E) IW + case 0x4d: // Same as ESC a2 (ESC M) IW + case 0x4e: // 10 cpi, 80 dpi graphics (ESC N) IW + case 0x4f: // Disable paper-out detector (ESC O) IW + case 0x50: // Proportional, 160 dpi graphics (ESC P) IW + case 0x51: // 17 cpi, 136 dpi graphics (ESC Q) IW + case 0x57: // Cancel halfheight printing (ESC W) IW + case 0x58: // Turn underline on (ESC X) IW + case 0x59: // Turn underline off (ESC Y) IW + case 0x63: // Initialize printer (ESC c) IW + case 0x65: // 13.4 cpi, 107 dpi graphics (ESC e) IW + case 0x66: // Select forward feed mode (ESC f) IW + case 0x6b: // Select optional font (ESC k) IW LQ + case 0x6d: // Same as ESC a0 (ESC m) IW + case 0x6e: // 9 cpi, 72 dpi graphics (ESC n) IW + case 0x6f: // Enable paper-out detector (ESC o) IW + case 0x70: // Proportional, 144 dpi graphics (ESC p) IW + case 0x72: // Select reverse feed mode (ESC r) IW + case 0x71: // 15 cpi, 120 dpi graphics (ESC q) IW + case 0x77: // Select halfheight printing (ESC w) IW + case 0x78: // Select superscript printing (ESC x) IW + case 0x79: // Select subscript printing (ESC y) IW + case 0x7a: // Cancel superscript/subscript printing (ESC z) IW + neededParam = 0; + break; + case 0x3d: // Internal font ID (ESC = n) IW LQ + case 0x40: // Select output bin (ESC @ n) IW LQ + case 0x4b: // Select printing color (ESC K n) IW + case 0x61: // Select font (ESC a n) IW + case 0x6c: // Insert CR before LF and FF (ESC l n) IW + case 0x73: // Set intercharacter space (ESC s n) IW + case 0x74: // Shift printing downward n/216 inch (ESC t n) IW LQ + case 0x833: // Feed n lines of blank space (US n) IW + neededParam = 1; + break; + case 0x44: // Set soft switches to closed (on)= 1 (ESC D nn) IW + case 0x54: // Distance between lines to be nn/144 inch (ESC T nn) IW + case 0x5a: // Set soft switches to open (off) = 0 (ESC Z nn) IW + neededParam = 2; + break; + case 0x4c: // Set left margin at column nnn (ESC L nnn) IW + case 0x67: // Print graphics for next nnn * 8 databytes (ESC g nnn) IW + case 0x75: // Add one tab stop at nnn (ESC u nnn) IW + neededParam = 3; + break; + case 0x28: // Set horizontal tabs (ESC ( nnn,) IW + numHorizTabs = 0; + case 0x29: // Delete horizontal tabs (ESC ) nnn,) IW + case 0x43: // Print hi-res graphics for next nnnn*3 databytes (ESC C nnnn) IW LQ + case 0x47: // Print graphics for next nnnn databytes (ESC G nnnn) IW + case 0x46: // Place printhead nnnn dots from left margin (ESC F nnnn) IW + case 0x48: // Set pagelength to nnnn/144 (ESC H nnnn) IW + case 0x53: // Print graphics for next nnnn databytes (ESC S nnnn) IW + case 0x52: // Repeat character c nnn times (ESC R nnn c) IW + case 0x68: // Place printhead nnnn hi-res dots from left margin (ESC h nnnn) IW LQ + neededParam = 4; + break; + case 0x56: //Repeat Print nnnn repetitions of dot column c (ESC V nnnn c) IW + neededParam = 5; + msb = 255; + break; + case 0x55: //Repeat Print nnnn repetitions of hi-res dot column abc (ESC U nnnn abc) IW LQ + neededParam = 7; + msb = 255; + break; + case 0x27: // Select user-defined set (ESC ') + case 0x49: // Define user-defined characters (ESC I) + //LOG(LOG_MISC,LOG_ERROR)("User-defined characters not supported!"); + return true; + default: + /*LOG_MSG("PRINTER: Unknown command %c (%02Xh) %c , unable to skip parameters.", + (ESCCmd & 0x800)?"FS":"ESC",ESCCmd, ESCCmd);*/ + + neededParam = 0; + ESCCmd = 0; + return true; + } + + if (neededParam > 0) + return true; + } + + if (numParam < neededParam) + { + params[numParam++] = ch; + + if (numParam < neededParam) + return true; + } + if (ESCCmd != 0) + { + switch (ESCCmd) + { + case 0x19: // Control paper loading/ejecting (ESC EM) + // We are not really loading paper, so most commands can be ignored + if (params[0] == 'R') + newPage(true,false); // TODO resetx? + break; + case 0x73: // Set intercharacter space (ESC s) IW + if (style & STYLE_PROP) + { + extraIntraSpace = (Real64)paramc(0); + updateFont(); + } + break; + case 0x46: // Set absolute horizontal print position (ESC F nnnn) IW + { + int x = 0; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + Real64 unitSize = definedUnit; + if (unitSize < 0) + unitSize = (Real64)72.0; + + Real64 newX = leftMargin + ((Real64)PARAM4(0)/unitSize); + if (newX <= rightMargin) + curX = newX; + } + break; + case 0x68: // Set absolute horizontal hi-res print position (ESC h nnnn) IW LQ + { + int x = 0; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + Real64 unitSize = definedUnit*2; + if (unitSize < 0) + unitSize = (Real64)72.0; + + Real64 newX = leftMargin + ((Real64)PARAM4(0)/unitSize); + if (newX <= rightMargin) + curX = newX; + } + break; + case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36:// Insert 1-6 intercharacter spaces (ESC 1 to 6) IW + { + if (style & STYLE_PROP) //This function only works in proportional mode + { + Real64 unitSize = definedUnit; + if (unitSize < 0) + unitSize = (Real64)72.0; + + Real64 newX = ((Real64)(ESCCmd-'0')/unitSize); + if (newX <= rightMargin) + curX = newX; + } + break; + } + case 0x47: case 0x53: // Print graphics (ESC G nnnn) IW + { + int x = 0; + printRes &= ~8; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + setupBitImage(printRes, PARAM4(0)); + break; + } + case 0x43: // Print hi-res graphics (ESC G nnnn) IW LQ + { + int x = 0; + printRes |= 8; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + setupBitImage(printRes, PARAM4(0)); + break; + } + case 0x67: // Print graphics (ESC g nnn) IW + { + int x = 0; + printRes &= ~8; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + setupBitImage(printRes, (PARAM3(0)*8)); + break; + } + case 0x56: //Repeat Print nnnn repetitions of dot column byte c (ESC V nnnn c)IW + { + int x = 0; + printRes &= ~8; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + x = 0; + while ( x < PARAM4(0)) + { + setupBitImage(printRes, 1); + printBitGraph(params[4]); + x++; + } + msb = 0; + break; + } + case 0x55: //Repeat Print nnnn repetitions of hi-res dot column byte abc (ESC U nnnn abc) IW LQ + { + int x = 0; + printRes |= 8; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + x = 0; + while ( x < PARAM4(0)) + { + setupBitImage(printRes, 1); + printBitGraph(params[4]); + printBitGraph(params[5]); + printBitGraph(params[6]); + x++; + } + msb = 0; + break; + } + case 0x74: // Shift printing downward n/216 inch (ESC t n) IW LQ + { + verticalDot = paramc(0); + break; + } + case 0x6e: // 9 cpi, 72/144 dpi graphics (ESC n) IW + cpi = 9.0; + style &= (0xffff - STYLE_PROP); + printRes = 0; + definedUnit = 72; + extraIntraSpace = 0.0; + LQtypeFace = fixed; + updateFont(); + break; + case 0x4e: // 10 cpi, 80/160 dpi graphics (ESC N) IW + cpi = 10.0; + printRes = 1; + style &= (0xffff - STYLE_PROP); + definedUnit = 80; + extraIntraSpace = 0.0; + LQtypeFace = fixed; + updateFont(); + break; + case 0x45: // 12 cpi, 96/192 dpi graphics (ESC E) IW + cpi = 12.0; + printRes = 2; + style &= (0xffff - STYLE_PROP); + definedUnit = 96; + extraIntraSpace = 0.0; + LQtypeFace = fixed; + updateFont(); + break; + case 0x65: // 13.4 cpi, 107/216 dpi graphics (ESC e) IW + cpi = 13.4; + printRes = 3; + style &= (0xffff - STYLE_PROP); + definedUnit = 107; + extraIntraSpace = 0.0; + LQtypeFace = fixed; + updateFont(); + break; + case 0x71: // 15 cpi, 120/240 dpi graphics (ESC q) IW + cpi = 15; + printRes = 4; + style &= (0xffff - STYLE_PROP); + definedUnit = 120; + extraIntraSpace = 0.0; + LQtypeFace = fixed; + updateFont(); + break; + case 0x51: // 17 cpi, 136/272 dpi graphics (ESC Q) IW + cpi = 17; + printRes = 5; + style &= (0xffff - STYLE_PROP); + definedUnit = 136; + extraIntraSpace = 0.0; + LQtypeFace = fixed; + updateFont(); + break; + case 0x70: // Proportional, 144/288 dpi graphics (ESC p) IW + style |= STYLE_PROP; + cpi = 10; + //printQuality = QUALITY_LQ; + printRes = 6; + definedUnit = 144; + LQtypeFace = prop; + updateFont(); + break; + case 0x50: // Proportional, 160/320 dpi graphics (ESC P) IW + style |= STYLE_PROP; + cpi = 12; + //printQuality = QUALITY_LQ; + printRes = 7; + definedUnit = 160; + LQtypeFace = prop; + updateFont(); + break; + case 0x54: // Set n/144-inch line spacing (ESC T nn) IW + lineSpacing = (Real64)PARAM2(0)/144; + break; + case 0x59: // Turn underline off (ESC Y) IW + style &= ~STYLE_UNDERLINE; + updateFont(); + break; + case 0x58: // Turn underline on (ESC X) IW + style |= STYLE_UNDERLINE; + score = SCORE_SINGLE; + updateFont(); + break; + case 0x42: // Select 1/8-inch line spacing (ESC B) IW + lineSpacing = (Real64)1/8; + break; + case 0x41: // Select 1/6-inch line spacing (ESC A) IW + lineSpacing = (Real64)1/6; + break; + case 0x3c: case 0x3e: // Unidirectional mode (one line) (ESC <) + // We don't have a print head, so just ignore this + break; + case 0x63: // Initialize printer (ESC c) IW + resetPrinter(); + break; + case 0x48: // Set page length in lines (ESC H nnnn) IW + { + int x = 0; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + pageHeight = (Real64)PARAM4(0)/144; + bottomMargin = pageHeight; + topMargin = 0.0; + break; + } + case 0x21: // Select bold font (ESC !) IW + style |= STYLE_BOLD; + updateFont(); + break; + case 0x22: // Cancel bold font (ESC ") IW + style &= ~STYLE_BOLD; + updateFont(); + break; + case 0x78: // Select superscript printing (ESC x) IW + style |= STYLE_SUPERSCRIPT; + updateFont(); + break; + case 0x79: // Select subscript printing (ESC y) IW + style |= STYLE_SUBSCRIPT; + updateFont(); + break; + case 0x7a: // Cancel superscript/subscript printing (ESC z) IW + style &= 0xFFFF - STYLE_SUPERSCRIPT - STYLE_SUBSCRIPT; + updateFont(); + break; + case 0x77: // Select halfheight printing (ESC w) IW + style |= STYLE_HALFHEIGHT; + updateFont(); + break; + case 0x57: // Cancel halfheight printing (ESC W) IW + style &= ~STYLE_HALFHEIGHT; + updateFont(); + break; + case 0x72: // Reverse paper feed (ESC r) IW + { + printf("Reverse Feed\n"); + if(lineSpacing > 0) lineSpacing *= -1; + break; + } + case 0x66: // Forward paper feed (ESC f) IW + { + if(lineSpacing < 0) lineSpacing *= -1; + break; + } + case 0x61: // Select typeface (ESC a n) IW worry about this later + break; + case 0x6d: case 0x4d: //Same as ESC a n commands + break; + case 0x4c: // Set left margin (ESC L nnn) IW + { + int x = 0; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + leftMargin = (Real64)(PARAM3(0)-1.0) / (Real64)cpi; + if (curX < leftMargin) + curX = leftMargin; + break; + } + case 0x4b: // Select printing color (ESC K) IW + + switch (paramc(0)) + { + case 0: break; + case 1: params[0] = 4; break; + case 2: params[0] = 1; break; + case 3: params[0] = 2; break; + case 4: params[0] = 5; break; + case 5: params[0] = 6; break; + case 6: params[0] = 3; break; + } + if(paramc(0)==0) color = COLOR_BLACK; + else color = params[0]<<5; + break; + case 0x3d: // Internal font ID (ESC = n) IW LQ + //Ignore for now + break; + case 0x3f: //Send ID string to computer (ESC ?) IW + //insert SCC send code here + printf("Sending ID String\n"); + iw_scc_write = true; + break; + case 0x52: // Repeat character c for nnn times (ESC R nnn c) IW + { + int x = 0; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + x = 0; + ESCCmd = 0; + while (x < PARAM3(0)) + { + printChar(params[3]); + x++; + } + break; + } + case 0x30: //Clear all tabs + numHorizTabs = 0; + break; + case 0x28: // Set horizontal tabs (ESC ( nnn,) IW + { + int x = 0; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + if (params[3] == '.' || (numHorizTabs>0 && horiztabs[numHorizTabs-1] > (Real64)PARAM3(0)*(1/(Real64)cpi))) + { + horiztabs[numHorizTabs++] = (Real64)PARAM3(0)*(1/(Real64)cpi); + //printf("Adding tab %d, and end\n",PARAM3(0)); + //printf("Number of Tabs:%d\n",numHorizTabs); + } + else if (params[3] == ',' && numHorizTabs < 32) + { + horiztabs[numHorizTabs++] = (Real64)PARAM3(0)*(1/(Real64)cpi); + numParam = 0; + neededParam = 4; + //printf("Adding tab %d, plus more\n", PARAM3(0)); + //printf("Number of Tabs:%d\n",numHorizTabs); + return true; + } + x = 0; + break; + } + case 0x29: // Delete horizontal tabs (ESC ) nnn,) IW + { + int x = 0; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + x = 0; + while (x < numHorizTabs) + { + if (horiztabs[x] == (Real64)PARAM3(0)*(1/(Real64)cpi)) + { printf("Tab Found %d\n",PARAM3(0)); + horiztabs[x] = 0; + } + x++; + } + + if (params[3] == '.') + { + printf("Deleting tab %d, and end\n",PARAM3(0)); + } + else if (params[3] == ',') + { + numParam = 0; + neededParam = 4; + //printf("Deleting tab %d, plus more\n", PARAM3(0)); + return true; + } + x = 0; + break; + } + case 0x5a: // Set switches to open (off) (ESC Z nn) IW + //printf ("switcha is: %x switchb is: %x\n",switcha,switchb); + //printf ("(Setting to 0) param 0 is: %x param 1 is: %x\n",params[0],params[1]); + switcha &= ~params[0]; + switchb &= ~params[1]; + //printf ("switcha is now: %x switchb is now: %x\n",switcha,switchb); + updateSwitch(); + break; + case 0x44: // Set switches to closed (on) (ESC D nn) IW + //printf ("switcha is: %x switchb is: %x\n",switcha,switchb); + //printf ("(Setting to 1) param 0 is: %x param 1 is: %x\n",params[0],params[1]); + switcha |= params[0]; + switchb |= params[1]; + //printf ("switcha is now: %x switchb is now: %x\n",switcha,switchb); + updateSwitch(); + break; + case 0x75: // Add one tab stop at nnn (ESC u nnn) IW + { + bool haveStop = false; + int lastEmpty; + //If the list is full, we assume there are no empty spaces to fill until the list is scanned + if (numHorizTabs == 32) lastEmpty = 33; + else lastEmpty = numHorizTabs; + int x = 0; + //convert any leading spaces in parameters to zeros + while (x < 4) + { + if (params[x] == ' ') params[x] = '0'; + x++; + } + x = 0; + //see if we have the tab stop already on the list and check for any deleted entries to reuse + while (x < numHorizTabs) + { + if (horiztabs[x] == (Real64)PARAM3(0)*(1/(Real64)cpi)) + { + //printf("We have this tab already! at list entry: %d\n", x); + haveStop = true; + } + if (horiztabs[x] == 0) lastEmpty = x; + //printf("at list entry: %d\n", x); + x++; + } + if (!haveStop && lastEmpty < 33) + { + //printf("Adding tab %d\n", PARAM3(0)); + horiztabs[lastEmpty] = (Real64)PARAM3(0)*(1/(Real64)cpi); + if (lastEmpty == numHorizTabs) numHorizTabs++; //only increase if we don't reuse an empty tab entry + //printf("Number of Tabs:%d\n",numHorizTabs); + } + } + break; + case 0x833: // Feed n lines of blank space (US n) IW + { + int x = 0; + while (x < paramc(0)) + { + curY += lineSpacing; + if (curY > bottomMargin) + newPage(true,false); + x++; + } + } + break; + default: + if (ESCCmd < 0x100); + //LOG(LOG_MISC,LOG_WARN) + //LOG_MSG("PRINTER: Skipped unsupported command ESC %c (%02X)", ESCCmd, ESCCmd); + else; + //LOG(LOG_MISC,LOG_WARN) + //LOG_MSG("PRINTER: Skipped unsupported command ESC ( %c (%02X)", ESCCmd-0x200, ESCCmd-0x200); + } + + ESCCmd = 0; + return true; + } + + switch (ch) + { + case 0x00: // NUL is ignored by the printer + return true; + case 0x07: // Beeper (BEL) + // BEEEP! + return true; + case 0x08: // Backspace (BS) + { + Real64 newX = curX - (1/(Real64)actcpi); + if (hmi > 0) + newX = curX - hmi; + if (newX >= leftMargin) + curX = newX; + } + return true; + case 0x09: // Tab horizontally (HT) + { + // Find tab right to current pos + Real64 moveTo = -1; + for (Bit8u i=0; i curX) + moveTo = horiztabs[i]; + // Nothing found => Ignore + if (moveTo > 0 && moveTo < rightMargin) + curX = moveTo; + } + return true; + case 0x0b: // Tab vertically (VT) + if (numVertTabs == 0) // All tabs cancelled => Act like CR + curX = leftMargin; + else if (numVertTabs == 255) // No tabs set since reset => Act like LF + { + curX = leftMargin; + curY += lineSpacing; + if (curY > bottomMargin) + newPage(true,false); + } + else + { + // Find tab below current pos + Real64 moveTo = -1; + for (Bit8u i=0; i curY) + moveTo = verttabs[i]; + + // Nothing found => Act like FF + if (moveTo > bottomMargin || moveTo < 0) + newPage(true,false); + else + curY = moveTo; + } + return true; + case 0x0c: // Form feed (FF) + newPage(true,true); + return true; + case 0x0d: // Carriage Return (CR) + curX = leftMargin; + if ((switcha&=128)) curY += lineSpacing; // If switch A-8 is set, send a LF after CR + if (!autoFeed) + return true; + case 0x0a: // Line feed + //curX = leftMargin; + curY += lineSpacing; + if (curY > bottomMargin) + newPage(true,false); + return true; + case 0x0e: //Select double width printing (SO) IW + style |= STYLE_DOUBLEWIDTH; + updateFont(); + return true; + case 0x0f: // Dis-select double width printing (SI) IW + style &= ~STYLE_DOUBLEWIDTH; + updateFont(); + return true; + case 0x11: // Select printer (DC1) + // Ignore + return true; + case 0x12: // Cancel condensed printing (DC2) + hmi = -1; + style &= ~STYLE_CONDENSED; + updateFont(); + return true; + case 0x13: // Deselect printer (DC3) + // Ignore + return true; + case 0x14: // Cancel double-width printing (one line) (DC4) + return true; + case 0x18: // Cancel line (CAN) + return true; + case 0x1b: // ESC + ESCSeen = true; + return true; + case 0x1f: // unit seperator (US) Feed 1 to 15 line commands + FSSeen = true; + return true; + default: + return false; + } + + return false; +} +#endif // HAVE_SDL + +//static void PRINTER_EventHandler(Bitu param); + +void Imagewriter::newPage(bool save, bool resetx) +{ + //PIC_RemoveEvents(PRINTER_EventHandler); + if(printer_timout) timeout_dirty=false; + +#ifdef HAVE_SDL + if (save) + outputPage(); + + if(resetx) curX=leftMargin; + curY = topMargin; + + SDL_Rect rect; + rect.x = 0; + rect.y = 0; + rect.w = page->w; + rect.h = page->h; + SDL_FillRect(page, &rect, SDL_MapRGB(page->format, 255, 255, 255)); + + /*for(int i = 0; i < 256; i++) + { + *((Bit8u*)page->pixels+i)=i; + }*/ +#endif // HAVE_SDL + if (strcasecmp(output, "text") == 0) { /* Text file */ + if (textPrinterFile) { + fclose(textPrinterFile); + textPrinterFile = NULL; + } + } +} + +void Imagewriter::printChar(Bit8u ch) +{ +#ifdef HAVE_SDL + + charRead = true; + if (page == NULL) return; +// Apply MSB if desired, but only if we aren't printing graphics! + if (msb != 255) { + if (!bitGraph.remBytes) ch &= 0x7F; + } +#endif // HAVE_SDL + if (strcasecmp(output, "text") == 0) { + if (!textPrinterFile) { + textPrinterFile = fopen(textPrinterFileName,"ab"); + } + fprintf(textPrinterFile,"%c",ch); + fflush(textPrinterFile); + return; + } +#ifdef HAVE_SDL + + // Are we currently printing a bit graphic? + if (bitGraph.remBytes > 0) { + printBitGraph(ch); + return; + } + // Print everything? + if (numPrintAsChar > 0) numPrintAsChar--; + else if (processCommandChar(ch)) return; + + // Do not print if no font is available + if (!curFont) return; + if(ch==0x1) ch=0x20; + + // Find the glyph for the char to render + FT_UInt index = FT_Get_Char_Index(curFont, curMap[ch]); + + // Load the glyph + FT_Load_Glyph(curFont, index, FT_LOAD_DEFAULT); + + + // Render a high-quality bitmap + FT_Render_Glyph(curFont->glyph, FT_RENDER_MODE_NORMAL); + + Bit16u penX = PIXX + curFont->glyph->bitmap_left; + Bit16u penY = PIXY - curFont->glyph->bitmap_top + curFont->size->metrics.ascender/64; + + //if (style & STYLE_SUBSCRIPT) penY += curFont->glyph->bitmap.rows / 2; + //if (style & STYLE_HALFHEIGHT) penY += curFont->glyph->bitmap.rows / 4; + if (style & STYLE_SUBSCRIPT) penY += 20; + if (style & STYLE_SUPERSCRIPT) penY -= 10; + if (style & STYLE_HALFHEIGHT) penY += 15; + + // Copy bitmap into page + SDL_LockSurface(page); + + blitGlyph(curFont->glyph->bitmap, penX, penY, false); + blitGlyph(curFont->glyph->bitmap, penX+1, penY, true); + + // Bold => Print the glyph a second time one pixel to the right + // or be a bit more bold... + if (style & STYLE_BOLD) { + blitGlyph(curFont->glyph->bitmap, penX+1, penY, true); + blitGlyph(curFont->glyph->bitmap, penX+2, penY, true); + blitGlyph(curFont->glyph->bitmap, penX+3, penY, true); + } + SDL_UnlockSurface(page); + + // For line printing + Bit16u lineStart = PIXX; + // Print a slashed zero if the softswitch B-1 is set + if(switchb&1 && ch=='0') slashzero(penX,penY); + // advance the cursor to the right + Real64 x_advance; + if (style & STYLE_PROP) + x_advance = (Real64)((Real64)(curFont->glyph->advance.x)/(Real64)(dpi*64)); + else { + x_advance = 1/(Real64)actcpi; + } + x_advance += extraIntraSpace; + curX += x_advance; + + // Draw lines if desired + if ((score != SCORE_NONE) && (style & + (STYLE_UNDERLINE))) + { + // Find out where to put the line + Bit16u lineY = PIXY; + double height = (curFont->size->metrics.height>>6); // TODO height is fixed point madness... + + if (style & STYLE_UNDERLINE) lineY = PIXY + (Bit16u)(height*0.9); + + drawLine(lineStart, PIXX, lineY, score==SCORE_SINGLEBROKEN || score==SCORE_DOUBLEBROKEN); + + // draw second line if needed + if ((score == SCORE_DOUBLE)||(score == SCORE_DOUBLEBROKEN)) + drawLine(lineStart, PIXX, lineY + 5, score==SCORE_SINGLEBROKEN || score==SCORE_DOUBLEBROKEN); + } + // If the next character would go beyond the right margin, line-wrap. + if((curX + x_advance) > rightMargin) { + curX = leftMargin; + curY += lineSpacing; + if (curY > bottomMargin) newPage(true,false); + } +#endif // HAVE_SDL +} + +#ifdef HAVE_SDL +void Imagewriter::blitGlyph(FT_Bitmap bitmap, Bit16u destx, Bit16u desty, bool add) { + for (Bitu y=0; y 0 && (destx+x < page->w) && (desty+y < page->h) ) { + Bit8u* target = (Bit8u*)page->pixels + (x+destx) + (y+desty)*page->pitch; + source>>=3; + + if (add) { + if (((*target)&0x1f )+ source > 31) *target |= (color|0x1f); + else { + *target += source; + *target |= color; + } + } + else *target = source|color; + } + } + } +} + +void Imagewriter::drawLine(Bitu fromx, Bitu tox, Bitu y, bool broken) +{ + SDL_LockSurface(page); + + Bitu breakmod = dpi / 15; + Bitu gapstart = (breakmod * 4)/5; + + // Draw anti-aliased line + for (Bitu x=fromx; x<=tox; x++) + { + // Skip parts if broken line or going over the border + if ((!broken || (x%breakmod <= gapstart)) && (x < page->w)) + { + if (y > 0 && (y-1) < page->h) + *((Bit8u*)page->pixels + x + (y-1)*page->pitch) = 240; + if (y < page->h) + *((Bit8u*)page->pixels + x + y*page->pitch) = !broken?255:240; + if (y+1 < page->h) + *((Bit8u*)page->pixels + x + (y+1)*page->pitch) = 240; + } + } + SDL_UnlockSurface(page); +} + +void Imagewriter::setAutofeed(bool feed) { + autoFeed = feed; +} + +bool Imagewriter::getAutofeed() { + return autoFeed; +} + +bool Imagewriter::isBusy() { + // We're never busy + return false; +} + +bool Imagewriter::ack() { + // Acknowledge last char read + if(charRead) { + charRead=false; + return true; + } + return false; +} + +void Imagewriter::setupBitImage(Bit8u dens, Bit16u numCols) { + switch (dens) + { + case 0: + bitGraph.horizDens = 72; + bitGraph.vertDens = 72; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 1; + break; + case 1: + bitGraph.horizDens = 80; + bitGraph.vertDens = 72; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 1; + break; + case 2: + bitGraph.horizDens = 96; + bitGraph.vertDens = 72; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 1; + break; + case 3: + bitGraph.horizDens = 107; + bitGraph.vertDens = 72; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 1; + break; + case 4: + bitGraph.horizDens = 120; + bitGraph.vertDens = 72; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 1; + break; + case 5: + bitGraph.horizDens = 136; + bitGraph.vertDens = 72; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 1; + case 6: + bitGraph.horizDens = 144; + bitGraph.vertDens = 72; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 1; + case 7: + bitGraph.horizDens = 160; + bitGraph.vertDens = 72; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 1; + break; + //Imagewriter LQ resolutions + case 8: + bitGraph.horizDens = 144; + bitGraph.vertDens = 216; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 3; + break; + case 9: + bitGraph.horizDens = 160; + bitGraph.vertDens = 216; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 3; + break; + case 10: + bitGraph.horizDens = 192; + bitGraph.vertDens = 216; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 3; + break; + case 11: + bitGraph.horizDens = 216; + bitGraph.vertDens = 216; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 3; + break; + case 12: + bitGraph.horizDens = 240; + bitGraph.vertDens = 216; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 3; + break; + case 13: + bitGraph.horizDens = 272; + bitGraph.vertDens = 216; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 3; + case 14: + bitGraph.horizDens = 288; + bitGraph.vertDens = 216; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 3; + case 15: + bitGraph.horizDens = 320; + bitGraph.vertDens = 216; + bitGraph.adjacent = true; + bitGraph.bytesColumn = 3; + break; + default: + //break; + printf("PRINTER: Unsupported bit image density"); + } + + bitGraph.remBytes = numCols * bitGraph.bytesColumn; + bitGraph.readBytesColumn = 0; +} + +void Imagewriter::printBitGraph(Bit8u ch) +{ + bitGraph.column[bitGraph.readBytesColumn++] = ch; + bitGraph.remBytes--; + + // Only print after reading a full column + if (bitGraph.readBytesColumn < bitGraph.bytesColumn) + return; + + Real64 oldY = curY; + SDL_LockSurface(page); + + // When page dpi is greater than graphics dpi, the drawn pixels get "bigger" + Bitu pixsizeX=1; + Bitu pixsizeY=1; + if(bitGraph.adjacent) { + pixsizeX = dpi/bitGraph.horizDens > 0? dpi/bitGraph.horizDens : 1; + if(dpi%bitGraph.horizDens) + { + if(PIXX%(bitGraph.horizDens*8) || (PIXX == 0)) //Primative scaling function + { + pixsizeX++; + } + } + pixsizeY = dpi/bitGraph.vertDens > 0? dpi/bitGraph.vertDens : 1; + if(bitGraph.vertDens == 216) + { + if(PIXY%(bitGraph.vertDens*8) || (PIXY == 0)) //Primative scaling function + { + pixsizeY++; + } + } + } + if ((printRes > 7) && (verticalDot != 0)) //for ESC t + { + curY += (Real64)verticalDot/(Real64)bitGraph.vertDens; + } + // TODO figure this out for 360dpi mode in windows + +// Bitu pixsizeX = dpi/bitGraph.horizDens > 0? dpi/bitGraph.horizDens : 1; +// Bitu pixsizeY = dpi/bitGraph.vertDens > 0? dpi/bitGraph.vertDens : 1; + + for (Bitu i=0; iw) && ((PIXY + yy) < page->h)) + *((Bit8u*)page->pixels + (PIXX+xx) + (PIXY+yy)*page->pitch) |= (color|0x1F); + } + } // else white pixel + curY += (Real64)1/(Real64)bitGraph.vertDens; // TODO line wrap? + } + } + SDL_UnlockSurface(page); + + curY = oldY; + bitGraph.readBytesColumn = 0; + + // Advance to the left + curX += (Real64)1/(Real64)bitGraph.horizDens; +} +#endif // HAVE_SDL + +void Imagewriter::formFeed() +{ +#ifdef HAVE_SDL + // Don't output blank pages + newPage(!isBlank(),true); + finishMultipage(); +#endif // HAVE_SDL +} + +#ifdef HAVE_SDL +static void findNextName(char* front, char* ext, char* fname) +{ + document_path = ""; + Bitu i = 1; + Bitu slen = strlen(document_path); + if(slen>(200-15)) { + fname[0]=0; + return; + } + FILE *test = NULL; + do + { + strcpy(fname, document_path); + printf(fname); +#ifdef WIN32 + const char* const pathstring = ".\\%s%d%s"; +#else + const char* const pathstring = "./%s%d%s"; +#endif + sprintf(fname+strlen(fname), pathstring, front,i++,ext); + test = fopen(fname, "rb"); + if (test != NULL) + fclose(test); + } + while (test != NULL ); +} + +void Imagewriter::outputPage() +{/* + SDL_Surface *screen; + screen = SDL_SetVideoMode(1024, 768, 16, SDL_DOUBLEBUF | SDL_RESIZABLE); +if (screen == NULL) { + printf("Unable to set video mode: %s\n", SDL_GetError()); +} +SDL_Surface *image; +SDL_LockSurface(page); +image = SDL_DisplayFormat(page); +SDL_UnlockSurface(page); +SDL_Rect src, dest; + +src.x = 0; +src.y = 0; +src.w = image->w; +src.h = image->h; + +dest.x = 100; +dest.y = 100; +dest.w = image->w; +dest.h = image->h; + +SDL_BlitSurface(image, &src, screen, &dest); +SDL_Flip(screen); + +SDL_Delay(2000); +SDL_FreeSurface(image);*/ + char fname[200]; + if (strcasecmp(output, "printer") == 0) + { +#if defined (WIN32) + + Bit16u physW = GetDeviceCaps(printerDC, PHYSICALWIDTH); + Bit16u physH = GetDeviceCaps(printerDC, PHYSICALHEIGHT); + + Real64 scaleW, scaleH; + + if (page->w > physW) + scaleW = (Real64)page->w / (Real64)physW; + else + scaleW = (Real64)physW / (Real64)page->w; + + if (page->h > physH) + scaleH = (Real64)page->h / (Real64)physH; + else + scaleH = (Real64)physH / (Real64)page->h; + + HDC memHDC = CreateCompatibleDC(printerDC); + BITMAPINFO *BitmapInfo; + HBITMAP bitmap; + + // Start new printer job? + if (outputHandle == NULL) + { + DOCINFO docinfo; + docinfo.cbSize = sizeof(docinfo); + docinfo.lpszDocName = "GSport Virtual Imagewriter"; + docinfo.lpszOutput = NULL; + docinfo.lpszDatatype = NULL; + docinfo.fwType = 0; + + StartDoc(printerDC, &docinfo); + multiPageCounter = 1; + } + SDL_LockSurface(page); + StartPage(printerDC); + DWORD TotalSize; + HGDIOBJ Prev; + void* Pixels; + BitmapInfo = (BITMAPINFO*) + malloc (sizeof (BITMAPINFO)+255*sizeof (RGBQUAD)); + memset (BitmapInfo,0,sizeof (bitmap)); + BitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + BitmapInfo->bmiHeader.biWidth = page->w; + BitmapInfo->bmiHeader.biHeight = -page->h; + BitmapInfo->bmiHeader.biPlanes = 1; + BitmapInfo->bmiHeader.biBitCount = page->format->BitsPerPixel; + BitmapInfo->bmiHeader.biCompression = BI_RGB; + BitmapInfo->bmiHeader.biSizeImage = page->h * page->pitch; + BitmapInfo->bmiHeader.biXPelsPerMeter = 0; + BitmapInfo->bmiHeader.biYPelsPerMeter = 0; + BitmapInfo->bmiHeader.biClrUsed = page->format->palette->ncolors; + BitmapInfo->bmiHeader.biClrImportant = 0; + if (page->format->palette) { + for (int I=0; Iformat->palette->ncolors; I++) { + BitmapInfo->bmiColors[I].rgbRed = + (page->format->palette->colors+I)->r; + BitmapInfo->bmiColors[I].rgbGreen = + (page->format->palette->colors+I)->g; + BitmapInfo->bmiColors[I].rgbBlue = + (page->format->palette->colors+I)->b; + } + } + memHDC = CreateCompatibleDC(printerDC); + if (memHDC) { + bitmap = CreateDIBSection(memHDC, BitmapInfo, DIB_RGB_COLORS, + (&Pixels), NULL, 0); + if (bitmap) { + memcpy (Pixels, page->pixels, + BitmapInfo->bmiHeader.biSizeImage); + Prev = SelectObject (memHDC, bitmap); + StretchBlt(printerDC, 0, 0, physW, physH, memHDC, 0, 0, page->w, page->h, SRCCOPY); + SelectObject (memHDC,Prev); + DeleteObject (bitmap); + } + } + free (BitmapInfo); + SDL_UnlockSurface(page); + EndPage(printerDC); + + if (multipageOutput) + { + multiPageCounter++; + outputHandle = printerDC; + } + else + { + EndDoc(printerDC); + outputHandle = NULL; + } + DeleteObject(bitmap); + DeleteDC(memHDC); +#else + //LOG_MSG("PRINTER: Direct printing not supported under this OS"); +#endif + } +#ifdef C_LIBPNG + else if (strcasecmp(output, "png") == 0) + { + // Find a page that does not exists + findNextName("page", ".png", &fname[0]); + + png_structp png_ptr; + png_infop info_ptr; + png_bytep * row_pointers; + png_color palette[256]; + Bitu i; + + /* Open the actual file */ + FILE * fp=fopen(fname,"wb"); + if (!fp) + { + //LOG(LOG_MISC,LOG_ERROR)("PRINTER: Can't open file %s for printer output", fname); + return; + } + + /* First try to alloacte the png structures */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL, NULL); + if (!png_ptr) return; + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_write_struct(&png_ptr,(png_infopp)NULL); + return; + } + + /* Finalize the initing of png library */ + png_init_io(png_ptr, fp); + png_set_compression_level(png_ptr,Z_BEST_COMPRESSION); + + /* set other zlib parameters */ + png_set_compression_mem_level(png_ptr, 8); + png_set_compression_strategy(png_ptr,Z_DEFAULT_STRATEGY); + png_set_compression_window_bits(png_ptr, 15); + png_set_compression_method(png_ptr, 8); + png_set_compression_buffer_size(png_ptr, 8192); + + + png_set_IHDR(png_ptr, info_ptr, page->w, page->h, + 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + for (i=0;i<256;i++) + { + palette[i].red = page->format->palette->colors[i].r; + palette[i].green = page->format->palette->colors[i].g; + palette[i].blue = page->format->palette->colors[i].b; + } + png_set_PLTE(png_ptr, info_ptr, palette,256); + png_set_packing(png_ptr); + SDL_LockSurface(page); + + // Allocate an array of scanline pointers + row_pointers = (png_bytep*)malloc(page->h*sizeof(png_bytep)); + for (i=0; ih; i++) + row_pointers[i] = ((Bit8u*)page->pixels+(i*page->pitch)); + + // tell the png library what to encode. + png_set_rows(png_ptr, info_ptr, row_pointers); + + // Write image to file + png_write_png(png_ptr, info_ptr, 0, NULL); + + + + + SDL_UnlockSurface(page); + + /*close file*/ + fclose(fp); + + /*Destroy PNG structs*/ + png_destroy_write_struct(&png_ptr, &info_ptr); + + /*clean up dynamically allocated RAM.*/ + free(row_pointers); + } +#endif + else if (strcasecmp(output, "colorps") == 0) + { + FILE* psfile = NULL; + Uint8 r, g, b; + int x, y; + int cur_line_len = 0; + int plane; + // Continue postscript file? + if (outputHandle != NULL) + psfile = (FILE*)outputHandle; + + // Create new file? + if (psfile == NULL) + { + if (!multipageOutput) + findNextName("page", ".ps", &fname[0]); + else + findNextName("doc", ".ps", &fname[0]); + + psfile = fopen(fname, "wb"); + if (!psfile) + { + printf("PRINTER: Can't open file %s for printer output", fname); + return; + } + + // Print header + fprintf(psfile, "%%!PS-Adobe-2.0 EPSF-2.0\n"); + fprintf(psfile, "%%%%Pages: (atend)\n"); + fprintf(psfile, "%%%%BoundingBox: 0 0 %i %i\n", (Bit16u)(defaultPageWidth*74), (Bit16u)(defaultPageHeight*74)); + fprintf(psfile, "%%%%Creator: GSport Virtual Printer\n"); + fprintf(psfile, "%%%%LanguageLevel: 2\n"); + fprintf(psfile, "%%%%EndComments\n"); + multiPageCounter = 1; + } + + + + fprintf(psfile, "%%%%Page: %i %i\n", multiPageCounter, multiPageCounter); + + fprintf(psfile, "<< /PageSize [ %d %d ] /ImagingBBox null >> setpagedevice\n", + (Bit16u)(defaultPageWidth*74), (Bit16u)(defaultPageHeight*74)); +/* Define a 'readstring' routine and 'picstr' routines for RGB: */ + +fprintf(psfile, "/readstring {\n"); +fprintf(psfile, " currentfile exch readhexstring pop\n"); +fprintf(psfile, "} bind def\n"); + +fprintf(psfile, "/rpicstr %d string def\n", page->w); +fprintf(psfile, "/gpicstr %d string def\n", page->w); +fprintf(psfile, "/bpicstr %d string def\n", page->w); +fprintf(psfile, "%%%%EndProlog\n"); + fprintf(psfile, "gsave\n"); + fprintf(psfile, "%i %i scale\n", (Bit16u)(defaultPageWidth*74), (Bit16u)(defaultPageHeight*74)); + + fprintf(psfile, "%d %d 8\n", page->w, page->h); + fprintf(psfile, "%i %i 8 [%i 0 0 -%i 0 %i]\n", page->w, page->h, page->w, page->h, page->h); + + fprintf(psfile, "{ rpicstr readstring }\n"); + fprintf(psfile, "{ gpicstr readstring }\n"); + fprintf(psfile, "{ bpicstr readstring }\n"); + + fprintf(psfile, "true 3\n"); + fprintf(psfile, "colorimage\n"); + + for (y = 0; y < page->h; y++) + { + for (plane = 0; plane < 3; plane++) + { + for (x = 0; x < page->w; x++) + { + SDL_GetRGB(getxyPixel(x,y), page->format, &r, &g, &b); + fprintf(psfile, "%02x", (plane == 0 ? r : (plane == 1 ? g : b))); + + cur_line_len++; + if (cur_line_len >= 30) + { + fprintf(psfile, "\n"); + cur_line_len = 0; + } + } + } + } + fprintf(psfile, "\n"); + fprintf(psfile, "grestore\n"); + + SDL_UnlockSurface(page); + + fprintf(psfile, "showpage\n"); + + if (multipageOutput) + { + multiPageCounter++; + outputHandle = psfile; + } + else + { + fprintf(psfile, "%%%%Pages: 1\n"); + fprintf(psfile, "%%%%EOF\n"); + fclose(psfile); + outputHandle = NULL; + } + } + else if (strcasecmp(output, "ps") == 0) + { + FILE* psfile = NULL; + printf("%d\n",getPixel(2)); + + // Continue postscript file? + if (outputHandle != NULL) + psfile = (FILE*)outputHandle; + + // Create new file? + if (psfile == NULL) + { + if (!multipageOutput) + findNextName("page", ".ps", &fname[0]); + else + findNextName("doc", ".ps", &fname[0]); + + psfile = fopen(fname, "wb"); + if (!psfile) + { + //LOG(LOG_MISC,LOG_ERROR)("PRINTER: Can't open file %s for printer output", fname); + return; + } + + // Print header + fprintf(psfile, "%%!PS-Adobe-3.0\n"); + fprintf(psfile, "%%%%Pages: (atend)\n"); + fprintf(psfile, "%%%%BoundingBox: 0 0 %i %i\n", (Bit16u)(defaultPageWidth*74), (Bit16u)(defaultPageHeight*74)); + fprintf(psfile, "%%%%Creator: GSport Virtual Printer\n"); + fprintf(psfile, "%%%%DocumentData: Clean7Bit\n"); + fprintf(psfile, "%%%%LanguageLevel: 2\n"); + fprintf(psfile, "%%%%EndComments\n"); + multiPageCounter = 1; + } + + fprintf(psfile, "%%%%Page: %i %i\n", multiPageCounter, multiPageCounter); + fprintf(psfile, "%i %i scale\n", (Bit16u)(defaultPageWidth*74), (Bit16u)(defaultPageHeight*74)); + fprintf(psfile, "%i %i 8 [%i 0 0 -%i 0 %i]\n", page->w, page->h, page->w, page->h, page->h); + fprintf(psfile, "currentfile\n"); + fprintf(psfile, "/ASCII85Decode filter\n"); + fprintf(psfile, "/RunLengthDecode filter\n"); + fprintf(psfile, "image\n"); + + SDL_LockSurface(page); + + Bit32u pix = 0; + Bit32u numpix = page->h*page->w; + ASCII85BufferPos = ASCII85CurCol = 0; + + while (pix < numpix) + { + // Compress data using RLE + + if ((pix < numpix-2) && (getPixel(pix) == getPixel(pix+1)) && (getPixel(pix) == getPixel(pix+2))) + { + // Found three or more pixels with the same color + Bit8u sameCount = 3; + Bit8u col = getPixel(pix); + while (sameCount < 128 && sameCount+pix < numpix && col == getPixel(pix+sameCount)) + sameCount++; + + fprintASCII85(psfile, 257-sameCount); + fprintASCII85(psfile, 255-col); + + // Skip ahead + pix += sameCount; + } + else + { + // Find end of heterogenous area + Bit8u diffCount = 1; + while (diffCount < 128 && diffCount+pix < numpix && + ( + (diffCount+pix < numpix-2) + || (getPixel(pix+diffCount) != getPixel(pix+diffCount+1)) + || (getPixel(pix+diffCount) != getPixel(pix+diffCount+2)) + )) + diffCount++; + + fprintASCII85(psfile, diffCount-1); + for (Bit8u i=0; i= 79) + { + ASCII85CurCol = 0; + fprintf(f, "\n"); + } + } + else + { + char buffer[5]; + for (Bit8s i=4; i>=0; i--) + { + buffer[i] = (Bit8u)((Bit32u)num % (Bit32u)85); + buffer[i] += 33; + num /= (Bit32u)85; + } + + // Make sure a line never starts with a % (which may be mistaken as start of a comment) + if (ASCII85CurCol == 0 && buffer[0] == '%') + fprintf(f, " "); + + for (int i=0; i<((b != 257)?5:ASCII85BufferPos+1); i++) + { + fprintf(f, "%c", buffer[i]); + if (++ASCII85CurCol >= 79) + { + ASCII85CurCol = 0; + fprintf(f, "\n"); + } + } + } + + ASCII85BufferPos = 0; + } + + } + else // Close string + { + // Partial tupel if there are still bytes in the buffer + if (ASCII85BufferPos > 0) + { + for (Bit8u i = ASCII85BufferPos; i < 4; i++) + ASCII85Buffer[i] = 0; + + fprintASCII85(f, 257); + } + + fprintf(f, "~"); + fprintf(f, ">\n"); + } +} + +void Imagewriter::finishMultipage() +{ + if (outputHandle != NULL) + { + if (strcasecmp(output, "ps") == 0) + { + FILE* psfile = (FILE*)outputHandle; + fprintf(psfile, "%%%%Pages: %i\n", multiPageCounter); + fprintf(psfile, "%%%%EOF\n"); + fclose(psfile); + } + if (strcasecmp(output, "colorps") == 0) + { + FILE* psfile = (FILE*)outputHandle; + fprintf(psfile, "%%%%Pages: %i\n", multiPageCounter); + fprintf(psfile, "%%%%EOF\n"); + fclose(psfile); + } + else if (strcasecmp(output, "printer") == 0) + { +#if defined (WIN32) + EndDoc(printerDC); +#endif + } + outputHandle = NULL; + } +} + +bool Imagewriter::isBlank() { + bool blank = true; + SDL_LockSurface(page); + + for (Bit16u y=0; yh; y++) + for (Bit16u x=0; xw; x++) + if (*((Bit8u*)page->pixels + x + (y*page->pitch)) != 0) + blank = false; + + SDL_UnlockSurface(page); + return blank; +} + +Bit8u Imagewriter::getxyPixel(Bit32u x,Bit32u y) { + Bit8u *p; + + /* get the X/Y values within the bounds of this surface */ + if ((unsigned) x > (unsigned) page->w - 1u) + x = (x < 0) ? 0 : page->w - 1; + if ((unsigned) y > (unsigned) page->h - 1u) + y = (y < 0) ? 0 : page->h - 1; + + /* Set a pointer to the exact location in memory of the pixel + in question: */ + + p = (Bit8u *) (((Bit8u *) page->pixels) + /* Start at top of RAM */ + (y * page->pitch) + /* Go down Y lines */ + x); /* Go in X pixels */ + + + /* Return the correctly-sized piece of data containing the + * pixel's value (an 8-bit palette value, or a 16-, 24- or 32-bit + * RGB value) */ + + return (*p); +} +Bit8u Imagewriter::getPixel(Bit32u num) { + Bit32u pixel = *((Bit8u*)page->pixels + (num % page->w) + ((num / page->w) * page->pitch)); + return *((Bit8u*)page->pixels + (num % page->w) + ((num / page->w) * page->pitch)); +} +#endif // HAVE_SDL + +//Interfaces to C code + + +extern "C" void imagewriter_init(int pdpi, int pwidth, int pheight, char* poutput, bool mpage, int port) +{ + if (defaultImagewriter != NULL) return; //if Imagewriter on this port is initialized, reuse it + defaultImagewriter = new Imagewriter(pdpi, pwidth,pheight, poutput, mpage, port); +} +extern "C" void imagewriter_loop(Bit8u pchar, int port) +{ + if (defaultImagewriter == NULL) return; + defaultImagewriter->printChar(pchar); +} + +extern "C" void imagewriter_close(int port) +{ + delete defaultImagewriter; + defaultImagewriter = NULL; +} +extern "C" void imagewriter_feed(int port) +{ + if(defaultImagewriter == NULL) return; + defaultImagewriter->formFeed(); +} diff --git a/src/imagewriter.h b/src/imagewriter.h new file mode 100644 index 0000000..3dc1338 --- /dev/null +++ b/src/imagewriter.h @@ -0,0 +1,312 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2011 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + 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 the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + 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 +*/ + +/* + * Copyright (C) 2002-2004 The DOSBox Team + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * 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. + */ + +/* + Modified for the GSport emulator by Christopher G. Mason 02/2014 + Extensively rewritten to provide full emulation of the Apple ImageWriter II + printer. + + Information used to write this emulator was provided by + Apple's "ImageWriter II Technical Reference Manual" + ISBN# 0-201-17766-8 + + Apple's "ImageWriter LQ Reference Manual" + ISBN# 0-201-17751-X + */ + +#if !defined __IMAGEWRITER_H +#define __IMAGEWRITER_H +#ifdef __cplusplus +#ifdef C_LIBPNG +#include +#endif + +#include + +#ifdef HAVE_SDL +#include "SDL.h" + +#include +#include FT_FREETYPE_H +#endif // HAVE_SDL + +#if defined (WIN32) +#include +#include +#endif + +#define STYLE_PROP 0x01 +#define STYLE_CONDENSED 0x02 +#define STYLE_BOLD 0x04 +#define STYLE_DOUBLESTRIKE 0x08 +#define STYLE_DOUBLEWIDTH 0x10 +#define STYLE_ITALICS 0x20 +#define STYLE_UNDERLINE 0x40 +#define STYLE_SUPERSCRIPT 0x80 +#define STYLE_SUBSCRIPT 0x100 +#define STYLE_HALFHEIGHT 0x200 + +#define SCORE_NONE 0x00 +#define SCORE_SINGLE 0x01 +#define SCORE_DOUBLE 0x02 +#define SCORE_SINGLEBROKEN 0x05 +#define SCORE_DOUBLEBROKEN 0x06 + +#define QUALITY_DRAFT 0x01 +#define QUALITY_LQ 0x02 + +#define COLOR_BLACK 7<<5 +typedef unsigned Bitu; +typedef signed Bits; +typedef unsigned char Bit8u; +typedef signed char Bit8s; +typedef unsigned short Bit16u; +typedef signed short Bit16s; +typedef unsigned long Bit32u; +typedef signed long Bit32s; +typedef double Real64; +#if defined(_MSC_VER) +typedef unsigned __int64 Bit64u; +typedef signed __int64 Bit64s; +#else +typedef unsigned long long int Bit64u; +typedef signed long long int Bit64s; +#endif +enum Typeface +{ + fixed = 0, + prop = 1 +}; + +typedef struct { + Bitu codepage; + const Bit16u* map; +} IWCHARMAP; + + +class Imagewriter { +public: + + Imagewriter (Bit16u dpi, Bit16u width, Bit16u height, char* output, bool multipageOutput, int port); + virtual ~Imagewriter(); + + // Process one character sent to virtual printer + void printChar(Bit8u ch); + + // Hard Reset (like switching printer off and on) + void resetPrinterHard(); + + // Set Autofeed value + void setAutofeed(bool feed); + + // Get Autofeed value + bool getAutofeed(); + + // True if printer is unable to process more data right now (do not use printChar) + bool isBusy(); + + // True if the last sent character was received + bool ack(); + + // Manual formfeed + void formFeed(); + +#ifdef HAVE_SDL + // Returns true if the current page is blank + bool isBlank(); +#endif // HAVE_SDL + +private: + + // Resets the printer to the factory settings + void resetPrinter(); + + // Clears page. If save is true, saves the current page to a bitmap + void newPage(bool save, bool resetx); + + // Closes a multipage document + void finishMultipage(); + + // Output current page + void outputPage(); + +#ifdef HAVE_SDL + // used to fill the color "sub-pallettes" + void FillPalette(Bit8u redmax, Bit8u greenmax, Bit8u bluemax, Bit8u colorID, + SDL_Palette* pal); + + // Checks if given char belongs to a command and process it. If false, the character + // should be printed + bool processCommandChar(Bit8u ch); + + // Reload font. Must be called after changing dpi, style or cpi + void updateFont(); + + // Reconfigures printer parameters after changing soft-switches with ESC Z and ESC D + void updateSwitch(); + + // Overprints a slash over zero if softswitch B-1 is set + void slashzero(Bit16u penX, Bit16u penY); + + // Blits the given glyph on the page surface. If add is true, the values of bitmap are + // added to the values of the pixels in the page + void blitGlyph(FT_Bitmap bitmap, Bit16u destx, Bit16u desty, bool add); + + // Draws an anti-aliased line from (fromx, y) to (tox, y). If broken is true, gaps are included + void drawLine(Bitu fromx, Bitu tox, Bitu y, bool broken); + + // Setup the bitGraph structure + void setupBitImage(Bit8u dens, Bit16u numCols); + + // Process a character that is part of bit image. Must be called iff bitGraph.remBytes > 0. + void printBitGraph(Bit8u ch); + + // Copies the codepage mapping from the constant array to CurMap + void selectCodepage(Bit16u cp); + + // Prints out a byte using ASCII85 encoding (only outputs something every four bytes). When b>255, closes the ASCII85 string + void fprintASCII85(FILE* f, Bit16u b); + + // Returns value of the num-th pixel (couting left-right, top-down) in a safe way + Bit8u getPixel(Bit32u num); + Bit8u getxyPixel(Bit32u x,Bit32u y); + + FT_Library FTlib; // FreeType2 library used to render the characters + + SDL_Surface* page; // Surface representing the current page + FT_Face curFont; // The font currently used to render characters + Bit8u color; + Bit8u switcha; //Imagewriter softswitch A + Bit8u switchb; //Imagewriter softswitch B + + Real64 curX, curY; // Position of the print head (in inch) + + Bit16u dpi; // dpi of the page + Bit16u ESCCmd; // ESC-command that is currently processed + bool ESCSeen; // True if last read character was an ESC (0x1B) + bool FSSeen; // True if last read character was an FS (0x1C) (IBM commands) + Bit8u numParam, neededParam; // Numbers of parameters already read/needed to process command + + Bit8u params[20]; // Buffer for the read params + Bit16u style; // Style of font (see STYLE_* constants) + Real64 cpi, actcpi; // CPI value set by program and the actual one (taking in account font types) + Bit8u score; // Score for lines (see SCORE_* constants) + Bit8u verticalDot; // Vertical dot shift for Imagewriter LQ modes + + Real64 topMargin, bottomMargin, rightMargin, leftMargin; // Margins of the page (in inch) + Real64 pageWidth, pageHeight; // Size of page (in inch) + Real64 defaultPageWidth, defaultPageHeight; // Default size of page (in inch) + Real64 lineSpacing; // Size of one line (in inch) + + Real64 horiztabs[32]; // Stores the set horizontal tabs (in inch) + Bit8u numHorizTabs; // Number of configured tabs + + Real64 verttabs[16]; // Stores the set vertical tabs (in inch) + Bit8u numVertTabs; // Number of configured tabs + + Bit8u curCharTable; // Currently used char table und charset + Bit8u printQuality; // Print quality (see QUALITY_* constants) + Bit8u printRes; // Graphics resolution + Typeface LQtypeFace; // Typeface used in LQ printing mode + + Real64 extraIntraSpace; // Extra space between two characters (set by program, in inch) + + bool charRead; // True if a character was read since the printer was last initialized + bool autoFeed; // True if a LF should automatically added after a CR + bool printUpperContr; // True if the upper command characters should be printed + + struct bitGraphicParams // Holds information about printing bit images + { + Bit16u horizDens, vertDens; // Density of image to print (in dpi) + bool adjacent; // Print adjacent pixels? (ignored) + Bit8u bytesColumn; // Bytes per column + Bit16u remBytes; // Bytes left to read before image is done + Bit8u column[6]; // Bytes of the current and last column + Bit8u readBytesColumn; // Bytes read so far for the current column + } bitGraph; + + Bit8u densk, densl, densy, densz; // Image density modes used in ESC K/L/Y/Z commands + + Bit16u curMap[256]; // Currently used ASCII => Unicode mapping + Bit16u charTables[4]; // Charactertables + + Real64 definedUnit; // Unit used by some ESC/P2 commands (negative => use default) + + bool multipoint; // If multipoint mode is enabled + Real64 multiPointSize; // Point size of font in multipoint mode + Real64 multicpi; // CPI used in multipoint mode + + Real64 hmi; // Horizontal motion index (in inch; overrides CPI settings) + + Bit16u numPrintAsChar; // Number of bytes to print as characters (even when normally control codes) + +#if defined (WIN32) + HDC printerDC; // Win32 printer device +#endif + int port; // SCC Port + +#endif // HAVE_SDL + Bit8u msb; // MSB mode + + char* output; // Output method selected by user + void* outputHandle; // If not null, additional pages will be appended to the given handle + bool multipageOutput; // If true, all pages are combined to one file/print job etc. until the "eject page" button is pressed + Bit16u multiPageCounter; // Current page (when printing multipages) + + Bit8u ASCII85Buffer[4]; // Buffer used in ASCII85 encoding + Bit8u ASCII85BufferPos; // Position in ASCII85 encode buffer + Bit8u ASCII85CurCol; // Columns printed so far in the current lines +}; + + +//Interfaces to C code +#ifdef __cplusplus +extern "C" +{ +#endif +void imagewriter_init(int pdpi, int pwidth, int pheight, char* poutput, bool mpage, int port); +void imagewriter_loop(Bit8u pchar,int port); +void imagewriter_close(int port); +void imagewriter_feed(int port); +#ifdef __cplusplus +} +#endif + +#endif +#endif diff --git a/src/iw_charmaps.h b/src/iw_charmaps.h new file mode 100644 index 0000000..c7a2f8d --- /dev/null +++ b/src/iw_charmaps.h @@ -0,0 +1,60 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + 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 the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + 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 +*/ + +// Various ASCII codepage to unicode maps + +static const Bit16u cp437Map[256] = { +0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, +0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, +0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, +0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, +0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, +0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, +0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, +0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, +0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5, +0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,0x00ff,0x00d6,0x00dc,0x00a2,0x00a3,0x00a5,0x20a7,0x0192, +0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, +0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, +0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, +0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, +0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, +0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 +}; + +IWCHARMAP iwcharmap[] = { + {437, cp437Map}, + {0, NULL}, +}; + +static const Bit16u codepages[15] = {0, 437}; + +static const Bit16u intCharSets[8][10] = +{ + {0x0023, 0x0040, 0x005b, 0x005c, 0x005d, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e}, // USA + {0x00a3, 0x00a7, 0x00b0, 0x00e7, 0x00e9, 0x00f9, 0x00e0, 0x00f2, 0x00e8, 0x00ec}, // Italian + {0x0023, 0x0040, 0x00c6, 0x00d8, 0x00c5, 0x0060, 0x00e6, 0x00f8, 0x00e5, 0x007e}, // Danish + {0x00a3, 0x0040, 0x005b, 0x005c, 0x005d, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e}, // UK + {0x0023, 0x00a7, 0x00c4, 0x00d6, 0x00dc, 0x0060, 0x00e4, 0x00f6, 0x00fc, 0x00df}, // Germany + {0x0023, 0x0040, 0x00c4, 0x00d6, 0x00c5, 0x0060, 0x00e4, 0x00f6, 0x00e5, 0x007e}, // Swedish + {0x00a3, 0x00e0, 0x00b0, 0x00e7, 0x00a7, 0x0060, 0x00e9, 0x00f9, 0x00e8, 0x00a8}, // France + {0x00a3, 0x00a7, 0x00a1, 0x00d1, 0x00bf, 0x0060, 0x00b0, 0x00f1, 0x00e7, 0x007e}, // Spanish +}; diff --git a/src/protos.h b/src/protos.h index 3f90007..6e34724 100644 --- a/src/protos.h +++ b/src/protos.h @@ -288,6 +288,11 @@ void scc_socket_modem_connect(int port, double dcycs); void scc_socket_modem_do_ring(int port, double dcycs); void scc_socket_do_answer(int port, double dcycs); +/* scc_imagewriter.c*/ +int scc_imagewriter_init(int port); +void scc_imagewriter_fill_readbuf(int port, int space_left, double dcycs); +void scc_imagewriter_empty_writebuf(int port, double dcycs); +void imagewriter_update(); /* scc_windriver.c */ diff --git a/src/scc.c b/src/scc.c index 0610225..753b411 100644 --- a/src/scc.c +++ b/src/scc.c @@ -1,1282 +1,1309 @@ -/* - GSport - an Apple //gs Emulator - Copyright (C) 2010 by GSport contributors - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - 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 the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - 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 "defc.h" - -#ifdef UNDER_CE -#define vsnprintf _vsnprintf -#endif - -extern int Verbose; -extern int g_code_yellow; -extern double g_cur_dcycs; -extern int g_serial_type[]; -extern int g_serial_out_masking; -extern int g_irq_pending; - -/* my scc port 0 == channel A = slot 1 = c039/c03b */ -/* port 1 == channel B = slot 2 = c038/c03a */ - -#include "scc.h" -#define SCC_R14_DPLL_SOURCE_BRG 0x100 -#define SCC_R14_FM_MODE 0x200 - -#define SCC_DCYCS_PER_PCLK ((DCYCS_1_MHZ) / ((DCYCS_28_MHZ) /8)) -#define SCC_DCYCS_PER_XTAL ((DCYCS_1_MHZ) / 3686400.0) - -#define SCC_BR_EVENT 1 -#define SCC_TX_EVENT 2 -#define SCC_RX_EVENT 3 -#define SCC_MAKE_EVENT(port, a) (((a) << 1) + (port)) - -Scc scc_stat[2]; - -int g_baud_table[] = { - 110, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200 -}; - -int g_scc_overflow = 0; - -void -scc_init() -{ - Scc *scc_ptr; - int i, j; - - for(i = 0; i < 2; i++) { - scc_ptr = &(scc_stat[i]); - scc_ptr->accfd = -1; - scc_ptr->sockfd = -1; - scc_ptr->socket_state = -1; - scc_ptr->rdwrfd = -1; - scc_ptr->state = 0; - scc_ptr->host_handle = 0; - scc_ptr->host_handle2 = 0; - scc_ptr->br_event_pending = 0; - scc_ptr->rx_event_pending = 0; - scc_ptr->tx_event_pending = 0; - scc_ptr->char_size = 8; - scc_ptr->baud_rate = 9600; - scc_ptr->telnet_mode = 0; - scc_ptr->telnet_iac = 0; - scc_ptr->out_char_dcycs = 0.0; - scc_ptr->socket_num_rings = 0; - scc_ptr->socket_last_ring_dcycs = 0; - scc_ptr->modem_mode = 0; - scc_ptr->modem_dial_or_acc_mode = 0; - scc_ptr->modem_plus_mode = 0; - scc_ptr->modem_s0_val = 0; - scc_ptr->modem_cmd_len = 0; - scc_ptr->modem_cmd_str[0] = 0; - for(j = 0; j < 2; j++) { - scc_ptr->telnet_local_mode[j] = 0; - scc_ptr->telnet_remote_mode[j] = 0; - scc_ptr->telnet_reqwill_mode[j] = 0; - scc_ptr->telnet_reqdo_mode[j] = 0; - } - } - - scc_reset(); - // Initialize ports right away - enable incoming data before PR#x - scc_port_init(0); - scc_port_init(1); -} - -void -scc_reset() -{ - Scc *scc_ptr; - int i; - - for(i = 0; i < 2; i++) { - scc_ptr = &(scc_stat[i]); - - scc_ptr->port = i; - scc_ptr->mode = 0; - scc_ptr->reg_ptr = 0; - scc_ptr->in_rdptr = 0; - scc_ptr->in_wrptr = 0; - scc_ptr->out_rdptr = 0; - scc_ptr->out_wrptr = 0; - scc_ptr->dcd = 0; - scc_ptr->wantint_rx = 0; - scc_ptr->wantint_tx = 0; - scc_ptr->wantint_zerocnt = 0; - scc_ptr->read_called_this_vbl = 0; - scc_ptr->write_called_this_vbl = 0; - scc_evaluate_ints(i); - scc_hard_reset_port(i); - } -} - -void -scc_hard_reset_port(int port) -{ - Scc *scc_ptr; - - scc_reset_port(port); - - scc_ptr = &(scc_stat[port]); - scc_ptr->reg[14] = 0; /* zero bottom two bits */ - scc_ptr->reg[13] = 0; - scc_ptr->reg[12] = 0; - scc_ptr->reg[11] = 0x08; - scc_ptr->reg[10] = 0; - scc_ptr->reg[7] = 0; - scc_ptr->reg[6] = 0; - scc_ptr->reg[5] = 0; - scc_ptr->reg[4] = 0x04; - scc_ptr->reg[3] = 0; - scc_ptr->reg[2] = 0; - scc_ptr->reg[1] = 0; - - /* HACK HACK: */ - scc_stat[0].reg[9] = 0; /* Clear all interrupts */ - - scc_evaluate_ints(port); - - scc_regen_clocks(port); -} - -void -scc_reset_port(int port) -{ - Scc *scc_ptr; - - scc_ptr = &(scc_stat[port]); - scc_ptr->reg[15] = 0xf8; - scc_ptr->reg[14] &= 0x03; /* 0 most (including >= 0x100) bits */ - scc_ptr->reg[10] = 0; - scc_ptr->reg[5] &= 0x65; /* leave tx bits and sdlc/crc bits */ - scc_ptr->reg[4] |= 0x04; /* Set async mode */ - scc_ptr->reg[3] &= 0xfe; /* clear receiver enable */ - scc_ptr->reg[1] &= 0xfe; /* clear ext int enable */ - - scc_ptr->br_is_zero = 0; - scc_ptr->tx_buf_empty = 1; - - scc_ptr->wantint_rx = 0; - scc_ptr->wantint_tx = 0; - scc_ptr->wantint_zerocnt = 0; - - scc_ptr->rx_queue_depth = 0; - - scc_evaluate_ints(port); - - scc_regen_clocks(port); - - scc_clr_tx_int(port); - scc_clr_rx_int(port); -} - -void -scc_regen_clocks(int port) -{ - Scc *scc_ptr; - double br_dcycs, tx_dcycs, rx_dcycs; - double rx_char_size, tx_char_size; - double clock_mult; - word32 reg4; - word32 reg14; - word32 reg11; - word32 br_const; - word32 baud; - word32 max_diff; - word32 diff; - int state; - int baud_entries; - int pos; - int i; - - /* Always do baud rate generator */ - scc_ptr = &(scc_stat[port]); - br_const = (scc_ptr->reg[13] << 8) + scc_ptr->reg[12]; - br_const += 2; /* counts down past 0 */ - - reg4 = scc_ptr->reg[4]; - clock_mult = 1.0; - switch((reg4 >> 6) & 3) { - case 0: /* x1 */ - clock_mult = 1.0; - break; - case 1: /* x16 */ - clock_mult = 16.0; - break; - case 2: /* x32 */ - clock_mult = 32.0; - break; - case 3: /* x64 */ - clock_mult = 64.0; - break; - } - - br_dcycs = 0.01; - reg14 = scc_ptr->reg[14]; - if(reg14 & 0x1) { - br_dcycs = SCC_DCYCS_PER_XTAL; - if(reg14 & 0x2) { - br_dcycs = SCC_DCYCS_PER_PCLK; - } - } - - br_dcycs = br_dcycs * (double)br_const; - - tx_dcycs = 1; - rx_dcycs = 1; - reg11 = scc_ptr->reg[11]; - if(((reg11 >> 3) & 3) == 2) { - tx_dcycs = 2.0 * br_dcycs * clock_mult; - } - if(((reg11 >> 5) & 3) == 2) { - rx_dcycs = 2.0 * br_dcycs * clock_mult; - } - - tx_char_size = 8.0; - switch((scc_ptr->reg[5] >> 5) & 0x3) { - case 0: // 5 bits - tx_char_size = 5.0; - break; - case 1: // 7 bits - tx_char_size = 7.0; - break; - case 2: // 6 bits - tx_char_size = 6.0; - break; - } - - scc_ptr->char_size = (int)tx_char_size; - - switch((scc_ptr->reg[4] >> 2) & 0x3) { - case 1: // 1 stop bit - tx_char_size += 2.0; // 1 stop + 1 start bit - break; - case 2: // 1.5 stop bit - tx_char_size += 2.5; // 1.5 stop + 1 start bit - break; - case 3: // 2 stop bits - tx_char_size += 3.0; // 2.0 stop + 1 start bit - break; - } - - if(scc_ptr->reg[4] & 1) { - // parity enabled - tx_char_size += 1.0; - } - - if(scc_ptr->reg[14] & 0x10) { - /* loopback mode, make it go faster...*/ - rx_char_size = 1.0; - tx_char_size = 1.0; - } - - rx_char_size = tx_char_size; /* HACK */ - - baud = (int)(DCYCS_1_MHZ / tx_dcycs); - max_diff = 5000000; - pos = 0; - baud_entries = sizeof(g_baud_table)/sizeof(g_baud_table[0]); - for(i = 0; i < baud_entries; i++) { - diff = abs((int)(g_baud_table[i] - baud)); - if(diff < max_diff) { - pos = i; - max_diff = diff; - } - } - - scc_ptr->baud_rate = g_baud_table[pos]; - - scc_ptr->br_dcycs = br_dcycs; - scc_ptr->tx_dcycs = tx_dcycs * tx_char_size; - scc_ptr->rx_dcycs = rx_dcycs * rx_char_size; - - state = scc_ptr->state; - if(state == 2) { - /* real serial ports */ -#ifdef MAC - scc_serial_mac_change_params(port); -#endif -#ifdef _WIN32 - scc_serial_win_change_params(port); -#endif - } else { - scc_socket_change_params(port); - } -} - -void -scc_port_init(int port) -{ - int state; - - state = 0; - switch (g_serial_type[port]) { - case 0: - break; - case 1: - #ifdef MAC - state = scc_serial_mac_init(port); - #endif - #ifdef _WIN32 - state = scc_serial_win_init(port); - #endif - break; - default: - break; - } - - if(state <= 0) { - scc_socket_init(port); - } -} - -void -scc_try_to_empty_writebuf(int port, double dcycs) -{ - Scc *scc_ptr; - int state; - - scc_ptr = &(scc_stat[port]); - state = scc_ptr->state; - if(scc_ptr->write_called_this_vbl) { - return; - } - - scc_ptr->write_called_this_vbl = 1; - - if(state == 2) { -#if defined(MAC) - scc_serial_mac_empty_writebuf(port); -#endif -#if defined(_WIN32) - scc_serial_win_empty_writebuf(port); -#endif - } else if(state == 1) { - scc_socket_empty_writebuf(port, dcycs); - } -} - -void -scc_try_fill_readbuf(int port, double dcycs) -{ - Scc *scc_ptr; - int space_used, space_left; - int state; - - scc_ptr = &(scc_stat[port]); - state = scc_ptr->state; - - space_used = scc_ptr->in_wrptr - scc_ptr->in_rdptr; - if(space_used < 0) { - space_used += SCC_INBUF_SIZE; - } - space_left = (7*SCC_INBUF_SIZE/8) - space_used; - if(space_left < 1) { - /* Buffer is pretty full, don't try to get more */ - return; - } - -#if 0 - if(scc_ptr->read_called_this_vbl) { - return; - } -#endif - - scc_ptr->read_called_this_vbl = 1; - - if(state == 2) { -#if defined(MAC) - scc_serial_mac_fill_readbuf(port, space_left, dcycs); -#endif -#if defined(_WIN32) - scc_serial_win_fill_readbuf(port, space_left, dcycs); -#endif - } else if(state == 1) { - scc_socket_fill_readbuf(port, space_left, dcycs); - } -} - -void -scc_update(double dcycs) -{ - /* called each VBL update */ - scc_stat[0].write_called_this_vbl = 0; - scc_stat[1].write_called_this_vbl = 0; - scc_stat[0].read_called_this_vbl = 0; - scc_stat[1].read_called_this_vbl = 0; - - scc_try_to_empty_writebuf(0, dcycs); - scc_try_to_empty_writebuf(1, dcycs); - scc_try_fill_readbuf(0, dcycs); - scc_try_fill_readbuf(1, dcycs); - - scc_stat[0].write_called_this_vbl = 0; - scc_stat[1].write_called_this_vbl = 0; - scc_stat[0].read_called_this_vbl = 0; - scc_stat[1].read_called_this_vbl = 0; -} - -void -do_scc_event(int type, double dcycs) -{ - Scc *scc_ptr; - int port; - - port = type & 1; - type = (type >> 1); - - scc_ptr = &(scc_stat[port]); - if(type == SCC_BR_EVENT) { - /* baud rate generator counted down to 0 */ - scc_ptr->br_event_pending = 0; - scc_set_zerocnt_int(port); - scc_maybe_br_event(port, dcycs); - } else if(type == SCC_TX_EVENT) { - scc_ptr->tx_event_pending = 0; - scc_ptr->tx_buf_empty = 1; - scc_handle_tx_event(port, dcycs); - } else if(type == SCC_RX_EVENT) { - scc_ptr->rx_event_pending = 0; - scc_maybe_rx_event(port, dcycs); - } else { - halt_printf("do_scc_event: %08x!\n", type); - } - return; -} - -void -show_scc_state() -{ - Scc *scc_ptr; - int i, j; - - for(i = 0; i < 2; i++) { - scc_ptr = &(scc_stat[i]); - printf("SCC port: %d\n", i); - for(j = 0; j < 16; j += 4) { - printf("Reg %2d-%2d: %02x %02x %02x %02x\n", j, j+3, - scc_ptr->reg[j], scc_ptr->reg[j+1], - scc_ptr->reg[j+2], scc_ptr->reg[j+3]); - } - printf("state: %d, accfd: %d, rdwrfd: %d, host:%p, host2:%p\n", - scc_ptr->state, scc_ptr->accfd, scc_ptr->rdwrfd, - scc_ptr->host_handle, scc_ptr->host_handle2); - printf("in_rdptr: %04x, in_wr:%04x, out_rd:%04x, out_wr:%04x\n", - scc_ptr->in_rdptr, scc_ptr->in_wrptr, - scc_ptr->out_rdptr, scc_ptr->out_wrptr); - printf("rx_queue_depth: %d, queue: %02x, %02x, %02x, %02x\n", - scc_ptr->rx_queue_depth, scc_ptr->rx_queue[0], - scc_ptr->rx_queue[1], scc_ptr->rx_queue[2], - scc_ptr->rx_queue[3]); - printf("want_ints: rx:%d, tx:%d, zc:%d\n", - scc_ptr->wantint_rx, scc_ptr->wantint_tx, - scc_ptr->wantint_zerocnt); - printf("ev_pendings: rx:%d, tx:%d, br:%d\n", - scc_ptr->rx_event_pending, - scc_ptr->tx_event_pending, - scc_ptr->br_event_pending); - printf("br_dcycs: %f, tx_dcycs: %f, rx_dcycs: %f\n", - scc_ptr->br_dcycs, scc_ptr->tx_dcycs, - scc_ptr->rx_dcycs); - printf("char_size: %d, baud_rate: %d, mode: %d\n", - scc_ptr->char_size, scc_ptr->baud_rate, - scc_ptr->mode); - printf("modem_dial_mode:%d, telnet_mode:%d iac:%d, " - "modem_cmd_len:%d\n", scc_ptr->modem_dial_or_acc_mode, - scc_ptr->telnet_mode, scc_ptr->telnet_iac, - scc_ptr->modem_cmd_len); - printf("telnet_loc_modes:%08x %08x, telnet_rem_motes:" - "%08x %08x\n", scc_ptr->telnet_local_mode[0], - scc_ptr->telnet_local_mode[1], - scc_ptr->telnet_remote_mode[0], - scc_ptr->telnet_remote_mode[1]); - printf("modem_mode:%08x plus_mode: %d, out_char_dcycs: %f\n", - scc_ptr->modem_mode, scc_ptr->modem_plus_mode, - scc_ptr->out_char_dcycs); - } - -} - -#define LEN_SCC_LOG 50 -STRUCT(Scc_log) { - int regnum; - word32 val; - double dcycs; -}; - -Scc_log g_scc_log[LEN_SCC_LOG]; -int g_scc_log_pos = 0; - -#define SCC_REGNUM(wr,port,reg) ((wr << 8) + (port << 4) + reg) - -void -scc_log(int regnum, word32 val, double dcycs) -{ - int pos; - - pos = g_scc_log_pos; - g_scc_log[pos].regnum = regnum; - g_scc_log[pos].val = val; - g_scc_log[pos].dcycs = dcycs; - pos++; - if(pos >= LEN_SCC_LOG) { - pos = 0; - } - g_scc_log_pos = pos; -} - -void -show_scc_log(void) -{ - double dcycs; - int regnum; - int pos; - int i; - - pos = g_scc_log_pos; - dcycs = g_cur_dcycs; - printf("SCC log pos: %d, cur dcycs:%f\n", pos, dcycs); - for(i = 0; i < LEN_SCC_LOG; i++) { - pos--; - if(pos < 0) { - pos = LEN_SCC_LOG - 1; - } - regnum = g_scc_log[pos].regnum; - printf("%d:%d: port:%d wr:%d reg: %d val:%02x at t:%f\n", - i, pos, (regnum >> 4) & 0xf, (regnum >> 8), - (regnum & 0xf), - g_scc_log[pos].val, - g_scc_log[pos].dcycs - dcycs); - } -} - -word32 -scc_read_reg(int port, double dcycs) -{ - Scc *scc_ptr; - word32 ret; - int regnum; - - scc_ptr = &(scc_stat[port]); - scc_ptr->mode = 0; - regnum = scc_ptr->reg_ptr; - - /* port 0 is channel A, port 1 is channel B */ - switch(regnum) { - case 0: - case 4: - ret = 0x60; /* 0x44 = no dcd, no cts,0x6c = dcd ok, cts ok*/ - if(scc_ptr->dcd) { - ret |= 0x08; - } - ret |= 0x8; /* HACK HACK */ - if(scc_ptr->rx_queue_depth) { - ret |= 0x01; - } - if(scc_ptr->tx_buf_empty) { - ret |= 0x04; - } - if(scc_ptr->br_is_zero) { - ret |= 0x02; - } - //printf("Read scc[%d] stat: %f : %02x\n", port, dcycs, ret); - break; - case 1: - case 5: - /* HACK: residue codes not right */ - ret = 0x07; /* all sent */ - break; - case 2: - case 6: - if(port == 0) { - ret = scc_ptr->reg[2]; - } else { - - halt_printf("Read of RR2B...stopping\n"); - ret = 0; -#if 0 - ret = scc_stat[0].reg[2]; - wr9 = scc_stat[0].reg[9]; - for(i = 0; i < 8; i++) { - if(ZZZ){}; - } - if(wr9 & 0x10) { - /* wr9 status high */ - - } -#endif - } - break; - case 3: - case 7: - if(port == 0) { - ret = (g_irq_pending & 0x3f); - } else { - ret = 0; - } - break; - case 8: - ret = scc_read_data(port, dcycs); - break; - case 9: - case 13: - ret = scc_ptr->reg[13]; - break; - case 10: - case 14: - ret = 0; - break; - case 11: - case 15: - ret = scc_ptr->reg[15]; - break; - case 12: - ret = scc_ptr->reg[12]; - break; - default: - halt_printf("Tried reading c03%x with regnum: %d!\n", 8+port, - regnum); - ret = 0; - } - - scc_ptr->reg_ptr = 0; - scc_printf("Read c03%x, rr%d, ret: %02x\n", 8+port, regnum, ret); - if(regnum != 0 && regnum != 3) { - scc_log(SCC_REGNUM(0,port,regnum), ret, dcycs); - } - - return ret; -} - -void -scc_write_reg(int port, word32 val, double dcycs) -{ - Scc *scc_ptr; - word32 old_val; - word32 changed_bits; - word32 irq_mask; - int regnum; - int mode; - int tmp1; - - scc_ptr = &(scc_stat[port]); - regnum = scc_ptr->reg_ptr & 0xf; - mode = scc_ptr->mode; - - if(mode == 0) { - if((val & 0xf0) == 0) { - /* Set reg_ptr */ - scc_ptr->reg_ptr = val & 0xf; - regnum = 0; - scc_ptr->mode = 1; - } else { - scc_log(SCC_REGNUM(1,port,0), val, dcycs); - } - } else { - scc_ptr->reg_ptr = 0; - scc_ptr->mode = 0; - } - - if(regnum != 0) { - scc_log(SCC_REGNUM(1,port,regnum), val, dcycs); - } - - changed_bits = (scc_ptr->reg[regnum] ^ val) & 0xff; - - /* Set reg reg */ - switch(regnum) { - case 0: /* wr0 */ - tmp1 = (val >> 3) & 0x7; - switch(tmp1) { - case 0x0: - case 0x1: - break; - case 0x2: /* reset ext/status ints */ - /* should clear other ext ints */ - scc_clr_zerocnt_int(port); - break; - case 0x5: /* reset tx int pending */ - scc_clr_tx_int(port); - break; - case 0x6: /* reset rr1 bits */ - break; - case 0x7: /* reset highest pri int pending */ - irq_mask = g_irq_pending; - if(port == 0) { - /* Move SCC0 ints into SCC1 positions */ - irq_mask = irq_mask >> 3; - } - if(irq_mask & IRQ_PENDING_SCC1_RX) { - scc_clr_rx_int(port); - } else if(irq_mask & IRQ_PENDING_SCC1_TX) { - scc_clr_tx_int(port); - } else if(irq_mask & IRQ_PENDING_SCC1_ZEROCNT) { - scc_clr_zerocnt_int(port); - } - break; - case 0x4: /* enable int on next rx char */ - default: - halt_printf("Wr c03%x to wr0 of %02x, bad cmd cd:%x!\n", - 8+port, val, tmp1); - } - tmp1 = (val >> 6) & 0x3; - switch(tmp1) { - case 0x0: /* null code */ - break; - case 0x1: /* reset rx crc */ - case 0x2: /* reset tx crc */ - printf("Wr c03%x to wr0 of %02x!\n", 8+port, val); - break; - case 0x3: /* reset tx underrun/eom latch */ - /* if no extern status pending, or being reset now */ - /* and tx disabled, ext int with tx underrun */ - /* ah, just do nothing */ - break; - } - return; - case 1: /* wr1 */ - /* proterm sets this == 0x10, which is int on all rx */ - scc_ptr->reg[regnum] = val; - return; - case 2: /* wr2 */ - /* All values do nothing, let 'em all through! */ - scc_ptr->reg[regnum] = val; - return; - case 3: /* wr3 */ - if((val & 0x1e) != 0x0) { - halt_printf("Wr c03%x to wr3 of %02x!\n", 8+port, val); - } - scc_ptr->reg[regnum] = val; - return; - case 4: /* wr4 */ - if((val & 0x30) != 0x00 || (val & 0x0c) == 0) { - halt_printf("Wr c03%x to wr4 of %02x!\n", 8+port, val); - } - scc_ptr->reg[regnum] = val; - if(changed_bits) { - scc_regen_clocks(port); - } - return; - case 5: /* wr5 */ - if((val & 0x15) != 0x0) { - halt_printf("Wr c03%x to wr5 of %02x!\n", 8+port, val); - } - scc_ptr->reg[regnum] = val; - if(changed_bits & 0x60) { - scc_regen_clocks(port); - } - return; - case 6: /* wr6 */ - if(val != 0) { - halt_printf("Wr c03%x to wr6 of %02x!\n", 8+port, val); - } - scc_ptr->reg[regnum] = val; - return; - case 7: /* wr7 */ - if(val != 0) { - halt_printf("Wr c03%x to wr7 of %02x!\n", 8+port, val); - } - scc_ptr->reg[regnum] = val; - return; - case 8: /* wr8 */ - scc_write_data(port, val, dcycs); - return; - case 9: /* wr9 */ - if((val & 0xc0)) { - if(val & 0x80) { - scc_reset_port(0); - } - if(val & 0x40) { - scc_reset_port(1); - } - if((val & 0xc0) == 0xc0) { - scc_hard_reset_port(0); - scc_hard_reset_port(1); - } - } - if((val & 0x35) != 0x00) { - printf("Write c03%x to wr9 of %02x!\n", 8+port, val); - halt_printf("val & 0x35: %02x\n", (val & 0x35)); - } - old_val = scc_stat[0].reg[9]; - scc_stat[0].reg[regnum] = val; - scc_evaluate_ints(0); - scc_evaluate_ints(1); - return; - case 10: /* wr10 */ - if((val & 0xff) != 0x00) { - printf("Wr c03%x to wr10 of %02x!\n", 8+port, val); - } - scc_ptr->reg[regnum] = val; - return; - case 11: /* wr11 */ - scc_ptr->reg[regnum] = val; - if(changed_bits) { - scc_regen_clocks(port); - } - return; - case 12: /* wr12 */ - scc_ptr->reg[regnum] = val; - if(changed_bits) { - scc_regen_clocks(port); - } - return; - case 13: /* wr13 */ - scc_ptr->reg[regnum] = val; - if(changed_bits) { - scc_regen_clocks(port); - } - return; - case 14: /* wr14 */ - old_val = scc_ptr->reg[regnum]; - val = val + (old_val & (~0xff)); - switch((val >> 5) & 0x7) { - case 0x0: - case 0x1: - case 0x2: - case 0x3: - break; - - case 0x4: /* DPLL source is BR gen */ - val |= SCC_R14_DPLL_SOURCE_BRG; - break; - default: - halt_printf("Wr c03%x to wr14 of %02x, bad dpll cd!\n", - 8+port, val); - } - if((val & 0x0c) != 0x0) { - halt_printf("Wr c03%x to wr14 of %02x!\n", 8+port, val); - } - scc_ptr->reg[regnum] = val; - if(changed_bits) { - scc_regen_clocks(port); - } - scc_maybe_br_event(port, dcycs); - return; - case 15: /* wr15 */ - /* ignore all accesses since IIgs self test messes with it */ - if((val & 0xff) != 0x0) { - scc_printf("Write c03%x to wr15 of %02x!\n", 8+port, - val); - } - if((scc_stat[0].reg[9] & 0x8) && (val != 0)) { - printf("Write wr15:%02x and master int en = 1!\n",val); - /* set_halt(1); */ - } - scc_ptr->reg[regnum] = val; - scc_maybe_br_event(port, dcycs); - scc_evaluate_ints(port); - return; - default: - halt_printf("Wr c03%x to wr%d of %02x!\n", 8+port, regnum, val); - return; - } -} - -void -scc_maybe_br_event(int port, double dcycs) -{ - Scc *scc_ptr; - double br_dcycs; - - scc_ptr = &(scc_stat[port]); - - if(((scc_ptr->reg[14] & 0x01) == 0) || scc_ptr->br_event_pending) { - return; - } - /* also, if ext ints not enabled, don't do baud rate ints */ - if((scc_ptr->reg[15] & 0x02) == 0) { - return; - } - - br_dcycs = scc_ptr->br_dcycs; - if(br_dcycs < 1.0) { - halt_printf("br_dcycs: %f!\n", br_dcycs); - } - - scc_ptr->br_event_pending = 1; - add_event_scc(dcycs + br_dcycs, SCC_MAKE_EVENT(port, SCC_BR_EVENT)); -} - -void -scc_evaluate_ints(int port) -{ - Scc *scc_ptr; - word32 irq_add_mask, irq_remove_mask; - int mie; - - scc_ptr = &(scc_stat[port]); - mie = scc_stat[0].reg[9] & 0x8; /* Master int en */ - - if(!mie) { - /* There can be no interrupts if MIE=0 */ - remove_irq(IRQ_PENDING_SCC1_RX | IRQ_PENDING_SCC1_TX | - IRQ_PENDING_SCC1_ZEROCNT | - IRQ_PENDING_SCC0_RX | IRQ_PENDING_SCC0_TX | - IRQ_PENDING_SCC0_ZEROCNT); - return; - } - - irq_add_mask = 0; - irq_remove_mask = 0; - if(scc_ptr->wantint_rx) { - irq_add_mask |= IRQ_PENDING_SCC1_RX; - } else { - irq_remove_mask |= IRQ_PENDING_SCC1_RX; - } - if(scc_ptr->wantint_tx) { - irq_add_mask |= IRQ_PENDING_SCC1_TX; - } else { - irq_remove_mask |= IRQ_PENDING_SCC1_TX; - } - if(scc_ptr->wantint_zerocnt) { - irq_add_mask |= IRQ_PENDING_SCC1_ZEROCNT; - } else { - irq_remove_mask |= IRQ_PENDING_SCC1_ZEROCNT; - } - if(port == 0) { - /* Port 1 is in bits 0-2 and port 0 is in bits 3-5 */ - irq_add_mask = irq_add_mask << 3; - irq_remove_mask = irq_remove_mask << 3; - } - if(irq_add_mask) { - add_irq(irq_add_mask); - } - if(irq_remove_mask) { - remove_irq(irq_remove_mask); - } -} - - -void -scc_maybe_rx_event(int port, double dcycs) -{ - Scc *scc_ptr; - double rx_dcycs; - int in_rdptr, in_wrptr; - int depth; - - scc_ptr = &(scc_stat[port]); - - if(scc_ptr->rx_event_pending) { - /* one pending already, wait for the event to arrive */ - return; - } - - in_rdptr = scc_ptr->in_rdptr; - in_wrptr = scc_ptr->in_wrptr; - depth = scc_ptr->rx_queue_depth; - if((in_rdptr == in_wrptr) || (depth >= 3)) { - /* no more chars or no more space, just get out */ - return; - } - - if(depth < 0) { - depth = 0; - } - - /* pull char from in_rdptr into queue */ - scc_ptr->rx_queue[depth] = scc_ptr->in_buf[in_rdptr]; - scc_ptr->in_rdptr = (in_rdptr + 1) & (SCC_INBUF_SIZE - 1); - scc_ptr->rx_queue_depth = depth + 1; - scc_maybe_rx_int(port, dcycs); - rx_dcycs = scc_ptr->rx_dcycs; - scc_ptr->rx_event_pending = 1; - add_event_scc(dcycs + rx_dcycs, SCC_MAKE_EVENT(port, SCC_RX_EVENT)); -} - -void -scc_maybe_rx_int(int port, double dcycs) -{ - Scc *scc_ptr; - int depth; - int rx_int_mode; - - scc_ptr = &(scc_stat[port]); - - depth = scc_ptr->rx_queue_depth; - if(depth <= 0) { - /* no more chars, just get out */ - scc_clr_rx_int(port); - return; - } - rx_int_mode = (scc_ptr->reg[1] >> 3) & 0x3; - if(rx_int_mode == 1 || rx_int_mode == 2) { - scc_ptr->wantint_rx = 1; - } - scc_evaluate_ints(port); -} - -void -scc_clr_rx_int(int port) -{ - scc_stat[port].wantint_rx = 0; - scc_evaluate_ints(port); -} - -void -scc_handle_tx_event(int port, double dcycs) -{ - Scc *scc_ptr; - int tx_int_mode; - - scc_ptr = &(scc_stat[port]); - - /* nothing pending, see if ints on */ - tx_int_mode = (scc_ptr->reg[1] & 0x2); - if(tx_int_mode) { - scc_ptr->wantint_tx = 1; - } - scc_evaluate_ints(port); -} - -void -scc_maybe_tx_event(int port, double dcycs) -{ - Scc *scc_ptr; - double tx_dcycs; - - scc_ptr = &(scc_stat[port]); - - if(scc_ptr->tx_event_pending) { - /* one pending already, tx_buf is full */ - scc_ptr->tx_buf_empty = 0; - } else { - /* nothing pending, see ints on */ - scc_evaluate_ints(port); - tx_dcycs = scc_ptr->tx_dcycs; - scc_ptr->tx_event_pending = 1; - add_event_scc(dcycs + tx_dcycs, - SCC_MAKE_EVENT(port, SCC_TX_EVENT)); - } -} - -void -scc_clr_tx_int(int port) -{ - scc_stat[port].wantint_tx = 0; - scc_evaluate_ints(port); -} - -void -scc_set_zerocnt_int(int port) -{ - Scc *scc_ptr; - - scc_ptr = &(scc_stat[port]); - - if(scc_ptr->reg[15] & 0x2) { - scc_ptr->wantint_zerocnt = 1; - } - scc_evaluate_ints(port); -} - -void -scc_clr_zerocnt_int(int port) -{ - scc_stat[port].wantint_zerocnt = 0; - scc_evaluate_ints(port); -} - -void -scc_add_to_readbuf(int port, word32 val, double dcycs) -{ - Scc *scc_ptr; - int in_wrptr; - int in_wrptr_next; - int in_rdptr; - - scc_ptr = &(scc_stat[port]); - - in_wrptr = scc_ptr->in_wrptr; - in_rdptr = scc_ptr->in_rdptr; - in_wrptr_next = (in_wrptr + 1) & (SCC_INBUF_SIZE - 1); - if(in_wrptr_next != in_rdptr) { - scc_ptr->in_buf[in_wrptr] = val; - scc_ptr->in_wrptr = in_wrptr_next; - scc_printf("scc in port[%d] add char 0x%02x, %d,%d != %d\n", - scc_ptr->port, val, - in_wrptr, in_wrptr_next, in_rdptr); - g_scc_overflow = 0; - } else { - if(g_scc_overflow == 0) { - g_code_yellow++; - printf("scc inbuf overflow port %d\n", port); - } - g_scc_overflow = 1; - } - - scc_maybe_rx_event(port, dcycs); -} - -void -scc_add_to_readbufv(int port, double dcycs, const char *fmt, ...) -{ - va_list ap; - char *bufptr; - int ret, len, c; - int i; - - va_start(ap, fmt); - bufptr = (char*)malloc(4096); // OG cast added - bufptr[0] = 0; - ret = vsnprintf(bufptr, 4090, fmt, ap); - len = strlen(bufptr); - for(i = 0; i < len; i++) { - c = bufptr[i]; - if(c == 0x0a) { - scc_add_to_readbuf(port, 0x0d, dcycs); - } - scc_add_to_readbuf(port, c, dcycs); - } - va_end(ap); -} - -void -scc_transmit(int port, word32 val, double dcycs) -{ - Scc *scc_ptr; - int out_wrptr; - int out_rdptr; - - scc_ptr = &(scc_stat[port]); - - /* See if port initialized, if not, do so now */ - if(scc_ptr->state == 0) { - scc_port_init(port); - } - if(scc_ptr->state < 0) { - /* No working serial port, just toss it and go */ - return; - } - - if(!scc_ptr->tx_buf_empty) { - /* toss character! */ - printf("Tossing char\n"); - return; - } - - out_wrptr = scc_ptr->out_wrptr; - out_rdptr = scc_ptr->out_rdptr; - if(scc_ptr->tx_dcycs < 1.0) { - if(out_wrptr != out_rdptr) { - /* do just one char, then get out */ - printf("tx_dcycs < 1\n"); - return; - } - } - if(g_serial_out_masking) { - val = val & 0x7f; - } - - scc_add_to_writebuf(port, val, dcycs); -} - -void -scc_add_to_writebuf(int port, word32 val, double dcycs) -{ - Scc *scc_ptr; - int out_wrptr; - int out_wrptr_next; - int out_rdptr; - - scc_ptr = &(scc_stat[port]); - - /* See if port initialized, if not, do so now */ - if(scc_ptr->state == 0) { - scc_port_init(port); - } - if(scc_ptr->state < 0) { - /* No working serial port, just toss it and go */ - return; - } - - out_wrptr = scc_ptr->out_wrptr; - out_rdptr = scc_ptr->out_rdptr; - - out_wrptr_next = (out_wrptr + 1) & (SCC_OUTBUF_SIZE - 1); - if(out_wrptr_next != out_rdptr) { - scc_ptr->out_buf[out_wrptr] = val; - scc_ptr->out_wrptr = out_wrptr_next; - scc_printf("scc wrbuf port %d had char 0x%02x added\n", - scc_ptr->port, val); - g_scc_overflow = 0; - } else { - if(g_scc_overflow == 0) { - g_code_yellow++; - printf("scc outbuf overflow port %d\n", port); - } - g_scc_overflow = 1; - } -} - -word32 -scc_read_data(int port, double dcycs) -{ - Scc *scc_ptr; - word32 ret; - int depth; - int i; - - scc_ptr = &(scc_stat[port]); - - scc_try_fill_readbuf(port, dcycs); - - depth = scc_ptr->rx_queue_depth; - - ret = 0; - if(depth != 0) { - ret = scc_ptr->rx_queue[0]; - for(i = 1; i < depth; i++) { - scc_ptr->rx_queue[i-1] = scc_ptr->rx_queue[i]; - } - scc_ptr->rx_queue_depth = depth - 1; - scc_maybe_rx_event(port, dcycs); - scc_maybe_rx_int(port, dcycs); - } - - scc_printf("SCC read %04x: ret %02x, depth:%d\n", 0xc03b-port, ret, - depth); - - scc_log(SCC_REGNUM(0,port,8), ret, dcycs); - - return ret; -} - - -void -scc_write_data(int port, word32 val, double dcycs) -{ - Scc *scc_ptr; - - scc_printf("SCC write %04x: %02x\n", 0xc03b-port, val); - scc_log(SCC_REGNUM(1,port,8), val, dcycs); - - scc_ptr = &(scc_stat[port]); - if(scc_ptr->reg[14] & 0x10) { - /* local loopback! */ - scc_add_to_readbuf(port, val, dcycs); - } else { - scc_transmit(port, val, dcycs); - } - scc_try_to_empty_writebuf(port, dcycs); - - scc_maybe_tx_event(port, dcycs); -} +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + 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 the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + 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 "defc.h" + +#ifdef UNDER_CE +#define vsnprintf _vsnprintf +#endif + +extern int Verbose; +extern int g_code_yellow; +extern double g_cur_dcycs; +extern int g_serial_type[]; +extern int g_serial_out_masking; +extern int g_irq_pending; + +/* my scc port 0 == channel A = slot 1 = c039/c03b */ +/* port 1 == channel B = slot 2 = c038/c03a */ + +#include "scc.h" +#define SCC_R14_DPLL_SOURCE_BRG 0x100 +#define SCC_R14_FM_MODE 0x200 + +#define SCC_DCYCS_PER_PCLK ((DCYCS_1_MHZ) / ((DCYCS_28_MHZ) /8)) +#define SCC_DCYCS_PER_XTAL ((DCYCS_1_MHZ) / 3686400.0) + +#define SCC_BR_EVENT 1 +#define SCC_TX_EVENT 2 +#define SCC_RX_EVENT 3 +#define SCC_MAKE_EVENT(port, a) (((a) << 1) + (port)) + +Scc scc_stat[2]; + +int g_baud_table[] = { + 110, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200 , 230400 +}; + +int g_scc_overflow = 0; + +void +scc_init() +{ + Scc *scc_ptr; + int i, j; + + for(i = 0; i < 2; i++) { + scc_ptr = &(scc_stat[i]); + scc_ptr->accfd = -1; + scc_ptr->sockfd = -1; + scc_ptr->socket_state = -1; + scc_ptr->rdwrfd = -1; + scc_ptr->state = 0; + scc_ptr->host_handle = 0; + scc_ptr->host_handle2 = 0; + scc_ptr->br_event_pending = 0; + scc_ptr->rx_event_pending = 0; + scc_ptr->tx_event_pending = 0; + scc_ptr->char_size = 8; + scc_ptr->baud_rate = 115200; + scc_ptr->telnet_mode = 0; + scc_ptr->telnet_iac = 0; + scc_ptr->out_char_dcycs = 0.0; + scc_ptr->socket_num_rings = 0; + scc_ptr->socket_last_ring_dcycs = 0; + scc_ptr->modem_mode = 0; + scc_ptr->modem_dial_or_acc_mode = 0; + scc_ptr->modem_plus_mode = 0; + scc_ptr->modem_s0_val = 0; + scc_ptr->modem_cmd_len = 0; + scc_ptr->modem_cmd_str[0] = 0; + for(j = 0; j < 2; j++) { + scc_ptr->telnet_local_mode[j] = 0; + scc_ptr->telnet_remote_mode[j] = 0; + scc_ptr->telnet_reqwill_mode[j] = 0; + scc_ptr->telnet_reqdo_mode[j] = 0; + } + } + + scc_reset(); + // Initialize ports right away - enable incoming data before PR#x + scc_port_init(0); + scc_port_init(1); +} + +void +scc_reset() +{ + Scc *scc_ptr; + int i; + + for(i = 0; i < 2; i++) { + scc_ptr = &(scc_stat[i]); + + scc_ptr->port = i; + scc_ptr->mode = 0; + scc_ptr->reg_ptr = 0; + scc_ptr->in_rdptr = 0; + scc_ptr->in_wrptr = 0; + scc_ptr->out_rdptr = 0; + scc_ptr->out_wrptr = 0; + scc_ptr->dcd = 0; + scc_ptr->wantint_rx = 0; + scc_ptr->wantint_tx = 0; + scc_ptr->wantint_zerocnt = 0; + scc_ptr->read_called_this_vbl = 0; + scc_ptr->write_called_this_vbl = 0; + scc_evaluate_ints(i); + scc_hard_reset_port(i); + } +} + +void +scc_hard_reset_port(int port) +{ + Scc *scc_ptr; + + scc_reset_port(port); + + scc_ptr = &(scc_stat[port]); + scc_ptr->reg[14] = 0; /* zero bottom two bits */ + scc_ptr->reg[13] = 0; + scc_ptr->reg[12] = 0; + scc_ptr->reg[11] = 0x08; + scc_ptr->reg[10] = 0; + scc_ptr->reg[7] = 0; + scc_ptr->reg[6] = 0; + scc_ptr->reg[5] = 0; + scc_ptr->reg[4] = 0x04; + scc_ptr->reg[3] = 0; + scc_ptr->reg[2] = 0; + scc_ptr->reg[1] = 0; + + /* HACK HACK: */ + scc_stat[0].reg[9] = 0; /* Clear all interrupts */ + + scc_evaluate_ints(port); + + scc_regen_clocks(port); +} + +void +scc_reset_port(int port) +{ + Scc *scc_ptr; + + scc_ptr = &(scc_stat[port]); + scc_ptr->reg[15] = 0xf8; + scc_ptr->reg[14] &= 0x03; /* 0 most (including >= 0x100) bits */ + scc_ptr->reg[10] = 0; + scc_ptr->reg[5] &= 0x65; /* leave tx bits and sdlc/crc bits */ + scc_ptr->reg[4] |= 0x04; /* Set async mode */ + scc_ptr->reg[3] &= 0xfe; /* clear receiver enable */ + scc_ptr->reg[1] &= 0xfe; /* clear ext int enable */ + + scc_ptr->br_is_zero = 0; + scc_ptr->tx_buf_empty = 1; + + scc_ptr->wantint_rx = 0; + scc_ptr->wantint_tx = 0; + scc_ptr->wantint_zerocnt = 0; + + scc_ptr->rx_queue_depth = 0; + + scc_evaluate_ints(port); + + scc_regen_clocks(port); + + scc_clr_tx_int(port); + scc_clr_rx_int(port); +} + +void +scc_regen_clocks(int port) +{ + Scc *scc_ptr; + double br_dcycs, tx_dcycs, rx_dcycs; + double rx_char_size, tx_char_size; + double clock_mult; + word32 reg4; + word32 reg14; + word32 reg11; + word32 br_const; + word32 baud; + word32 max_diff; + word32 diff; + int state; + int baud_entries; + int pos; + int i; + + /* Always do baud rate generator */ + scc_ptr = &(scc_stat[port]); + br_const = (scc_ptr->reg[13] << 8) + scc_ptr->reg[12]; + br_const += 2; /* counts down past 0 */ + + reg4 = scc_ptr->reg[4]; + clock_mult = 1.0; + switch((reg4 >> 6) & 3) { + case 0: /* x1 */ + clock_mult = 1.0; + break; + case 1: /* x16 */ + clock_mult = 16.0; + break; + case 2: /* x32 */ + clock_mult = 32.0; + break; + case 3: /* x64 */ + clock_mult = 64.0; + break; + } + + br_dcycs = 0.01; + reg14 = scc_ptr->reg[14]; + if(reg14 & 0x1) { + br_dcycs = SCC_DCYCS_PER_XTAL; + if(reg14 & 0x2) { + br_dcycs = SCC_DCYCS_PER_PCLK; + } + } + + br_dcycs = br_dcycs * (double)br_const; + + tx_dcycs = 1; + rx_dcycs = 1; + reg11 = scc_ptr->reg[11]; + if(((reg11 >> 3) & 3) == 2) { + tx_dcycs = 2.0 * br_dcycs * clock_mult; + } + if(((reg11 >> 5) & 3) == 2) { + rx_dcycs = 2.0 * br_dcycs * clock_mult; + } + + tx_char_size = 8.0; + switch((scc_ptr->reg[5] >> 5) & 0x3) { + case 0: // 5 bits + tx_char_size = 5.0; + break; + case 1: // 7 bits + tx_char_size = 7.0; + break; + case 2: // 6 bits + tx_char_size = 6.0; + break; + } + + scc_ptr->char_size = (int)tx_char_size; + + switch((scc_ptr->reg[4] >> 2) & 0x3) { + case 1: // 1 stop bit + tx_char_size += 2.0; // 1 stop + 1 start bit + break; + case 2: // 1.5 stop bit + tx_char_size += 2.5; // 1.5 stop + 1 start bit + break; + case 3: // 2 stop bits + tx_char_size += 3.0; // 2.0 stop + 1 start bit + break; + } + + if(scc_ptr->reg[4] & 1) { + // parity enabled + tx_char_size += 1.0; + } + + if(scc_ptr->reg[14] & 0x10) { + /* loopback mode, make it go faster...*/ + rx_char_size = 1.0; + tx_char_size = 1.0; + } + + rx_char_size = tx_char_size; /* HACK */ + + baud = (int)(DCYCS_1_MHZ / tx_dcycs); + max_diff = 5000000; + pos = 0; + baud_entries = sizeof(g_baud_table)/sizeof(g_baud_table[0]); + for(i = 0; i < baud_entries; i++) { + diff = abs((int)(g_baud_table[i] - baud)); + if(diff < max_diff) { + pos = i; + max_diff = diff; + } + } + + scc_ptr->baud_rate = g_baud_table[pos]; + + scc_ptr->br_dcycs = br_dcycs; + scc_ptr->tx_dcycs = tx_dcycs * tx_char_size; + scc_ptr->rx_dcycs = rx_dcycs * rx_char_size; + + state = scc_ptr->state; + switch (scc_ptr->state) { + case 1: /* socket */ + scc_socket_change_params(port); + break; + case 2: /* real serial ports */ +#ifdef MAC + scc_serial_mac_change_params(port); +#endif +#ifdef _WIN32 + scc_serial_win_change_params(port); +#endif + break; + case 4: /* Imagewriter */ + scc_ptr->baud_rate = 230400; + scc_ptr->tx_dcycs = tx_dcycs * 1.2; //Somehow this speeds up serial transfer without overrunning the buffer + scc_ptr->rx_dcycs = rx_dcycs * 1.2; + break; + } +} + +void +scc_port_init(int port) +{ + int state; + state = 0; + switch (g_serial_type[port]) { + case 0: + break; + case 1: + #ifdef MAC + state = scc_serial_mac_init(port); + #endif + #ifdef _WIN32 + state = scc_serial_win_init(port); + #endif + break; + case 2: + state = scc_imagewriter_init(port); + break; + default: + break; + } + + if(state <= 0) { + scc_socket_init(port); + } +} + +void +scc_try_to_empty_writebuf(int port, double dcycs) +{ + Scc *scc_ptr; + int state; + + scc_ptr = &(scc_stat[port]); + state = scc_ptr->state; + if(scc_ptr->write_called_this_vbl) { + return; + } + + scc_ptr->write_called_this_vbl = 1; + + switch (state) + { + case 2: +#if defined(MAC) + scc_serial_mac_empty_writebuf(port); +#endif +#if defined(_WIN32) + scc_serial_win_empty_writebuf(port); +#endif + break; + + case 1: + scc_socket_empty_writebuf(port, dcycs); + break; + + case 4: + scc_imagewriter_empty_writebuf(port, dcycs); + break; + } +} + +void +scc_try_fill_readbuf(int port, double dcycs) +{ + Scc *scc_ptr; + int space_used, space_left; + int state; + + scc_ptr = &(scc_stat[port]); + state = scc_ptr->state; + + space_used = scc_ptr->in_wrptr - scc_ptr->in_rdptr; + if(space_used < 0) { + space_used += SCC_INBUF_SIZE; + } + space_left = (7*SCC_INBUF_SIZE/8) - space_used; + if(space_left < 1) { + /* Buffer is pretty full, don't try to get more */ + return; + } + +#if 0 + if(scc_ptr->read_called_this_vbl) { + return; + } +#endif + + scc_ptr->read_called_this_vbl = 1; + + switch (state) + { + case 2: +#if defined(MAC) + scc_serial_mac_fill_readbuf(port, space_left, dcycs); +#endif +#if defined(_WIN32) + scc_serial_win_fill_readbuf(port, space_left, dcycs); +#endif + break; + + case 1: + scc_socket_fill_readbuf(port, space_left, dcycs); + break; + + case 4: + scc_imagewriter_fill_readbuf(port, space_left, dcycs); + break; + } +} + +void +scc_update(double dcycs) +{ + /* called each VBL update */ + scc_stat[0].write_called_this_vbl = 0; + scc_stat[1].write_called_this_vbl = 0; + scc_stat[0].read_called_this_vbl = 0; + scc_stat[1].read_called_this_vbl = 0; + + scc_try_to_empty_writebuf(0, dcycs); + scc_try_to_empty_writebuf(1, dcycs); + scc_try_fill_readbuf(0, dcycs); + scc_try_fill_readbuf(1, dcycs); + + scc_stat[0].write_called_this_vbl = 0; + scc_stat[1].write_called_this_vbl = 0; + scc_stat[0].read_called_this_vbl = 0; + scc_stat[1].read_called_this_vbl = 0; +} + +void +do_scc_event(int type, double dcycs) +{ + Scc *scc_ptr; + int port; + + port = type & 1; + type = (type >> 1); + + scc_ptr = &(scc_stat[port]); + if(type == SCC_BR_EVENT) { + /* baud rate generator counted down to 0 */ + scc_ptr->br_event_pending = 0; + scc_set_zerocnt_int(port); + scc_maybe_br_event(port, dcycs); + } else if(type == SCC_TX_EVENT) { + scc_ptr->tx_event_pending = 0; + scc_ptr->tx_buf_empty = 1; + scc_handle_tx_event(port, dcycs); + } else if(type == SCC_RX_EVENT) { + scc_ptr->rx_event_pending = 0; + scc_maybe_rx_event(port, dcycs); + } else { + halt_printf("do_scc_event: %08x!\n", type); + } + return; +} + +void +show_scc_state() +{ + Scc *scc_ptr; + int i, j; + + for(i = 0; i < 2; i++) { + scc_ptr = &(scc_stat[i]); + printf("SCC port: %d\n", i); + for(j = 0; j < 16; j += 4) { + printf("Reg %2d-%2d: %02x %02x %02x %02x\n", j, j+3, + scc_ptr->reg[j], scc_ptr->reg[j+1], + scc_ptr->reg[j+2], scc_ptr->reg[j+3]); + } + printf("state: %d, accfd: %d, rdwrfd: %d, host:%p, host2:%p\n", + scc_ptr->state, scc_ptr->accfd, scc_ptr->rdwrfd, + scc_ptr->host_handle, scc_ptr->host_handle2); + printf("in_rdptr: %04x, in_wr:%04x, out_rd:%04x, out_wr:%04x\n", + scc_ptr->in_rdptr, scc_ptr->in_wrptr, + scc_ptr->out_rdptr, scc_ptr->out_wrptr); + printf("rx_queue_depth: %d, queue: %02x, %02x, %02x, %02x\n", + scc_ptr->rx_queue_depth, scc_ptr->rx_queue[0], + scc_ptr->rx_queue[1], scc_ptr->rx_queue[2], + scc_ptr->rx_queue[3]); + printf("want_ints: rx:%d, tx:%d, zc:%d\n", + scc_ptr->wantint_rx, scc_ptr->wantint_tx, + scc_ptr->wantint_zerocnt); + printf("ev_pendings: rx:%d, tx:%d, br:%d\n", + scc_ptr->rx_event_pending, + scc_ptr->tx_event_pending, + scc_ptr->br_event_pending); + printf("br_dcycs: %f, tx_dcycs: %f, rx_dcycs: %f\n", + scc_ptr->br_dcycs, scc_ptr->tx_dcycs, + scc_ptr->rx_dcycs); + printf("char_size: %d, baud_rate: %d, mode: %d\n", + scc_ptr->char_size, scc_ptr->baud_rate, + scc_ptr->mode); + printf("modem_dial_mode:%d, telnet_mode:%d iac:%d, " + "modem_cmd_len:%d\n", scc_ptr->modem_dial_or_acc_mode, + scc_ptr->telnet_mode, scc_ptr->telnet_iac, + scc_ptr->modem_cmd_len); + printf("telnet_loc_modes:%08x %08x, telnet_rem_motes:" + "%08x %08x\n", scc_ptr->telnet_local_mode[0], + scc_ptr->telnet_local_mode[1], + scc_ptr->telnet_remote_mode[0], + scc_ptr->telnet_remote_mode[1]); + printf("modem_mode:%08x plus_mode: %d, out_char_dcycs: %f\n", + scc_ptr->modem_mode, scc_ptr->modem_plus_mode, + scc_ptr->out_char_dcycs); + } + +} + +#define LEN_SCC_LOG 50 +STRUCT(Scc_log) { + int regnum; + word32 val; + double dcycs; +}; + +Scc_log g_scc_log[LEN_SCC_LOG]; +int g_scc_log_pos = 0; + +#define SCC_REGNUM(wr,port,reg) ((wr << 8) + (port << 4) + reg) + +void +scc_log(int regnum, word32 val, double dcycs) +{ + int pos; + + pos = g_scc_log_pos; + g_scc_log[pos].regnum = regnum; + g_scc_log[pos].val = val; + g_scc_log[pos].dcycs = dcycs; + pos++; + if(pos >= LEN_SCC_LOG) { + pos = 0; + } + g_scc_log_pos = pos; +} + +void +show_scc_log(void) +{ + double dcycs; + int regnum; + int pos; + int i; + + pos = g_scc_log_pos; + dcycs = g_cur_dcycs; + printf("SCC log pos: %d, cur dcycs:%f\n", pos, dcycs); + for(i = 0; i < LEN_SCC_LOG; i++) { + pos--; + if(pos < 0) { + pos = LEN_SCC_LOG - 1; + } + regnum = g_scc_log[pos].regnum; + printf("%d:%d: port:%d wr:%d reg: %d val:%02x at t:%f\n", + i, pos, (regnum >> 4) & 0xf, (regnum >> 8), + (regnum & 0xf), + g_scc_log[pos].val, + g_scc_log[pos].dcycs - dcycs); + } +} + +word32 +scc_read_reg(int port, double dcycs) +{ + Scc *scc_ptr; + word32 ret; + int regnum; + + scc_ptr = &(scc_stat[port]); + scc_ptr->mode = 0; + regnum = scc_ptr->reg_ptr; + + /* port 0 is channel A, port 1 is channel B */ + switch(regnum) { + case 0: + case 4: + ret = 0x60; /* 0x44 = no dcd, no cts,0x6c = dcd ok, cts ok*/ + if(scc_ptr->dcd) { + ret |= 0x08; + } + ret |= 0x8; /* HACK HACK */ + if(scc_ptr->rx_queue_depth) { + ret |= 0x01; + } + if(scc_ptr->tx_buf_empty) { + ret |= 0x04; + } + if(scc_ptr->br_is_zero) { + ret |= 0x02; + } + //printf("Read scc[%d] stat: %f : %02x\n", port, dcycs, ret); + break; + case 1: + case 5: + /* HACK: residue codes not right */ + ret = 0x07; /* all sent */ + break; + case 2: + case 6: + if(port == 0) { + ret = scc_ptr->reg[2]; + } else { + + halt_printf("Read of RR2B...stopping\n"); + ret = 0; +#if 0 + ret = scc_stat[0].reg[2]; + wr9 = scc_stat[0].reg[9]; + for(i = 0; i < 8; i++) { + if(ZZZ){}; + } + if(wr9 & 0x10) { + /* wr9 status high */ + + } +#endif + } + break; + case 3: + case 7: + if(port == 0) { + ret = (g_irq_pending & 0x3f); + } else { + ret = 0; + } + break; + case 8: + ret = scc_read_data(port, dcycs); + break; + case 9: + case 13: + ret = scc_ptr->reg[13]; + break; + case 10: + case 14: + ret = 0; + break; + case 11: + case 15: + ret = scc_ptr->reg[15]; + break; + case 12: + ret = scc_ptr->reg[12]; + break; + default: + halt_printf("Tried reading c03%x with regnum: %d!\n", 8+port, + regnum); + ret = 0; + } + + scc_ptr->reg_ptr = 0; + scc_printf("Read c03%x, rr%d, ret: %02x\n", 8+port, regnum, ret); + if(regnum != 0 && regnum != 3) { + scc_log(SCC_REGNUM(0,port,regnum), ret, dcycs); + } + + return ret; +} + +void +scc_write_reg(int port, word32 val, double dcycs) +{ + Scc *scc_ptr; + word32 old_val; + word32 changed_bits; + word32 irq_mask; + int regnum; + int mode; + int tmp1; + + scc_ptr = &(scc_stat[port]); + regnum = scc_ptr->reg_ptr & 0xf; + mode = scc_ptr->mode; + + if(mode == 0) { + if((val & 0xf0) == 0) { + /* Set reg_ptr */ + scc_ptr->reg_ptr = val & 0xf; + regnum = 0; + scc_ptr->mode = 1; + } else { + scc_log(SCC_REGNUM(1,port,0), val, dcycs); + } + } else { + scc_ptr->reg_ptr = 0; + scc_ptr->mode = 0; + } + + if(regnum != 0) { + scc_log(SCC_REGNUM(1,port,regnum), val, dcycs); + } + + changed_bits = (scc_ptr->reg[regnum] ^ val) & 0xff; + + /* Set reg reg */ + switch(regnum) { + case 0: /* wr0 */ + tmp1 = (val >> 3) & 0x7; + switch(tmp1) { + case 0x0: + case 0x1: + break; + case 0x2: /* reset ext/status ints */ + /* should clear other ext ints */ + scc_clr_zerocnt_int(port); + break; + case 0x5: /* reset tx int pending */ + scc_clr_tx_int(port); + break; + case 0x6: /* reset rr1 bits */ + break; + case 0x7: /* reset highest pri int pending */ + irq_mask = g_irq_pending; + if(port == 0) { + /* Move SCC0 ints into SCC1 positions */ + irq_mask = irq_mask >> 3; + } + if(irq_mask & IRQ_PENDING_SCC1_RX) { + scc_clr_rx_int(port); + } else if(irq_mask & IRQ_PENDING_SCC1_TX) { + scc_clr_tx_int(port); + } else if(irq_mask & IRQ_PENDING_SCC1_ZEROCNT) { + scc_clr_zerocnt_int(port); + } + break; + case 0x4: /* enable int on next rx char */ + default: + halt_printf("Wr c03%x to wr0 of %02x, bad cmd cd:%x!\n", + 8+port, val, tmp1); + } + tmp1 = (val >> 6) & 0x3; + switch(tmp1) { + case 0x0: /* null code */ + break; + case 0x1: /* reset rx crc */ + case 0x2: /* reset tx crc */ + printf("Wr c03%x to wr0 of %02x!\n", 8+port, val); + break; + case 0x3: /* reset tx underrun/eom latch */ + /* if no extern status pending, or being reset now */ + /* and tx disabled, ext int with tx underrun */ + /* ah, just do nothing */ + break; + } + return; + case 1: /* wr1 */ + /* proterm sets this == 0x10, which is int on all rx */ + scc_ptr->reg[regnum] = val; + return; + case 2: /* wr2 */ + /* All values do nothing, let 'em all through! */ + scc_ptr->reg[regnum] = val; + return; + case 3: /* wr3 */ + if((val & 0x1e) != 0x0) { + halt_printf("Wr c03%x to wr3 of %02x!\n", 8+port, val); + } + scc_ptr->reg[regnum] = val; + return; + case 4: /* wr4 */ + if((val & 0x30) != 0x00 || (val & 0x0c) == 0) { + halt_printf("Wr c03%x to wr4 of %02x!\n", 8+port, val); + } + scc_ptr->reg[regnum] = val; + if(changed_bits) { + scc_regen_clocks(port); + } + return; + case 5: /* wr5 */ + if((val & 0x15) != 0x0) { + halt_printf("Wr c03%x to wr5 of %02x!\n", 8+port, val); + } + scc_ptr->reg[regnum] = val; + if(changed_bits & 0x60) { + scc_regen_clocks(port); + } + return; + case 6: /* wr6 */ + if(val != 0) { + halt_printf("Wr c03%x to wr6 of %02x!\n", 8+port, val); + } + scc_ptr->reg[regnum] = val; + return; + case 7: /* wr7 */ + if(val != 0) { + halt_printf("Wr c03%x to wr7 of %02x!\n", 8+port, val); + } + scc_ptr->reg[regnum] = val; + return; + case 8: /* wr8 */ + scc_write_data(port, val, dcycs); + return; + case 9: /* wr9 */ + if((val & 0xc0)) { + if(val & 0x80) { + scc_reset_port(0); + } + if(val & 0x40) { + scc_reset_port(1); + } + if((val & 0xc0) == 0xc0) { + scc_hard_reset_port(0); + scc_hard_reset_port(1); + } + } + if((val & 0x35) != 0x00) { + printf("Write c03%x to wr9 of %02x!\n", 8+port, val); + halt_printf("val & 0x35: %02x\n", (val & 0x35)); + } + old_val = scc_stat[0].reg[9]; + scc_stat[0].reg[regnum] = val; + scc_evaluate_ints(0); + scc_evaluate_ints(1); + return; + case 10: /* wr10 */ + if((val & 0xff) != 0x00) { + printf("Wr c03%x to wr10 of %02x!\n", 8+port, val); + } + scc_ptr->reg[regnum] = val; + return; + case 11: /* wr11 */ + scc_ptr->reg[regnum] = val; + if(changed_bits) { + scc_regen_clocks(port); + } + return; + case 12: /* wr12 */ + scc_ptr->reg[regnum] = val; + if(changed_bits) { + scc_regen_clocks(port); + } + return; + case 13: /* wr13 */ + scc_ptr->reg[regnum] = val; + if(changed_bits) { + scc_regen_clocks(port); + } + return; + case 14: /* wr14 */ + old_val = scc_ptr->reg[regnum]; + val = val + (old_val & (~0xff)); + switch((val >> 5) & 0x7) { + case 0x0: + case 0x1: + case 0x2: + case 0x3: + break; + + case 0x4: /* DPLL source is BR gen */ + val |= SCC_R14_DPLL_SOURCE_BRG; + break; + default: + halt_printf("Wr c03%x to wr14 of %02x, bad dpll cd!\n", + 8+port, val); + } + if((val & 0x0c) != 0x0) { + halt_printf("Wr c03%x to wr14 of %02x!\n", 8+port, val); + } + scc_ptr->reg[regnum] = val; + if(changed_bits) { + scc_regen_clocks(port); + } + scc_maybe_br_event(port, dcycs); + return; + case 15: /* wr15 */ + /* ignore all accesses since IIgs self test messes with it */ + if((val & 0xff) != 0x0) { + scc_printf("Write c03%x to wr15 of %02x!\n", 8+port, + val); + } + if((scc_stat[0].reg[9] & 0x8) && (val != 0)) { + printf("Write wr15:%02x and master int en = 1!\n",val); + /* set_halt(1); */ + } + scc_ptr->reg[regnum] = val; + scc_maybe_br_event(port, dcycs); + scc_evaluate_ints(port); + return; + default: + halt_printf("Wr c03%x to wr%d of %02x!\n", 8+port, regnum, val); + return; + } +} + +void +scc_maybe_br_event(int port, double dcycs) +{ + Scc *scc_ptr; + double br_dcycs; + + scc_ptr = &(scc_stat[port]); + + if(((scc_ptr->reg[14] & 0x01) == 0) || scc_ptr->br_event_pending) { + return; + } + /* also, if ext ints not enabled, don't do baud rate ints */ + if((scc_ptr->reg[15] & 0x02) == 0) { + return; + } + + br_dcycs = scc_ptr->br_dcycs; + if(br_dcycs < 1.0) { + halt_printf("br_dcycs: %f!\n", br_dcycs); + } + + scc_ptr->br_event_pending = 1; + add_event_scc(dcycs + br_dcycs, SCC_MAKE_EVENT(port, SCC_BR_EVENT)); +} + +void +scc_evaluate_ints(int port) +{ + Scc *scc_ptr; + word32 irq_add_mask, irq_remove_mask; + int mie; + + scc_ptr = &(scc_stat[port]); + mie = scc_stat[0].reg[9] & 0x8; /* Master int en */ + + if(!mie) { + /* There can be no interrupts if MIE=0 */ + remove_irq(IRQ_PENDING_SCC1_RX | IRQ_PENDING_SCC1_TX | + IRQ_PENDING_SCC1_ZEROCNT | + IRQ_PENDING_SCC0_RX | IRQ_PENDING_SCC0_TX | + IRQ_PENDING_SCC0_ZEROCNT); + return; + } + + irq_add_mask = 0; + irq_remove_mask = 0; + if(scc_ptr->wantint_rx) { + irq_add_mask |= IRQ_PENDING_SCC1_RX; + } else { + irq_remove_mask |= IRQ_PENDING_SCC1_RX; + } + if(scc_ptr->wantint_tx) { + irq_add_mask |= IRQ_PENDING_SCC1_TX; + } else { + irq_remove_mask |= IRQ_PENDING_SCC1_TX; + } + if(scc_ptr->wantint_zerocnt) { + irq_add_mask |= IRQ_PENDING_SCC1_ZEROCNT; + } else { + irq_remove_mask |= IRQ_PENDING_SCC1_ZEROCNT; + } + if(port == 0) { + /* Port 1 is in bits 0-2 and port 0 is in bits 3-5 */ + irq_add_mask = irq_add_mask << 3; + irq_remove_mask = irq_remove_mask << 3; + } + if(irq_add_mask) { + add_irq(irq_add_mask); + } + if(irq_remove_mask) { + remove_irq(irq_remove_mask); + } +} + + +void +scc_maybe_rx_event(int port, double dcycs) +{ + Scc *scc_ptr; + double rx_dcycs; + int in_rdptr, in_wrptr; + int depth; + + scc_ptr = &(scc_stat[port]); + + if(scc_ptr->rx_event_pending) { + /* one pending already, wait for the event to arrive */ + return; + } + + in_rdptr = scc_ptr->in_rdptr; + in_wrptr = scc_ptr->in_wrptr; + depth = scc_ptr->rx_queue_depth; + if((in_rdptr == in_wrptr) || (depth >= 3)) { + /* no more chars or no more space, just get out */ + return; + } + + if(depth < 0) { + depth = 0; + } + + /* pull char from in_rdptr into queue */ + scc_ptr->rx_queue[depth] = scc_ptr->in_buf[in_rdptr]; + scc_ptr->in_rdptr = (in_rdptr + 1) & (SCC_INBUF_SIZE - 1); + scc_ptr->rx_queue_depth = depth + 1; + scc_maybe_rx_int(port, dcycs); + rx_dcycs = scc_ptr->rx_dcycs; + scc_ptr->rx_event_pending = 1; + add_event_scc(dcycs + rx_dcycs, SCC_MAKE_EVENT(port, SCC_RX_EVENT)); +} + +void +scc_maybe_rx_int(int port, double dcycs) +{ + Scc *scc_ptr; + int depth; + int rx_int_mode; + + scc_ptr = &(scc_stat[port]); + + depth = scc_ptr->rx_queue_depth; + if(depth <= 0) { + /* no more chars, just get out */ + scc_clr_rx_int(port); + return; + } + rx_int_mode = (scc_ptr->reg[1] >> 3) & 0x3; + if(rx_int_mode == 1 || rx_int_mode == 2) { + scc_ptr->wantint_rx = 1; + } + scc_evaluate_ints(port); +} + +void +scc_clr_rx_int(int port) +{ + scc_stat[port].wantint_rx = 0; + scc_evaluate_ints(port); +} + +void +scc_handle_tx_event(int port, double dcycs) +{ + Scc *scc_ptr; + int tx_int_mode; + + scc_ptr = &(scc_stat[port]); + + /* nothing pending, see if ints on */ + tx_int_mode = (scc_ptr->reg[1] & 0x2); + if(tx_int_mode) { + scc_ptr->wantint_tx = 1; + } + scc_evaluate_ints(port); +} + +void +scc_maybe_tx_event(int port, double dcycs) +{ + Scc *scc_ptr; + double tx_dcycs; + + scc_ptr = &(scc_stat[port]); + + if(scc_ptr->tx_event_pending) { + /* one pending already, tx_buf is full */ + scc_ptr->tx_buf_empty = 0; + } else { + /* nothing pending, see ints on */ + scc_evaluate_ints(port); + tx_dcycs = scc_ptr->tx_dcycs; + scc_ptr->tx_event_pending = 1; + add_event_scc(dcycs + tx_dcycs, + SCC_MAKE_EVENT(port, SCC_TX_EVENT)); + } +} + +void +scc_clr_tx_int(int port) +{ + scc_stat[port].wantint_tx = 0; + scc_evaluate_ints(port); +} + +void +scc_set_zerocnt_int(int port) +{ + Scc *scc_ptr; + + scc_ptr = &(scc_stat[port]); + + if(scc_ptr->reg[15] & 0x2) { + scc_ptr->wantint_zerocnt = 1; + } + scc_evaluate_ints(port); +} + +void +scc_clr_zerocnt_int(int port) +{ + scc_stat[port].wantint_zerocnt = 0; + scc_evaluate_ints(port); +} + +void +scc_add_to_readbuf(int port, word32 val, double dcycs) +{ + Scc *scc_ptr; + int in_wrptr; + int in_wrptr_next; + int in_rdptr; + + scc_ptr = &(scc_stat[port]); + + in_wrptr = scc_ptr->in_wrptr; + in_rdptr = scc_ptr->in_rdptr; + in_wrptr_next = (in_wrptr + 1) & (SCC_INBUF_SIZE - 1); + if(in_wrptr_next != in_rdptr) { + scc_ptr->in_buf[in_wrptr] = val; + scc_ptr->in_wrptr = in_wrptr_next; + scc_printf("scc in port[%d] add char 0x%02x, %d,%d != %d\n", + scc_ptr->port, val, + in_wrptr, in_wrptr_next, in_rdptr); + g_scc_overflow = 0; + } else { + if(g_scc_overflow == 0) { + g_code_yellow++; + printf("scc inbuf overflow port %d\n", port); + } + g_scc_overflow = 1; + } + + scc_maybe_rx_event(port, dcycs); +} + +void +scc_add_to_readbufv(int port, double dcycs, const char *fmt, ...) +{ + va_list ap; + char *bufptr; + int ret, len, c; + int i; + + va_start(ap, fmt); + bufptr = (char*)malloc(4096); // OG cast added + bufptr[0] = 0; + ret = vsnprintf(bufptr, 4090, fmt, ap); + len = strlen(bufptr); + for(i = 0; i < len; i++) { + c = bufptr[i]; + if(c == 0x0a) { + scc_add_to_readbuf(port, 0x0d, dcycs); + } + scc_add_to_readbuf(port, c, dcycs); + } + va_end(ap); +} + +void +scc_transmit(int port, word32 val, double dcycs) +{ + Scc *scc_ptr; + int out_wrptr; + int out_rdptr; + + scc_ptr = &(scc_stat[port]); + + /* See if port initialized, if not, do so now */ + if(scc_ptr->state == 0) { + scc_port_init(port); + } + if(scc_ptr->state < 0) { + /* No working serial port, just toss it and go */ + return; + } + + if(!scc_ptr->tx_buf_empty) { + /* toss character! */ + printf("Tossing char\n"); + return; + } + + out_wrptr = scc_ptr->out_wrptr; + out_rdptr = scc_ptr->out_rdptr; + if(scc_ptr->tx_dcycs < 1.0) { + if(out_wrptr != out_rdptr) { + /* do just one char, then get out */ + printf("tx_dcycs < 1\n"); + return; + } + } + if(g_serial_out_masking) { + val = val & 0x7f; + } + + scc_add_to_writebuf(port, val, dcycs); +} + +void +scc_add_to_writebuf(int port, word32 val, double dcycs) +{ + Scc *scc_ptr; + int out_wrptr; + int out_wrptr_next; + int out_rdptr; + + scc_ptr = &(scc_stat[port]); + + /* See if port initialized, if not, do so now */ + if(scc_ptr->state == 0) { + scc_port_init(port); + } + if(scc_ptr->state < 0) { + /* No working serial port, just toss it and go */ + return; + } + + out_wrptr = scc_ptr->out_wrptr; + out_rdptr = scc_ptr->out_rdptr; + + out_wrptr_next = (out_wrptr + 1) & (SCC_OUTBUF_SIZE - 1); + if(out_wrptr_next != out_rdptr) { + scc_ptr->out_buf[out_wrptr] = val; + scc_ptr->out_wrptr = out_wrptr_next; + scc_printf("scc wrbuf port %d had char 0x%02x added\n", + scc_ptr->port, val); + g_scc_overflow = 0; + } else { + if(g_scc_overflow == 0) { + g_code_yellow++; + printf("scc outbuf overflow port %d\n", port); + } + g_scc_overflow = 1; + } +} + +word32 +scc_read_data(int port, double dcycs) +{ + Scc *scc_ptr; + word32 ret; + int depth; + int i; + + scc_ptr = &(scc_stat[port]); + + scc_try_fill_readbuf(port, dcycs); + + depth = scc_ptr->rx_queue_depth; + + ret = 0; + if(depth != 0) { + ret = scc_ptr->rx_queue[0]; + for(i = 1; i < depth; i++) { + scc_ptr->rx_queue[i-1] = scc_ptr->rx_queue[i]; + } + scc_ptr->rx_queue_depth = depth - 1; + scc_maybe_rx_event(port, dcycs); + scc_maybe_rx_int(port, dcycs); + } + + scc_printf("SCC read %04x: ret %02x, depth:%d\n", 0xc03b-port, ret, + depth); + + scc_log(SCC_REGNUM(0,port,8), ret, dcycs); + + return ret; +} + + +void +scc_write_data(int port, word32 val, double dcycs) +{ + Scc *scc_ptr; + + scc_printf("SCC write %04x: %02x\n", 0xc03b-port, val); + scc_log(SCC_REGNUM(1,port,8), val, dcycs); + + scc_ptr = &(scc_stat[port]); + if(scc_ptr->reg[14] & 0x10) { + /* local loopback! */ + scc_add_to_readbuf(port, val, dcycs); + } else { + scc_transmit(port, val, dcycs); + } + scc_try_to_empty_writebuf(port, dcycs); + + scc_maybe_tx_event(port, dcycs); +} \ No newline at end of file diff --git a/src/scc_imagewriter.c b/src/scc_imagewriter.c new file mode 100644 index 0000000..33e504d --- /dev/null +++ b/src/scc_imagewriter.c @@ -0,0 +1,156 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2013 - 2014 by GSport contributors + Originally authored by Christopher Mason + + 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 the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + 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 +*/ + +/* This is an interface between the SCC emulation and the Virtual Imagewriter. */ + +#include "defc.h" +#include "scc.h" +extern Scc scc_stat[2]; +extern int g_vbl_count; + +extern int g_imagewriter; +extern int g_imagewriter_dpi; +extern char* g_imagewriter_output; +extern int g_imagewriter_multipage; +extern int g_imagewriter_timeout; + +int imagewriter_vbl_count = 0; +int imagewriter_port_block = 0; +int iw_scc_write = 0; + +int scc_imagewriter_init(int port) +{ + Scc *scc_ptr; + scc_ptr = &(scc_stat[port]); + imagewriter_init(g_imagewriter_dpi,85,110,g_imagewriter_output,g_imagewriter_multipage, port); + scc_ptr->state = 4; + return 4; +} + +/** Transfer data from Imagewriter to the SCC **/ +void scc_imagewriter_fill_readbuf(int port, int space_left, double dcycs) +{ + if (iw_scc_write) + { + size_t bytes_read; + size_t i; + byte data[9]; + if (g_imagewriter == 1) + { + //Imagewriter LQ self ID string. Tell machine we have a color ribbon and sheet feeder installed. + data[0] = 0; //Start bit + data[1] ='L'; //Printer type is Imagewriter LQ + data[2] ='Q'; //(cont) + data[3] ='1'; //15 inch carriage width + data[4] ='C'; //Color ribbon installed + data[5] ='F'; //Sheet feeder installed, no envelope attachment + data[6] ='1'; //Number of sheet feeder bins + data[7] = 0x0D; //CR terminates string + data[8] = 0; //Stop bit + bytes_read = 9; + } + else + { + //Imagewriter II self ID string. Tell machine we have a color ribbon and sheet feeder installed. + data[0] = 0; //Start bit + data[1] ='I'; //Printer type is Imagewriter II + data[2] ='W'; //(cont) + data[3] ='1'; //10 inch carriage width + data[4] ='0'; //(cont) + data[5] ='C'; //Color ribbon installed + data[6] ='F'; //Sheet feeder installed + data[7] = 0; //Stop bit + bytes_read = 8; + } + for(i = 0; i < bytes_read; i++) { + scc_add_to_readbuf(port, data[i], dcycs); + } + iw_scc_write = 0; + } +} + +/** Transfer data from the SCC to the Imagewriter. **/ +void scc_imagewriter_empty_writebuf(int port, double dcycs) +{ + Scc* scc_ptr; + + int rdptr; + int wrptr; + int len; + int done; + //int ret; + DWORD bytes_written; + + scc_ptr = &(scc_stat[port]); + done = 0; + while(!done) { + rdptr = scc_ptr->out_rdptr; + wrptr = scc_ptr->out_wrptr; + if(rdptr == wrptr) { + //printf("...rdptr == wrptr\n"); + done = 1; + break; + } + len = wrptr - rdptr; + if(len < 0) { + len = SCC_OUTBUF_SIZE - rdptr; + } + if(len > 32) { + len = 32; + } + if(len <= 0) { + done = 1; + break; + } + bytes_written = 1; + imagewriter_port_block = 1; + imagewriter_loop(scc_ptr->out_buf[rdptr],port); + imagewriter_vbl_count = g_vbl_count+(g_imagewriter_timeout*60); + imagewriter_port_block = 0; + //printf("Write Imagewriter ret: %d, bytes_written:%d, len:%d\n", ret, + //(int)bytes_written, len); + + if((bytes_written == 0)) { + done = 1; + break; + } else { + rdptr = rdptr + bytes_written; + if(rdptr >= SCC_OUTBUF_SIZE) { + rdptr = rdptr - SCC_OUTBUF_SIZE; + } + scc_ptr->out_rdptr = rdptr; + } + } +} + +//This function handles the automatic timeout of the virtual printer if an +//application doesn't send a form feed at the end of the page. It also +//allows multipage mode Postscript and native printer documents to +//print somewhat how a regular application would. +void imagewriter_update() +{ + if (imagewriter_port_block != 1 && imagewriter_vbl_count != 0 && g_vbl_count >= imagewriter_vbl_count) + { + printf("Calling imagewriter_update and flushing!\n"); + imagewriter_feed(); + imagewriter_vbl_count = 0; + } + return; +} \ No newline at end of file diff --git a/src/sim65816.c b/src/sim65816.c index e4f1061..893136a 100644 --- a/src/sim65816.c +++ b/src/sim65816.c @@ -1,209 +1,217 @@ -/* - GSport - an Apple //gs Emulator - Copyright (C) 2010 - 2013 by GSport contributors - - Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey - - 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 the - Free Software Foundation; either version 2 of the License, or (at your - option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - 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 - -#include "defc.h" -#ifdef HAVE_TFE - #include "tfe/tfesupp.h" - #include "tfe/protos_tfe.h" -#endif - #include "printer.h" - -#ifdef UNDER_CE -#define vsnprintf _vsnprintf -#endif - -#if defined(__CYGWIN__) -#define WIN32_LEAN_AND_MEAN /* Tell windows we want less header gunk */ -#define STRICT /* Tell Windows we want compile type checks */ -#include /* Need a definition for LPTSTR in CYGWIN */ -#endif -#if defined (_WIN32) || defined(__CYGWIN__) -extern void get_cwd(LPTSTR buffer, int size); -#endif - -#define PC_LOG_LEN (8*1024) - +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2013 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + 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 the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + 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 + +#include "defc.h" +#ifdef HAVE_TFE + #include "tfe/tfesupp.h" + #include "tfe/protos_tfe.h" +#endif + #include "printer.h" + +#ifdef UNDER_CE +#define vsnprintf _vsnprintf +#endif + +#if defined(__CYGWIN__) +#define WIN32_LEAN_AND_MEAN /* Tell windows we want less header gunk */ +#define STRICT /* Tell Windows we want compile type checks */ +#include /* Need a definition for LPTSTR in CYGWIN */ +#endif +#if defined (_WIN32) || defined(__CYGWIN__) +extern void get_cwd(LPTSTR buffer, int size); +#endif + +#define PC_LOG_LEN (8*1024) + int g_speed_fast ; // OG Expose fast parameter int g_initialized = 0; // OG To know if the emulator has finalized its initialization int g_accept_events = 0; // OG To know if the emulator is ready to accept external events - -char g_argv0_path[256] = "./"; - -const char *g_gsport_default_paths[] = { "", "./", "${HOME}/","${PWD}/", -#ifdef MAC - "${0}/../", -#endif - "${HOME}/Library/GSport/", - "${0}/Contents/Resources/", "/usr/local/lib/", - "/usr/local/gsport/", "/usr/local/lib/gsport/", "/usr/share/gsport/", - "/var/lib/", "/usr/lib/gsport/", "${0}/", 0 }; - -#define MAX_EVENTS 64 - -/* All EV_* must be less than 256, since upper bits reserved for other use */ -/* e.g., DOC_INT uses upper bits to encode oscillator */ -#define EV_60HZ 1 -#define EV_STOP 2 -#define EV_SCAN_INT 3 -#define EV_DOC_INT 4 -#define EV_VBL_INT 5 -#define EV_SCC 6 -#define EV_VID_UPD 7 - -extern int g_stepping; - -extern int g_c068_statereg; -extern int g_cur_a2_stat; - -extern int g_c08x_wrdefram; -extern int g_c02d_int_crom; - -extern int g_c035_shadow_reg; -extern int g_c036_val_speed; - -extern int g_c023_val; -extern int g_c041_val; -extern int g_c046_val; -extern int g_zipgs_reg_c059; -extern int g_zipgs_reg_c05a; -extern int g_zipgs_reg_c05b; -extern int g_zipgs_unlock; - -extern int g_engine_c_mode; -extern int defs_instr_start_8; -extern int defs_instr_start_16; -extern int defs_instr_end_8; -extern int defs_instr_end_16; -extern int op_routs_start; -extern int op_routs_end; - -Engine_reg engine; -extern word32 table8[]; -extern word32 table16[]; - -extern byte doc_ram[]; - -extern int g_iwm_motor_on; -extern int g_fast_disk_emul; -extern int g_slow_525_emul_wr; -extern int g_c031_disk35; -extern int g_config_control_panel; - -extern int g_audio_enable; -extern int g_preferred_rate; - -void U_STACK_TRACE(); - -double g_fcycles_stop = 0.0; -int halt_sim = 0; -int enter_debug = 0; -int g_rom_version = -1; -int g_user_halt_bad = 0; -int g_halt_on_bad_read = 0; -int g_ignore_bad_acc = 1; -int g_ignore_halts = 1; -int g_code_red = 0; -int g_code_yellow = 0; -int g_use_alib = 0; -int g_serial_type[2]; -int g_iw2_emul = 0; -int g_serial_out_masking = 0; -int g_serial_modem[2] = { 0, 1 }; -int g_ethernet = 0; -int g_ethernet_interface = 0; -int g_parallel = 0; -int g_parallel_out_masking = 0; -int g_printer = 0; -int g_printer_dpi = 360; -char* g_printer_output = "bmp"; -int g_printer_multipage = 0; -int g_printer_timeout = 2; -char* g_printer_font_roman = "lib/letgothl.ttf"; -char* g_printer_font_sans = "sansserif.ttf"; -char* g_printer_font_courier = "courier.ttf"; -char* g_printer_font_prestige = "prestige.ttf"; -char* g_printer_font_script = "script.ttf"; -char* g_printer_font_ocra = "ocra.ttf"; - -int g_config_iwm_vbl_count = 0; -extern const char g_gsport_version_str[] = "0.2"; -int g_pause=0; // OG Added pause - -#define START_DCYCS (0.0) - -double g_last_vbl_dcycs = START_DCYCS; -double g_cur_dcycs = START_DCYCS; - -double g_last_vbl_dadjcycs = 0.0; -double g_dadjcycs = 0.0; - - -int g_wait_pending = 0; -int g_stp_pending = 0; -extern int g_irq_pending; - -int g_num_irq = 0; -int g_num_brk = 0; -int g_num_cop = 0; -int g_num_enter_engine = 0; -int g_io_amt = 0; -int g_engine_action = 0; -int g_engine_halt_event = 0; -int g_engine_scan_int = 0; -int g_engine_doc_int = 0; - -int g_testing = 0; -int g_testing_enabled = 0; - -#define MAX_FATAL_LOGS 20 - -int g_debug_file_fd = -1; -int g_fatal_log = -1; -char *g_fatal_log_strs[MAX_FATAL_LOGS]; - -word32 stop_run_at; - -int g_25sec_cntr = 0; -int g_1sec_cntr = 0; - -double g_dnatcycs_1sec = 0.0; -word32 g_natcycs_lastvbl = 0; - -int Verbose = 0; -int Halt_on = 0; - -word32 g_mem_size_base = 256*1024; /* size of motherboard memory */ -word32 g_mem_size_exp = 8*1024*1024; /* size of expansion RAM card */ -word32 g_mem_size_total = 256*1024; /* Total contiguous RAM from 0 */ - -extern word32 slow_mem_changed[]; - -byte *g_slow_memory_ptr = 0; -byte *g_memory_ptr = 0; -byte *g_dummy_memory1_ptr = 0; -byte *g_rom_fc_ff_ptr = 0; -byte *g_rom_cards_ptr = 0; - + +char g_argv0_path[256] = "./"; + +const char *g_gsport_default_paths[] = { "", "./", "${HOME}/","${PWD}/", +#ifdef MAC + "${0}/../", +#endif + "${HOME}/Library/GSport/", + "${0}/Contents/Resources/", "/usr/local/lib/", + "/usr/local/gsport/", "/usr/local/lib/gsport/", "/usr/share/gsport/", + "/var/lib/", "/usr/lib/gsport/", "${0}/", 0 }; + +#define MAX_EVENTS 64 + +/* All EV_* must be less than 256, since upper bits reserved for other use */ +/* e.g., DOC_INT uses upper bits to encode oscillator */ +#define EV_60HZ 1 +#define EV_STOP 2 +#define EV_SCAN_INT 3 +#define EV_DOC_INT 4 +#define EV_VBL_INT 5 +#define EV_SCC 6 +#define EV_VID_UPD 7 + +extern int g_stepping; + +extern int g_c068_statereg; +extern int g_cur_a2_stat; + +extern int g_c08x_wrdefram; +extern int g_c02d_int_crom; + +extern int g_c035_shadow_reg; +extern int g_c036_val_speed; + +extern int g_c023_val; +extern int g_c041_val; +extern int g_c046_val; +extern int g_zipgs_reg_c059; +extern int g_zipgs_reg_c05a; +extern int g_zipgs_reg_c05b; +extern int g_zipgs_unlock; + +extern int g_engine_c_mode; +extern int defs_instr_start_8; +extern int defs_instr_start_16; +extern int defs_instr_end_8; +extern int defs_instr_end_16; +extern int op_routs_start; +extern int op_routs_end; + +Engine_reg engine; +extern word32 table8[]; +extern word32 table16[]; + +extern byte doc_ram[]; + +extern int g_iwm_motor_on; +extern int g_fast_disk_emul; +extern int g_slow_525_emul_wr; +extern int g_c031_disk35; +extern int g_config_control_panel; + +extern int g_audio_enable; +extern int g_preferred_rate; + +void U_STACK_TRACE(); + +double g_fcycles_stop = 0.0; +int halt_sim = 0; +int enter_debug = 0; +int g_rom_version = -1; +int g_user_halt_bad = 0; +int g_halt_on_bad_read = 0; +int g_ignore_bad_acc = 1; +int g_ignore_halts = 1; +int g_code_red = 0; +int g_code_yellow = 0; +int g_use_alib = 0; +int g_serial_type[2]; +int g_iw2_emul = 0; +int g_serial_out_masking = 0; +int g_serial_modem[2] = { 0, 1 }; +int g_ethernet = 0; +int g_ethernet_interface = 0; +int g_parallel = 0; +int g_parallel_out_masking = 0; +int g_printer = 0; +int g_printer_dpi = 360; +char* g_printer_output = "bmp"; +int g_printer_multipage = 0; +int g_printer_timeout = 2; +char* g_printer_font_roman = "lib/letgothl.ttf"; +char* g_printer_font_sans = "sansserif.ttf"; +char* g_printer_font_courier = "courier.ttf"; +char* g_printer_font_prestige = "prestige.ttf"; +char* g_printer_font_script = "script.ttf"; +char* g_printer_font_ocra = "ocra.ttf"; + +int g_imagewriter = 0; +int g_imagewriter_dpi = 360; +char* g_imagewriter_output = "bmp"; +int g_imagewriter_multipage = 0; +int g_imagewriter_timeout = 2; +char* g_imagewriter_fixed_font = "roman.ttf"; +char* g_imagewriter_prop_font = "roman.ttf"; + +int g_config_iwm_vbl_count = 0; +extern const char g_gsport_version_str[] = "0.2"; +int g_pause=0; // OG Added pause + +#define START_DCYCS (0.0) + +double g_last_vbl_dcycs = START_DCYCS; +double g_cur_dcycs = START_DCYCS; + +double g_last_vbl_dadjcycs = 0.0; +double g_dadjcycs = 0.0; + + +int g_wait_pending = 0; +int g_stp_pending = 0; +extern int g_irq_pending; + +int g_num_irq = 0; +int g_num_brk = 0; +int g_num_cop = 0; +int g_num_enter_engine = 0; +int g_io_amt = 0; +int g_engine_action = 0; +int g_engine_halt_event = 0; +int g_engine_scan_int = 0; +int g_engine_doc_int = 0; + +int g_testing = 0; +int g_testing_enabled = 0; + +#define MAX_FATAL_LOGS 20 + +int g_debug_file_fd = -1; +int g_fatal_log = -1; +char *g_fatal_log_strs[MAX_FATAL_LOGS]; + +word32 stop_run_at; + +int g_25sec_cntr = 0; +int g_1sec_cntr = 0; + +double g_dnatcycs_1sec = 0.0; +word32 g_natcycs_lastvbl = 0; + +int Verbose = 0; +int Halt_on = 0; + +word32 g_mem_size_base = 256*1024; /* size of motherboard memory */ +word32 g_mem_size_exp = 8*1024*1024; /* size of expansion RAM card */ +word32 g_mem_size_total = 256*1024; /* Total contiguous RAM from 0 */ + +extern word32 slow_mem_changed[]; + +byte *g_slow_memory_ptr = 0; +byte *g_memory_ptr = 0; +byte *g_dummy_memory1_ptr = 0; +byte *g_rom_fc_ff_ptr = 0; +byte *g_rom_cards_ptr = 0; + // OG Added allocated pointers byte *g_slow_memory_ptr_allocated = 0; byte *g_memory_ptr_allocated = 0; @@ -211,25 +219,25 @@ byte *g_dummy_memory1_ptr_allocated = 0; byte *g_rom_fc_ff_ptr_allocated = 0; byte *g_rom_cards_ptr_allocated = 0; -void *g_memory_alloc_ptr = 0; /* for freeing memory area */ - -Page_info page_info_rd_wr[2*65536 + PAGE_INFO_PAD_SIZE]; - -Pc_log g_pc_log_array[PC_LOG_LEN + 2]; -Data_log g_data_log_array[PC_LOG_LEN + 2]; - -Pc_log *g_log_pc_ptr = &(g_pc_log_array[0]); -Pc_log *g_log_pc_start_ptr = &(g_pc_log_array[0]); -Pc_log *g_log_pc_end_ptr = &(g_pc_log_array[PC_LOG_LEN]); - -Data_log *g_log_data_ptr = &(g_data_log_array[0]); -Data_log *g_log_data_start_ptr = &(g_data_log_array[0]); -Data_log *g_log_data_end_ptr = &(g_data_log_array[PC_LOG_LEN]); - +void *g_memory_alloc_ptr = 0; /* for freeing memory area */ + +Page_info page_info_rd_wr[2*65536 + PAGE_INFO_PAD_SIZE]; + +Pc_log g_pc_log_array[PC_LOG_LEN + 2]; +Data_log g_data_log_array[PC_LOG_LEN + 2]; + +Pc_log *g_log_pc_ptr = &(g_pc_log_array[0]); +Pc_log *g_log_pc_start_ptr = &(g_pc_log_array[0]); +Pc_log *g_log_pc_end_ptr = &(g_pc_log_array[PC_LOG_LEN]); + +Data_log *g_log_data_ptr = &(g_data_log_array[0]); +Data_log *g_log_data_start_ptr = &(g_data_log_array[0]); +Data_log *g_log_data_end_ptr = &(g_data_log_array[PC_LOG_LEN]); + // OG Added sim65816_initglobals() void sim65816_initglobals() { - + g_fcycles_stop = 0.0; halt_sim = 0; enter_debug = 0; @@ -289,429 +297,429 @@ void sim65816_initglobals() g_mem_size_total = 256*1024; /* Total contiguous RAM from 0 */ } -void -show_pc_log() -{ - FILE *pcfile; - Pc_log *log_pc_ptr; - Data_log *log_data_ptr; - double dcycs; - double start_dcycs; - word32 instr; - word32 psr; - word32 acc, xreg, yreg; - word32 stack, direct; - word32 dbank; - word32 kpc; - int data_wrap; - int accsize, xsize; - int num; - int i; - - pcfile = fopen("pc_log_out", "w"); - if(pcfile == 0) { - fprintf(stderr,"fopen failed...errno: %d\n", errno); - exit(2); - } - - log_pc_ptr = g_log_pc_ptr; - log_data_ptr = g_log_data_ptr; -#if 0 - fprintf(pcfile, "current pc_log_ptr: %p, start: %p, end: %p\n", - log_pc_ptr, log_pc_start_ptr, log_pc_end_ptr); -#endif - - start_dcycs = log_pc_ptr->dcycs; - dcycs = start_dcycs; - - data_wrap = 0; - /* find first data entry */ - while(data_wrap < 2 && (log_data_ptr->dcycs < dcycs)) { - log_data_ptr++; - if(log_data_ptr >= g_log_data_end_ptr) { - log_data_ptr = g_log_data_start_ptr; - data_wrap++; - } - } - fprintf(pcfile, "start_dcycs: %9.2f\n", start_dcycs); - - for(i = 0; i < PC_LOG_LEN; i++) { - dcycs = log_pc_ptr->dcycs; - while((data_wrap < 2) && (log_data_ptr->dcycs <= dcycs) && - (log_data_ptr->dcycs >= start_dcycs)) { - fprintf(pcfile, "DATA set %06x = %06x (%d) %9.2f\n", - log_data_ptr->addr, log_data_ptr->val, - log_data_ptr->size, - log_data_ptr->dcycs - start_dcycs); - log_data_ptr++; - if(log_data_ptr >= g_log_data_end_ptr) { - log_data_ptr = g_log_data_start_ptr; - data_wrap++; - } - } - dbank = (log_pc_ptr->dbank_kpc >> 24) & 0xff; - kpc = log_pc_ptr->dbank_kpc & 0xffffff; - instr = log_pc_ptr->instr; - psr = (log_pc_ptr->psr_acc >> 16) & 0xffff;; - acc = log_pc_ptr->psr_acc & 0xffff;; - xreg = (log_pc_ptr->xreg_yreg >> 16) & 0xffff;; - yreg = log_pc_ptr->xreg_yreg & 0xffff;; - stack = (log_pc_ptr->stack_direct >> 16) & 0xffff;; - direct = log_pc_ptr->stack_direct & 0xffff;; - - num = log_pc_ptr - g_log_pc_start_ptr; - - accsize = 2; - xsize = 2; - if(psr & 0x20) { - accsize = 1; - } - if(psr & 0x10) { - xsize = 1; - } - - fprintf(pcfile, "%04x: A:%04x X:%04x Y:%04x P:%03x " - "S:%04x D:%04x B:%02x %9.2f ", i, - acc, xreg, yreg, psr, stack, direct, dbank, - (dcycs-start_dcycs)); - - do_dis(pcfile, kpc, accsize, xsize, 1, instr); - log_pc_ptr++; - if(log_pc_ptr >= g_log_pc_end_ptr) { - log_pc_ptr = g_log_pc_start_ptr; - } - } - - fclose(pcfile); -} - - -#define TOOLBOX_LOG_LEN 64 - -int g_toolbox_log_pos = 0; -word32 g_toolbox_log_array[TOOLBOX_LOG_LEN][8]; - -word32 -toolbox_debug_4byte(word32 addr) -{ - word32 part1, part2; - - /* If addr looks safe, use it */ - if(addr > 0xbffc) { - return (word32)-1; - } - - part1 = get_memory16_c(addr, 0); - part1 = (part1 >> 8) + ((part1 & 0xff) << 8); - part2 = get_memory16_c(addr+2, 0); - part2 = (part2 >> 8) + ((part2 & 0xff) << 8); - - return (part1 << 16) + part2; -} - -void -toolbox_debug_c(word32 xreg, word32 stack, double *cyc_ptr) -{ - int pos; - - pos = g_toolbox_log_pos; - - stack += 9; +void +show_pc_log() +{ + FILE *pcfile; + Pc_log *log_pc_ptr; + Data_log *log_data_ptr; + double dcycs; + double start_dcycs; + word32 instr; + word32 psr; + word32 acc, xreg, yreg; + word32 stack, direct; + word32 dbank; + word32 kpc; + int data_wrap; + int accsize, xsize; + int num; + int i; + + pcfile = fopen("pc_log_out", "w"); + if(pcfile == 0) { + fprintf(stderr,"fopen failed...errno: %d\n", errno); + exit(2); + } + + log_pc_ptr = g_log_pc_ptr; + log_data_ptr = g_log_data_ptr; +#if 0 + fprintf(pcfile, "current pc_log_ptr: %p, start: %p, end: %p\n", + log_pc_ptr, log_pc_start_ptr, log_pc_end_ptr); +#endif + + start_dcycs = log_pc_ptr->dcycs; + dcycs = start_dcycs; + + data_wrap = 0; + /* find first data entry */ + while(data_wrap < 2 && (log_data_ptr->dcycs < dcycs)) { + log_data_ptr++; + if(log_data_ptr >= g_log_data_end_ptr) { + log_data_ptr = g_log_data_start_ptr; + data_wrap++; + } + } + fprintf(pcfile, "start_dcycs: %9.2f\n", start_dcycs); + + for(i = 0; i < PC_LOG_LEN; i++) { + dcycs = log_pc_ptr->dcycs; + while((data_wrap < 2) && (log_data_ptr->dcycs <= dcycs) && + (log_data_ptr->dcycs >= start_dcycs)) { + fprintf(pcfile, "DATA set %06x = %06x (%d) %9.2f\n", + log_data_ptr->addr, log_data_ptr->val, + log_data_ptr->size, + log_data_ptr->dcycs - start_dcycs); + log_data_ptr++; + if(log_data_ptr >= g_log_data_end_ptr) { + log_data_ptr = g_log_data_start_ptr; + data_wrap++; + } + } + dbank = (log_pc_ptr->dbank_kpc >> 24) & 0xff; + kpc = log_pc_ptr->dbank_kpc & 0xffffff; + instr = log_pc_ptr->instr; + psr = (log_pc_ptr->psr_acc >> 16) & 0xffff;; + acc = log_pc_ptr->psr_acc & 0xffff;; + xreg = (log_pc_ptr->xreg_yreg >> 16) & 0xffff;; + yreg = log_pc_ptr->xreg_yreg & 0xffff;; + stack = (log_pc_ptr->stack_direct >> 16) & 0xffff;; + direct = log_pc_ptr->stack_direct & 0xffff;; + + num = log_pc_ptr - g_log_pc_start_ptr; + + accsize = 2; + xsize = 2; + if(psr & 0x20) { + accsize = 1; + } + if(psr & 0x10) { + xsize = 1; + } + + fprintf(pcfile, "%04x: A:%04x X:%04x Y:%04x P:%03x " + "S:%04x D:%04x B:%02x %9.2f ", i, + acc, xreg, yreg, psr, stack, direct, dbank, + (dcycs-start_dcycs)); + + do_dis(pcfile, kpc, accsize, xsize, 1, instr); + log_pc_ptr++; + if(log_pc_ptr >= g_log_pc_end_ptr) { + log_pc_ptr = g_log_pc_start_ptr; + } + } + + fclose(pcfile); +} + + +#define TOOLBOX_LOG_LEN 64 + +int g_toolbox_log_pos = 0; +word32 g_toolbox_log_array[TOOLBOX_LOG_LEN][8]; + +word32 +toolbox_debug_4byte(word32 addr) +{ + word32 part1, part2; + + /* If addr looks safe, use it */ + if(addr > 0xbffc) { + return (word32)-1; + } + + part1 = get_memory16_c(addr, 0); + part1 = (part1 >> 8) + ((part1 & 0xff) << 8); + part2 = get_memory16_c(addr+2, 0); + part2 = (part2 >> 8) + ((part2 & 0xff) << 8); + + return (part1 << 16) + part2; +} + +void +toolbox_debug_c(word32 xreg, word32 stack, double *cyc_ptr) +{ + int pos; + + pos = g_toolbox_log_pos; + + stack += 9; g_toolbox_log_array[pos][0] = (word32)(g_last_vbl_dcycs + *cyc_ptr); - g_toolbox_log_array[pos][1] = stack+1; - g_toolbox_log_array[pos][2] = xreg; - g_toolbox_log_array[pos][3] = toolbox_debug_4byte(stack+1); - g_toolbox_log_array[pos][4] = toolbox_debug_4byte(stack+5); - g_toolbox_log_array[pos][5] = toolbox_debug_4byte(stack+9); - g_toolbox_log_array[pos][6] = toolbox_debug_4byte(stack+13); - g_toolbox_log_array[pos][7] = toolbox_debug_4byte(stack+17); - - pos++; - if(pos >= TOOLBOX_LOG_LEN) { - pos = 0; - } - - g_toolbox_log_pos = pos; -} - -void -show_toolbox_log() -{ - int pos; - int i; - - pos = g_toolbox_log_pos; - - for(i = TOOLBOX_LOG_LEN - 1; i >= 0; i--) { - printf("%2d:%2d: %08x %06x %04x: %08x %08x %08x %08x %08x\n", - i, pos, - g_toolbox_log_array[pos][0], - g_toolbox_log_array[pos][1], - g_toolbox_log_array[pos][2], - g_toolbox_log_array[pos][3], - g_toolbox_log_array[pos][4], - g_toolbox_log_array[pos][5], - g_toolbox_log_array[pos][6], - g_toolbox_log_array[pos][7]); - pos++; - if(pos >= TOOLBOX_LOG_LEN) { - pos = 0; - } - } -} - -#if 0 -/* get_memory_c is not used, get_memory_asm is, but this does what the */ -/* assembly language would do */ -word32 -get_memory_c(word32 loc, int diff_cycles) -{ - byte *addr; - word32 result; - int index; - -#ifdef CHECK_BREAKPOINTS - check_breakpoints_c(loc); -#endif - - index = loc >> 8; - result = page_info[index].rd; - if(result & BANK_IO_BIT) { - return get_memory_io(loc, diff_cycles); - } - - addr = (byte *)((result & 0xffffff00) + (loc & 0xff)); - - return *addr; -} -#endif - - -word32 -get_memory_io(word32 loc, double *cyc_ptr) -{ - int tmp; - - if(loc > 0xffffff) { - halt_printf("get_memory_io:%08x out of range==halt!\n", loc); - return 0; - } - tmp = loc & 0xfef000; - if(tmp == 0xc000 || tmp == 0xe0c000) { - return(io_read(loc & 0xfff, cyc_ptr)); - } - - /* Else it's an illegal addr...skip if memory sizing */ - if(loc >= g_mem_size_total) { - if((loc & 0xfffe) == 0) { -#if 0 - printf("get_io assuming mem sizing, not halting\n"); -#endif - return 0; - } - } - - /* Skip reads to f80000 and f00000, just return 0 */ - if((loc & 0xf70000) == 0xf00000) { - return 0; - } - - if((loc & 0xff0000) == 0xef0000) { - /* DOC RAM */ - return (doc_ram[loc & 0xffff]); - } - - g_code_yellow++; - if(g_ignore_bad_acc && !g_user_halt_bad) { - /* print no message, just get out. User doesn't want */ - /* to be bothered by buggy programs */ - return 0; - } - - printf("get_memory_io for addr: %06x\n", loc); - printf("stat for addr: %06x = %p\n", loc, - GET_PAGE_INFO_RD((loc >> 8) & 0xffff)); - set_halt(g_halt_on_bad_read | g_user_halt_bad); - - return 0; -} - -#if 0 -word32 -get_memory16_pieces(word32 loc, int diff_cycles) -{ - return(get_memory_c(loc, diff_cycles) + - (get_memory_c(loc+1, diff_cycles) << 8)); -} - -word32 -get_memory24(word32 loc, int diff_cycles) -{ - return(get_memory_c(loc, diff_cycles) + - (get_memory_c(loc+1, diff_cycles) << 8) + - (get_memory_c(loc+2, diff_cycles) << 16)); -} -#endif - -#if 0 -void -set_memory(word32 loc, int val, int diff_cycles) -{ - byte *ptr; - word32 new_addr; - word32 tmp; - word32 or_val; - int or_pos; - int old_slow_val; - -#ifdef CHECK_BREAKPOINTS - check_breakpoints_c(loc); -#endif - - tmp = GET_PAGE_INFO_WR((loc>>8) & 0xffff); - if(tmp & BANK_IO) { - set_memory_io(loc, val, diff_cycles); - return; - } - - if((loc & 0xfef000) == 0xe0c000) { - printf("set_memory_special: non-io for addr %08x, %02x, %d\n", - loc, val, diff_cycles); - halt_printf("tmp: %08x\n", tmp); - } - - ptr = (byte *)(tmp & (~0xff)); - - new_addr = loc & 0xffff; - old_slow_val = val; - - if(tmp & BANK_SHADOW) { - old_slow_val = g_slow_memory_ptr[new_addr]; - } else if(tmp & BANK_SHADOW2) { - new_addr += 0x10000; - old_slow_val = g_slow_memory_ptr[new_addr]; - } - - if(old_slow_val != val) { - g_slow_memory_ptr[new_addr] = val; - or_pos = (new_addr >> SHIFT_PER_CHANGE) & 0x1f; - or_val = DEP1(1, or_pos, 0); - if((new_addr >> CHANGE_SHIFT) >= SLOW_MEM_CH_SIZE) { - printf("new_addr: %08x\n", new_addr); - exit(12); - } - slow_mem_changed[(new_addr & 0xffff) >> CHANGE_SHIFT] |= or_val; - } - - ptr[loc & 0xff] = val; - -} -#endif - -void -set_memory_io(word32 loc, int val, double *cyc_ptr) -{ - word32 tmp; - tmp = loc & 0xfef000; - if(tmp == 0xc000 || tmp == 0xe0c000) { - io_write(loc, val, cyc_ptr); - return; - } - - /* Else it's an illegal addr */ - if(loc >= g_mem_size_total) { - if((loc & 0xfffe) == 0) { -#if 0 - printf("set_io assuming mem sizing, not halting\n"); -#endif - return; - } - } - - /* ignore writes to ROM */ - if((loc & 0xfc0000) == 0xfc0000) { - return; - } - - if((loc & 0xff0000) == 0xef0000) { - /* DOC RAM */ - doc_ram[loc & 0xffff] = val; - return; - } - - if(g_ignore_bad_acc && !g_user_halt_bad) { - /* print no message, just get out. User doesn't want */ - /* to be bothered by buggy programs */ - return; - } - - if((loc & 0xffc000) == 0x00c000) { - printf("set_memory %06x = %02x, warning\n", loc, val); - return; - } - - halt_printf("set_memory %06x = %02x, stopping\n", loc, val); - - return; -} - - -#if 0 -void -check_breakpoints_c(word32 loc) -{ - int index; - int count; - int i; - - index = (loc & (MAX_BP_INDEX-1)); - count = breakpoints[index].count; - if(count) { - for(i = 0; i < count; i++) { - if(loc == breakpoints[index].addrs[i]) { - halt_printf("Write hit breakpoint %d!\n", i); - } - } - } -} -#endif - - -void -show_regs_act(Engine_reg *eptr) -{ - int tmp_acc, tmp_x, tmp_y, tmp_psw; - int kpc; - int direct_page, dbank; - int stack; - - kpc = eptr->kpc; - tmp_acc = eptr->acc; - direct_page = eptr->direct; - dbank = eptr->dbank; - stack = eptr->stack; - - tmp_x = eptr->xreg; - tmp_y = eptr->yreg; - - tmp_psw = eptr->psr; - - printf(" PC=%02x.%04x A=%04x X=%04x Y=%04x P=%03x", - kpc>>16, kpc & 0xffff ,tmp_acc,tmp_x,tmp_y,tmp_psw); - printf(" S=%04x D=%04x B=%02x,cyc:%.3f\n", stack, direct_page, - dbank, g_cur_dcycs); -} - -void -show_regs() -{ - show_regs_act(&engine); -} - + g_toolbox_log_array[pos][1] = stack+1; + g_toolbox_log_array[pos][2] = xreg; + g_toolbox_log_array[pos][3] = toolbox_debug_4byte(stack+1); + g_toolbox_log_array[pos][4] = toolbox_debug_4byte(stack+5); + g_toolbox_log_array[pos][5] = toolbox_debug_4byte(stack+9); + g_toolbox_log_array[pos][6] = toolbox_debug_4byte(stack+13); + g_toolbox_log_array[pos][7] = toolbox_debug_4byte(stack+17); + + pos++; + if(pos >= TOOLBOX_LOG_LEN) { + pos = 0; + } + + g_toolbox_log_pos = pos; +} + +void +show_toolbox_log() +{ + int pos; + int i; + + pos = g_toolbox_log_pos; + + for(i = TOOLBOX_LOG_LEN - 1; i >= 0; i--) { + printf("%2d:%2d: %08x %06x %04x: %08x %08x %08x %08x %08x\n", + i, pos, + g_toolbox_log_array[pos][0], + g_toolbox_log_array[pos][1], + g_toolbox_log_array[pos][2], + g_toolbox_log_array[pos][3], + g_toolbox_log_array[pos][4], + g_toolbox_log_array[pos][5], + g_toolbox_log_array[pos][6], + g_toolbox_log_array[pos][7]); + pos++; + if(pos >= TOOLBOX_LOG_LEN) { + pos = 0; + } + } +} + +#if 0 +/* get_memory_c is not used, get_memory_asm is, but this does what the */ +/* assembly language would do */ +word32 +get_memory_c(word32 loc, int diff_cycles) +{ + byte *addr; + word32 result; + int index; + +#ifdef CHECK_BREAKPOINTS + check_breakpoints_c(loc); +#endif + + index = loc >> 8; + result = page_info[index].rd; + if(result & BANK_IO_BIT) { + return get_memory_io(loc, diff_cycles); + } + + addr = (byte *)((result & 0xffffff00) + (loc & 0xff)); + + return *addr; +} +#endif + + +word32 +get_memory_io(word32 loc, double *cyc_ptr) +{ + int tmp; + + if(loc > 0xffffff) { + halt_printf("get_memory_io:%08x out of range==halt!\n", loc); + return 0; + } + tmp = loc & 0xfef000; + if(tmp == 0xc000 || tmp == 0xe0c000) { + return(io_read(loc & 0xfff, cyc_ptr)); + } + + /* Else it's an illegal addr...skip if memory sizing */ + if(loc >= g_mem_size_total) { + if((loc & 0xfffe) == 0) { +#if 0 + printf("get_io assuming mem sizing, not halting\n"); +#endif + return 0; + } + } + + /* Skip reads to f80000 and f00000, just return 0 */ + if((loc & 0xf70000) == 0xf00000) { + return 0; + } + + if((loc & 0xff0000) == 0xef0000) { + /* DOC RAM */ + return (doc_ram[loc & 0xffff]); + } + + g_code_yellow++; + if(g_ignore_bad_acc && !g_user_halt_bad) { + /* print no message, just get out. User doesn't want */ + /* to be bothered by buggy programs */ + return 0; + } + + printf("get_memory_io for addr: %06x\n", loc); + printf("stat for addr: %06x = %p\n", loc, + GET_PAGE_INFO_RD((loc >> 8) & 0xffff)); + set_halt(g_halt_on_bad_read | g_user_halt_bad); + + return 0; +} + +#if 0 +word32 +get_memory16_pieces(word32 loc, int diff_cycles) +{ + return(get_memory_c(loc, diff_cycles) + + (get_memory_c(loc+1, diff_cycles) << 8)); +} + +word32 +get_memory24(word32 loc, int diff_cycles) +{ + return(get_memory_c(loc, diff_cycles) + + (get_memory_c(loc+1, diff_cycles) << 8) + + (get_memory_c(loc+2, diff_cycles) << 16)); +} +#endif + +#if 0 +void +set_memory(word32 loc, int val, int diff_cycles) +{ + byte *ptr; + word32 new_addr; + word32 tmp; + word32 or_val; + int or_pos; + int old_slow_val; + +#ifdef CHECK_BREAKPOINTS + check_breakpoints_c(loc); +#endif + + tmp = GET_PAGE_INFO_WR((loc>>8) & 0xffff); + if(tmp & BANK_IO) { + set_memory_io(loc, val, diff_cycles); + return; + } + + if((loc & 0xfef000) == 0xe0c000) { + printf("set_memory_special: non-io for addr %08x, %02x, %d\n", + loc, val, diff_cycles); + halt_printf("tmp: %08x\n", tmp); + } + + ptr = (byte *)(tmp & (~0xff)); + + new_addr = loc & 0xffff; + old_slow_val = val; + + if(tmp & BANK_SHADOW) { + old_slow_val = g_slow_memory_ptr[new_addr]; + } else if(tmp & BANK_SHADOW2) { + new_addr += 0x10000; + old_slow_val = g_slow_memory_ptr[new_addr]; + } + + if(old_slow_val != val) { + g_slow_memory_ptr[new_addr] = val; + or_pos = (new_addr >> SHIFT_PER_CHANGE) & 0x1f; + or_val = DEP1(1, or_pos, 0); + if((new_addr >> CHANGE_SHIFT) >= SLOW_MEM_CH_SIZE) { + printf("new_addr: %08x\n", new_addr); + exit(12); + } + slow_mem_changed[(new_addr & 0xffff) >> CHANGE_SHIFT] |= or_val; + } + + ptr[loc & 0xff] = val; + +} +#endif + +void +set_memory_io(word32 loc, int val, double *cyc_ptr) +{ + word32 tmp; + tmp = loc & 0xfef000; + if(tmp == 0xc000 || tmp == 0xe0c000) { + io_write(loc, val, cyc_ptr); + return; + } + + /* Else it's an illegal addr */ + if(loc >= g_mem_size_total) { + if((loc & 0xfffe) == 0) { +#if 0 + printf("set_io assuming mem sizing, not halting\n"); +#endif + return; + } + } + + /* ignore writes to ROM */ + if((loc & 0xfc0000) == 0xfc0000) { + return; + } + + if((loc & 0xff0000) == 0xef0000) { + /* DOC RAM */ + doc_ram[loc & 0xffff] = val; + return; + } + + if(g_ignore_bad_acc && !g_user_halt_bad) { + /* print no message, just get out. User doesn't want */ + /* to be bothered by buggy programs */ + return; + } + + if((loc & 0xffc000) == 0x00c000) { + printf("set_memory %06x = %02x, warning\n", loc, val); + return; + } + + halt_printf("set_memory %06x = %02x, stopping\n", loc, val); + + return; +} + + +#if 0 +void +check_breakpoints_c(word32 loc) +{ + int index; + int count; + int i; + + index = (loc & (MAX_BP_INDEX-1)); + count = breakpoints[index].count; + if(count) { + for(i = 0; i < count; i++) { + if(loc == breakpoints[index].addrs[i]) { + halt_printf("Write hit breakpoint %d!\n", i); + } + } + } +} +#endif + + +void +show_regs_act(Engine_reg *eptr) +{ + int tmp_acc, tmp_x, tmp_y, tmp_psw; + int kpc; + int direct_page, dbank; + int stack; + + kpc = eptr->kpc; + tmp_acc = eptr->acc; + direct_page = eptr->direct; + dbank = eptr->dbank; + stack = eptr->stack; + + tmp_x = eptr->xreg; + tmp_y = eptr->yreg; + + tmp_psw = eptr->psr; + + printf(" PC=%02x.%04x A=%04x X=%04x Y=%04x P=%03x", + kpc>>16, kpc & 0xffff ,tmp_acc,tmp_x,tmp_y,tmp_psw); + printf(" S=%04x D=%04x B=%02x,cyc:%.3f\n", stack, direct_page, + dbank, g_cur_dcycs); +} + +void +show_regs() +{ + show_regs_act(&engine); +} + //OG for regular exit, use quitEmulator() void quitEmulator() -{ +{ printf("set_halt(HALT_WANTTOQUIT)\n"); set_halt(HALT_WANTTOQUIT); } @@ -723,163 +731,164 @@ void quitEmulator() #define fatalExit exit #else extern void fatalExit(int); -#endif +#endif void my_exit(int ret) { end_screen(); - printer_close(); + imagewriter_close(); + printer_close(); printf("exiting (ret=%d)\n",ret); fatalExit(ret); -} - - -void -do_reset() -{ - - // OG Cleared remaining IRQS on RESET - extern int g_irq_pending; - extern int g_scan_int_events ; - extern int g_c023_val; - - g_c068_statereg = 0x08 + 0x04 + 0x01; /* rdrom, lcbank2, intcx */ - g_c035_shadow_reg = 0; - - g_c08x_wrdefram = 1; - g_c02d_int_crom = 0; - g_c023_val = 0; - g_c041_val = 0; - - engine.psr = (engine.psr | 0x134) & ~(0x08); - engine.stack = 0x100 + (engine.stack & 0xff); - engine.dbank = 0; - engine.direct = 0; - engine.xreg &= 0xff; - engine.yreg &= 0xff; - g_wait_pending = 0; - g_stp_pending = 0; - - - video_reset(); - adb_reset(); - iwm_reset(); - scc_reset(); - sound_reset(g_cur_dcycs); - setup_pageinfo(); - change_display_mode(g_cur_dcycs); - - g_irq_pending = 0; - - engine.kpc = get_memory16_c(0x00fffc, 0); - - g_stepping = 0; - +} + + +void +do_reset() +{ + + // OG Cleared remaining IRQS on RESET + extern int g_irq_pending; + extern int g_scan_int_events ; + extern int g_c023_val; + + g_c068_statereg = 0x08 + 0x04 + 0x01; /* rdrom, lcbank2, intcx */ + g_c035_shadow_reg = 0; + + g_c08x_wrdefram = 1; + g_c02d_int_crom = 0; + g_c023_val = 0; + g_c041_val = 0; + + engine.psr = (engine.psr | 0x134) & ~(0x08); + engine.stack = 0x100 + (engine.stack & 0xff); + engine.dbank = 0; + engine.direct = 0; + engine.xreg &= 0xff; + engine.yreg &= 0xff; + g_wait_pending = 0; + g_stp_pending = 0; + + + video_reset(); + adb_reset(); + iwm_reset(); + scc_reset(); + sound_reset(g_cur_dcycs); + setup_pageinfo(); + change_display_mode(g_cur_dcycs); + + g_irq_pending = 0; + + engine.kpc = get_memory16_c(0x00fffc, 0); + + g_stepping = 0; + if (g_irq_pending) halt_printf("*** irq remainings...\n"); -} - -#define CHECK(start, var, value, var1, var2) \ - var2 = PTR2WORD(&(var)); \ - var1 = PTR2WORD((start)); \ - if((var2 - var1) != value) { \ - printf("CHECK: " #var " is 0x%x, but " #value " is 0x%x\n", \ - (var2 - var1), value); \ - exit(5); \ - } - -void -check_engine_asm_defines() -{ - Fplus fplus; - Fplus *fplusptr; - Pc_log pclog; - Pc_log *pcptr; - Engine_reg ereg; - Engine_reg *eptr; - word32 val1; - word32 val2; - - eptr = &ereg; - CHECK(eptr, eptr->fcycles, ENGINE_FCYCLES, val1, val2); - CHECK(eptr, eptr->fplus_ptr, ENGINE_FPLUS_PTR, val1, val2); - CHECK(eptr, eptr->acc, ENGINE_REG_ACC, val1, val2); - CHECK(eptr, eptr->xreg, ENGINE_REG_XREG, val1, val2); - CHECK(eptr, eptr->yreg, ENGINE_REG_YREG, val1, val2); - CHECK(eptr, eptr->stack, ENGINE_REG_STACK, val1, val2); - CHECK(eptr, eptr->dbank, ENGINE_REG_DBANK, val1, val2); - CHECK(eptr, eptr->direct, ENGINE_REG_DIRECT, val1, val2); - CHECK(eptr, eptr->psr, ENGINE_REG_PSR, val1, val2); - CHECK(eptr, eptr->kpc, ENGINE_REG_KPC, val1, val2); - - pcptr = &pclog; - CHECK(pcptr, pcptr->dbank_kpc, LOG_PC_DBANK_KPC, val1, val2); - CHECK(pcptr, pcptr->instr, LOG_PC_INSTR, val1, val2); - CHECK(pcptr, pcptr->psr_acc, LOG_PC_PSR_ACC, val1, val2); - CHECK(pcptr, pcptr->xreg_yreg, LOG_PC_XREG_YREG, val1, val2); - CHECK(pcptr, pcptr->stack_direct, LOG_PC_STACK_DIRECT, val1, val2); - if(LOG_PC_SIZE != sizeof(pclog)) { - printf("LOG_PC_SIZE: %d != sizeof=%d\n", LOG_PC_SIZE, - (int)sizeof(pclog)); - exit(2); - } - - fplusptr = &fplus; - CHECK(fplusptr, fplusptr->plus_1, FPLUS_PLUS_1, val1, val2); - CHECK(fplusptr, fplusptr->plus_2, FPLUS_PLUS_2, val1, val2); - CHECK(fplusptr, fplusptr->plus_3, FPLUS_PLUS_3, val1, val2); - CHECK(fplusptr, fplusptr->plus_x_minus_1, FPLUS_PLUS_X_M1, val1, val2); -} - -byte * -memalloc_align(int size, int skip_amt, void **alloc_ptr) -{ - byte *bptr; - word32 addr; - word32 offset; - - skip_amt = MAX(256, skip_amt); +} + +#define CHECK(start, var, value, var1, var2) \ + var2 = PTR2WORD(&(var)); \ + var1 = PTR2WORD((start)); \ + if((var2 - var1) != value) { \ + printf("CHECK: " #var " is 0x%x, but " #value " is 0x%x\n", \ + (var2 - var1), value); \ + exit(5); \ + } + +void +check_engine_asm_defines() +{ + Fplus fplus; + Fplus *fplusptr; + Pc_log pclog; + Pc_log *pcptr; + Engine_reg ereg; + Engine_reg *eptr; + word32 val1; + word32 val2; + + eptr = &ereg; + CHECK(eptr, eptr->fcycles, ENGINE_FCYCLES, val1, val2); + CHECK(eptr, eptr->fplus_ptr, ENGINE_FPLUS_PTR, val1, val2); + CHECK(eptr, eptr->acc, ENGINE_REG_ACC, val1, val2); + CHECK(eptr, eptr->xreg, ENGINE_REG_XREG, val1, val2); + CHECK(eptr, eptr->yreg, ENGINE_REG_YREG, val1, val2); + CHECK(eptr, eptr->stack, ENGINE_REG_STACK, val1, val2); + CHECK(eptr, eptr->dbank, ENGINE_REG_DBANK, val1, val2); + CHECK(eptr, eptr->direct, ENGINE_REG_DIRECT, val1, val2); + CHECK(eptr, eptr->psr, ENGINE_REG_PSR, val1, val2); + CHECK(eptr, eptr->kpc, ENGINE_REG_KPC, val1, val2); + + pcptr = &pclog; + CHECK(pcptr, pcptr->dbank_kpc, LOG_PC_DBANK_KPC, val1, val2); + CHECK(pcptr, pcptr->instr, LOG_PC_INSTR, val1, val2); + CHECK(pcptr, pcptr->psr_acc, LOG_PC_PSR_ACC, val1, val2); + CHECK(pcptr, pcptr->xreg_yreg, LOG_PC_XREG_YREG, val1, val2); + CHECK(pcptr, pcptr->stack_direct, LOG_PC_STACK_DIRECT, val1, val2); + if(LOG_PC_SIZE != sizeof(pclog)) { + printf("LOG_PC_SIZE: %d != sizeof=%d\n", LOG_PC_SIZE, + (int)sizeof(pclog)); + exit(2); + } + + fplusptr = &fplus; + CHECK(fplusptr, fplusptr->plus_1, FPLUS_PLUS_1, val1, val2); + CHECK(fplusptr, fplusptr->plus_2, FPLUS_PLUS_2, val1, val2); + CHECK(fplusptr, fplusptr->plus_3, FPLUS_PLUS_3, val1, val2); + CHECK(fplusptr, fplusptr->plus_x_minus_1, FPLUS_PLUS_X_M1, val1, val2); +} + +byte * +memalloc_align(int size, int skip_amt, void **alloc_ptr) +{ + byte *bptr; + word32 addr; + word32 offset; + + skip_amt = MAX(256, skip_amt); bptr = (byte*)calloc(size + skip_amt + 256, 1); // OG Added cast - if(alloc_ptr) { - /* Save allocation address */ - *alloc_ptr = bptr; - } - - addr = PTR2WORD(bptr) & 0xff; - - /* must align bptr to be 256-byte aligned */ - /* this code should work even if ptrs are > 32 bits */ - - offset = ((addr + skip_amt - 1) & (~0xff)) - addr; - - return (bptr + offset); -} - -void -memory_ptr_init() -{ - word32 mem_size; - - /* This routine may be called several times--each time the ROM file */ - /* changes this will be called */ - mem_size = MIN(0xdf0000, g_mem_size_base + g_mem_size_exp); - g_mem_size_total = mem_size; + if(alloc_ptr) { + /* Save allocation address */ + *alloc_ptr = bptr; + } + + addr = PTR2WORD(bptr) & 0xff; + + /* must align bptr to be 256-byte aligned */ + /* this code should work even if ptrs are > 32 bits */ + + offset = ((addr + skip_amt - 1) & (~0xff)) - addr; + + return (bptr + offset); +} + +void +memory_ptr_init() +{ + word32 mem_size; + + /* This routine may be called several times--each time the ROM file */ + /* changes this will be called */ + mem_size = MIN(0xdf0000, g_mem_size_base + g_mem_size_exp); + g_mem_size_total = mem_size; // OG using memory_ptr_shut() instead memory_ptr_shut(); /* - if(g_memory_alloc_ptr) { - free(g_memory_alloc_ptr); - g_memory_alloc_ptr = 0; - } + if(g_memory_alloc_ptr) { + free(g_memory_alloc_ptr); + g_memory_alloc_ptr = 0; + } */ - g_memory_ptr = memalloc_align(mem_size, 256, &g_memory_alloc_ptr); - - printf("RAM size is 0 - %06x (%.2fMB)\n", mem_size, - (double)mem_size/(1024.0*1024.0)); -} - + g_memory_ptr = memalloc_align(mem_size, 256, &g_memory_alloc_ptr); + + printf("RAM size is 0 - %06x (%.2fMB)\n", mem_size, + (double)mem_size/(1024.0*1024.0)); +} + // OG Added memory_ptr_shut void memory_ptr_shut() @@ -893,24 +902,24 @@ memory_ptr_shut() } -extern int g_screen_redraw_skip_amt; -extern int g_use_shmem; -extern int g_use_dhr140; -extern int g_use_bw_hires; - -char g_display_env[512]; -int g_force_depth = -1; -int g_screen_depth = 8; - - -int -gsportmain(int argc, char **argv) -{ - int diff; - int skip_amt; - int tmp1; - int i; - char *final_arg = 0; +extern int g_screen_redraw_skip_amt; +extern int g_use_shmem; +extern int g_use_dhr140; +extern int g_use_bw_hires; + +char g_display_env[512]; +int g_force_depth = -1; +int g_screen_depth = 8; + + +int +gsportmain(int argc, char **argv) +{ + int diff; + int skip_amt; + int tmp1; + int i; + char *final_arg = 0; // OG Restoring globals sim65816_initglobals(); @@ -919,219 +928,219 @@ gsportmain(int argc, char **argv) //OG Disabling argument parsing #ifndef ACTIVEGS - /* parse args */ + /* parse args */ for(i = 1; i < argc; i++) { - if(!strcmp("-badrd", argv[i])) { - printf("Halting on bad reads\n"); - g_halt_on_bad_read = 2; - } else if(!strcmp("-noignbadacc", argv[i])) { - printf("Not ignoring bad memory accesses\n"); - g_ignore_bad_acc = 0; - } else if(!strcmp("-noignhalt", argv[i])) { - printf("Not ignoring code red halts\n"); - g_ignore_halts = 0; - } else if(!strcmp("-test", argv[i])) { - printf("Allowing testing\n"); - g_testing_enabled = 1; - } else if(!strcmp("-hpdev", argv[i])) { - printf("Using /dev/audio\n"); - g_use_alib = 0; - } else if(!strcmp("-alib", argv[i])) { - printf("Using Aserver audio server\n"); - g_use_alib = 1; - } else if(!strcmp("-24", argv[i])) { - printf("Using 24-bit visual\n"); - g_force_depth = 24; - } else if(!strcmp("-16", argv[i])) { - printf("Using 16-bit visual\n"); - g_force_depth = 16; - } else if(!strcmp("-15", argv[i])) { - printf("Using 15-bit visual\n"); - g_force_depth = 15; - } else if(!strcmp("-mem", argv[i])) { - if((i+1) >= argc) { - printf("Missing argument\n"); - exit(1); - } - g_mem_size_exp = strtol(argv[i+1], 0, 0) & 0x00ff0000; - printf("Using %d as memory size\n", g_mem_size_exp); - i++; - } else if(!strcmp("-skip", argv[i])) { - if((i+1) >= argc) { - printf("Missing argument\n"); - exit(1); - } - skip_amt = strtol(argv[i+1], 0, 0); - printf("Using %d as skip_amt\n", skip_amt); - g_screen_redraw_skip_amt = skip_amt; - i++; - } else if(!strcmp("-audio", argv[i])) { - if((i+1) >= argc) { - printf("Missing argument\n"); - exit(1); - } - tmp1 = strtol(argv[i+1], 0, 0); - printf("Using %d as audio enable val\n", tmp1); - g_audio_enable = tmp1; - i++; - } else if(!strcmp("-arate", argv[i])) { - if((i+1) >= argc) { - printf("Missing argument\n"); - exit(1); - } - tmp1 = strtol(argv[i+1], 0, 0); - printf("Using %d as preferred audio rate\n", tmp1); - g_preferred_rate = tmp1; - i++; - } else if(!strcmp("-v", argv[i])) { - if((i+1) >= argc) { - printf("Missing argument\n"); - exit(1); - } - tmp1 = strtol(argv[i+1], 0, 0); - printf("Setting Verbose = 0x%03x\n", tmp1); - Verbose = tmp1; - i++; -#ifndef __NeXT__ - } else if(!strcmp("-display", argv[i])) { - if((i+1) >= argc) { - printf("Missing argument\n"); - exit(1); - } - printf("Using %s as display\n", argv[i+1]); - sprintf(g_display_env, "DISPLAY=%s", argv[i+1]); - putenv(&g_display_env[0]); - i++; -#endif - } else if(!strcmp("-noshm", argv[i])) { - printf("Not using X shared memory\n"); - g_use_shmem = 0; - } else if(!strcmp("-joystick", argv[i])) { - printf("Ignoring -joystick option\n"); - } else if(!strcmp("-dhr140", argv[i])) { - printf("Using simple dhires color map\n"); - g_use_dhr140 = 1; - } else if(!strcmp("-bw", argv[i])) { - printf("Forcing black-and-white hires modes\n"); - g_cur_a2_stat |= ALL_STAT_COLOR_C021; - g_use_bw_hires = 1; - } else if(!strcmp("-enet", argv[i])) { - if((i+1) >= argc) { - printf("Missing argument\n"); - exit(1); - } - tmp1 = strtol(argv[i+1], 0, 0); - printf("Using %d as ethernet enable val\n", tmp1); - g_ethernet = tmp1; - i++; - } else { - if ((i == (argc - 1)) && (strncmp("-", argv[i], 1) != 0)) { - final_arg = argv[i]; - } else { - printf("Bad option: %s\n", argv[i]); - exit(3); - } - } + if(!strcmp("-badrd", argv[i])) { + printf("Halting on bad reads\n"); + g_halt_on_bad_read = 2; + } else if(!strcmp("-noignbadacc", argv[i])) { + printf("Not ignoring bad memory accesses\n"); + g_ignore_bad_acc = 0; + } else if(!strcmp("-noignhalt", argv[i])) { + printf("Not ignoring code red halts\n"); + g_ignore_halts = 0; + } else if(!strcmp("-test", argv[i])) { + printf("Allowing testing\n"); + g_testing_enabled = 1; + } else if(!strcmp("-hpdev", argv[i])) { + printf("Using /dev/audio\n"); + g_use_alib = 0; + } else if(!strcmp("-alib", argv[i])) { + printf("Using Aserver audio server\n"); + g_use_alib = 1; + } else if(!strcmp("-24", argv[i])) { + printf("Using 24-bit visual\n"); + g_force_depth = 24; + } else if(!strcmp("-16", argv[i])) { + printf("Using 16-bit visual\n"); + g_force_depth = 16; + } else if(!strcmp("-15", argv[i])) { + printf("Using 15-bit visual\n"); + g_force_depth = 15; + } else if(!strcmp("-mem", argv[i])) { + if((i+1) >= argc) { + printf("Missing argument\n"); + exit(1); + } + g_mem_size_exp = strtol(argv[i+1], 0, 0) & 0x00ff0000; + printf("Using %d as memory size\n", g_mem_size_exp); + i++; + } else if(!strcmp("-skip", argv[i])) { + if((i+1) >= argc) { + printf("Missing argument\n"); + exit(1); + } + skip_amt = strtol(argv[i+1], 0, 0); + printf("Using %d as skip_amt\n", skip_amt); + g_screen_redraw_skip_amt = skip_amt; + i++; + } else if(!strcmp("-audio", argv[i])) { + if((i+1) >= argc) { + printf("Missing argument\n"); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); + printf("Using %d as audio enable val\n", tmp1); + g_audio_enable = tmp1; + i++; + } else if(!strcmp("-arate", argv[i])) { + if((i+1) >= argc) { + printf("Missing argument\n"); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); + printf("Using %d as preferred audio rate\n", tmp1); + g_preferred_rate = tmp1; + i++; + } else if(!strcmp("-v", argv[i])) { + if((i+1) >= argc) { + printf("Missing argument\n"); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); + printf("Setting Verbose = 0x%03x\n", tmp1); + Verbose = tmp1; + i++; +#ifndef __NeXT__ + } else if(!strcmp("-display", argv[i])) { + if((i+1) >= argc) { + printf("Missing argument\n"); + exit(1); + } + printf("Using %s as display\n", argv[i+1]); + sprintf(g_display_env, "DISPLAY=%s", argv[i+1]); + putenv(&g_display_env[0]); + i++; +#endif + } else if(!strcmp("-noshm", argv[i])) { + printf("Not using X shared memory\n"); + g_use_shmem = 0; + } else if(!strcmp("-joystick", argv[i])) { + printf("Ignoring -joystick option\n"); + } else if(!strcmp("-dhr140", argv[i])) { + printf("Using simple dhires color map\n"); + g_use_dhr140 = 1; + } else if(!strcmp("-bw", argv[i])) { + printf("Forcing black-and-white hires modes\n"); + g_cur_a2_stat |= ALL_STAT_COLOR_C021; + g_use_bw_hires = 1; + } else if(!strcmp("-enet", argv[i])) { + if((i+1) >= argc) { + printf("Missing argument\n"); + exit(1); + } + tmp1 = strtol(argv[i+1], 0, 0); + printf("Using %d as ethernet enable val\n", tmp1); + g_ethernet = tmp1; + i++; + } else { + if ((i == (argc - 1)) && (strncmp("-", argv[i], 1) != 0)) { + final_arg = argv[i]; + } else { + printf("Bad option: %s\n", argv[i]); + exit(3); + } + } } -#endif - check_engine_asm_defines(); - fixed_memory_ptrs_init(); - - if(sizeof(word32) != 4) { - printf("sizeof(word32) = %d, must be 4!\n", - (int)sizeof(word32)); - exit(1); - } - - if(!g_engine_c_mode) { - diff = &defs_instr_end_8 - &defs_instr_start_8; - if(diff != 1) { - printf("defs_instr_end_8 - start is %d\n",diff); - exit(1); - } - - diff = &defs_instr_end_16 - &defs_instr_start_16; - if(diff != 1) { - printf("defs_instr_end_16 - start is %d\n", diff); - exit(1); - } - - diff = &op_routs_end - &op_routs_start; - if(diff != 1) { - printf("op_routs_end - start is %d\n", diff); - exit(1); - } - } - - iwm_init(); - config_init(); - // If the final argument was not a switch, then treat it like a disk image filename to insert - if (final_arg) { - // ...and flag it to boot - cfg_inspect_maybe_insert_file(final_arg, 1); - } - printer_init(g_printer_dpi,85,110,g_printer_output,g_printer_multipage != 0); - //If ethernet is enabled in config.gsport, let's initialize it -#ifdef HAVE_TFE - if (g_ethernet == 1) - { - int i = 0; - char *ppname = NULL; - char *ppdes = NULL; - if (tfe_enumadapter_open()) - { - //Loop through the available adapters until we reach the interface number specified in config.gsport - while(tfe_enumadapter(&ppname,&ppdes)) - { - if (i == g_ethernet_interface) break; - i++; - } - tfe_enumadapter_close(); - printf("Using host ethernet interface: %s\nUthernet support is ON.\n",ppdes); - } - else - { - printf("No ethernet host adapters found. Do you have PCap installed/enabled?\nUthernet support is OFF.\n"); - } - set_tfe_interface(ppname); //Connect the emulated ethernet device with the selected host adapter - lib_free(ppname); - lib_free(ppdes); - tfe_init(); - } -#endif - - load_roms_init_memory(); - - init_reg(); - clear_halt(); - - initialize_events(); - - video_init(); - -#ifndef _WIN32 - //sleep(1); -#endif - sound_init(); - scc_init(); - adb_init(); - joystick_init(); - if(g_rom_version >= 3) { - g_c036_val_speed |= 0x40; /* set power-on bit */ - } - - do_reset(); - g_stepping = 0; +#endif + check_engine_asm_defines(); + fixed_memory_ptrs_init(); + + if(sizeof(word32) != 4) { + printf("sizeof(word32) = %d, must be 4!\n", + (int)sizeof(word32)); + exit(1); + } + + if(!g_engine_c_mode) { + diff = &defs_instr_end_8 - &defs_instr_start_8; + if(diff != 1) { + printf("defs_instr_end_8 - start is %d\n",diff); + exit(1); + } + + diff = &defs_instr_end_16 - &defs_instr_start_16; + if(diff != 1) { + printf("defs_instr_end_16 - start is %d\n", diff); + exit(1); + } + + diff = &op_routs_end - &op_routs_start; + if(diff != 1) { + printf("op_routs_end - start is %d\n", diff); + exit(1); + } + } + + iwm_init(); + config_init(); + // If the final argument was not a switch, then treat it like a disk image filename to insert + if (final_arg) { + // ...and flag it to boot + cfg_inspect_maybe_insert_file(final_arg, 1); + } + printer_init(g_printer_dpi,85,110,g_printer_output,g_printer_multipage != 0); + //If ethernet is enabled in config.gsport, let's initialize it +#ifdef HAVE_TFE + if (g_ethernet == 1) + { + int i = 0; + char *ppname = NULL; + char *ppdes = NULL; + if (tfe_enumadapter_open()) + { + //Loop through the available adapters until we reach the interface number specified in config.gsport + while(tfe_enumadapter(&ppname,&ppdes)) + { + if (i == g_ethernet_interface) break; + i++; + } + tfe_enumadapter_close(); + printf("Using host ethernet interface: %s\nUthernet support is ON.\n",ppdes); + } + else + { + printf("No ethernet host adapters found. Do you have PCap installed/enabled?\nUthernet support is OFF.\n"); + } + set_tfe_interface(ppname); //Connect the emulated ethernet device with the selected host adapter + lib_free(ppname); + lib_free(ppdes); + tfe_init(); + } +#endif + + load_roms_init_memory(); + + init_reg(); + clear_halt(); + + initialize_events(); + + video_init(); + +#ifndef _WIN32 + //sleep(1); +#endif + sound_init(); + scc_init(); + adb_init(); + joystick_init(); + if(g_rom_version >= 3) { + g_c036_val_speed |= 0x40; /* set power-on bit */ + } + + do_reset(); + g_stepping = 0; // OG Notify emulator has been initialized and ready to accept external events g_initialized = 1; g_accept_events = 1; - do_go(); - - /* If we get here, we hit a breakpoint, call debug intfc */ - do_debug_intfc(); - + do_go(); + + /* If we get here, we hit a breakpoint, call debug intfc */ + do_debug_intfc(); + // OG Notify emulator is being closed, and cannot accept events anymore g_accept_events = 0; @@ -1149,30 +1158,30 @@ gsportmain(int argc, char **argv) //my_exit(0); end_screen(); - return 0; -} - -void -load_roms_init_memory() -{ - config_load_roms(); - memory_ptr_init(); - clk_setup_bram_version(); /* Must be after config_load_roms */ - if(g_rom_version >= 3) { - g_c036_val_speed |= 0x40; /* set power-on bit */ - } else { - g_c036_val_speed &= (~0x40); /* clear the bit */ - } - do_reset(); - - /* if user booted ROM 01, switches to ROM 03, then switches back */ - /* to ROM 01, then the reset routines call to Tool $0102 looks */ - /* at uninitialized $e1/15fe and if it is negative it will JMP */ - /* through $e1/1688 which ROM 03 left pointing to fc/0199 */ - /* So set e1/15fe = 0 */ - set_memory16_c(0xe115fe, 0, 0); -} - + return 0; +} + +void +load_roms_init_memory() +{ + config_load_roms(); + memory_ptr_init(); + clk_setup_bram_version(); /* Must be after config_load_roms */ + if(g_rom_version >= 3) { + g_c036_val_speed |= 0x40; /* set power-on bit */ + } else { + g_c036_val_speed &= (~0x40); /* clear the bit */ + } + do_reset(); + + /* if user booted ROM 01, switches to ROM 03, then switches back */ + /* to ROM 01, then the reset routines call to Tool $0102 looks */ + /* at uninitialized $e1/15fe and if it is negative it will JMP */ + /* through $e1/1688 which ROM 03 left pointing to fc/0199 */ + /* So set e1/15fe = 0 */ + set_memory16_c(0xe115fe, 0, 0); +} + // OG Added load_roms_shut_memory void load_roms_shut_memory() { @@ -1181,939 +1190,939 @@ void load_roms_shut_memory() #ifndef ACTIVEGS -void -gsport_expand_path(char *out_ptr, const char *in_ptr, int maxlen) -{ - char name_buf[256]; - char *tmp_ptr; - int name_len; - int in_char; - int state; - - out_ptr[0] = 0; - - name_len = 0; - state = 0; - - /* See if in_ptr has ${} notation, replace with getenv or argv0 */ - while(maxlen > 0) { - in_char = *in_ptr++; - *out_ptr++ = in_char; - maxlen--; - if(state == 0) { - /* No $ seen yet, look for it */ - if(in_char == '$') { - state = 1; - } - } else if(state == 1) { - /* See if next char is '{' (dummy }) */ - if(in_char == '{') { /* add dummy } */ - state = 2; - name_len = 0; - out_ptr -= 2; - } else { - state = 0; - } - } else if(state == 2) { - /* fill name_buf ... dummy '{' */ - out_ptr--; - if(in_char == '}') { - name_buf[name_len] = 0; - - /* got token, now look it up */ - tmp_ptr = ""; - if(!strncmp("0", name_buf, 128)) { - /* Replace ${0} with g_argv0_path */ - tmp_ptr = &(g_argv0_path[0]); -#if defined (_WIN32) || defined(__CYGWIN__) - } else if(!strncmp("PWD", name_buf, 128)) { - /* Replace ${PWD} with cwd in Windows */ - get_cwd(out_ptr,128); - tmp_ptr = out_ptr; -#endif - } else { - tmp_ptr = getenv(name_buf); - if(tmp_ptr == 0) { - tmp_ptr = ""; - } - } - strncpy(out_ptr, tmp_ptr, maxlen); - out_ptr += strlen(tmp_ptr); - maxlen -= strlen(tmp_ptr); - state = 0; - } else { - name_buf[name_len++] = in_char; - } - } - if(in_char == 0) { - /* make sure its null terminated */ - *out_ptr++ = 0; - break; - } - } -} - -void -setup_gsport_file(char *outname, int maxlen, int ok_if_missing, - int can_create_file, const char **name_ptr) -{ - char local_path[256]; - struct stat stat_buf; - const char **path_ptr; - const char **cur_name_ptr, **save_path_ptr; - int ret; - - outname[0] = 0; - - path_ptr = &g_gsport_default_paths[0]; - - save_path_ptr = path_ptr; - while(*path_ptr) { - gsport_expand_path(&(local_path[0]), *path_ptr, 250); - cur_name_ptr = name_ptr; - while(*cur_name_ptr) { - strcpy(outname, &(local_path[0])); - strncat(outname, *cur_name_ptr, 255-strlen(outname)); - if(!ok_if_missing) { - printf("Trying '%s'\n", outname); - } - ret = stat(outname, &stat_buf); - if(ret == 0) { - /* got it! */ - return; - } - cur_name_ptr++; - } - path_ptr++; - } - - outname[0] = 0; - if(ok_if_missing > 0) { - return; - } - - /* couldn't find it, print out all the attempts */ - path_ptr = save_path_ptr; - fatal_printf("Could not find required file \"%s\" in any of these " - "directories:\n", *name_ptr); - while(*path_ptr) { - fatal_printf(" %s\n", *path_ptr++); - } - - if(can_create_file) { - // If we didn't find a file, pick a place to put it. - // Default is the current working directory. -#ifdef MAC - gsport_expand_path(&(local_path[0]), "${0}/../config.txt", 250); -#else - gsport_expand_path(&(local_path[0]), "${PWD}/config.txt", 250); -#endif - strcpy(outname, &(local_path[0])); - // Ask user if it's OK to create the file (or just create it) - x_dialog_create_gsport_conf(*name_ptr); - can_create_file = 0; - - // But clear out the fatal_printfs first - clear_fatal_logs(); - setup_gsport_file(outname, maxlen, ok_if_missing, - can_create_file, name_ptr); - // It's one-level of recursion--it cannot loop since we - // clear can_create_file. - // If it returns, then there was succes and we should get out - return; - } else if(ok_if_missing) { - /* Just show an alert and return if ok_if_missing < 0 */ - x_show_alert(0, 0); - return; - } - - my_exit(2); -} - +void +gsport_expand_path(char *out_ptr, const char *in_ptr, int maxlen) +{ + char name_buf[256]; + char *tmp_ptr; + int name_len; + int in_char; + int state; + + out_ptr[0] = 0; + + name_len = 0; + state = 0; + + /* See if in_ptr has ${} notation, replace with getenv or argv0 */ + while(maxlen > 0) { + in_char = *in_ptr++; + *out_ptr++ = in_char; + maxlen--; + if(state == 0) { + /* No $ seen yet, look for it */ + if(in_char == '$') { + state = 1; + } + } else if(state == 1) { + /* See if next char is '{' (dummy }) */ + if(in_char == '{') { /* add dummy } */ + state = 2; + name_len = 0; + out_ptr -= 2; + } else { + state = 0; + } + } else if(state == 2) { + /* fill name_buf ... dummy '{' */ + out_ptr--; + if(in_char == '}') { + name_buf[name_len] = 0; + + /* got token, now look it up */ + tmp_ptr = ""; + if(!strncmp("0", name_buf, 128)) { + /* Replace ${0} with g_argv0_path */ + tmp_ptr = &(g_argv0_path[0]); +#if defined (_WIN32) || defined(__CYGWIN__) + } else if(!strncmp("PWD", name_buf, 128)) { + /* Replace ${PWD} with cwd in Windows */ + get_cwd(out_ptr,128); + tmp_ptr = out_ptr; +#endif + } else { + tmp_ptr = getenv(name_buf); + if(tmp_ptr == 0) { + tmp_ptr = ""; + } + } + strncpy(out_ptr, tmp_ptr, maxlen); + out_ptr += strlen(tmp_ptr); + maxlen -= strlen(tmp_ptr); + state = 0; + } else { + name_buf[name_len++] = in_char; + } + } + if(in_char == 0) { + /* make sure its null terminated */ + *out_ptr++ = 0; + break; + } + } +} + +void +setup_gsport_file(char *outname, int maxlen, int ok_if_missing, + int can_create_file, const char **name_ptr) +{ + char local_path[256]; + struct stat stat_buf; + const char **path_ptr; + const char **cur_name_ptr, **save_path_ptr; + int ret; + + outname[0] = 0; + + path_ptr = &g_gsport_default_paths[0]; + + save_path_ptr = path_ptr; + while(*path_ptr) { + gsport_expand_path(&(local_path[0]), *path_ptr, 250); + cur_name_ptr = name_ptr; + while(*cur_name_ptr) { + strcpy(outname, &(local_path[0])); + strncat(outname, *cur_name_ptr, 255-strlen(outname)); + if(!ok_if_missing) { + printf("Trying '%s'\n", outname); + } + ret = stat(outname, &stat_buf); + if(ret == 0) { + /* got it! */ + return; + } + cur_name_ptr++; + } + path_ptr++; + } + + outname[0] = 0; + if(ok_if_missing > 0) { + return; + } + + /* couldn't find it, print out all the attempts */ + path_ptr = save_path_ptr; + fatal_printf("Could not find required file \"%s\" in any of these " + "directories:\n", *name_ptr); + while(*path_ptr) { + fatal_printf(" %s\n", *path_ptr++); + } + + if(can_create_file) { + // If we didn't find a file, pick a place to put it. + // Default is the current working directory. +#ifdef MAC + gsport_expand_path(&(local_path[0]), "${0}/../config.txt", 250); +#else + gsport_expand_path(&(local_path[0]), "${PWD}/config.txt", 250); +#endif + strcpy(outname, &(local_path[0])); + // Ask user if it's OK to create the file (or just create it) + x_dialog_create_gsport_conf(*name_ptr); + can_create_file = 0; + + // But clear out the fatal_printfs first + clear_fatal_logs(); + setup_gsport_file(outname, maxlen, ok_if_missing, + can_create_file, name_ptr); + // It's one-level of recursion--it cannot loop since we + // clear can_create_file. + // If it returns, then there was succes and we should get out + return; + } else if(ok_if_missing) { + /* Just show an alert and return if ok_if_missing < 0 */ + x_show_alert(0, 0); + return; + } + + my_exit(2); +} + #endif -Event g_event_list[MAX_EVENTS]; -Event g_event_free; -Event g_event_start; - -void -initialize_events() -{ - int i; - - for(i = 1; i < MAX_EVENTS; i++) { - g_event_list[i-1].next = &g_event_list[i]; - } - g_event_free.next = &g_event_list[0]; - g_event_list[MAX_EVENTS-1].next = 0; - - g_event_start.next = 0; - g_event_start.dcycs = 0.0; - - add_event_entry(DCYCS_IN_16MS, EV_60HZ); -} - -void -check_for_one_event_type(int type) -{ - Event *ptr; - int count; - int depth; - - count = 0; - depth = 0; - ptr = g_event_start.next; - while(ptr != 0) { - depth++; - if(ptr->type == type) { - count++; - if(count != 1) { - halt_printf("in check_for_1, type %d found at " - "depth: %d, count: %d, at %f\n", - type, depth, count, ptr->dcycs); - } - } - ptr = ptr->next; - } -} - - -void -add_event_entry(double dcycs, int type) -{ - Event *this_event; - Event *ptr, *prev_ptr; - int tmp_type; - int done; - - this_event = g_event_free.next; - if(this_event == 0) { - halt_printf("Out of queue entries!\n"); - show_all_events(); - return; - } - g_event_free.next = this_event->next; - - this_event->type = type; - - tmp_type = type & 0xff; - if((dcycs < 0.0) || (dcycs > (g_cur_dcycs + 50*1000*1000.0)) || - ((dcycs < g_cur_dcycs) && (tmp_type != EV_SCAN_INT))) { - halt_printf("add_event: dcycs: %f, type:%05x, cur_dcycs: %f!\n", - dcycs, type, g_cur_dcycs); - dcycs = g_cur_dcycs + 1000.0; - } - - ptr = g_event_start.next; - if(ptr && (dcycs < ptr->dcycs)) { - /* create event before next expected event */ - /* do this by setting HALT_EVENT */ - set_halt(HALT_EVENT); - } - - prev_ptr = &g_event_start; - ptr = g_event_start.next; - - done = 0; - while(!done) { - if(ptr == 0) { - this_event->next = ptr; - this_event->dcycs = dcycs; - prev_ptr->next = this_event; - return; - } else { - if(ptr->dcycs < dcycs) { - /* step across this guy */ - prev_ptr = ptr; - ptr = ptr->next; - } else { - /* go in front of this guy */ - this_event->dcycs = dcycs; - this_event->next = ptr; - prev_ptr->next = this_event; - return; - } - } - } -} - -extern int g_doc_saved_ctl; - -double -remove_event_entry(int type) -{ - Event *ptr, *prev_ptr; - Event *next_ptr; - - ptr = g_event_start.next; - prev_ptr = &g_event_start; - - while(ptr != 0) { - if((ptr->type & 0xffff) == type) { - /* got it, remove it */ - next_ptr = ptr->next; - prev_ptr->next = next_ptr; - - /* Add ptr to free list */ - ptr->next = g_event_free.next; - g_event_free.next = ptr; - - return ptr->dcycs; - } - prev_ptr = ptr; - ptr = ptr->next; - } - - halt_printf("remove event_entry: %08x, but not found!\n", type); - if((type & 0xff) == EV_DOC_INT) { - printf("DOC, g_doc_saved_ctl = %02x\n", g_doc_saved_ctl); - } -#ifdef HPUX - U_STACK_TRACE(); -#endif - show_all_events(); - - return 0.0; -} - -void -add_event_stop(double dcycs) -{ - add_event_entry(dcycs, EV_STOP); -} - -void -add_event_doc(double dcycs, int osc) -{ - if(dcycs < g_cur_dcycs) { - dcycs = g_cur_dcycs; -#if 0 - halt_printf("add_event_doc: dcycs: %f, cur_dcycs: %f\n", - dcycs, g_cur_dcycs); -#endif - } - - add_event_entry(dcycs, EV_DOC_INT + (osc << 8)); -} - -void -add_event_scc(double dcycs, int type) -{ - if(dcycs < g_cur_dcycs) { - dcycs = g_cur_dcycs; - } - - add_event_entry(dcycs, EV_SCC + (type << 8)); -} - -void -add_event_vbl() -{ - double dcycs; - - dcycs = g_last_vbl_dcycs + (DCYCS_IN_16MS * (192.0/262.0)); - add_event_entry(dcycs, EV_VBL_INT); -} - -void -add_event_vid_upd(int line) -{ - double dcycs; - - dcycs = g_last_vbl_dcycs + ((DCYCS_IN_16MS * line) / 262.0); - add_event_entry(dcycs, EV_VID_UPD + (line << 8)); -} - -double -remove_event_doc(int osc) -{ - return remove_event_entry(EV_DOC_INT + (osc << 8)); -} - -double -remove_event_scc(int type) -{ - return remove_event_entry(EV_SCC + (type << 8)); -} - -void -show_all_events() -{ - Event *ptr; - int count; - double dcycs; - - count = 0; - ptr = g_event_start.next; - while(ptr != 0) { - dcycs = ptr->dcycs; - printf("Event: %02x: type: %05x, dcycs: %f (%f)\n", - count, ptr->type, dcycs, dcycs - g_cur_dcycs); - ptr = ptr->next; - count++; - } - -} - -word32 g_vbl_count = 0; -int g_vbl_index_count = 0; -double dtime_array[60]; -double g_dadjcycs_array[60]; -double g_dtime_diff3_array[60]; -double g_dtime_this_vbl_array[60]; -double g_dtime_exp_array[60]; -double g_dtime_pmhz_array[60]; -double g_dtime_eff_pmhz_array[60]; -int g_limit_speed = 2; -double sim_time[60]; -double g_sim_sum = 0.0; - -double g_cur_sim_dtime = 0.0; -double g_projected_pmhz = 1.0; -double g_zip_pmhz = 8.0; -double g_sim_mhz = 100.0; -int g_line_ref_amt = 1; -int g_video_line_update_interval = 0; - -Fplus g_recip_projected_pmhz_slow; -Fplus g_recip_projected_pmhz_fast; -Fplus g_recip_projected_pmhz_zip; -Fplus g_recip_projected_pmhz_unl; - -void -show_pmhz() -{ - printf("Pmhz: %f, c036:%02x, limit: %d\n", - g_projected_pmhz, g_c036_val_speed, g_limit_speed); - -} - -void -setup_zip_speeds() -{ - double frecip; - double fmhz; - int mult; - - mult = 16 - ((g_zipgs_reg_c05a >> 4) & 0xf); - // 16 = full speed, 1 = 1/16th speed - fmhz = (8.0 * mult) / 16.0; -#if 0 - if(mult == 16) { - /* increase full speed by 19% to make zipgs freq measuring */ - /* programs work correctly */ - fmhz = fmhz * 1.19; - } -#endif - frecip = 1.0 / fmhz; - g_zip_pmhz = fmhz; - g_recip_projected_pmhz_zip.plus_1 = frecip; - g_recip_projected_pmhz_zip.plus_2 = 2.0 * frecip; - g_recip_projected_pmhz_zip.plus_3 = 3.0 * frecip; - if(frecip >= 0.5) { - g_recip_projected_pmhz_zip.plus_x_minus_1 = 1.01; - } else { - g_recip_projected_pmhz_zip.plus_x_minus_1 = 1.01 - frecip; - } -} - -void -run_prog() -{ - Fplus *fplus_ptr; - Event *this_event; - Event *db1; - double dcycs; - double now_dtime; - double prev_dtime; - double prerun_fcycles; - double fspeed_mult; - double fcycles_stop; - word32 ret; - word32 zip_speed_0tof, zip_speed_0tof_new; - int zip_en, zip_follow_cps; - int type; - int motor_on; - int iwm_1; - int iwm_25; - int limit_speed; - int apple35_sel; - int fast, zip_speed, faster_than_28, unl_speed; - int this_type; - - fflush(stdout); - - g_cur_sim_dtime = 0.0; - - g_recip_projected_pmhz_slow.plus_1 = 1.0; - g_recip_projected_pmhz_slow.plus_2 = 2.0; - g_recip_projected_pmhz_slow.plus_3 = 3.0; - g_recip_projected_pmhz_slow.plus_x_minus_1 = 0.9; - - g_recip_projected_pmhz_fast.plus_1 = (1.0 / 2.5); - g_recip_projected_pmhz_fast.plus_2 = (2.0 / 2.5); - g_recip_projected_pmhz_fast.plus_3 = (3.0 / 2.5); - g_recip_projected_pmhz_fast.plus_x_minus_1 = (1.98 - (1.0/2.5)); - - zip_speed_0tof = g_zipgs_reg_c05a & 0xf0; - setup_zip_speeds(); - - if(engine.fplus_ptr == 0) { - g_recip_projected_pmhz_unl = g_recip_projected_pmhz_slow; - } - - while(1) { - fflush(stdout); +Event g_event_list[MAX_EVENTS]; +Event g_event_free; +Event g_event_start; + +void +initialize_events() +{ + int i; + + for(i = 1; i < MAX_EVENTS; i++) { + g_event_list[i-1].next = &g_event_list[i]; + } + g_event_free.next = &g_event_list[0]; + g_event_list[MAX_EVENTS-1].next = 0; + + g_event_start.next = 0; + g_event_start.dcycs = 0.0; + + add_event_entry(DCYCS_IN_16MS, EV_60HZ); +} + +void +check_for_one_event_type(int type) +{ + Event *ptr; + int count; + int depth; + + count = 0; + depth = 0; + ptr = g_event_start.next; + while(ptr != 0) { + depth++; + if(ptr->type == type) { + count++; + if(count != 1) { + halt_printf("in check_for_1, type %d found at " + "depth: %d, count: %d, at %f\n", + type, depth, count, ptr->dcycs); + } + } + ptr = ptr->next; + } +} + + +void +add_event_entry(double dcycs, int type) +{ + Event *this_event; + Event *ptr, *prev_ptr; + int tmp_type; + int done; + + this_event = g_event_free.next; + if(this_event == 0) { + halt_printf("Out of queue entries!\n"); + show_all_events(); + return; + } + g_event_free.next = this_event->next; + + this_event->type = type; + + tmp_type = type & 0xff; + if((dcycs < 0.0) || (dcycs > (g_cur_dcycs + 50*1000*1000.0)) || + ((dcycs < g_cur_dcycs) && (tmp_type != EV_SCAN_INT))) { + halt_printf("add_event: dcycs: %f, type:%05x, cur_dcycs: %f!\n", + dcycs, type, g_cur_dcycs); + dcycs = g_cur_dcycs + 1000.0; + } + + ptr = g_event_start.next; + if(ptr && (dcycs < ptr->dcycs)) { + /* create event before next expected event */ + /* do this by setting HALT_EVENT */ + set_halt(HALT_EVENT); + } + + prev_ptr = &g_event_start; + ptr = g_event_start.next; + + done = 0; + while(!done) { + if(ptr == 0) { + this_event->next = ptr; + this_event->dcycs = dcycs; + prev_ptr->next = this_event; + return; + } else { + if(ptr->dcycs < dcycs) { + /* step across this guy */ + prev_ptr = ptr; + ptr = ptr->next; + } else { + /* go in front of this guy */ + this_event->dcycs = dcycs; + this_event->next = ptr; + prev_ptr->next = this_event; + return; + } + } + } +} + +extern int g_doc_saved_ctl; + +double +remove_event_entry(int type) +{ + Event *ptr, *prev_ptr; + Event *next_ptr; + + ptr = g_event_start.next; + prev_ptr = &g_event_start; + + while(ptr != 0) { + if((ptr->type & 0xffff) == type) { + /* got it, remove it */ + next_ptr = ptr->next; + prev_ptr->next = next_ptr; + + /* Add ptr to free list */ + ptr->next = g_event_free.next; + g_event_free.next = ptr; + + return ptr->dcycs; + } + prev_ptr = ptr; + ptr = ptr->next; + } + + halt_printf("remove event_entry: %08x, but not found!\n", type); + if((type & 0xff) == EV_DOC_INT) { + printf("DOC, g_doc_saved_ctl = %02x\n", g_doc_saved_ctl); + } +#ifdef HPUX + U_STACK_TRACE(); +#endif + show_all_events(); + + return 0.0; +} + +void +add_event_stop(double dcycs) +{ + add_event_entry(dcycs, EV_STOP); +} + +void +add_event_doc(double dcycs, int osc) +{ + if(dcycs < g_cur_dcycs) { + dcycs = g_cur_dcycs; +#if 0 + halt_printf("add_event_doc: dcycs: %f, cur_dcycs: %f\n", + dcycs, g_cur_dcycs); +#endif + } + + add_event_entry(dcycs, EV_DOC_INT + (osc << 8)); +} + +void +add_event_scc(double dcycs, int type) +{ + if(dcycs < g_cur_dcycs) { + dcycs = g_cur_dcycs; + } + + add_event_entry(dcycs, EV_SCC + (type << 8)); +} + +void +add_event_vbl() +{ + double dcycs; + + dcycs = g_last_vbl_dcycs + (DCYCS_IN_16MS * (192.0/262.0)); + add_event_entry(dcycs, EV_VBL_INT); +} + +void +add_event_vid_upd(int line) +{ + double dcycs; + + dcycs = g_last_vbl_dcycs + ((DCYCS_IN_16MS * line) / 262.0); + add_event_entry(dcycs, EV_VID_UPD + (line << 8)); +} + +double +remove_event_doc(int osc) +{ + return remove_event_entry(EV_DOC_INT + (osc << 8)); +} + +double +remove_event_scc(int type) +{ + return remove_event_entry(EV_SCC + (type << 8)); +} + +void +show_all_events() +{ + Event *ptr; + int count; + double dcycs; + + count = 0; + ptr = g_event_start.next; + while(ptr != 0) { + dcycs = ptr->dcycs; + printf("Event: %02x: type: %05x, dcycs: %f (%f)\n", + count, ptr->type, dcycs, dcycs - g_cur_dcycs); + ptr = ptr->next; + count++; + } + +} + +word32 g_vbl_count = 0; +int g_vbl_index_count = 0; +double dtime_array[60]; +double g_dadjcycs_array[60]; +double g_dtime_diff3_array[60]; +double g_dtime_this_vbl_array[60]; +double g_dtime_exp_array[60]; +double g_dtime_pmhz_array[60]; +double g_dtime_eff_pmhz_array[60]; +int g_limit_speed = 2; +double sim_time[60]; +double g_sim_sum = 0.0; + +double g_cur_sim_dtime = 0.0; +double g_projected_pmhz = 1.0; +double g_zip_pmhz = 8.0; +double g_sim_mhz = 100.0; +int g_line_ref_amt = 1; +int g_video_line_update_interval = 0; + +Fplus g_recip_projected_pmhz_slow; +Fplus g_recip_projected_pmhz_fast; +Fplus g_recip_projected_pmhz_zip; +Fplus g_recip_projected_pmhz_unl; + +void +show_pmhz() +{ + printf("Pmhz: %f, c036:%02x, limit: %d\n", + g_projected_pmhz, g_c036_val_speed, g_limit_speed); + +} + +void +setup_zip_speeds() +{ + double frecip; + double fmhz; + int mult; + + mult = 16 - ((g_zipgs_reg_c05a >> 4) & 0xf); + // 16 = full speed, 1 = 1/16th speed + fmhz = (8.0 * mult) / 16.0; +#if 0 + if(mult == 16) { + /* increase full speed by 19% to make zipgs freq measuring */ + /* programs work correctly */ + fmhz = fmhz * 1.19; + } +#endif + frecip = 1.0 / fmhz; + g_zip_pmhz = fmhz; + g_recip_projected_pmhz_zip.plus_1 = frecip; + g_recip_projected_pmhz_zip.plus_2 = 2.0 * frecip; + g_recip_projected_pmhz_zip.plus_3 = 3.0 * frecip; + if(frecip >= 0.5) { + g_recip_projected_pmhz_zip.plus_x_minus_1 = 1.01; + } else { + g_recip_projected_pmhz_zip.plus_x_minus_1 = 1.01 - frecip; + } +} + +void +run_prog() +{ + Fplus *fplus_ptr; + Event *this_event; + Event *db1; + double dcycs; + double now_dtime; + double prev_dtime; + double prerun_fcycles; + double fspeed_mult; + double fcycles_stop; + word32 ret; + word32 zip_speed_0tof, zip_speed_0tof_new; + int zip_en, zip_follow_cps; + int type; + int motor_on; + int iwm_1; + int iwm_25; + int limit_speed; + int apple35_sel; + int fast, zip_speed, faster_than_28, unl_speed; + int this_type; + + fflush(stdout); + + g_cur_sim_dtime = 0.0; + + g_recip_projected_pmhz_slow.plus_1 = 1.0; + g_recip_projected_pmhz_slow.plus_2 = 2.0; + g_recip_projected_pmhz_slow.plus_3 = 3.0; + g_recip_projected_pmhz_slow.plus_x_minus_1 = 0.9; + + g_recip_projected_pmhz_fast.plus_1 = (1.0 / 2.5); + g_recip_projected_pmhz_fast.plus_2 = (2.0 / 2.5); + g_recip_projected_pmhz_fast.plus_3 = (3.0 / 2.5); + g_recip_projected_pmhz_fast.plus_x_minus_1 = (1.98 - (1.0/2.5)); + + zip_speed_0tof = g_zipgs_reg_c05a & 0xf0; + setup_zip_speeds(); + + if(engine.fplus_ptr == 0) { + g_recip_projected_pmhz_unl = g_recip_projected_pmhz_slow; + } + + while(1) { + fflush(stdout); // OG Disabling control panel #ifndef ACTIVEGS - if(g_config_control_panel) { - config_control_panel(); - } + if(g_config_control_panel) { + config_control_panel(); + } #endif - if(g_irq_pending && !(engine.psr & 0x4)) { - irq_printf("taking an irq!\n"); - take_irq(0); - /* Interrupt! */ - } - - motor_on = g_iwm_motor_on; - limit_speed = g_limit_speed; - apple35_sel = g_c031_disk35 & 0x40; - zip_en = ((g_zipgs_reg_c05b & 0x10) == 0); - zip_follow_cps = ((g_zipgs_reg_c059 & 0x8) != 0); - zip_speed_0tof_new = g_zipgs_reg_c05a & 0xf0; - fast = (g_c036_val_speed & 0x80) || (zip_en && !zip_follow_cps); + if(g_irq_pending && !(engine.psr & 0x4)) { + irq_printf("taking an irq!\n"); + take_irq(0); + /* Interrupt! */ + } + + motor_on = g_iwm_motor_on; + limit_speed = g_limit_speed; + apple35_sel = g_c031_disk35 & 0x40; + zip_en = ((g_zipgs_reg_c05b & 0x10) == 0); + zip_follow_cps = ((g_zipgs_reg_c059 & 0x8) != 0); + zip_speed_0tof_new = g_zipgs_reg_c05a & 0xf0; + fast = (g_c036_val_speed & 0x80) || (zip_en && !zip_follow_cps); // OG Make fast parameter public g_speed_fast = fast; - if(zip_speed_0tof_new != zip_speed_0tof) { - zip_speed_0tof = zip_speed_0tof_new; - setup_zip_speeds(); - } - - iwm_1 = motor_on && !apple35_sel && - (g_c036_val_speed & 0x4) && - (g_slow_525_emul_wr || !g_fast_disk_emul); - iwm_25 = (motor_on && apple35_sel) && !g_fast_disk_emul; - faster_than_28 = fast && (!iwm_1 && !iwm_25) && zip_en && - ((limit_speed == 0) || (limit_speed == 3)); - zip_speed = faster_than_28 && - ((zip_speed_0tof != 0) || (limit_speed == 3) || - (g_zipgs_unlock >= 4) ); + if(zip_speed_0tof_new != zip_speed_0tof) { + zip_speed_0tof = zip_speed_0tof_new; + setup_zip_speeds(); + } + + iwm_1 = motor_on && !apple35_sel && + (g_c036_val_speed & 0x4) && + (g_slow_525_emul_wr || !g_fast_disk_emul); + iwm_25 = (motor_on && apple35_sel) && !g_fast_disk_emul; + faster_than_28 = fast && (!iwm_1 && !iwm_25) && zip_en && + ((limit_speed == 0) || (limit_speed == 3)); + zip_speed = faster_than_28 && + ((zip_speed_0tof != 0) || (limit_speed == 3) || + (g_zipgs_unlock >= 4) ); // OG unlimited speed should not be affected by zip. // unl_speed = faster_than_28 && !zip_speed; unl_speed = (limit_speed == 0) && faster_than_28; - if(unl_speed) { - /* use unlimited speed */ - fspeed_mult = g_projected_pmhz; - fplus_ptr = &g_recip_projected_pmhz_unl; - } else if(zip_speed) { - fspeed_mult = g_zip_pmhz; - fplus_ptr = &g_recip_projected_pmhz_zip; - } else if(fast && !iwm_1 && !(limit_speed == 1)) { - fspeed_mult = 2.5; - fplus_ptr = &g_recip_projected_pmhz_fast; - } else { - /* else run slow */ - fspeed_mult = 1.0; - fplus_ptr = &g_recip_projected_pmhz_slow; - } - - engine.fplus_ptr = fplus_ptr; - - this_type = g_event_start.next->type; - - prerun_fcycles = g_cur_dcycs - g_last_vbl_dcycs; - engine.fcycles = prerun_fcycles; - fcycles_stop = (g_event_start.next->dcycs - g_last_vbl_dcycs) + - 0.001; - if(g_stepping) { - fcycles_stop = prerun_fcycles; - } - g_fcycles_stop = fcycles_stop; - -#if 0 - printf("Enter engine, fcycs: %f, stop: %f\n", - prerun_fcycles, fcycles_stop); - printf("g_cur_dcycs: %f, last_vbl_dcyc: %f\n", g_cur_dcycs, - g_last_vbl_dcycs); -#endif - - g_num_enter_engine++; - prev_dtime = get_dtime(); - - ret = enter_engine(&engine); - - now_dtime = get_dtime(); - - g_cur_sim_dtime += (now_dtime - prev_dtime); - - dcycs = g_last_vbl_dcycs + (double)(engine.fcycles); - - g_dadjcycs += (engine.fcycles - prerun_fcycles) * - fspeed_mult; - -#if 0 - printf("...back, engine.fcycles: %f, dcycs: %f\n", - (double)engine.fcycles, dcycs); -#endif - - g_cur_dcycs = dcycs; - - if(ret != 0) { - g_engine_action++; - handle_action(ret); - } - - if(halt_sim == HALT_EVENT) { - g_engine_halt_event++; - /* if we needed to stop to check for interrupts, */ - /* clear halt */ - halt_sim = 0; - } - -#if 0 - if(!g_testing && run_cycles < -2000000) { - halt_printf("run_cycles: %d, cycles: %d\n", run_cycles, - cycles); - printf("this_type: %05x\n", this_type); - printf("duff_cycles: %d\n", duff_cycles); - printf("start.next->rel_time: %d, type: %05x\n", - g_event_start.next->rel_time, - g_event_start.next->type); - } -#endif - - this_event = g_event_start.next; - while(dcycs >= this_event->dcycs) { - /* Pop this guy off of the queue */ - g_event_start.next = this_event->next; - - type = this_event->type; - this_event->next = g_event_free.next; - g_event_free.next = this_event; - switch(type & 0xff) { - case EV_60HZ: - update_60hz(dcycs, now_dtime); - break; - case EV_STOP: - printf("type: EV_STOP\n"); - printf("next: %p, dcycs: %f\n", - g_event_start.next, dcycs); - db1 = g_event_start.next; - halt_printf("next.dcycs: %f\n", db1->dcycs); - break; - case EV_SCAN_INT: - g_engine_scan_int++; - irq_printf("type: scan int\n"); - do_scan_int(dcycs, type >> 8); - break; - case EV_DOC_INT: - g_engine_doc_int++; - doc_handle_event(type >> 8, dcycs); - break; - case EV_VBL_INT: - do_vbl_int(); - break; - case EV_SCC: - do_scc_event(type >> 8, dcycs); - break; - case EV_VID_UPD: - video_update_event_line(type >> 8); - break; - default: - printf("Unknown event: %d!\n", type); - exit(3); - } - - this_event = g_event_start.next; - - } - - if(g_event_start.next == 0) { - halt_printf("ERROR...run_prog, event_start.n=0!\n"); - } - -#if 0 - if(!g_testing && g_event_start.next->rel_time > 2000000) { - printf("Z:start.next->rel_time: %d, duff_cycles: %d\n", - g_event_start.next->rel_time, duff_cycles); - halt_printf("Zrun_cycles:%d, cycles:%d\n", run_cycles, - cycles); - - show_all_events(); - } -#endif - - if(halt_sim != 0 && halt_sim != HALT_EVENT) { - break; - } - if(g_stepping) { - break; - } - } - - if(!g_testing) { - printf("leaving run_prog, halt_sim:%d\n", halt_sim); - } - - x_auto_repeat_on(0); -} - -void -add_irq(word32 irq_mask) -{ - if(g_irq_pending & irq_mask) { - /* Already requested, just get out */ - return; - } - g_irq_pending |= irq_mask; - set_halt(HALT_EVENT); -} - -void -remove_irq(word32 irq_mask) -{ - g_irq_pending = g_irq_pending & (~irq_mask); -} - -void -take_irq(int is_it_brk) -{ - word32 new_kpc; - word32 va; - - irq_printf("Taking irq, at: %02x/%04x, psw: %02x, dcycs: %f\n", - engine.kpc>>16, engine.kpc & 0xffff, engine.psr, - g_cur_dcycs); - - g_num_irq++; - if(g_wait_pending) { - /* step over WAI instruction */ - engine.kpc++; - g_wait_pending = 0; - } - - if(engine.psr & 0x100) { - /* Emulation */ - set_memory_c(engine.stack, (engine.kpc >> 8) & 0xff, 0); - engine.stack = ((engine.stack -1) & 0xff) + 0x100; - - set_memory_c(engine.stack, engine.kpc & 0xff, 0); - engine.stack = ((engine.stack -1) & 0xff) + 0x100; - - set_memory_c(engine.stack, - (engine.psr & 0xef)|(is_it_brk<<4),0); - /* Clear B bit in psr on stack */ - engine.stack = ((engine.stack -1) & 0xff) + 0x100; - - va = 0xfffffe; - if(g_c035_shadow_reg & 0x40) { - /* I/O shadowing off...use ram locs */ - va = 0x00fffe; - } - - } else { - /* native */ - set_memory_c(engine.stack, (engine.kpc >> 16) & 0xff, 0); - engine.stack = ((engine.stack -1) & 0xffff); - - set_memory_c(engine.stack, (engine.kpc >> 8) & 0xff, 0); - engine.stack = ((engine.stack -1) & 0xffff); - - set_memory_c(engine.stack, engine.kpc & 0xff, 0); - engine.stack = ((engine.stack -1) & 0xffff); - - set_memory_c(engine.stack, engine.psr & 0xff, 0); - engine.stack = ((engine.stack -1) & 0xffff); - - if(is_it_brk) { - /* break */ - va = 0xffffe6; - if(g_c035_shadow_reg & 0x40) { - va = 0xffe6; - } - } else { - /* irq */ - va = 0xffffee; - if(g_c035_shadow_reg & 0x40) { - va = 0xffee; - } - } - - } - - new_kpc = get_memory_c(va, 0); - new_kpc = new_kpc + (get_memory_c(va+1, 0) << 8); - - engine.psr = ((engine.psr & 0x1f3) | 0x4); - - engine.kpc = new_kpc; - HALT_ON(HALT_ON_IRQ, "Halting on IRQ\n"); - -} - -double g_dtime_last_vbl = 0.0; -double g_dtime_expected = (1.0/60.0); - -int g_scan_int_events = 0; - - - -void -show_dtime_array() -{ - double dfirst_time; - double first_total_cycs; - int i; - int pos; - - dfirst_time = 0.0; - first_total_cycs = 0.0; - - - for(i = 0; i < 60; i++) { - pos = (g_vbl_index_count + i) % 60; - printf("%2d:%2d dt:%.5f adjc:%9.1f this_vbl:%.6f " - "exp:%.5f p:%2.2f ep:%2.2f\n", - i, pos, - dtime_array[pos] - dfirst_time, - g_dadjcycs_array[pos] - first_total_cycs, - g_dtime_this_vbl_array[pos], - g_dtime_exp_array[pos] - dfirst_time, - g_dtime_pmhz_array[pos], - g_dtime_eff_pmhz_array[pos]); - dfirst_time = dtime_array[pos]; - first_total_cycs = g_dadjcycs_array[pos]; - } -} - -extern word32 g_cycs_in_40col; -extern word32 g_cycs_in_xredraw; -extern word32 g_cycs_in_check_input; -extern word32 g_cycs_in_refresh_line; -extern word32 g_cycs_in_refresh_ximage; -extern word32 g_cycs_in_io_read; -extern word32 g_cycs_in_sound1; -extern word32 g_cycs_in_sound2; -extern word32 g_cycs_in_sound3; -extern word32 g_cycs_in_sound4; -extern word32 g_cycs_in_start_sound; -extern word32 g_cycs_in_est_sound; -extern word32 g_refresh_bytes_xfer; - -extern int g_num_snd_plays; -extern int g_num_doc_events; -extern int g_num_start_sounds; -extern int g_num_scan_osc; -extern int g_num_recalc_snd_parms; -extern float g_fvoices; - -extern int g_doc_vol; -extern int g_a2vid_palette; - -extern int g_status_refresh_needed; - - -void -update_60hz(double dcycs, double dtime_now) -{ - register word32 end_time; - char status_buf[1024]; - char sim_mhz_buf[128]; - char total_mhz_buf[128]; - char *sim_mhz_ptr, *total_mhz_ptr; - char *code_str1, *code_str2, *sp_str; - double eff_pmhz; - double planned_dcycs; - double predicted_pmhz; - double recip_predicted_pmhz; - double dtime_this_vbl_sim; - double dtime_diff_1sec; - double dratio; - double dtime_till_expected; - double dtime_diff; - double dtime_this_vbl; - double dadjcycs_this_vbl; - double dadj_cycles_1sec; - double dtmp1, dtmp2, dtmp3, dtmp4, dtmp5; - double dnatcycs_1sec; - int tmp; - int doit_3_persec; - int cur_vbl_index; - int prev_vbl_index; - - g_vbl_count++; - - /* NOTE: this event is defined to occur before line 0 */ - /* It's actually happening at the start of the border for line (-1) */ - /* All other timings should be adjusted for this */ - - irq_printf("vbl_60hz: vbl: %d, dcycs: %f, last_vbl_dcycs: %f\n", - g_vbl_count, dcycs, g_last_vbl_dcycs); - - planned_dcycs = DCYCS_IN_16MS; - - g_last_vbl_dcycs = g_last_vbl_dcycs + planned_dcycs; - - add_event_entry(g_last_vbl_dcycs + planned_dcycs, EV_60HZ); - check_for_one_event_type(EV_60HZ); - - cur_vbl_index = g_vbl_index_count; - - /* figure out dtime spent running SIM, not all the overhead */ - dtime_this_vbl_sim = g_cur_sim_dtime; - g_cur_sim_dtime = 0.0; - g_sim_sum = g_sim_sum - sim_time[cur_vbl_index] + dtime_this_vbl_sim; - sim_time[cur_vbl_index] = dtime_this_vbl_sim; - - dadj_cycles_1sec = g_dadjcycs - g_dadjcycs_array[cur_vbl_index]; - - /* dtime_diff_1sec is dtime total spent over the last 60 ticks */ - dtime_diff_1sec = dtime_now - dtime_array[cur_vbl_index]; - - dtime_array[cur_vbl_index] = dtime_now; - g_dadjcycs_array[cur_vbl_index] = g_dadjcycs; - - prev_vbl_index = cur_vbl_index; - cur_vbl_index = prev_vbl_index + 1; - if(cur_vbl_index >= 60) { - cur_vbl_index = 0; - } - g_vbl_index_count = cur_vbl_index; - - GET_ITIMER(end_time); - g_dnatcycs_1sec += (double)(end_time - g_natcycs_lastvbl); - g_natcycs_lastvbl = end_time; - - if(prev_vbl_index == 0) { - if(g_sim_sum < (1.0/250.0)) { - sim_mhz_ptr = "???"; - g_sim_mhz = 250.0; - } else { - g_sim_mhz = (dadj_cycles_1sec / g_sim_sum) / - (1000.0*1000.0); - sprintf(sim_mhz_buf, "%6.2f", g_sim_mhz); - sim_mhz_ptr = sim_mhz_buf; - } - if(dtime_diff_1sec < (1.0/250.0)) { - total_mhz_ptr = "???"; - } else { - sprintf(total_mhz_buf, "%6.2f", - (dadj_cycles_1sec / dtime_diff_1sec) / - (1000000.0)); - total_mhz_ptr = total_mhz_buf; - } - - switch(g_limit_speed) { - case 1: sp_str = "1Mhz"; break; - case 2: sp_str = "2.8Mhz"; break; - case 3: sp_str = "8.0Mhz"; break; - default: sp_str = "Unlimited"; break; - } - + if(unl_speed) { + /* use unlimited speed */ + fspeed_mult = g_projected_pmhz; + fplus_ptr = &g_recip_projected_pmhz_unl; + } else if(zip_speed) { + fspeed_mult = g_zip_pmhz; + fplus_ptr = &g_recip_projected_pmhz_zip; + } else if(fast && !iwm_1 && !(limit_speed == 1)) { + fspeed_mult = 2.5; + fplus_ptr = &g_recip_projected_pmhz_fast; + } else { + /* else run slow */ + fspeed_mult = 1.0; + fplus_ptr = &g_recip_projected_pmhz_slow; + } + + engine.fplus_ptr = fplus_ptr; + + this_type = g_event_start.next->type; + + prerun_fcycles = g_cur_dcycs - g_last_vbl_dcycs; + engine.fcycles = prerun_fcycles; + fcycles_stop = (g_event_start.next->dcycs - g_last_vbl_dcycs) + + 0.001; + if(g_stepping) { + fcycles_stop = prerun_fcycles; + } + g_fcycles_stop = fcycles_stop; + +#if 0 + printf("Enter engine, fcycs: %f, stop: %f\n", + prerun_fcycles, fcycles_stop); + printf("g_cur_dcycs: %f, last_vbl_dcyc: %f\n", g_cur_dcycs, + g_last_vbl_dcycs); +#endif + + g_num_enter_engine++; + prev_dtime = get_dtime(); + + ret = enter_engine(&engine); + + now_dtime = get_dtime(); + + g_cur_sim_dtime += (now_dtime - prev_dtime); + + dcycs = g_last_vbl_dcycs + (double)(engine.fcycles); + + g_dadjcycs += (engine.fcycles - prerun_fcycles) * + fspeed_mult; + +#if 0 + printf("...back, engine.fcycles: %f, dcycs: %f\n", + (double)engine.fcycles, dcycs); +#endif + + g_cur_dcycs = dcycs; + + if(ret != 0) { + g_engine_action++; + handle_action(ret); + } + + if(halt_sim == HALT_EVENT) { + g_engine_halt_event++; + /* if we needed to stop to check for interrupts, */ + /* clear halt */ + halt_sim = 0; + } + +#if 0 + if(!g_testing && run_cycles < -2000000) { + halt_printf("run_cycles: %d, cycles: %d\n", run_cycles, + cycles); + printf("this_type: %05x\n", this_type); + printf("duff_cycles: %d\n", duff_cycles); + printf("start.next->rel_time: %d, type: %05x\n", + g_event_start.next->rel_time, + g_event_start.next->type); + } +#endif + + this_event = g_event_start.next; + while(dcycs >= this_event->dcycs) { + /* Pop this guy off of the queue */ + g_event_start.next = this_event->next; + + type = this_event->type; + this_event->next = g_event_free.next; + g_event_free.next = this_event; + switch(type & 0xff) { + case EV_60HZ: + update_60hz(dcycs, now_dtime); + break; + case EV_STOP: + printf("type: EV_STOP\n"); + printf("next: %p, dcycs: %f\n", + g_event_start.next, dcycs); + db1 = g_event_start.next; + halt_printf("next.dcycs: %f\n", db1->dcycs); + break; + case EV_SCAN_INT: + g_engine_scan_int++; + irq_printf("type: scan int\n"); + do_scan_int(dcycs, type >> 8); + break; + case EV_DOC_INT: + g_engine_doc_int++; + doc_handle_event(type >> 8, dcycs); + break; + case EV_VBL_INT: + do_vbl_int(); + break; + case EV_SCC: + do_scc_event(type >> 8, dcycs); + break; + case EV_VID_UPD: + video_update_event_line(type >> 8); + break; + default: + printf("Unknown event: %d!\n", type); + exit(3); + } + + this_event = g_event_start.next; + + } + + if(g_event_start.next == 0) { + halt_printf("ERROR...run_prog, event_start.n=0!\n"); + } + +#if 0 + if(!g_testing && g_event_start.next->rel_time > 2000000) { + printf("Z:start.next->rel_time: %d, duff_cycles: %d\n", + g_event_start.next->rel_time, duff_cycles); + halt_printf("Zrun_cycles:%d, cycles:%d\n", run_cycles, + cycles); + + show_all_events(); + } +#endif + + if(halt_sim != 0 && halt_sim != HALT_EVENT) { + break; + } + if(g_stepping) { + break; + } + } + + if(!g_testing) { + printf("leaving run_prog, halt_sim:%d\n", halt_sim); + } + + x_auto_repeat_on(0); +} + +void +add_irq(word32 irq_mask) +{ + if(g_irq_pending & irq_mask) { + /* Already requested, just get out */ + return; + } + g_irq_pending |= irq_mask; + set_halt(HALT_EVENT); +} + +void +remove_irq(word32 irq_mask) +{ + g_irq_pending = g_irq_pending & (~irq_mask); +} + +void +take_irq(int is_it_brk) +{ + word32 new_kpc; + word32 va; + + irq_printf("Taking irq, at: %02x/%04x, psw: %02x, dcycs: %f\n", + engine.kpc>>16, engine.kpc & 0xffff, engine.psr, + g_cur_dcycs); + + g_num_irq++; + if(g_wait_pending) { + /* step over WAI instruction */ + engine.kpc++; + g_wait_pending = 0; + } + + if(engine.psr & 0x100) { + /* Emulation */ + set_memory_c(engine.stack, (engine.kpc >> 8) & 0xff, 0); + engine.stack = ((engine.stack -1) & 0xff) + 0x100; + + set_memory_c(engine.stack, engine.kpc & 0xff, 0); + engine.stack = ((engine.stack -1) & 0xff) + 0x100; + + set_memory_c(engine.stack, + (engine.psr & 0xef)|(is_it_brk<<4),0); + /* Clear B bit in psr on stack */ + engine.stack = ((engine.stack -1) & 0xff) + 0x100; + + va = 0xfffffe; + if(g_c035_shadow_reg & 0x40) { + /* I/O shadowing off...use ram locs */ + va = 0x00fffe; + } + + } else { + /* native */ + set_memory_c(engine.stack, (engine.kpc >> 16) & 0xff, 0); + engine.stack = ((engine.stack -1) & 0xffff); + + set_memory_c(engine.stack, (engine.kpc >> 8) & 0xff, 0); + engine.stack = ((engine.stack -1) & 0xffff); + + set_memory_c(engine.stack, engine.kpc & 0xff, 0); + engine.stack = ((engine.stack -1) & 0xffff); + + set_memory_c(engine.stack, engine.psr & 0xff, 0); + engine.stack = ((engine.stack -1) & 0xffff); + + if(is_it_brk) { + /* break */ + va = 0xffffe6; + if(g_c035_shadow_reg & 0x40) { + va = 0xffe6; + } + } else { + /* irq */ + va = 0xffffee; + if(g_c035_shadow_reg & 0x40) { + va = 0xffee; + } + } + + } + + new_kpc = get_memory_c(va, 0); + new_kpc = new_kpc + (get_memory_c(va+1, 0) << 8); + + engine.psr = ((engine.psr & 0x1f3) | 0x4); + + engine.kpc = new_kpc; + HALT_ON(HALT_ON_IRQ, "Halting on IRQ\n"); + +} + +double g_dtime_last_vbl = 0.0; +double g_dtime_expected = (1.0/60.0); + +int g_scan_int_events = 0; + + + +void +show_dtime_array() +{ + double dfirst_time; + double first_total_cycs; + int i; + int pos; + + dfirst_time = 0.0; + first_total_cycs = 0.0; + + + for(i = 0; i < 60; i++) { + pos = (g_vbl_index_count + i) % 60; + printf("%2d:%2d dt:%.5f adjc:%9.1f this_vbl:%.6f " + "exp:%.5f p:%2.2f ep:%2.2f\n", + i, pos, + dtime_array[pos] - dfirst_time, + g_dadjcycs_array[pos] - first_total_cycs, + g_dtime_this_vbl_array[pos], + g_dtime_exp_array[pos] - dfirst_time, + g_dtime_pmhz_array[pos], + g_dtime_eff_pmhz_array[pos]); + dfirst_time = dtime_array[pos]; + first_total_cycs = g_dadjcycs_array[pos]; + } +} + +extern word32 g_cycs_in_40col; +extern word32 g_cycs_in_xredraw; +extern word32 g_cycs_in_check_input; +extern word32 g_cycs_in_refresh_line; +extern word32 g_cycs_in_refresh_ximage; +extern word32 g_cycs_in_io_read; +extern word32 g_cycs_in_sound1; +extern word32 g_cycs_in_sound2; +extern word32 g_cycs_in_sound3; +extern word32 g_cycs_in_sound4; +extern word32 g_cycs_in_start_sound; +extern word32 g_cycs_in_est_sound; +extern word32 g_refresh_bytes_xfer; + +extern int g_num_snd_plays; +extern int g_num_doc_events; +extern int g_num_start_sounds; +extern int g_num_scan_osc; +extern int g_num_recalc_snd_parms; +extern float g_fvoices; + +extern int g_doc_vol; +extern int g_a2vid_palette; + +extern int g_status_refresh_needed; + + +void +update_60hz(double dcycs, double dtime_now) +{ + register word32 end_time; + char status_buf[1024]; + char sim_mhz_buf[128]; + char total_mhz_buf[128]; + char *sim_mhz_ptr, *total_mhz_ptr; + char *code_str1, *code_str2, *sp_str; + double eff_pmhz; + double planned_dcycs; + double predicted_pmhz; + double recip_predicted_pmhz; + double dtime_this_vbl_sim; + double dtime_diff_1sec; + double dratio; + double dtime_till_expected; + double dtime_diff; + double dtime_this_vbl; + double dadjcycs_this_vbl; + double dadj_cycles_1sec; + double dtmp1, dtmp2, dtmp3, dtmp4, dtmp5; + double dnatcycs_1sec; + int tmp; + int doit_3_persec; + int cur_vbl_index; + int prev_vbl_index; + + g_vbl_count++; + + /* NOTE: this event is defined to occur before line 0 */ + /* It's actually happening at the start of the border for line (-1) */ + /* All other timings should be adjusted for this */ + + irq_printf("vbl_60hz: vbl: %d, dcycs: %f, last_vbl_dcycs: %f\n", + g_vbl_count, dcycs, g_last_vbl_dcycs); + + planned_dcycs = DCYCS_IN_16MS; + + g_last_vbl_dcycs = g_last_vbl_dcycs + planned_dcycs; + + add_event_entry(g_last_vbl_dcycs + planned_dcycs, EV_60HZ); + check_for_one_event_type(EV_60HZ); + + cur_vbl_index = g_vbl_index_count; + + /* figure out dtime spent running SIM, not all the overhead */ + dtime_this_vbl_sim = g_cur_sim_dtime; + g_cur_sim_dtime = 0.0; + g_sim_sum = g_sim_sum - sim_time[cur_vbl_index] + dtime_this_vbl_sim; + sim_time[cur_vbl_index] = dtime_this_vbl_sim; + + dadj_cycles_1sec = g_dadjcycs - g_dadjcycs_array[cur_vbl_index]; + + /* dtime_diff_1sec is dtime total spent over the last 60 ticks */ + dtime_diff_1sec = dtime_now - dtime_array[cur_vbl_index]; + + dtime_array[cur_vbl_index] = dtime_now; + g_dadjcycs_array[cur_vbl_index] = g_dadjcycs; + + prev_vbl_index = cur_vbl_index; + cur_vbl_index = prev_vbl_index + 1; + if(cur_vbl_index >= 60) { + cur_vbl_index = 0; + } + g_vbl_index_count = cur_vbl_index; + + GET_ITIMER(end_time); + g_dnatcycs_1sec += (double)(end_time - g_natcycs_lastvbl); + g_natcycs_lastvbl = end_time; + + if(prev_vbl_index == 0) { + if(g_sim_sum < (1.0/250.0)) { + sim_mhz_ptr = "???"; + g_sim_mhz = 250.0; + } else { + g_sim_mhz = (dadj_cycles_1sec / g_sim_sum) / + (1000.0*1000.0); + sprintf(sim_mhz_buf, "%6.2f", g_sim_mhz); + sim_mhz_ptr = sim_mhz_buf; + } + if(dtime_diff_1sec < (1.0/250.0)) { + total_mhz_ptr = "???"; + } else { + sprintf(total_mhz_buf, "%6.2f", + (dadj_cycles_1sec / dtime_diff_1sec) / + (1000000.0)); + total_mhz_ptr = total_mhz_buf; + } + + switch(g_limit_speed) { + case 1: sp_str = "1Mhz"; break; + case 2: sp_str = "2.8Mhz"; break; + case 3: sp_str = "8.0Mhz"; break; + default: sp_str = "Unlimited"; break; + } + // OG Pass speed info to the control (ActiveX specific) #ifdef ACTIVEGS { @@ -2121,238 +2130,238 @@ update_60hz(double dcycs, double dtime_now) updateInfo(sp_str,total_mhz_ptr); } #endif - sprintf(status_buf, "dcycs:%9.1f sim MHz:%s " - "Eff MHz:%s, sec:%1.3f vol:%02x pal:%x, Limit:%s", - dcycs/(1000.0*1000.0), sim_mhz_ptr, total_mhz_ptr, - dtime_diff_1sec, g_doc_vol, g_a2vid_palette, - sp_str); - video_update_status_line(0, status_buf); - - if(g_video_line_update_interval == 0) { - if(g_sim_mhz > 12.0) { - /* just set video line_ref_amt to 1 */ - g_line_ref_amt = 1; - } else if(g_line_ref_amt == 1 && g_sim_mhz < 4.0) { - g_line_ref_amt = 8; - } - } else { - g_line_ref_amt = g_video_line_update_interval; - } - - if(g_dnatcycs_1sec < (1000.0*1000.0)) { - /* make it so large that all %'s become 0 */ - g_dnatcycs_1sec = 800.0*1000.0*1000.0*1000.0; - } - dnatcycs_1sec = g_dnatcycs_1sec / 100.0; /* eff mult by 100 */ - - dtmp2 = (double)(g_cycs_in_check_input) / dnatcycs_1sec; - dtmp3 = (double)(g_cycs_in_refresh_line) / dnatcycs_1sec; - dtmp4 = (double)(g_cycs_in_refresh_ximage) / dnatcycs_1sec; - sprintf(status_buf, "xfer:%08x, %5.1f ref_amt:%d " - "ch_in:%4.1f%% ref_l:%4.1f%% ref_x:%4.1f%%", - g_refresh_bytes_xfer, g_dnatcycs_1sec/(1000.0*1000.0), - g_line_ref_amt, dtmp2, dtmp3, dtmp4); - video_update_status_line(1, status_buf); - - sprintf(status_buf, "Ints:%3d I/O:%4dK BRK:%3d COP:%2d " - "Eng:%3d act:%3d hev:%3d esi:%3d edi:%3d", - g_num_irq, g_io_amt>>10, g_num_brk, g_num_cop, - g_num_enter_engine, g_engine_action, - g_engine_halt_event, g_engine_scan_int, - g_engine_doc_int); - video_update_status_line(2, status_buf); - - dtmp1 = (double)(g_cycs_in_sound1) / dnatcycs_1sec; - dtmp2 = (double)(g_cycs_in_sound2) / dnatcycs_1sec; - dtmp3 = (double)(g_cycs_in_sound3) / dnatcycs_1sec; - dtmp4 = (double)(g_cycs_in_start_sound) / dnatcycs_1sec; - dtmp5 = (double)(g_cycs_in_est_sound) / dnatcycs_1sec; - sprintf(status_buf, "snd1:%4.1f%%, 2:%4.1f%%, " - "3:%4.1f%%, st:%4.1f%% est:%4.1f%% %4.2f", - dtmp1, dtmp2, dtmp3, dtmp4, dtmp5, g_fvoices); - video_update_status_line(3, status_buf); - - code_str1 = ""; - code_str2 = ""; - if(g_code_yellow) { - code_str1 = "Code: Yellow"; - code_str2 = "Emulated system state suspect, save work"; - } - if(g_code_red) { - code_str1 = "Code: RED"; - code_str2 = "Emulated system state probably corrupt"; - } - sprintf(status_buf, "snd_plays:%4d, doc_ev:%4d, st_snd:%4d " - "snd_parms: %4d %s", - g_num_snd_plays, g_num_doc_events, g_num_start_sounds, - g_num_recalc_snd_parms, code_str1); - video_update_status_line(4, status_buf); - - draw_iwm_status(5, status_buf); - - sprintf(status_buf, "GSport v%-6s " - "Press F4 for Config Menu %s", - g_gsport_version_str, code_str2); - video_update_status_line(6, status_buf); - - g_status_refresh_needed = 1; - - g_num_irq = 0; - g_num_brk = 0; - g_num_cop = 0; - g_num_enter_engine = 0; - g_io_amt = 0; - g_engine_action = 0; - g_engine_halt_event = 0; - g_engine_scan_int = 0; - g_engine_doc_int = 0; - - g_cycs_in_40col = 0; - g_cycs_in_xredraw = 0; - g_cycs_in_check_input = 0; - g_cycs_in_refresh_line = 0; - g_cycs_in_refresh_ximage = 0; - g_cycs_in_io_read = 0; - g_cycs_in_sound1 = 0; - g_cycs_in_sound2 = 0; - g_cycs_in_sound3 = 0; - g_cycs_in_sound4 = 0; - g_cycs_in_start_sound = 0; - g_cycs_in_est_sound = 0; - g_dnatcycs_1sec = 0.0; - g_refresh_bytes_xfer = 0; - - g_num_snd_plays = 0; - g_num_doc_events = 0; - g_num_start_sounds = 0; - g_num_scan_osc = 0; - g_num_recalc_snd_parms = 0; - - g_fvoices = (float)0.0; - } - - dtime_this_vbl = dtime_now - g_dtime_last_vbl; - if(dtime_this_vbl < 0.001) { - dtime_this_vbl = 0.001; - } - - g_dtime_last_vbl = dtime_now; - - dadjcycs_this_vbl = g_dadjcycs - g_last_vbl_dadjcycs; - g_last_vbl_dadjcycs = g_dadjcycs; - - g_dtime_expected += (1.0/60.0); - - eff_pmhz = ((dadjcycs_this_vbl) / (dtime_this_vbl)) / - DCYCS_1_MHZ; - - /* using eff_pmhz, predict how many cycles can be run by */ - /* g_dtime_expected */ - - dtime_till_expected = g_dtime_expected - dtime_now; - - dratio = 60.0 * dtime_till_expected; - - predicted_pmhz = eff_pmhz * dratio; - - if(! (predicted_pmhz < (1.4 * g_projected_pmhz))) { - predicted_pmhz = 1.4 * g_projected_pmhz; - } - - if(! (predicted_pmhz > (0.7 * g_projected_pmhz))) { - predicted_pmhz = 0.7 * g_projected_pmhz; - } - - if(!(predicted_pmhz >= 1.0)) { - irq_printf("predicted: %f, setting to 1.0\n", predicted_pmhz); - predicted_pmhz = 1.0; - } - - if(!(predicted_pmhz < 250.0)) { - irq_printf("predicted: %f, setting to 250.0\n", predicted_pmhz); - predicted_pmhz = 250.0; - } - - recip_predicted_pmhz = 1.0/predicted_pmhz; - g_projected_pmhz = predicted_pmhz; - - g_recip_projected_pmhz_unl.plus_1 = 1.0*recip_predicted_pmhz; - g_recip_projected_pmhz_unl.plus_2 = 2.0*recip_predicted_pmhz; - g_recip_projected_pmhz_unl.plus_3 = 3.0*recip_predicted_pmhz; - g_recip_projected_pmhz_unl.plus_x_minus_1 = 1.01 - recip_predicted_pmhz; - - if(dtime_till_expected < -0.125) { - /* If we were way off, get back on track */ - /* this happens because our sim took much longer than */ - /* expected, so we're going to skip some VBL */ - irq_printf("adj1: dtexp:%f, dt_new:%f\n", - g_dtime_expected, dtime_now); - - dtime_diff = -dtime_till_expected; - - irq_printf("dtime_till_exp: %f, dtime_diff: %f, dcycs: %f\n", - dtime_till_expected, dtime_diff, dcycs); - - g_dtime_expected += dtime_diff; - } - - if(dtime_till_expected > (3/60.0)) { - /* we're running fast, usleep */ - micro_sleep(dtime_till_expected - (1/60.0)); - } - - g_dtime_this_vbl_array[prev_vbl_index] = dtime_this_vbl; - g_dtime_exp_array[prev_vbl_index] = g_dtime_expected; - g_dtime_pmhz_array[prev_vbl_index] = predicted_pmhz; - g_dtime_eff_pmhz_array[prev_vbl_index] = eff_pmhz; - - - if(g_c041_val & C041_EN_VBL_INTS) { - add_event_vbl(); - } - - g_25sec_cntr++; - if(g_25sec_cntr >= 16) { - g_25sec_cntr = 0; - if(g_c041_val & C041_EN_25SEC_INTS) { - add_irq(IRQ_PENDING_C046_25SEC); - g_c046_val |= 0x10; - irq_printf("Setting c046 .25 sec int, g_irq_pend:%d\n", - g_irq_pending); - } - } - - g_1sec_cntr++; - if(g_1sec_cntr >= 60) { - g_1sec_cntr = 0; - tmp = g_c023_val; - tmp |= 0x40; /* set 1sec int */ - if(tmp & 0x04) { - tmp |= 0x80; - add_irq(IRQ_PENDING_C023_1SEC); - irq_printf("Setting c023 to %02x irq_pend: %d\n", - tmp, g_irq_pending); - } - g_c023_val = tmp; - } - - if(!g_scan_int_events) { - check_scan_line_int(dcycs, 0); - } - - doit_3_persec = 0; - if(g_config_iwm_vbl_count > 0) { - g_config_iwm_vbl_count--; - } else { - g_config_iwm_vbl_count = 20; - doit_3_persec = 1; - } - - iwm_vbl_update(doit_3_persec); + sprintf(status_buf, "dcycs:%9.1f sim MHz:%s " + "Eff MHz:%s, sec:%1.3f vol:%02x pal:%x, Limit:%s", + dcycs/(1000.0*1000.0), sim_mhz_ptr, total_mhz_ptr, + dtime_diff_1sec, g_doc_vol, g_a2vid_palette, + sp_str); + video_update_status_line(0, status_buf); + + if(g_video_line_update_interval == 0) { + if(g_sim_mhz > 12.0) { + /* just set video line_ref_amt to 1 */ + g_line_ref_amt = 1; + } else if(g_line_ref_amt == 1 && g_sim_mhz < 4.0) { + g_line_ref_amt = 8; + } + } else { + g_line_ref_amt = g_video_line_update_interval; + } + + if(g_dnatcycs_1sec < (1000.0*1000.0)) { + /* make it so large that all %'s become 0 */ + g_dnatcycs_1sec = 800.0*1000.0*1000.0*1000.0; + } + dnatcycs_1sec = g_dnatcycs_1sec / 100.0; /* eff mult by 100 */ + + dtmp2 = (double)(g_cycs_in_check_input) / dnatcycs_1sec; + dtmp3 = (double)(g_cycs_in_refresh_line) / dnatcycs_1sec; + dtmp4 = (double)(g_cycs_in_refresh_ximage) / dnatcycs_1sec; + sprintf(status_buf, "xfer:%08x, %5.1f ref_amt:%d " + "ch_in:%4.1f%% ref_l:%4.1f%% ref_x:%4.1f%%", + g_refresh_bytes_xfer, g_dnatcycs_1sec/(1000.0*1000.0), + g_line_ref_amt, dtmp2, dtmp3, dtmp4); + video_update_status_line(1, status_buf); + + sprintf(status_buf, "Ints:%3d I/O:%4dK BRK:%3d COP:%2d " + "Eng:%3d act:%3d hev:%3d esi:%3d edi:%3d", + g_num_irq, g_io_amt>>10, g_num_brk, g_num_cop, + g_num_enter_engine, g_engine_action, + g_engine_halt_event, g_engine_scan_int, + g_engine_doc_int); + video_update_status_line(2, status_buf); + + dtmp1 = (double)(g_cycs_in_sound1) / dnatcycs_1sec; + dtmp2 = (double)(g_cycs_in_sound2) / dnatcycs_1sec; + dtmp3 = (double)(g_cycs_in_sound3) / dnatcycs_1sec; + dtmp4 = (double)(g_cycs_in_start_sound) / dnatcycs_1sec; + dtmp5 = (double)(g_cycs_in_est_sound) / dnatcycs_1sec; + sprintf(status_buf, "snd1:%4.1f%%, 2:%4.1f%%, " + "3:%4.1f%%, st:%4.1f%% est:%4.1f%% %4.2f", + dtmp1, dtmp2, dtmp3, dtmp4, dtmp5, g_fvoices); + video_update_status_line(3, status_buf); + + code_str1 = ""; + code_str2 = ""; + if(g_code_yellow) { + code_str1 = "Code: Yellow"; + code_str2 = "Emulated system state suspect, save work"; + } + if(g_code_red) { + code_str1 = "Code: RED"; + code_str2 = "Emulated system state probably corrupt"; + } + sprintf(status_buf, "snd_plays:%4d, doc_ev:%4d, st_snd:%4d " + "snd_parms: %4d %s", + g_num_snd_plays, g_num_doc_events, g_num_start_sounds, + g_num_recalc_snd_parms, code_str1); + video_update_status_line(4, status_buf); + + draw_iwm_status(5, status_buf); + + sprintf(status_buf, "GSport v%-6s " + "Press F4 for Config Menu %s", + g_gsport_version_str, code_str2); + video_update_status_line(6, status_buf); + + g_status_refresh_needed = 1; + + g_num_irq = 0; + g_num_brk = 0; + g_num_cop = 0; + g_num_enter_engine = 0; + g_io_amt = 0; + g_engine_action = 0; + g_engine_halt_event = 0; + g_engine_scan_int = 0; + g_engine_doc_int = 0; + + g_cycs_in_40col = 0; + g_cycs_in_xredraw = 0; + g_cycs_in_check_input = 0; + g_cycs_in_refresh_line = 0; + g_cycs_in_refresh_ximage = 0; + g_cycs_in_io_read = 0; + g_cycs_in_sound1 = 0; + g_cycs_in_sound2 = 0; + g_cycs_in_sound3 = 0; + g_cycs_in_sound4 = 0; + g_cycs_in_start_sound = 0; + g_cycs_in_est_sound = 0; + g_dnatcycs_1sec = 0.0; + g_refresh_bytes_xfer = 0; + + g_num_snd_plays = 0; + g_num_doc_events = 0; + g_num_start_sounds = 0; + g_num_scan_osc = 0; + g_num_recalc_snd_parms = 0; + + g_fvoices = (float)0.0; + } + + dtime_this_vbl = dtime_now - g_dtime_last_vbl; + if(dtime_this_vbl < 0.001) { + dtime_this_vbl = 0.001; + } + + g_dtime_last_vbl = dtime_now; + + dadjcycs_this_vbl = g_dadjcycs - g_last_vbl_dadjcycs; + g_last_vbl_dadjcycs = g_dadjcycs; + + g_dtime_expected += (1.0/60.0); + + eff_pmhz = ((dadjcycs_this_vbl) / (dtime_this_vbl)) / + DCYCS_1_MHZ; + + /* using eff_pmhz, predict how many cycles can be run by */ + /* g_dtime_expected */ + + dtime_till_expected = g_dtime_expected - dtime_now; + + dratio = 60.0 * dtime_till_expected; + + predicted_pmhz = eff_pmhz * dratio; + + if(! (predicted_pmhz < (1.4 * g_projected_pmhz))) { + predicted_pmhz = 1.4 * g_projected_pmhz; + } + + if(! (predicted_pmhz > (0.7 * g_projected_pmhz))) { + predicted_pmhz = 0.7 * g_projected_pmhz; + } + + if(!(predicted_pmhz >= 1.0)) { + irq_printf("predicted: %f, setting to 1.0\n", predicted_pmhz); + predicted_pmhz = 1.0; + } + + if(!(predicted_pmhz < 250.0)) { + irq_printf("predicted: %f, setting to 250.0\n", predicted_pmhz); + predicted_pmhz = 250.0; + } + + recip_predicted_pmhz = 1.0/predicted_pmhz; + g_projected_pmhz = predicted_pmhz; + + g_recip_projected_pmhz_unl.plus_1 = 1.0*recip_predicted_pmhz; + g_recip_projected_pmhz_unl.plus_2 = 2.0*recip_predicted_pmhz; + g_recip_projected_pmhz_unl.plus_3 = 3.0*recip_predicted_pmhz; + g_recip_projected_pmhz_unl.plus_x_minus_1 = 1.01 - recip_predicted_pmhz; + + if(dtime_till_expected < -0.125) { + /* If we were way off, get back on track */ + /* this happens because our sim took much longer than */ + /* expected, so we're going to skip some VBL */ + irq_printf("adj1: dtexp:%f, dt_new:%f\n", + g_dtime_expected, dtime_now); + + dtime_diff = -dtime_till_expected; + + irq_printf("dtime_till_exp: %f, dtime_diff: %f, dcycs: %f\n", + dtime_till_expected, dtime_diff, dcycs); + + g_dtime_expected += dtime_diff; + } + + if(dtime_till_expected > (3/60.0)) { + /* we're running fast, usleep */ + micro_sleep(dtime_till_expected - (1/60.0)); + } + + g_dtime_this_vbl_array[prev_vbl_index] = dtime_this_vbl; + g_dtime_exp_array[prev_vbl_index] = g_dtime_expected; + g_dtime_pmhz_array[prev_vbl_index] = predicted_pmhz; + g_dtime_eff_pmhz_array[prev_vbl_index] = eff_pmhz; + + + if(g_c041_val & C041_EN_VBL_INTS) { + add_event_vbl(); + } + + g_25sec_cntr++; + if(g_25sec_cntr >= 16) { + g_25sec_cntr = 0; + if(g_c041_val & C041_EN_25SEC_INTS) { + add_irq(IRQ_PENDING_C046_25SEC); + g_c046_val |= 0x10; + irq_printf("Setting c046 .25 sec int, g_irq_pend:%d\n", + g_irq_pending); + } + } + + g_1sec_cntr++; + if(g_1sec_cntr >= 60) { + g_1sec_cntr = 0; + tmp = g_c023_val; + tmp |= 0x40; /* set 1sec int */ + if(tmp & 0x04) { + tmp |= 0x80; + add_irq(IRQ_PENDING_C023_1SEC); + irq_printf("Setting c023 to %02x irq_pend: %d\n", + tmp, g_irq_pending); + } + g_c023_val = tmp; + } + + if(!g_scan_int_events) { + check_scan_line_int(dcycs, 0); + } + + doit_3_persec = 0; + if(g_config_iwm_vbl_count > 0) { + g_config_iwm_vbl_count--; + } else { + g_config_iwm_vbl_count = 20; + doit_3_persec = 1; + } + + iwm_vbl_update(doit_3_persec); // OG Disabling config update #ifndef ACTIVEGS - config_vbl_update(doit_3_persec); + config_vbl_update(doit_3_persec); #else // OG Added disk update { @@ -2360,373 +2369,377 @@ update_60hz(double dcycs, double dtime_now) checkImages(); } #endif - - video_update(); - sound_update(dcycs); - clock_update(); - scc_update(dcycs); - //Check and see if virtual printer timeout has been reached. - if (g_printer_timeout) + + video_update(); + sound_update(dcycs); + clock_update(); + scc_update(dcycs); + //Check and see if virtual printer timeout has been reached. + if (g_printer_timeout) + { + printer_update(); + } + if (g_imagewriter_timeout) { - printer_update(); - } - paddle_update_buttons(); -} - -void -do_vbl_int() -{ - if(g_c041_val & C041_EN_VBL_INTS) { - g_c046_val |= 0x08; - add_irq(IRQ_PENDING_C046_VBL); - irq_printf("Setting c046 vbl_int_status to 1, irq_pend: %d\n", - g_irq_pending); - } -} - - -void -do_scan_int(double dcycs, int line) -{ - int c023_val; - g_scan_int_events = 0; - - c023_val = g_c023_val; - if(c023_val & 0x20) { - halt_printf("c023 scan_int and another on line %03x\n", line); - } - - /* make sure scan int is still enabled for this line */ - if((g_slow_memory_ptr[0x19d00 + line] & 0x40) && - (g_cur_a2_stat & ALL_STAT_SUPER_HIRES)) { - /* valid interrupt, do it */ - c023_val |= 0xa0; /* vgc_int and scan_int */ - if(c023_val & 0x02) { - add_irq(IRQ_PENDING_C023_SCAN); - irq_printf("Setting c023 to %02x, irq_pend: %d\n", - c023_val, g_irq_pending); - } - g_c023_val = c023_val; - HALT_ON(HALT_ON_SCAN_INT, "In do_scan_int\n"); - } else { - /* scan int bit cleared on scan line control byte */ - /* look for next line, if any */ - check_scan_line_int(dcycs, line+1); - } -} - -void -check_scan_line_int(double dcycs, int cur_video_line) -{ - int delay; - int start; - int line; - int i; - /* Called during VBL interrupt phase */ - - if(!(g_cur_a2_stat & ALL_STAT_SUPER_HIRES)) { - return; - } - - if(g_c023_val & 0x20) { - /* don't check for any more */ - return; - } - - start = cur_video_line; - if(start < 0) { - halt_printf("check_scan_line_int: cur_video_line: %d\n", - cur_video_line); - start = 0; - } - - for(line = start; line < 200; line++) { - i = line; - - if(i < 0 || i >= 200) { - halt_printf("check_new_scan_int:i:%d, line:%d, st:%d\n", - i, line, start); - i = 0; - } - if(g_slow_memory_ptr[0x19d00+i] & 0x40) { - irq_printf("Adding scan_int for line %d\n", i); + imagewriter_update(); + } + paddle_update_buttons(); +} + +void +do_vbl_int() +{ + if(g_c041_val & C041_EN_VBL_INTS) { + g_c046_val |= 0x08; + add_irq(IRQ_PENDING_C046_VBL); + irq_printf("Setting c046 vbl_int_status to 1, irq_pend: %d\n", + g_irq_pending); + } +} + + +void +do_scan_int(double dcycs, int line) +{ + int c023_val; + g_scan_int_events = 0; + + c023_val = g_c023_val; + if(c023_val & 0x20) { + halt_printf("c023 scan_int and another on line %03x\n", line); + } + + /* make sure scan int is still enabled for this line */ + if((g_slow_memory_ptr[0x19d00 + line] & 0x40) && + (g_cur_a2_stat & ALL_STAT_SUPER_HIRES)) { + /* valid interrupt, do it */ + c023_val |= 0xa0; /* vgc_int and scan_int */ + if(c023_val & 0x02) { + add_irq(IRQ_PENDING_C023_SCAN); + irq_printf("Setting c023 to %02x, irq_pend: %d\n", + c023_val, g_irq_pending); + } + g_c023_val = c023_val; + HALT_ON(HALT_ON_SCAN_INT, "In do_scan_int\n"); + } else { + /* scan int bit cleared on scan line control byte */ + /* look for next line, if any */ + check_scan_line_int(dcycs, line+1); + } +} + +void +check_scan_line_int(double dcycs, int cur_video_line) +{ + int delay; + int start; + int line; + int i; + /* Called during VBL interrupt phase */ + + if(!(g_cur_a2_stat & ALL_STAT_SUPER_HIRES)) { + return; + } + + if(g_c023_val & 0x20) { + /* don't check for any more */ + return; + } + + start = cur_video_line; + if(start < 0) { + halt_printf("check_scan_line_int: cur_video_line: %d\n", + cur_video_line); + start = 0; + } + + for(line = start; line < 200; line++) { + i = line; + + if(i < 0 || i >= 200) { + halt_printf("check_new_scan_int:i:%d, line:%d, st:%d\n", + i, line, start); + i = 0; + } + if(g_slow_memory_ptr[0x19d00+i] & 0x40) { + irq_printf("Adding scan_int for line %d\n", i); delay = (int)( (DCYCS_IN_16MS/262.0) * ((double)line) ); - add_event_entry(g_last_vbl_dcycs + delay, EV_SCAN_INT + - (line << 8)); - g_scan_int_events = 1; - check_for_one_event_type(EV_SCAN_INT); - break; - } - } -} - -void -check_for_new_scan_int(double dcycs) -{ - int cur_video_line; - - cur_video_line = get_lines_since_vbl(dcycs) >> 8; - - check_scan_line_int(dcycs, cur_video_line); -} - -void -init_reg() -{ - engine.acc = 0; - engine.xreg = 0; - engine.yreg = 0; - engine.stack = 0x1ff; - engine.direct = 0; - engine.psr = 0x134; - engine.fplus_ptr = 0; - -} - - -void -handle_action(word32 ret) -{ - int type; - - type = EXTRU(ret,3,4); - switch(type) { - case RET_BREAK: - do_break(ret & 0xff); - break; - case RET_COP: - do_cop(ret & 0xff); - break; -#if 0 - case RET_MVN: - do_mvn(ret & 0xffff); - break; -#endif - case RET_C700: - do_c700(ret); - break; - case RET_C70A: - do_c70a(ret); - break; - case RET_C70D: - do_c70d(ret); - break; -#if 0 - case RET_ADD_DEC_8: - do_add_dec_8(ret); - break; - case RET_ADD_DEC_16: - do_add_dec_16(ret); - break; -#endif - case RET_IRQ: - irq_printf("Special fast IRQ response. irq_pending: %x\n", - g_irq_pending); - break; - case RET_WDM: - do_wdm(ret & 0xff); - break; - case RET_STP: - do_stp(); - break; - default: - halt_printf("Unknown special action: %08x!\n", ret); - } - -} - -#if 0 -void -do_add_dec_8(word32 ret) -{ - halt_printf("do_add_dec_8 called, ret: %08x\n", ret); -} - -void -do_add_dec_16(word32 ret) -{ - halt_printf("do_add_dec_16 called, ret: %08x\n", ret); -} -#endif - -void -do_break(word32 ret) -{ - if(!g_testing) { - printf("I think I got a break, second byte: %02x!\n", ret); - printf("kpc: %06x\n", engine.kpc); - } - - halt_printf("do_break, kpc: %06x\n", engine.kpc); - enter_debug = 1; -} - -void -do_cop(word32 ret) -{ - halt_printf("COP instr %02x!\n", ret); - fflush(stdout); -} - -#if 0 -void -do_mvn(word32 banks) -{ - int src_bank, dest_bank; - int dest, src; - int num; - int i; - int val; - - halt_printf("In MVN...just quitting\n"); - return; - printf("MVN instr with %04x, cycles: %08x\n", banks, engine.cycles); - src_bank = banks >> 8; - dest_bank = banks & 0xff; - printf("psr: %03x\n", engine.psr); - if((engine.psr & 0x30) != 0) { - halt_printf("MVN in non-native mode unimplemented!\n"); - } - - dest = dest_bank << 16 | engine.yreg; - src = src_bank << 16 | engine.xreg; - num = engine.acc; - printf("Moving %08x+1 bytes from %08x to %08x\n", num, src, dest); - - for(i = 0; i <= num; i++) { - val = get_memory_c(src, 0); - set_memory_c(dest, val, 0); - src = (src_bank << 16) | ((src + 1) & 0xffff); - dest = (dest_bank << 16) | ((dest + 1) & 0xffff); - } - engine.dbank = dest_bank; - engine.acc = 0xffff; - engine.yreg = dest & 0xffff; - engine.xreg = src & 0xffff; - engine.kpc = (engine.kpc + 3); - printf("move done. db: %02x, acc: %04x, y: %04x, x: %04x, num: %08x\n", - engine.dbank, engine.acc, engine.yreg, engine.xreg, num); -} -#endif - -void -do_wdm(word32 arg) -{ - switch(arg) { - case 0x8d: /* Bouncin Ferno does WDM 8d */ - break; - default: - halt_printf("do_wdm: %02x!\n", arg); - } -} - -void -do_wai() -{ - halt_printf("do_wai!\n"); -} - -void -do_stp() -{ - if(!g_stp_pending) { - g_stp_pending = 1; - halt_printf("Hit STP instruction at: %06x, press RESET to " - "continue\n", engine.kpc); - } -} - -void -size_fail(int val, word32 v1, word32 v2) -{ - halt_printf("Size failure, val: %08x, %08x %08x\n", val, v1, v2); -} - -int -fatal_printf(const char *fmt, ...) -{ - va_list ap; - int ret; - - va_start(ap, fmt); - - if(g_fatal_log < 0) { - g_fatal_log = 0; - } - ret = gsport_vprintf(fmt, ap); - va_end(ap); - - return ret; -} - -int -gsport_vprintf(const char *fmt, va_list ap) -{ - char *bufptr, *buf2ptr; - int len; - int ret; - + add_event_entry(g_last_vbl_dcycs + delay, EV_SCAN_INT + + (line << 8)); + g_scan_int_events = 1; + check_for_one_event_type(EV_SCAN_INT); + break; + } + } +} + +void +check_for_new_scan_int(double dcycs) +{ + int cur_video_line; + + cur_video_line = get_lines_since_vbl(dcycs) >> 8; + + check_scan_line_int(dcycs, cur_video_line); +} + +void +init_reg() +{ + engine.acc = 0; + engine.xreg = 0; + engine.yreg = 0; + engine.stack = 0x1ff; + engine.direct = 0; + engine.psr = 0x134; + engine.fplus_ptr = 0; + +} + + +void +handle_action(word32 ret) +{ + int type; + + type = EXTRU(ret,3,4); + switch(type) { + case RET_BREAK: + do_break(ret & 0xff); + break; + case RET_COP: + do_cop(ret & 0xff); + break; +#if 0 + case RET_MVN: + do_mvn(ret & 0xffff); + break; +#endif + case RET_C700: + do_c700(ret); + break; + case RET_C70A: + do_c70a(ret); + break; + case RET_C70D: + do_c70d(ret); + break; +#if 0 + case RET_ADD_DEC_8: + do_add_dec_8(ret); + break; + case RET_ADD_DEC_16: + do_add_dec_16(ret); + break; +#endif + case RET_IRQ: + irq_printf("Special fast IRQ response. irq_pending: %x\n", + g_irq_pending); + break; + case RET_WDM: + do_wdm(ret & 0xff); + break; + case RET_STP: + do_stp(); + break; + default: + halt_printf("Unknown special action: %08x!\n", ret); + } + +} + +#if 0 +void +do_add_dec_8(word32 ret) +{ + halt_printf("do_add_dec_8 called, ret: %08x\n", ret); +} + +void +do_add_dec_16(word32 ret) +{ + halt_printf("do_add_dec_16 called, ret: %08x\n", ret); +} +#endif + +void +do_break(word32 ret) +{ + if(!g_testing) { + printf("I think I got a break, second byte: %02x!\n", ret); + printf("kpc: %06x\n", engine.kpc); + } + + halt_printf("do_break, kpc: %06x\n", engine.kpc); + enter_debug = 1; +} + +void +do_cop(word32 ret) +{ + halt_printf("COP instr %02x!\n", ret); + fflush(stdout); +} + +#if 0 +void +do_mvn(word32 banks) +{ + int src_bank, dest_bank; + int dest, src; + int num; + int i; + int val; + + halt_printf("In MVN...just quitting\n"); + return; + printf("MVN instr with %04x, cycles: %08x\n", banks, engine.cycles); + src_bank = banks >> 8; + dest_bank = banks & 0xff; + printf("psr: %03x\n", engine.psr); + if((engine.psr & 0x30) != 0) { + halt_printf("MVN in non-native mode unimplemented!\n"); + } + + dest = dest_bank << 16 | engine.yreg; + src = src_bank << 16 | engine.xreg; + num = engine.acc; + printf("Moving %08x+1 bytes from %08x to %08x\n", num, src, dest); + + for(i = 0; i <= num; i++) { + val = get_memory_c(src, 0); + set_memory_c(dest, val, 0); + src = (src_bank << 16) | ((src + 1) & 0xffff); + dest = (dest_bank << 16) | ((dest + 1) & 0xffff); + } + engine.dbank = dest_bank; + engine.acc = 0xffff; + engine.yreg = dest & 0xffff; + engine.xreg = src & 0xffff; + engine.kpc = (engine.kpc + 3); + printf("move done. db: %02x, acc: %04x, y: %04x, x: %04x, num: %08x\n", + engine.dbank, engine.acc, engine.yreg, engine.xreg, num); +} +#endif + +void +do_wdm(word32 arg) +{ + switch(arg) { + case 0x8d: /* Bouncin Ferno does WDM 8d */ + break; + default: + halt_printf("do_wdm: %02x!\n", arg); + } +} + +void +do_wai() +{ + halt_printf("do_wai!\n"); +} + +void +do_stp() +{ + if(!g_stp_pending) { + g_stp_pending = 1; + halt_printf("Hit STP instruction at: %06x, press RESET to " + "continue\n", engine.kpc); + } +} + +void +size_fail(int val, word32 v1, word32 v2) +{ + halt_printf("Size failure, val: %08x, %08x %08x\n", val, v1, v2); +} + +int +fatal_printf(const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + + if(g_fatal_log < 0) { + g_fatal_log = 0; + } + ret = gsport_vprintf(fmt, ap); + va_end(ap); + + return ret; +} + +int +gsport_vprintf(const char *fmt, va_list ap) +{ + char *bufptr, *buf2ptr; + int len; + int ret; + bufptr = (char*)malloc(4096); // OG Added Cast - ret = vsnprintf(bufptr, 4090, fmt, ap); - + ret = vsnprintf(bufptr, 4090, fmt, ap); + // OG Display warning printf("Warning:%s",bufptr); - len = strlen(bufptr); - if(g_fatal_log >= 0 && g_fatal_log < MAX_FATAL_LOGS) { + len = strlen(bufptr); + if(g_fatal_log >= 0 && g_fatal_log < MAX_FATAL_LOGS) { buf2ptr = (char*)malloc(len+1); // OG Added Cast - memcpy(buf2ptr, bufptr, len+1); - g_fatal_log_strs[g_fatal_log++] = buf2ptr; - } - must_write(1, bufptr, len); - if(g_debug_file_fd >= 0) { - must_write(g_debug_file_fd, bufptr, len); - } - free(bufptr); - - return ret; -} - -void -must_write(int fd, char *bufptr, int len) -{ - int ret; -#ifndef __OS2__ - while(len > 0) { - ret = write(fd, bufptr, len); - if(ret >= 0) { - len -= ret; - bufptr += ret; - } else if(errno != EAGAIN && errno != EINTR) { - return; // just get out - } - } -#else - printf("%s\n",bufptr); -#endif -} - -void -clear_fatal_logs() -{ - int i; - - for(i = 0; i < g_fatal_log; i++) { - free(g_fatal_log_strs[i]); - g_fatal_log_strs[i] = 0; - } - g_fatal_log = -1; -} - -char * -gsport_malloc_str(char *in_str) -{ - char *str; - int len; - - len = strlen(in_str) + 1; + memcpy(buf2ptr, bufptr, len+1); + g_fatal_log_strs[g_fatal_log++] = buf2ptr; + } + must_write(1, bufptr, len); + if(g_debug_file_fd >= 0) { + must_write(g_debug_file_fd, bufptr, len); + } + free(bufptr); + + return ret; +} + +void +must_write(int fd, char *bufptr, int len) +{ + int ret; +#ifndef __OS2__ + while(len > 0) { + ret = write(fd, bufptr, len); + if(ret >= 0) { + len -= ret; + bufptr += ret; + } else if(errno != EAGAIN && errno != EINTR) { + return; // just get out + } + } +#else + printf("%s\n",bufptr); +#endif +} + +void +clear_fatal_logs() +{ + int i; + + for(i = 0; i < g_fatal_log; i++) { + free(g_fatal_log_strs[i]); + g_fatal_log_strs[i] = 0; + } + g_fatal_log = -1; +} + +char * +gsport_malloc_str(char *in_str) +{ + char *str; + int len; + + len = strlen(in_str) + 1; str = (char*)malloc(len); // OG Added cast - memcpy(str, in_str, len); - - return str; -} + memcpy(str, in_str, len); + + return str; +}