From 417e51eaeb197b4453099f61e42aeac80f71985c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Tue, 4 Jul 2023 11:26:39 +0200 Subject: [PATCH 01/29] Road to rc2 --- include/CPU.h | 17 + include/Config.h | 2 + include/Ports.h | 1 + include/Tape.h | 3 +- include/Video.h | 23 + include/Z80_JLS/z80.h | 6 +- include/ZXKeyb.h | 2 + include/messages.h | 29 +- platformio.ini | 12 +- sdkconfig.ESPectrum | 33 +- ...nfig.pico32.old => sdkconfig.ESPectrum.old | 112 +- sdkconfig.pico32 | 1260 ----------------- src/AySound.cpp | 7 +- src/CPU.cpp | 32 +- src/Config.cpp | 416 ++++-- src/ESPectrum.cpp | 576 +++++--- src/FileSNA.cpp | 15 +- src/FileUtils.cpp | 16 +- src/FileZ80.cpp | 16 +- src/OSDMain.cpp | 218 +-- src/OSDMenu.cpp | 360 ++--- src/Ports.cpp | 92 +- src/Tape.cpp | 20 +- src/Z80_JLS.cpp | 163 ++- src/ZXKeyb.cpp | 8 +- 25 files changed, 1463 insertions(+), 1976 deletions(-) rename sdkconfig.pico32.old => sdkconfig.ESPectrum.old (92%) delete mode 100644 sdkconfig.pico32 diff --git a/include/CPU.h b/include/CPU.h index 2e1cad92..d8fbb1c4 100644 --- a/include/CPU.h +++ b/include/CPU.h @@ -40,6 +40,16 @@ visit https://zxespectrum.speccy.org/contacto #include "ESPectrum.h" #include "ESP32Lib/ESP32Lib.h" +// #define INT_START48 0 +// #define INT_END48 32 +// #define INT_START128 0 +// #define INT_END128 36 + +#define INT_START48 0 +#define INT_END48 32 +#define INT_START128 0 +#define INT_END128 36 + class CPU { public: @@ -73,6 +83,13 @@ class CPU // Frames elapsed static uint32_t framecnt; + // Late timing + static uint8_t latetiming; + + // INT signal lenght + static uint8_t IntStart; + static uint8_t IntEnd; + }; static const unsigned char wait_st[228] = { diff --git a/include/Config.h b/include/Config.h index d536b49d..5a195b13 100644 --- a/include/Config.h +++ b/include/Config.h @@ -63,10 +63,12 @@ class Config static bool AY48; static uint8_t joystick; static uint8_t videomode; + static uint8_t AluTiming; // config persistence static void load(); static void save(); + static void save(string value); // // list of snapshot file names // static string sna_file_list; diff --git a/include/Ports.h b/include/Ports.h index 5dfcaf32..e42d8fd8 100644 --- a/include/Ports.h +++ b/include/Ports.h @@ -45,6 +45,7 @@ class Ports static uint8_t port[128]; static uint8_t IRAM_ATTR input(uint16_t address); static void IRAM_ATTR output(uint16_t address, uint8_t data); + // static void ContendedIODelay(uint16_t portNumber); }; diff --git a/include/Tape.h b/include/Tape.h index 34a9cf52..8f196167 100644 --- a/include/Tape.h +++ b/include/Tape.h @@ -85,9 +85,10 @@ class Tape static uint8_t romLoading; static void Init(); + static void Open(string name); static void TAP_Play(); static void TAP_Stop(); - static void TAP_Read(); + static void IRAM_ATTR TAP_Read(); static void Save(); }; diff --git a/include/Video.h b/include/Video.h index 81276cde..25d61d78 100644 --- a/include/Video.h +++ b/include/Video.h @@ -40,6 +40,29 @@ visit https://zxespectrum.speccy.org/contacto #include "ESPectrum.h" #include "ESP32Lib/ESP32Lib.h" +/* +.- - <-INT-> - - - - - - - - - - - - - -. --- --- +: VBLANK + Invisible Top Border : | 16 / 15 | +.---------------------------------.- - -: --- --- | +| Top Border | : | 48 | | +|----.-----------------------.----| : --- | | +|L | |R | : | | | +|e | |i | H : | | | +|f B| |g B| B : | | | +|t o| Paper |h o| L : | 192 | 296 | 312 / 311 +| r| |t r| A : | | | +| d| | d| N : | | | +| e| | e| K : | | | +| r| | r| : | | | +|----'-----------------------'----| : --- | | +| Bottom Border | : | 56 | | +'---------------------------------'- - -' --- --- --- + +|----|-----------------------|----| + 48 256 48 +|---------------------------------| + 352 */ + #define SPEC_W 256 #define SPEC_H 192 diff --git a/include/Z80_JLS/z80.h b/include/Z80_JLS/z80.h index b60f125e..d339d8c8 100644 --- a/include/Z80_JLS/z80.h +++ b/include/Z80_JLS/z80.h @@ -393,9 +393,9 @@ class Z80 { static void IRAM_ATTR execute(); // Check INT - static void checkINT(void); + static void IRAM_ATTR checkINT(void); - static void incRegR(uint8_t inc); + static void IRAM_ATTR incRegR(uint8_t inc); #ifdef WITH_BREAKPOINT_SUPPORT static bool isBreakpoint(void) { return breakpointEnabled; } @@ -509,6 +509,8 @@ class Z80 { // OUTD static void IRAM_ATTR outd(void); + static void SetAbortedINxR_OTxRFlags(); + // BIT n,r static inline void bitTest(uint8_t mask, uint8_t reg); diff --git a/include/ZXKeyb.h b/include/ZXKeyb.h index e24154b1..39073473 100644 --- a/include/ZXKeyb.h +++ b/include/ZXKeyb.h @@ -52,6 +52,8 @@ class ZXKeyb static uint8_t PrevFkeyOSD; + static bool Exists; + private: static void putRows(uint8_t row_pattern); static uint8_t getCols(); diff --git a/include/messages.h b/include/messages.h index 41ddee5e..4967bdf6 100644 --- a/include/messages.h +++ b/include/messages.h @@ -196,20 +196,29 @@ static const char *MENU_PERSIST_SAVE[2] = { MENU_PERSIST_SAVE_EN, MENU_PERSIST_S "Cargar snapshot\n" MENU_PERSIST_ES static const char *MENU_PERSIST_LOAD[2] = { MENU_PERSIST_LOAD_EN, MENU_PERSIST_LOAD_ES }; +// #define MENU_STORAGE_EN "Storage\n"\ +// "Internal\t[I]\n"\ +// "SD Card\t[S]\n"\ +// "Refresh directories\n" +// #define MENU_STORAGE_ES "Almacenamiento\n"\ +// "Interno\t[I]\n"\ +// "Tarjeta SD\t[S]\n"\ +// "Refrescar directorios\n" +// static const char *MENU_STORAGE[2] = { MENU_STORAGE_EN, MENU_STORAGE_ES }; + #define MENU_STORAGE_EN "Storage\n"\ - "Internal\t[I]\n"\ - "SD Card\t[S]\n"\ "Refresh directories\n" #define MENU_STORAGE_ES "Almacenamiento\n"\ - "Interno\t[I]\n"\ - "Tarjeta SD\t[S]\n"\ "Refrescar directorios\n" static const char *MENU_STORAGE[2] = { MENU_STORAGE_EN, MENU_STORAGE_ES }; + #define MENU_OTHER_EN "Other\n"\ - "AY on 48K\t>\n" + "AY on 48K\t>\n"\ + "ALU Timing\t>\n" #define MENU_OTHER_ES "Otros\n"\ - "AY en 48K\t>\n" + "AY en 48K\t>\n"\ + "Timing ULA\t>\n" static const char *MENU_OTHER[2] = { MENU_OTHER_EN, MENU_OTHER_ES }; #define MENU_AY48_EN "AY on 48K\n"\ @@ -220,6 +229,14 @@ static const char *MENU_OTHER[2] = { MENU_OTHER_EN, MENU_OTHER_ES }; "No\t[N]\n" static const char *MENU_AY48[2] = { MENU_AY48_EN, MENU_AY48_ES }; +#define MENU_ALUTIMING_EN "ALU Timing\n"\ + "Early\t[E]\n"\ + "Late\t[L]\n" +#define MENU_ALUTIMING_ES "Timing ULA\n"\ + "Early\t[E]\n"\ + "Late\t[L]\n" +static const char *MENU_ALUTIMING[2] = { MENU_ALUTIMING_EN, MENU_ALUTIMING_ES }; + #define MENU_ARCH_EN "Select machine\n"\ "ZX Spectrum 48K\n"\ "ZX Spectrum 128K\n" diff --git a/platformio.ini b/platformio.ini index da2acb12..6bb000bf 100644 --- a/platformio.ini +++ b/platformio.ini @@ -8,8 +8,9 @@ ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html -[env] +[env:ESPectrum] platform = espressif32@3.5 +platform_packages = toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 board = pico32 framework = espidf board_build.mcu = esp32 @@ -23,16 +24,7 @@ monitor_filters = esp32_exception_decoder board_build.partitions = ESPecpart.csv extra_scripts = download_fs.py - -[env:pico32] -build_flags = - -w - -O2 -build_type = release - -[env:ESPectrum] build_flags = -w -O2 - -D ZXKEYB=1 build_type = release \ No newline at end of file diff --git a/sdkconfig.ESPectrum b/sdkconfig.ESPectrum index 15c62535..08d95131 100644 --- a/sdkconfig.ESPectrum +++ b/sdkconfig.ESPectrum @@ -70,7 +70,6 @@ CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y # # Security features # -CONFIG_SECURE_BOOT_SUPPORTS_RSA=y # CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set # CONFIG_SECURE_BOOT is not set # CONFIG_SECURE_FLASH_ENC_ENABLED is not set @@ -272,10 +271,11 @@ CONFIG_ESP_TLS_USING_MBEDTLS=y # ESP32-specific # # CONFIG_ESP32_REV_MIN_0 is not set -# CONFIG_ESP32_REV_MIN_1 is not set +CONFIG_ESP32_REV_MIN_1=y # CONFIG_ESP32_REV_MIN_2 is not set -CONFIG_ESP32_REV_MIN_3=y -CONFIG_ESP32_REV_MIN=3 +# CONFIG_ESP32_REV_MIN_3 is not set +CONFIG_ESP32_REV_MIN=1 +CONFIG_ESP32_DPORT_WORKAROUND=y # CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set # CONFIG_ESP32_DEFAULT_CPU_FREQ_160 is not set CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y @@ -452,12 +452,12 @@ CONFIG_ESP_TIMER_IMPL_TG0_LAC=y # # Wi-Fi # -CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=4 -CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=8 -# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set -CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y -CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1 -CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=16 +CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=2 +CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=0 +CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y +# CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER is not set +CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0 +CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=16 # CONFIG_ESP32_WIFI_CSI_ENABLED is not set CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y CONFIG_ESP32_WIFI_TX_BA_WIN=6 @@ -473,8 +473,8 @@ CONFIG_WIFI_LOG_DEFAULT_LEVEL_ERROR=y # CONFIG_WIFI_LOG_DEFAULT_LEVEL_INFO is not set # CONFIG_WIFI_LOG_DEFAULT_LEVEL_DEBUG is not set # CONFIG_WIFI_LOG_DEFAULT_LEVEL_VERBOSE is not set -CONFIG_ESP32_WIFI_IRAM_OPT=y -CONFIG_ESP32_WIFI_RX_IRAM_OPT=y +# CONFIG_ESP32_WIFI_IRAM_OPT is not set +# CONFIG_ESP32_WIFI_RX_IRAM_OPT is not set # CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set # CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set # CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE is not set @@ -966,7 +966,7 @@ CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y # CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set # CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set # CONFIG_SPI_FLASH_USE_LEGACY_IMPL is not set -# CONFIG_SPI_FLASH_SHARE_SPI1_BUS is not set +CONFIG_SPI_FLASH_SHARE_SPI1_BUS=y # CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20 @@ -990,14 +990,12 @@ CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y # # SPIFFS Configuration # -CONFIG_SPIFFS_MAX_PARTITIONS=3 +CONFIG_SPIFFS_MAX_PARTITIONS=1 # # SPIFFS Cache Configuration # -CONFIG_SPIFFS_CACHE=y -CONFIG_SPIFFS_CACHE_WR=y -# CONFIG_SPIFFS_CACHE_STATS is not set +# CONFIG_SPIFFS_CACHE is not set # end of SPIFFS Cache Configuration CONFIG_SPIFFS_PAGE_CHECK=y @@ -1017,7 +1015,6 @@ CONFIG_SPIFFS_USE_MTIME=y # CONFIG_SPIFFS_DBG is not set # CONFIG_SPIFFS_API_DBG is not set # CONFIG_SPIFFS_GC_DBG is not set -# CONFIG_SPIFFS_CACHE_DBG is not set # CONFIG_SPIFFS_CHECK_DBG is not set # CONFIG_SPIFFS_TEST_VISUALISATION is not set # end of Debug Configuration diff --git a/sdkconfig.pico32.old b/sdkconfig.ESPectrum.old similarity index 92% rename from sdkconfig.pico32.old rename to sdkconfig.ESPectrum.old index 3d639627..ffcfd065 100644 --- a/sdkconfig.pico32.old +++ b/sdkconfig.ESPectrum.old @@ -70,7 +70,6 @@ CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y # # Security features # -CONFIG_SECURE_BOOT_SUPPORTS_RSA=y # CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set # CONFIG_SECURE_BOOT is not set # CONFIG_SECURE_FLASH_ENC_ENABLED is not set @@ -271,16 +270,77 @@ CONFIG_ESP_TLS_USING_MBEDTLS=y # # ESP32-specific # +CONFIG_ESP32_ECO3_CACHE_LOCK_FIX=y # CONFIG_ESP32_REV_MIN_0 is not set -# CONFIG_ESP32_REV_MIN_1 is not set +CONFIG_ESP32_REV_MIN_1=y # CONFIG_ESP32_REV_MIN_2 is not set -CONFIG_ESP32_REV_MIN_3=y -CONFIG_ESP32_REV_MIN=3 +# CONFIG_ESP32_REV_MIN_3 is not set +CONFIG_ESP32_REV_MIN=1 +CONFIG_ESP32_DPORT_WORKAROUND=y # CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set # CONFIG_ESP32_DEFAULT_CPU_FREQ_160 is not set CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240 -# CONFIG_ESP32_SPIRAM_SUPPORT is not set +CONFIG_ESP32_SPIRAM_SUPPORT=y + +# +# SPI RAM config +# +CONFIG_SPIRAM_TYPE_AUTO=y +# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set +# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set +# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set +CONFIG_SPIRAM_SIZE=-1 +# CONFIG_SPIRAM_SPEED_40M is not set +CONFIG_SPIRAM_SPEED_80M=y +CONFIG_SPIRAM=y +CONFIG_SPIRAM_BOOT_INIT=y +# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set +# CONFIG_SPIRAM_USE_MEMMAP is not set +CONFIG_SPIRAM_USE_CAPS_ALLOC=y +# CONFIG_SPIRAM_USE_MALLOC is not set +CONFIG_SPIRAM_MEMTEST=y +# CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP is not set +# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set +CONFIG_SPIRAM_CACHE_WORKAROUND=y + +# +# SPIRAM cache workaround debugging +# +CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW=y +# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST is not set +# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS is not set +# end of SPIRAM cache workaround debugging + +CONFIG_SPIRAM_BANKSWITCH_ENABLE=y +CONFIG_SPIRAM_BANKSWITCH_RESERVE=8 +# CONFIG_SPIRAM_OCCUPY_HSPI_HOST is not set +CONFIG_SPIRAM_OCCUPY_VSPI_HOST=y +# CONFIG_SPIRAM_OCCUPY_NO_HOST is not set + +# +# PSRAM clock and cs IO for ESP32-DOWD +# +CONFIG_D0WD_PSRAM_CLK_IO=17 +CONFIG_D0WD_PSRAM_CS_IO=16 +# end of PSRAM clock and cs IO for ESP32-DOWD + +# +# PSRAM clock and cs IO for ESP32-D2WD +# +CONFIG_D2WD_PSRAM_CLK_IO=9 +CONFIG_D2WD_PSRAM_CS_IO=10 +# end of PSRAM clock and cs IO for ESP32-D2WD + +# +# PSRAM clock and cs IO for ESP32-PICO +# +CONFIG_PICO_PSRAM_CS_IO=10 +# end of PSRAM clock and cs IO for ESP32-PICO + +# CONFIG_SPIRAM_2T_MODE is not set +# end of SPI RAM config + # CONFIG_ESP32_TRAX is not set CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0 # CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set @@ -429,7 +489,7 @@ CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER=y # CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT is not set CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT=y # CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set -CONFIG_ESP_SYSTEM_PD_FLASH=y +# CONFIG_ESP_SYSTEM_PSRAM_LEAKAGE_WORKAROUND is not set # CONFIG_ESP_SYSTEM_FLASH_LEAKAGE_WORKAROUND is not set # @@ -452,16 +512,18 @@ CONFIG_ESP_TIMER_IMPL_TG0_LAC=y # # Wi-Fi # -CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=4 -CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=8 -# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set -CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y -CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1 -CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=16 +CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=2 +CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=0 +CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y +# CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER is not set +CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0 +CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=16 +CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=32 # CONFIG_ESP32_WIFI_CSI_ENABLED is not set CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y CONFIG_ESP32_WIFI_TX_BA_WIN=6 # CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED is not set +# CONFIG_ESP32_WIFI_AMSDU_TX_ENABLED is not set CONFIG_ESP32_WIFI_NVS_ENABLED=y # CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0 is not set CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1=y @@ -473,8 +535,8 @@ CONFIG_WIFI_LOG_DEFAULT_LEVEL_ERROR=y # CONFIG_WIFI_LOG_DEFAULT_LEVEL_INFO is not set # CONFIG_WIFI_LOG_DEFAULT_LEVEL_DEBUG is not set # CONFIG_WIFI_LOG_DEFAULT_LEVEL_VERBOSE is not set -CONFIG_ESP32_WIFI_IRAM_OPT=y -CONFIG_ESP32_WIFI_RX_IRAM_OPT=y +# CONFIG_ESP32_WIFI_IRAM_OPT is not set +# CONFIG_ESP32_WIFI_RX_IRAM_OPT is not set # CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set # CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set # CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE is not set @@ -526,13 +588,14 @@ CONFIG_FATFS_CODEPAGE=437 # CONFIG_FATFS_LFN_NONE is not set CONFIG_FATFS_LFN_HEAP=y # CONFIG_FATFS_LFN_STACK is not set -CONFIG_FATFS_MAX_LFN=32 +CONFIG_FATFS_MAX_LFN=28 CONFIG_FATFS_API_ENCODING_ANSI_OEM=y # CONFIG_FATFS_API_ENCODING_UTF_16 is not set # CONFIG_FATFS_API_ENCODING_UTF_8 is not set CONFIG_FATFS_FS_LOCK=0 CONFIG_FATFS_TIMEOUT_MS=10000 # CONFIG_FATFS_PER_FILE_CACHE is not set +CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y # CONFIG_FATFS_USE_FASTSEEK is not set # end of FAT Filesystem support @@ -771,6 +834,7 @@ CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y # mbedTLS # CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y +# CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC is not set # CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set # CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y @@ -966,7 +1030,7 @@ CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y # CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set # CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set # CONFIG_SPI_FLASH_USE_LEGACY_IMPL is not set -# CONFIG_SPI_FLASH_SHARE_SPI1_BUS is not set +CONFIG_SPI_FLASH_SHARE_SPI1_BUS=y # CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20 @@ -990,14 +1054,12 @@ CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y # # SPIFFS Configuration # -CONFIG_SPIFFS_MAX_PARTITIONS=3 +CONFIG_SPIFFS_MAX_PARTITIONS=1 # # SPIFFS Cache Configuration # -CONFIG_SPIFFS_CACHE=y -CONFIG_SPIFFS_CACHE_WR=y -# CONFIG_SPIFFS_CACHE_STATS is not set +# CONFIG_SPIFFS_CACHE is not set # end of SPIFFS Cache Configuration CONFIG_SPIFFS_PAGE_CHECK=y @@ -1017,7 +1079,6 @@ CONFIG_SPIFFS_USE_MTIME=y # CONFIG_SPIFFS_DBG is not set # CONFIG_SPIFFS_API_DBG is not set # CONFIG_SPIFFS_GC_DBG is not set -# CONFIG_SPIFFS_CACHE_DBG is not set # CONFIG_SPIFFS_CHECK_DBG is not set # CONFIG_SPIFFS_TEST_VISUALISATION is not set # end of Debug Configuration @@ -1091,6 +1152,15 @@ CONFIG_WPA_MBEDTLS_CRYPTO=y # CONFIG_WPA_WPS_STRICT is not set # CONFIG_WPA_11KV_SUPPORT is not set # end of Supplicant + +# +# CMake Utilities +# +# CONFIG_CU_RELINKER_ENABLE is not set +# CONFIG_CU_DIAGNOSTICS_COLOR_NEVER is not set +CONFIG_CU_DIAGNOSTICS_COLOR_ALWAYS=y +# CONFIG_CU_DIAGNOSTICS_COLOR_AUTO is not set +# end of CMake Utilities # end of Component config # diff --git a/sdkconfig.pico32 b/sdkconfig.pico32 deleted file mode 100644 index 15c62535..00000000 --- a/sdkconfig.pico32 +++ /dev/null @@ -1,1260 +0,0 @@ -# -# Automatically generated file. DO NOT EDIT. -# Espressif IoT Development Framework (ESP-IDF) Project Configuration -# -CONFIG_IDF_CMAKE=y -CONFIG_IDF_TARGET_ARCH_XTENSA=y -CONFIG_IDF_TARGET="esp32" -CONFIG_IDF_TARGET_ESP32=y -CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000 - -# -# SDK tool configuration -# -CONFIG_SDK_TOOLPREFIX="xtensa-esp32-elf-" -# CONFIG_SDK_TOOLCHAIN_SUPPORTS_TIME_WIDE_64_BITS is not set -# end of SDK tool configuration - -# -# Build type -# -CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y -# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set -CONFIG_APP_BUILD_GENERATE_BINARIES=y -CONFIG_APP_BUILD_BOOTLOADER=y -CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y -# end of Build type - -# -# Application manager -# -CONFIG_APP_COMPILE_TIME_DATE=y -# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set -# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set -# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set -CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16 -# end of Application manager - -# -# Bootloader config -# -CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x1000 -CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y -# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set -# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set -# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set -# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set -# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set -# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set -CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y -# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set -# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set -CONFIG_BOOTLOADER_LOG_LEVEL=3 -# CONFIG_BOOTLOADER_SPI_CUSTOM_WP_PIN is not set -CONFIG_BOOTLOADER_SPI_WP_PIN=7 -CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y -# CONFIG_BOOTLOADER_FACTORY_RESET is not set -# CONFIG_BOOTLOADER_APP_TEST is not set -CONFIG_BOOTLOADER_WDT_ENABLE=y -# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set -CONFIG_BOOTLOADER_WDT_TIME_MS=9000 -# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set -# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set -# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set -# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set -CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0 -# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set -CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y -# end of Bootloader config - -# -# Security features -# -CONFIG_SECURE_BOOT_SUPPORTS_RSA=y -# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set -# CONFIG_SECURE_BOOT is not set -# CONFIG_SECURE_FLASH_ENC_ENABLED is not set -# end of Security features - -# -# Serial flasher config -# -CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200 -# CONFIG_ESPTOOLPY_NO_STUB is not set -CONFIG_ESPTOOLPY_FLASHMODE_QIO=y -# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set -# CONFIG_ESPTOOLPY_FLASHMODE_DIO is not set -# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set -CONFIG_ESPTOOLPY_FLASHMODE="dio" -CONFIG_ESPTOOLPY_FLASHFREQ_80M=y -# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set -CONFIG_ESPTOOLPY_FLASHFREQ="80m" -# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set -CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y -# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set -# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set -# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set -CONFIG_ESPTOOLPY_FLASHSIZE="2MB" -CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y -CONFIG_ESPTOOLPY_BEFORE_RESET=y -# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set -CONFIG_ESPTOOLPY_BEFORE="default_reset" -CONFIG_ESPTOOLPY_AFTER_RESET=y -# CONFIG_ESPTOOLPY_AFTER_NORESET is not set -CONFIG_ESPTOOLPY_AFTER="hard_reset" -# CONFIG_ESPTOOLPY_MONITOR_BAUD_CONSOLE is not set -# CONFIG_ESPTOOLPY_MONITOR_BAUD_9600B is not set -# CONFIG_ESPTOOLPY_MONITOR_BAUD_57600B is not set -# CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B is not set -# CONFIG_ESPTOOLPY_MONITOR_BAUD_230400B is not set -CONFIG_ESPTOOLPY_MONITOR_BAUD_921600B=y -# CONFIG_ESPTOOLPY_MONITOR_BAUD_2MB is not set -# CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER is not set -CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL=115200 -CONFIG_ESPTOOLPY_MONITOR_BAUD=921600 -# end of Serial flasher config - -# -# Partition Table -# -CONFIG_PARTITION_TABLE_SINGLE_APP=y -# CONFIG_PARTITION_TABLE_TWO_OTA is not set -# CONFIG_PARTITION_TABLE_CUSTOM is not set -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" -CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv" -CONFIG_PARTITION_TABLE_OFFSET=0x8000 -CONFIG_PARTITION_TABLE_MD5=y -# end of Partition Table - -# -# Compiler options -# -# CONFIG_COMPILER_OPTIMIZATION_DEFAULT is not set -# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set -CONFIG_COMPILER_OPTIMIZATION_PERF=y -# CONFIG_COMPILER_OPTIMIZATION_NONE is not set -# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE is not set -# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set -CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y -# CONFIG_COMPILER_CXX_EXCEPTIONS is not set -# CONFIG_COMPILER_CXX_RTTI is not set -CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y -# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set -# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set -# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set -# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set -# CONFIG_COMPILER_DISABLE_GCC8_WARNINGS is not set -# CONFIG_COMPILER_DUMP_RTL_FILES is not set -# end of Compiler options - -# -# Component config -# - -# -# Application Level Tracing -# -# CONFIG_APPTRACE_DEST_TRAX is not set -CONFIG_APPTRACE_DEST_NONE=y -CONFIG_APPTRACE_LOCK_ENABLE=y -# end of Application Level Tracing - -# -# Bluetooth -# -# CONFIG_BT_ENABLED is not set -CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF=0 -CONFIG_BTDM_CTRL_PCM_ROLE_EFF=0 -CONFIG_BTDM_CTRL_PCM_POLAR_EFF=0 -CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF=0 -CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF=0 -CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF=0 -CONFIG_BTDM_CTRL_PINNED_TO_CORE=0 -CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF=1 -CONFIG_BT_CTRL_MODE_EFF=1 -CONFIG_BT_CTRL_BLE_MAX_ACT=10 -CONFIG_BT_CTRL_BLE_MAX_ACT_EFF=10 -CONFIG_BT_CTRL_BLE_STATIC_ACL_TX_BUF_NB=0 -CONFIG_BT_CTRL_PINNED_TO_CORE=0 -CONFIG_BT_CTRL_HCI_TL=1 -CONFIG_BT_CTRL_ADV_DUP_FILT_MAX=30 -CONFIG_BT_CTRL_HW_CCA_EFF=0 -CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_EFF=0 -CONFIG_BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP=y -CONFIG_BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM=100 -CONFIG_BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD=20 -CONFIG_BT_CTRL_BLE_SCAN_DUPL=y -CONFIG_BT_CTRL_SCAN_DUPL_TYPE=0 -CONFIG_BT_CTRL_SCAN_DUPL_CACHE_SIZE=100 -CONFIG_BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_EFF=0 -CONFIG_BT_CTRL_SLEEP_MODE_EFF=0 -CONFIG_BT_CTRL_SLEEP_CLOCK_EFF=0 -CONFIG_BT_CTRL_HCI_TL_EFF=1 -CONFIG_BT_RESERVE_DRAM=0 -CONFIG_BT_NIMBLE_USE_ESP_TIMER=y -# end of Bluetooth - -CONFIG_COAP_LOG_DEFAULT_LEVEL=0 - -# -# Driver configurations -# - -# -# ADC configuration -# -# CONFIG_ADC_FORCE_XPD_FSM is not set -CONFIG_ADC_DISABLE_DAC=y -# end of ADC configuration - -# -# SPI configuration -# -# CONFIG_SPI_MASTER_IN_IRAM is not set -CONFIG_SPI_MASTER_ISR_IN_IRAM=y -# CONFIG_SPI_SLAVE_IN_IRAM is not set -CONFIG_SPI_SLAVE_ISR_IN_IRAM=y -# end of SPI configuration - -# -# TWAI configuration -# -# CONFIG_TWAI_ISR_IN_IRAM is not set -# CONFIG_TWAI_ERRATA_FIX_BUS_OFF_REC is not set -# CONFIG_TWAI_ERRATA_FIX_TX_INTR_LOST is not set -# CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID is not set -# CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT is not set -# end of TWAI configuration - -# -# UART configuration -# -# CONFIG_UART_ISR_IN_IRAM is not set -# end of UART configuration - -# -# RTCIO configuration -# -# CONFIG_RTCIO_SUPPORT_RTC_GPIO_DESC is not set -# end of RTCIO configuration - -# -# GPIO Configuration -# -# CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL is not set -# end of GPIO Configuration -# end of Driver configurations - -# -# eFuse Bit Manager -# -# CONFIG_EFUSE_CUSTOM_TABLE is not set -# CONFIG_EFUSE_VIRTUAL is not set -# CONFIG_EFUSE_CODE_SCHEME_COMPAT_NONE is not set -CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4=y -# CONFIG_EFUSE_CODE_SCHEME_COMPAT_REPEAT is not set -CONFIG_EFUSE_MAX_BLK_LEN=192 -# end of eFuse Bit Manager - -# -# ESP-TLS -# -CONFIG_ESP_TLS_USING_MBEDTLS=y -# CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set -# CONFIG_ESP_TLS_SERVER is not set -# CONFIG_ESP_TLS_PSK_VERIFICATION is not set -# CONFIG_ESP_TLS_INSECURE is not set -# end of ESP-TLS - -# -# ESP32-specific -# -# CONFIG_ESP32_REV_MIN_0 is not set -# CONFIG_ESP32_REV_MIN_1 is not set -# CONFIG_ESP32_REV_MIN_2 is not set -CONFIG_ESP32_REV_MIN_3=y -CONFIG_ESP32_REV_MIN=3 -# CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set -# CONFIG_ESP32_DEFAULT_CPU_FREQ_160 is not set -CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y -CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240 -# CONFIG_ESP32_SPIRAM_SUPPORT is not set -# CONFIG_ESP32_TRAX is not set -CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0 -# CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set -CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y -CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4 -# CONFIG_ESP32_ULP_COPROC_ENABLED is not set -CONFIG_ESP32_ULP_COPROC_RESERVE_MEM=0 -CONFIG_ESP32_DEBUG_OCDAWARE=y -CONFIG_ESP32_BROWNOUT_DET=y -CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0=y -# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_1 is not set -# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_2 is not set -# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_3 is not set -# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_4 is not set -# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_5 is not set -# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_6 is not set -# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_7 is not set -CONFIG_ESP32_BROWNOUT_DET_LVL=0 -CONFIG_ESP32_REDUCE_PHY_TX_POWER=y -CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y -# CONFIG_ESP32_TIME_SYSCALL_USE_RTC is not set -# CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 is not set -# CONFIG_ESP32_TIME_SYSCALL_USE_NONE is not set -CONFIG_ESP32_RTC_CLK_SRC_INT_RC=y -# CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS is not set -# CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC is not set -# CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256 is not set -CONFIG_ESP32_RTC_CLK_CAL_CYCLES=1024 -CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=2000 -CONFIG_ESP32_XTAL_FREQ_40=y -# CONFIG_ESP32_XTAL_FREQ_26 is not set -# CONFIG_ESP32_XTAL_FREQ_AUTO is not set -CONFIG_ESP32_XTAL_FREQ=40 -# CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE is not set -# CONFIG_ESP32_NO_BLOBS is not set -# CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set -# CONFIG_ESP32_COMPATIBLE_PRE_V3_1_BOOTLOADERS is not set -# CONFIG_ESP32_USE_FIXED_STATIC_RAM_SIZE is not set -CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL=5 -# end of ESP32-specific - -# -# ADC-Calibration -# -CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y -CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y -CONFIG_ADC_CAL_LUT_ENABLE=y -# end of ADC-Calibration - -# -# Common ESP-related -# -# CONFIG_ESP_ERR_TO_NAME_LOOKUP is not set -CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 -CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304 -CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584 -CONFIG_ESP_IPC_TASK_STACK_SIZE=1024 -CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y -CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 -CONFIG_ESP_CONSOLE_UART_DEFAULT=y -# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set -# CONFIG_ESP_CONSOLE_NONE is not set -CONFIG_ESP_CONSOLE_UART=y -CONFIG_ESP_CONSOLE_MULTIPLE_UART=y -CONFIG_ESP_CONSOLE_UART_NUM=0 -CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 -# CONFIG_ESP_INT_WDT is not set -# CONFIG_ESP_TASK_WDT is not set -# CONFIG_ESP_PANIC_HANDLER_IRAM is not set -CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y -CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y -CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y -CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y -# end of Common ESP-related - -# -# Ethernet -# -# CONFIG_ETH_USE_ESP32_EMAC is not set -# CONFIG_ETH_USE_SPI_ETHERNET is not set -# CONFIG_ETH_USE_OPENETH is not set -# end of Ethernet - -# -# Event Loop Library -# -# CONFIG_ESP_EVENT_LOOP_PROFILING is not set -CONFIG_ESP_EVENT_POST_FROM_ISR=y -CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y -# end of Event Loop Library - -# -# GDB Stub -# -# end of GDB Stub - -# -# ESP HTTP client -# -# CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS is not set -# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set -# end of ESP HTTP client - -# -# HTTP Server -# -CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 -CONFIG_HTTPD_MAX_URI_LEN=512 -CONFIG_HTTPD_ERR_RESP_NO_DELAY=y -CONFIG_HTTPD_PURGE_BUF_LEN=32 -# CONFIG_HTTPD_LOG_PURGE_DATA is not set -# CONFIG_HTTPD_WS_SUPPORT is not set -# end of HTTP Server - -# -# ESP HTTPS OTA -# -# CONFIG_OTA_ALLOW_HTTP is not set -# end of ESP HTTPS OTA - -# -# ESP HTTPS server -# -# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set -# end of ESP HTTPS server - -# -# ESP NETIF Adapter -# -CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120 -CONFIG_ESP_NETIF_TCPIP_LWIP=y -# CONFIG_ESP_NETIF_LOOPBACK is not set -CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER=y -# end of ESP NETIF Adapter - -# -# Power Management -# -# CONFIG_PM_ENABLE is not set -# end of Power Management - -# -# ESP System Settings -# -# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set -# CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT is not set -CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT=y -# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set -CONFIG_ESP_SYSTEM_PD_FLASH=y -# CONFIG_ESP_SYSTEM_FLASH_LEAKAGE_WORKAROUND is not set - -# -# Memory protection -# -# end of Memory protection -# end of ESP System Settings - -# -# High resolution timer (esp_timer) -# -# CONFIG_ESP_TIMER_PROFILING is not set -CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y -CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y -CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584 -# CONFIG_ESP_TIMER_IMPL_FRC2 is not set -CONFIG_ESP_TIMER_IMPL_TG0_LAC=y -# end of High resolution timer (esp_timer) - -# -# Wi-Fi -# -CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=4 -CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=8 -# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set -CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y -CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1 -CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=16 -# CONFIG_ESP32_WIFI_CSI_ENABLED is not set -CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y -CONFIG_ESP32_WIFI_TX_BA_WIN=6 -# CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED is not set -CONFIG_ESP32_WIFI_NVS_ENABLED=y -# CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0 is not set -CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1=y -CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752 -CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32 -# CONFIG_WIFI_LOG_DEFAULT_LEVEL_NONE is not set -CONFIG_WIFI_LOG_DEFAULT_LEVEL_ERROR=y -# CONFIG_WIFI_LOG_DEFAULT_LEVEL_WARN is not set -# CONFIG_WIFI_LOG_DEFAULT_LEVEL_INFO is not set -# CONFIG_WIFI_LOG_DEFAULT_LEVEL_DEBUG is not set -# CONFIG_WIFI_LOG_DEFAULT_LEVEL_VERBOSE is not set -CONFIG_ESP32_WIFI_IRAM_OPT=y -CONFIG_ESP32_WIFI_RX_IRAM_OPT=y -# CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set -# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set -# CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE is not set -# end of Wi-Fi - -# -# PHY -# -CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y -# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set -CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 -CONFIG_ESP32_PHY_MAX_TX_POWER=20 -# end of PHY - -# -# Core dump -# -# CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH is not set -# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set -CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y -# end of Core dump - -# -# FAT Filesystem support -# -# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set -CONFIG_FATFS_CODEPAGE_437=y -# CONFIG_FATFS_CODEPAGE_720 is not set -# CONFIG_FATFS_CODEPAGE_737 is not set -# CONFIG_FATFS_CODEPAGE_771 is not set -# CONFIG_FATFS_CODEPAGE_775 is not set -# CONFIG_FATFS_CODEPAGE_850 is not set -# CONFIG_FATFS_CODEPAGE_852 is not set -# CONFIG_FATFS_CODEPAGE_855 is not set -# CONFIG_FATFS_CODEPAGE_857 is not set -# CONFIG_FATFS_CODEPAGE_860 is not set -# CONFIG_FATFS_CODEPAGE_861 is not set -# CONFIG_FATFS_CODEPAGE_862 is not set -# CONFIG_FATFS_CODEPAGE_863 is not set -# CONFIG_FATFS_CODEPAGE_864 is not set -# CONFIG_FATFS_CODEPAGE_865 is not set -# CONFIG_FATFS_CODEPAGE_866 is not set -# CONFIG_FATFS_CODEPAGE_869 is not set -# CONFIG_FATFS_CODEPAGE_932 is not set -# CONFIG_FATFS_CODEPAGE_936 is not set -# CONFIG_FATFS_CODEPAGE_949 is not set -# CONFIG_FATFS_CODEPAGE_950 is not set -CONFIG_FATFS_CODEPAGE=437 -# CONFIG_FATFS_LFN_NONE is not set -CONFIG_FATFS_LFN_HEAP=y -# CONFIG_FATFS_LFN_STACK is not set -CONFIG_FATFS_MAX_LFN=28 -CONFIG_FATFS_API_ENCODING_ANSI_OEM=y -# CONFIG_FATFS_API_ENCODING_UTF_16 is not set -# CONFIG_FATFS_API_ENCODING_UTF_8 is not set -CONFIG_FATFS_FS_LOCK=0 -CONFIG_FATFS_TIMEOUT_MS=10000 -# CONFIG_FATFS_PER_FILE_CACHE is not set -# CONFIG_FATFS_USE_FASTSEEK is not set -# end of FAT Filesystem support - -# -# Modbus configuration -# -CONFIG_FMB_COMM_MODE_TCP_EN=y -CONFIG_FMB_TCP_PORT_DEFAULT=502 -CONFIG_FMB_TCP_PORT_MAX_CONN=5 -CONFIG_FMB_TCP_CONNECTION_TOUT_SEC=20 -CONFIG_FMB_COMM_MODE_RTU_EN=y -CONFIG_FMB_COMM_MODE_ASCII_EN=y -CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=150 -CONFIG_FMB_MASTER_DELAY_MS_CONVERT=200 -CONFIG_FMB_QUEUE_LENGTH=20 -CONFIG_FMB_PORT_TASK_STACK_SIZE=4096 -CONFIG_FMB_SERIAL_BUF_SIZE=256 -CONFIG_FMB_SERIAL_ASCII_BITS_PER_SYMB=8 -CONFIG_FMB_SERIAL_ASCII_TIMEOUT_RESPOND_MS=1000 -CONFIG_FMB_PORT_TASK_PRIO=10 -# CONFIG_FMB_PORT_TASK_AFFINITY_NO_AFFINITY is not set -CONFIG_FMB_PORT_TASK_AFFINITY_CPU0=y -# CONFIG_FMB_PORT_TASK_AFFINITY_CPU1 is not set -CONFIG_FMB_PORT_TASK_AFFINITY=0x0 -CONFIG_FMB_CONTROLLER_SLAVE_ID_SUPPORT=y -CONFIG_FMB_CONTROLLER_SLAVE_ID=0x00112233 -CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT=20 -CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE=20 -CONFIG_FMB_CONTROLLER_STACK_SIZE=4096 -CONFIG_FMB_EVENT_QUEUE_TIMEOUT=20 -# CONFIG_FMB_TIMER_PORT_ENABLED is not set -CONFIG_FMB_TIMER_GROUP=0 -CONFIG_FMB_TIMER_INDEX=0 -CONFIG_FMB_MASTER_TIMER_GROUP=0 -CONFIG_FMB_MASTER_TIMER_INDEX=0 -# CONFIG_FMB_TIMER_ISR_IN_IRAM is not set -# end of Modbus configuration - -# -# FreeRTOS -# -# CONFIG_FREERTOS_UNICORE is not set -CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF -CONFIG_FREERTOS_CORETIMER_0=y -# CONFIG_FREERTOS_CORETIMER_1 is not set -CONFIG_FREERTOS_HZ=1000 -CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y -# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set -# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set -CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y -# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set -CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y -CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1 -# CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set -CONFIG_FREERTOS_ASSERT_DISABLE=y -CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=2304 -CONFIG_FREERTOS_ISR_STACKSIZE=1536 -# CONFIG_FREERTOS_LEGACY_HOOKS is not set -CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 -CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y -# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set -CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1 -CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048 -CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10 -CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 -# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set -# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set -CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y -# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set -# CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set -CONFIG_FREERTOS_DEBUG_OCDAWARE=y -# CONFIG_FREERTOS_FPU_IN_ISR is not set -# end of FreeRTOS - -# -# Heap memory debugging -# -CONFIG_HEAP_POISONING_DISABLED=y -# CONFIG_HEAP_POISONING_LIGHT is not set -# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set -CONFIG_HEAP_TRACING_OFF=y -# CONFIG_HEAP_TRACING_STANDALONE is not set -# CONFIG_HEAP_TRACING_TOHOST is not set -# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set -# end of Heap memory debugging - -# -# jsmn -# -# CONFIG_JSMN_PARENT_LINKS is not set -# CONFIG_JSMN_STRICT is not set -# end of jsmn - -# -# libsodium -# -# end of libsodium - -# -# Log output -# -# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set -CONFIG_LOG_DEFAULT_LEVEL_ERROR=y -# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set -# CONFIG_LOG_DEFAULT_LEVEL_INFO is not set -# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set -# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set -CONFIG_LOG_DEFAULT_LEVEL=1 -CONFIG_LOG_COLORS=y -CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y -# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set -# end of Log output - -# -# LWIP -# -CONFIG_LWIP_LOCAL_HOSTNAME="espressif" -CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y -# CONFIG_LWIP_L2_TO_L3_COPY is not set -CONFIG_LWIP_IRAM_OPTIMIZATION=y -CONFIG_LWIP_TIMERS_ONDEMAND=y -CONFIG_LWIP_MAX_SOCKETS=10 -# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set -# CONFIG_LWIP_SO_LINGER is not set -CONFIG_LWIP_SO_REUSE=y -CONFIG_LWIP_SO_REUSE_RXTOALL=y -# CONFIG_LWIP_SO_RCVBUF is not set -# CONFIG_LWIP_NETBUF_RECVINFO is not set -CONFIG_LWIP_IP4_FRAG=y -# CONFIG_LWIP_IP4_REASSEMBLY is not set -# CONFIG_LWIP_IP_FORWARD is not set -# CONFIG_LWIP_STATS is not set -# CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set -CONFIG_LWIP_ESP_GRATUITOUS_ARP=y -CONFIG_LWIP_GARP_TMR_INTERVAL=60 -CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=16 -CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y -# CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID is not set -# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set - -# -# DHCP server -# -CONFIG_LWIP_DHCPS=y -CONFIG_LWIP_DHCPS_LEASE_UNIT=60 -CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8 -# end of DHCP server - -# CONFIG_LWIP_AUTOIP is not set -# CONFIG_LWIP_IPV6 is not set -CONFIG_LWIP_NETIF_LOOPBACK=y -CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8 - -# -# TCP -# -CONFIG_LWIP_MAX_ACTIVE_TCP=16 -CONFIG_LWIP_MAX_LISTENING_TCP=16 -CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y -CONFIG_LWIP_TCP_MAXRTX=12 -CONFIG_LWIP_TCP_SYNMAXRTX=12 -CONFIG_LWIP_TCP_MSS=1440 -CONFIG_LWIP_TCP_TMR_INTERVAL=250 -CONFIG_LWIP_TCP_MSL=60000 -CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5744 -CONFIG_LWIP_TCP_WND_DEFAULT=5744 -CONFIG_LWIP_TCP_RECVMBOX_SIZE=6 -CONFIG_LWIP_TCP_QUEUE_OOSEQ=y -# CONFIG_LWIP_TCP_SACK_OUT is not set -# CONFIG_LWIP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set -CONFIG_LWIP_TCP_OVERSIZE_MSS=y -# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set -# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set -CONFIG_LWIP_TCP_RTO_TIME=1500 -# end of TCP - -# -# UDP -# -CONFIG_LWIP_MAX_UDP_PCBS=16 -CONFIG_LWIP_UDP_RECVMBOX_SIZE=6 -# end of UDP - -# -# Checksums -# -# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set -# CONFIG_LWIP_CHECKSUM_CHECK_UDP is not set -CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y -# end of Checksums - -CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072 -CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y -# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set -# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set -CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF -# CONFIG_LWIP_PPP_SUPPORT is not set -# CONFIG_LWIP_SLIP_SUPPORT is not set - -# -# ICMP -# -CONFIG_LWIP_ICMP=y -# CONFIG_LWIP_MULTICAST_PING is not set -# CONFIG_LWIP_BROADCAST_PING is not set -# end of ICMP - -# -# LWIP RAW API -# -CONFIG_LWIP_MAX_RAW_PCBS=16 -# end of LWIP RAW API - -# -# SNTP -# -CONFIG_LWIP_DHCP_MAX_NTP_SERVERS=1 -CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000 -# end of SNTP - -# -# Hooks -# -# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set -CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT=y -# CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM is not set -CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y -# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set -# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set -# end of Hooks - -# CONFIG_LWIP_DEBUG is not set -# end of LWIP - -# -# mbedTLS -# -CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y -# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set -# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set -CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y -CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384 -CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=2048 -CONFIG_MBEDTLS_DYNAMIC_BUFFER=y -CONFIG_MBEDTLS_DYNAMIC_FREE_PEER_CERT=y -CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y -CONFIG_MBEDTLS_DYNAMIC_FREE_CA_CERT=y -# CONFIG_MBEDTLS_DEBUG is not set - -# -# Certificate Bundle -# -CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y -CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y -# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set -# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set -# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set -# end of Certificate Bundle - -# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set -# CONFIG_MBEDTLS_CMAC_C is not set -CONFIG_MBEDTLS_HARDWARE_AES=y -CONFIG_MBEDTLS_HARDWARE_MPI=y -CONFIG_MBEDTLS_HARDWARE_SHA=y -CONFIG_MBEDTLS_ROM_MD5=y -# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set -# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set -CONFIG_MBEDTLS_HAVE_TIME=y -# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set -CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y -CONFIG_MBEDTLS_SHA512_C=y -CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y -# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set -# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set -# CONFIG_MBEDTLS_TLS_DISABLED is not set -CONFIG_MBEDTLS_TLS_SERVER=y -CONFIG_MBEDTLS_TLS_CLIENT=y -CONFIG_MBEDTLS_TLS_ENABLED=y - -# -# TLS Key Exchange Methods -# -# CONFIG_MBEDTLS_PSK_MODES is not set -CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y -CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y -CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y -CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y -CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y -CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y -CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y -# end of TLS Key Exchange Methods - -CONFIG_MBEDTLS_SSL_RENEGOTIATION=y -# CONFIG_MBEDTLS_SSL_PROTO_SSL3 is not set -CONFIG_MBEDTLS_SSL_PROTO_TLS1=y -CONFIG_MBEDTLS_SSL_PROTO_TLS1_1=y -CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y -# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set -CONFIG_MBEDTLS_SSL_ALPN=y -CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y -CONFIG_MBEDTLS_X509_CHECK_KEY_USAGE=y -CONFIG_MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE=y -CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y - -# -# Symmetric Ciphers -# -CONFIG_MBEDTLS_AES_C=y -# CONFIG_MBEDTLS_CAMELLIA_C is not set -# CONFIG_MBEDTLS_DES_C is not set -CONFIG_MBEDTLS_RC4_DISABLED=y -# CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT is not set -# CONFIG_MBEDTLS_RC4_ENABLED is not set -# CONFIG_MBEDTLS_BLOWFISH_C is not set -# CONFIG_MBEDTLS_XTEA_C is not set -CONFIG_MBEDTLS_CCM_C=y -CONFIG_MBEDTLS_GCM_C=y -# CONFIG_MBEDTLS_NIST_KW_C is not set -# end of Symmetric Ciphers - -# CONFIG_MBEDTLS_RIPEMD160_C is not set - -# -# Certificates -# -CONFIG_MBEDTLS_PEM_PARSE_C=y -CONFIG_MBEDTLS_PEM_WRITE_C=y -CONFIG_MBEDTLS_X509_CRL_PARSE_C=y -CONFIG_MBEDTLS_X509_CSR_PARSE_C=y -# end of Certificates - -CONFIG_MBEDTLS_ECP_C=y -CONFIG_MBEDTLS_ECDH_C=y -CONFIG_MBEDTLS_ECDSA_C=y -# CONFIG_MBEDTLS_ECJPAKE_C is not set -CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y -CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y -CONFIG_MBEDTLS_ECP_NIST_OPTIM=y -# CONFIG_MBEDTLS_POLY1305_C is not set -# CONFIG_MBEDTLS_CHACHA20_C is not set -# CONFIG_MBEDTLS_HKDF_C is not set -# CONFIG_MBEDTLS_THREADING_C is not set -# CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI is not set -# CONFIG_MBEDTLS_SECURITY_RISKS is not set -# end of mbedTLS - -# -# mDNS -# -CONFIG_MDNS_MAX_SERVICES=10 -CONFIG_MDNS_TASK_PRIORITY=1 -CONFIG_MDNS_TASK_STACK_SIZE=4096 -# CONFIG_MDNS_TASK_AFFINITY_NO_AFFINITY is not set -CONFIG_MDNS_TASK_AFFINITY_CPU0=y -# CONFIG_MDNS_TASK_AFFINITY_CPU1 is not set -CONFIG_MDNS_TASK_AFFINITY=0x0 -CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS=2000 -# CONFIG_MDNS_STRICT_MODE is not set -CONFIG_MDNS_TIMER_PERIOD_MS=100 -# end of mDNS - -# -# ESP-MQTT Configurations -# -CONFIG_MQTT_PROTOCOL_311=y -CONFIG_MQTT_TRANSPORT_SSL=y -# CONFIG_MQTT_MSG_ID_INCREMENTAL is not set -# CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED is not set -# CONFIG_MQTT_REPORT_DELETED_MESSAGES is not set -# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set -# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set -# CONFIG_MQTT_CUSTOM_OUTBOX is not set -# end of ESP-MQTT Configurations - -# -# Newlib -# -CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y -# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set -# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set -# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set -# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set -CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y -CONFIG_NEWLIB_NANO_FORMAT=y -# end of Newlib - -# -# NVS -# -# end of NVS - -# -# OpenSSL -# -# CONFIG_OPENSSL_DEBUG is not set -CONFIG_OPENSSL_ERROR_STACK=y -# CONFIG_OPENSSL_ASSERT_DO_NOTHING is not set -CONFIG_OPENSSL_ASSERT_EXIT=y -# end of OpenSSL - -# -# PThreads -# -CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5 -CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 -CONFIG_PTHREAD_STACK_MIN=768 -CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY=y -# CONFIG_PTHREAD_DEFAULT_CORE_0 is not set -# CONFIG_PTHREAD_DEFAULT_CORE_1 is not set -CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1 -CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread" -# end of PThreads - -# -# SPI Flash driver -# -# CONFIG_SPI_FLASH_VERIFY_WRITE is not set -# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set -CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y -CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y -# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set -# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set -# CONFIG_SPI_FLASH_USE_LEGACY_IMPL is not set -# CONFIG_SPI_FLASH_SHARE_SPI1_BUS is not set -# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set -CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y -CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20 -CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1 -CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE=8192 -# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set -# CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set - -# -# Auto-detect flash chips -# -CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y -CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y -CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y -CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y -# end of Auto-detect flash chips - -# CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE is not set -# end of SPI Flash driver - -# -# SPIFFS Configuration -# -CONFIG_SPIFFS_MAX_PARTITIONS=3 - -# -# SPIFFS Cache Configuration -# -CONFIG_SPIFFS_CACHE=y -CONFIG_SPIFFS_CACHE_WR=y -# CONFIG_SPIFFS_CACHE_STATS is not set -# end of SPIFFS Cache Configuration - -CONFIG_SPIFFS_PAGE_CHECK=y -CONFIG_SPIFFS_GC_MAX_RUNS=10 -# CONFIG_SPIFFS_GC_STATS is not set -CONFIG_SPIFFS_PAGE_SIZE=256 -CONFIG_SPIFFS_OBJ_NAME_LEN=32 -# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set -CONFIG_SPIFFS_USE_MAGIC=y -CONFIG_SPIFFS_USE_MAGIC_LENGTH=y -CONFIG_SPIFFS_META_LENGTH=4 -CONFIG_SPIFFS_USE_MTIME=y - -# -# Debug Configuration -# -# CONFIG_SPIFFS_DBG is not set -# CONFIG_SPIFFS_API_DBG is not set -# CONFIG_SPIFFS_GC_DBG is not set -# CONFIG_SPIFFS_CACHE_DBG is not set -# CONFIG_SPIFFS_CHECK_DBG is not set -# CONFIG_SPIFFS_TEST_VISUALISATION is not set -# end of Debug Configuration -# end of SPIFFS Configuration - -# -# TCP Transport -# - -# -# Websocket -# -# CONFIG_WS_TRANSPORT is not set -# end of Websocket -# end of TCP Transport - -# -# TinyUSB -# -# end of TinyUSB - -# -# Unity unit testing library -# -CONFIG_UNITY_ENABLE_FLOAT=y -CONFIG_UNITY_ENABLE_DOUBLE=y -# CONFIG_UNITY_ENABLE_COLOR is not set -CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y -# CONFIG_UNITY_ENABLE_FIXTURE is not set -# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set -# end of Unity unit testing library - -# -# Virtual file system -# -CONFIG_VFS_SUPPORT_IO=y -CONFIG_VFS_SUPPORT_DIR=y -# CONFIG_VFS_SUPPORT_SELECT is not set -# CONFIG_VFS_SUPPORT_TERMIOS is not set - -# -# Host File System I/O (Semihosting) -# -CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1 -CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN=128 -# end of Host File System I/O (Semihosting) -# end of Virtual file system - -# -# Wear Levelling -# -# CONFIG_WL_SECTOR_SIZE_512 is not set -CONFIG_WL_SECTOR_SIZE_4096=y -CONFIG_WL_SECTOR_SIZE=4096 -# end of Wear Levelling - -# -# Wi-Fi Provisioning Manager -# -CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 -CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 -# end of Wi-Fi Provisioning Manager - -# -# Supplicant -# -CONFIG_WPA_MBEDTLS_CRYPTO=y -# CONFIG_WPA_WAPI_PSK is not set -# CONFIG_WPA_DEBUG_PRINT is not set -# CONFIG_WPA_TESTING_OPTIONS is not set -# CONFIG_WPA_WPS_STRICT is not set -# CONFIG_WPA_11KV_SUPPORT is not set -# end of Supplicant - -# -# CMake Utilities -# -# CONFIG_CU_RELINKER_ENABLE is not set -# CONFIG_CU_DIAGNOSTICS_COLOR_NEVER is not set -CONFIG_CU_DIAGNOSTICS_COLOR_ALWAYS=y -# CONFIG_CU_DIAGNOSTICS_COLOR_AUTO is not set -# end of CMake Utilities -# end of Component config - -# -# Compatibility options -# -# CONFIG_LEGACY_INCLUDE_COMMON_HEADERS is not set -# end of Compatibility options - -# Deprecated options for backward compatibility -CONFIG_TOOLPREFIX="xtensa-esp32-elf-" -# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set -# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set -# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set -CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y -# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set -# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set -CONFIG_LOG_BOOTLOADER_LEVEL=3 -# CONFIG_APP_ROLLBACK_ENABLE is not set -# CONFIG_FLASH_ENCRYPTION_ENABLED is not set -CONFIG_FLASHMODE_QIO=y -# CONFIG_FLASHMODE_QOUT is not set -# CONFIG_FLASHMODE_DIO is not set -# CONFIG_FLASHMODE_DOUT is not set -# CONFIG_MONITOR_BAUD_9600B is not set -# CONFIG_MONITOR_BAUD_57600B is not set -# CONFIG_MONITOR_BAUD_115200B is not set -# CONFIG_MONITOR_BAUD_230400B is not set -CONFIG_MONITOR_BAUD_921600B=y -# CONFIG_MONITOR_BAUD_2MB is not set -# CONFIG_MONITOR_BAUD_OTHER is not set -CONFIG_MONITOR_BAUD_OTHER_VAL=115200 -CONFIG_MONITOR_BAUD=921600 -# CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set -# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set -# CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED is not set -# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set -CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED=y -# CONFIG_CXX_EXCEPTIONS is not set -CONFIG_STACK_CHECK_NONE=y -# CONFIG_STACK_CHECK_NORM is not set -# CONFIG_STACK_CHECK_STRONG is not set -# CONFIG_STACK_CHECK_ALL is not set -# CONFIG_WARN_WRITE_STRINGS is not set -# CONFIG_DISABLE_GCC8_WARNINGS is not set -# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set -CONFIG_ESP32_APPTRACE_DEST_NONE=y -CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y -CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN_EFF=0 -CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_EFF=0 -CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF=0 -CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0 -CONFIG_ADC2_DISABLE_DAC=y -# CONFIG_SPIRAM_SUPPORT is not set -CONFIG_TRACEMEM_RESERVE_DRAM=0x0 -# CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set -CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y -CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS=4 -# CONFIG_ULP_COPROC_ENABLED is not set -CONFIG_ULP_COPROC_RESERVE_MEM=0 -CONFIG_BROWNOUT_DET=y -CONFIG_BROWNOUT_DET_LVL_SEL_0=y -# CONFIG_BROWNOUT_DET_LVL_SEL_1 is not set -# CONFIG_BROWNOUT_DET_LVL_SEL_2 is not set -# CONFIG_BROWNOUT_DET_LVL_SEL_3 is not set -# CONFIG_BROWNOUT_DET_LVL_SEL_4 is not set -# CONFIG_BROWNOUT_DET_LVL_SEL_5 is not set -# CONFIG_BROWNOUT_DET_LVL_SEL_6 is not set -# CONFIG_BROWNOUT_DET_LVL_SEL_7 is not set -CONFIG_BROWNOUT_DET_LVL=0 -CONFIG_REDUCE_PHY_TX_POWER=y -CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y -# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL is not set -# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC is not set -# CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256 is not set -# CONFIG_DISABLE_BASIC_ROM_CONSOLE is not set -# CONFIG_NO_BLOBS is not set -# CONFIG_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set -CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 -CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 -CONFIG_MAIN_TASK_STACK_SIZE=3584 -CONFIG_IPC_TASK_STACK_SIZE=1024 -CONFIG_CONSOLE_UART_DEFAULT=y -# CONFIG_CONSOLE_UART_CUSTOM is not set -# CONFIG_ESP_CONSOLE_UART_NONE is not set -CONFIG_CONSOLE_UART=y -CONFIG_CONSOLE_UART_NUM=0 -CONFIG_CONSOLE_UART_BAUDRATE=115200 -# CONFIG_INT_WDT is not set -# CONFIG_TASK_WDT is not set -# CONFIG_EVENT_LOOP_PROFILING is not set -CONFIG_POST_EVENTS_FROM_ISR=y -CONFIG_POST_EVENTS_FROM_IRAM_ISR=y -# CONFIG_ESP32S2_PANIC_PRINT_HALT is not set -# CONFIG_ESP32S2_PANIC_PRINT_REBOOT is not set -CONFIG_ESP32S2_PANIC_SILENT_REBOOT=y -# CONFIG_ESP32S2_PANIC_GDBSTUB is not set -CONFIG_TIMER_TASK_STACK_SIZE=3584 -# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set -# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set -CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y -CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND=150 -CONFIG_MB_MASTER_DELAY_MS_CONVERT=200 -CONFIG_MB_QUEUE_LENGTH=20 -CONFIG_MB_SERIAL_TASK_STACK_SIZE=4096 -CONFIG_MB_SERIAL_BUF_SIZE=256 -CONFIG_MB_SERIAL_TASK_PRIO=10 -CONFIG_MB_CONTROLLER_SLAVE_ID_SUPPORT=y -CONFIG_MB_CONTROLLER_SLAVE_ID=0x00112233 -CONFIG_MB_CONTROLLER_NOTIFY_TIMEOUT=20 -CONFIG_MB_CONTROLLER_NOTIFY_QUEUE_SIZE=20 -CONFIG_MB_CONTROLLER_STACK_SIZE=4096 -CONFIG_MB_EVENT_QUEUE_TIMEOUT=20 -# CONFIG_MB_TIMER_PORT_ENABLED is not set -CONFIG_MB_TIMER_GROUP=0 -CONFIG_MB_TIMER_INDEX=0 -# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set -CONFIG_TIMER_TASK_PRIORITY=1 -CONFIG_TIMER_TASK_STACK_DEPTH=2048 -CONFIG_TIMER_QUEUE_LENGTH=10 -# CONFIG_L2_TO_L3_COPY is not set -# CONFIG_USE_ONLY_LWIP_SELECT is not set -CONFIG_ESP_GRATUITOUS_ARP=y -CONFIG_GARP_TMR_INTERVAL=60 -CONFIG_TCPIP_RECVMBOX_SIZE=16 -CONFIG_TCP_MAXRTX=12 -CONFIG_TCP_SYNMAXRTX=12 -CONFIG_TCP_MSS=1440 -CONFIG_TCP_MSL=60000 -CONFIG_TCP_SND_BUF_DEFAULT=5744 -CONFIG_TCP_WND_DEFAULT=5744 -CONFIG_TCP_RECVMBOX_SIZE=6 -CONFIG_TCP_QUEUE_OOSEQ=y -# CONFIG_ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set -CONFIG_TCP_OVERSIZE_MSS=y -# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set -# CONFIG_TCP_OVERSIZE_DISABLE is not set -CONFIG_UDP_RECVMBOX_SIZE=6 -CONFIG_TCPIP_TASK_STACK_SIZE=3072 -CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y -# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set -# CONFIG_TCPIP_TASK_AFFINITY_CPU1 is not set -CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF -# CONFIG_PPP_SUPPORT is not set -CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5 -CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 -CONFIG_ESP32_PTHREAD_STACK_MIN=768 -CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY=y -# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0 is not set -# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1 is not set -CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1 -CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread" -CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y -# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set -# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set -# CONFIG_SUPPORT_TERMIOS is not set -CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1 -CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN=128 -# End of deprecated options diff --git a/src/AySound.cpp b/src/AySound.cpp index 75afed5f..2b1b5ce5 100644 --- a/src/AySound.cpp +++ b/src/AySound.cpp @@ -96,7 +96,7 @@ uint8_t AySound::selectedRegister; /* sound chip volume envelops (will calculated by gen_env()) */ static int bEnvGenInit = 0; -static int Envelope [16][128]; +static uint8_t Envelope [16][128]; /* AY volume table (c) by V_Soft and Lion 17 */ // static int Lion17_AY_table [16] = { @@ -131,6 +131,7 @@ static void gen_env() int dir; int vol; + // printf("Gen Env:\n"); for (env = 0; env < 16; env++) { hold = 0; dir = (env & 4)? 1 : -1; @@ -152,8 +153,10 @@ static void gen_env() } } } - Envelope[env][pos] = vol; + Envelope[env][pos] = (uint8_t) vol; + // printf("%d ",vol); } + // printf("\n"); } bEnvGenInit = 1; diff --git a/src/CPU.cpp b/src/CPU.cpp index 25502e32..0d8d3ece 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -63,6 +63,9 @@ uint32_t CPU::tstates = 0; uint64_t CPU::global_tstates = 0; uint32_t CPU::statesInFrame = 0; uint32_t CPU::framecnt = 0; +uint8_t CPU::latetiming = 0; +uint8_t CPU::IntStart = 0; +uint8_t CPU::IntEnd = 0; bool Z80Ops::is48 = true; @@ -75,12 +78,18 @@ void CPU::setup() statesInFrame = CPU::statesPerFrame(); + CPU::latetiming = Config::AluTiming; + if (Config::getArch() == "48K") { VIDEO::getFloatBusData = &VIDEO::getFloatBusData48; Z80Ops::is48 = true; + CPU::IntStart = INT_START48; + CPU::IntEnd = INT_END48 + CPU::latetiming; } else { VIDEO::getFloatBusData = &VIDEO::getFloatBusData128; Z80Ops::is48 = false; + CPU::IntStart = INT_START128; + CPU::IntEnd = INT_END128 + CPU::latetiming; } tstates = 0; @@ -96,12 +105,18 @@ void CPU::reset() { statesInFrame = CPU::statesPerFrame(); + CPU::latetiming = Config::AluTiming; + if (Config::getArch() == "48K") { VIDEO::getFloatBusData = &VIDEO::getFloatBusData48; Z80Ops::is48 = true; + CPU::IntStart = INT_START48; + CPU::IntEnd = INT_END48 + CPU::latetiming; } else { VIDEO::getFloatBusData = &VIDEO::getFloatBusData128; Z80Ops::is48 = false; + CPU::IntStart = INT_START128; + CPU::IntEnd = INT_END128 + CPU::latetiming; } tstates = 0; @@ -262,8 +277,21 @@ void IRAM_ATTR Z80Ops::addressOnBus(uint16_t address, int32_t wstates){ /* Callback to know when the INT signal is active */ bool IRAM_ATTR Z80Ops::isActiveINT(void) { - int tmp = CPU::tstates; + + // Early timing + // int tmp = CPU::tstates; + // if (tmp >= CPU::statesInFrame) tmp -= CPU::statesInFrame; + // return ((tmp >= 0) && (tmp < (is48 ? 32 : 36))); + + // // Late timing + // int tmp = CPU::tstates + 1; + // if (tmp >= CPU::statesInFrame) tmp -= CPU::statesInFrame; + // return ((tmp >= 0) && (tmp <= (is48 ? 32 : 36))); + + int tmp = CPU::tstates + CPU::latetiming; if (tmp >= CPU::statesInFrame) tmp -= CPU::statesInFrame; - return ((tmp >= 0) && (tmp < (is48 ? 32 : 36))); + // return ((tmp >= 0) && (tmp < (is48 ? 32 + CPU::latetiming: 36 + CPU::latetiming))); + return ((tmp >= CPU::IntStart) && (tmp < CPU::IntEnd)); } + diff --git a/src/Config.cpp b/src/Config.cpp index 71cc473a..852e6bff 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -33,6 +33,14 @@ visit https://zxespectrum.speccy.org/contacto */ +#include +#include +#include "nvs_flash.h" +#include "nvs.h" +#include "nvs_handle.hpp" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" #include #include #include @@ -41,7 +49,6 @@ visit https://zxespectrum.speccy.org/contacto #include "FileUtils.h" #include "messages.h" #include "ESPectrum.h" -#include "esp_spiffs.h" #include "pwm_audio.h" string Config::arch = "48K"; @@ -56,6 +63,7 @@ uint8_t Config::esp32rev = 0; uint8_t Config::lang = 0; bool Config::AY48 = false; uint8_t Config::joystick = 0; // 0 -> Cursor, 1 -> Kempston +uint8_t Config::AluTiming = 0; // erase control characters (in place) static inline void erase_cntrl(std::string &s) { @@ -90,140 +98,336 @@ void Config::load() { pwm_audio_stop(); - FILE *f = fopen(DISK_BOOT_FILENAME, "r"); - if (f==NULL) - { - // printf("Error opening %s",DISK_BOOT_FILENAME); - Config::save(); // Try to create file if doesn't exist - return; + // Initialize NVS + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + // NVS partition was truncated and needs to be erased + // Retry nvs_flash_init + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); } + ESP_ERROR_CHECK( err ); + + // Open + printf("\n"); + printf("Opening Non-Volatile Storage (NVS) handle... "); + nvs_handle_t handle; + err = nvs_open("storage", NVS_READWRITE, &handle); + if (err != ESP_OK) { + printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err)); + } else { + printf("Done\n"); + + size_t required_size; + char* str_data; + + err = nvs_get_str(handle, "arch", NULL, &required_size); + if (err == ESP_OK) { + str_data = (char *)malloc(required_size); + nvs_get_str(handle, "arch", str_data, &required_size); + printf("arch:%s\n",str_data); + arch = str_data; + + // FORCE MODEL FOR TESTING + // arch = "48K"; + + free(str_data); + } else { + // No nvs data found. Save it + nvs_close(handle); + Config::save(); + pwm_audio_start(); + return; + } - char buf[256]; - while(fgets(buf, sizeof(buf), f) != NULL) - { - string line = buf; - printf(line.c_str()); - if (line.find("ram:") != string::npos) { - ram_file = line.substr(line.find(':') + 1); - erase_cntrl(ram_file); - trim(ram_file); - } else if (line.find("arch:") != string::npos) { - arch = line.substr(line.find(':') + 1); - erase_cntrl(arch); - trim(arch); - } else if (line.find("romset:") != string::npos) { - romSet = line.substr(line.find(':') + 1); - erase_cntrl(romSet); - trim(romSet); - } else if (line.find("slog:") != string::npos) { - line = line.substr(line.find(':') + 1); - erase_cntrl(line); - trim(line); - slog_on = (line == "true" ? true : false); - } else if (line.find("asp169:") != string::npos) { - line = line.substr(line.find(':') + 1); - erase_cntrl(line); - trim(line); - aspect_16_9 = (line == "true"); - } else if (line.find("sdstorage:") != string::npos) { - if (FileUtils::SDReady) { - line = line.substr(line.find(':') + 1); - erase_cntrl(line); - trim(line); - FileUtils::MountPoint = (line == "true" ? MOUNT_POINT_SD : MOUNT_POINT_SPIFFS); - } else - FileUtils::MountPoint = MOUNT_POINT_SPIFFS; - // } else if (line.find("kbdlayout:") != string::npos) { - // kbd_layout = line.substr(line.find(':') + 1); - // erase_cntrl(kbd_layout); - // trim(kbd_layout); - } else if (line.find("videomode:") != string::npos) { - string svmode = line.substr(line.find(':') + 1); - erase_cntrl(svmode); - trim(svmode); - Config::videomode = stoi(svmode); - } else if (line.find("language:") != string::npos) { - string slang = line.substr(line.find(':') + 1); - erase_cntrl(slang); - trim(slang); - Config::lang = stoi(slang); - } else if (line.find("AY48:") != string::npos) { - line = line.substr(line.find(':') + 1); - erase_cntrl(line); - trim(line); - AY48 = (line == "true"); - } else if (line.find("joystick:") != string::npos) { - string sjoy = line.substr(line.find(':') + 1); - erase_cntrl(sjoy); - trim(sjoy); - Config::joystick = stoi(sjoy); + err = nvs_get_str(handle, "romSet", NULL, &required_size); + if (err == ESP_OK) { + str_data = (char *)malloc(required_size); + nvs_get_str(handle, "romSet", str_data, &required_size); + printf("romSet:%s\n",str_data); + romSet = str_data; + free(str_data); + } + + err = nvs_get_str(handle, "ram", NULL, &required_size); + if (err == ESP_OK) { + str_data = (char *)malloc(required_size); + nvs_get_str(handle, "ram", str_data, &required_size); + printf("ram:%s\n",str_data); + ram_file = str_data; + free(str_data); + } + + err = nvs_get_str(handle, "slog", NULL, &required_size); + if (err == ESP_OK) { + str_data = (char *)malloc(required_size); + nvs_get_str(handle, "slog", str_data, &required_size); + printf("slog:%s\n",str_data); + slog_on = strcmp(str_data, "false"); + free(str_data); + } + + err = nvs_get_str(handle, "sdstorage", NULL, &required_size); + if (err == ESP_OK) { + str_data = (char *)malloc(required_size); + nvs_get_str(handle, "sdstorage", str_data, &required_size); + printf("sdstorage:%s\n",str_data); + + // if (FileUtils::SDReady) { + // FileUtils::MountPoint = ( strcmp(str_data, "false") ? MOUNT_POINT_SD : MOUNT_POINT_SPIFFS); + // } else + // FileUtils::MountPoint = MOUNT_POINT_SPIFFS; + + // Force SD from now on + FileUtils::MountPoint = MOUNT_POINT_SD; + + free(str_data); + } + + err = nvs_get_str(handle, "asp169", NULL, &required_size); + if (err == ESP_OK) { + str_data = (char *)malloc(required_size); + nvs_get_str(handle, "asp169", str_data, &required_size); + printf("asp169:%s\n",str_data); + aspect_16_9 = strcmp(str_data, "false"); + free(str_data); + } + + err = nvs_get_u8(handle, "videomode", &Config::videomode); + if (err == ESP_OK) { + printf("videomode:%u\n",Config::videomode); + } + + + err = nvs_get_u8(handle, "language", &Config::lang); + if (err == ESP_OK) { + printf("language:%u\n",Config::lang); + } + + err = nvs_get_str(handle, "AY48", NULL, &required_size); + if (err == ESP_OK) { + str_data = (char *)malloc(required_size); + nvs_get_str(handle, "AY48", str_data, &required_size); + printf("AY48:%s\n",str_data); + AY48 = strcmp(str_data, "false"); + free(str_data); } + err = nvs_get_u8(handle, "joystick", &Config::joystick); + if (err == ESP_OK) { + printf("joystick:%u\n",Config::joystick); + } + err = nvs_get_u8(handle, "AluTiming", &Config::AluTiming); + if (err == ESP_OK) { + printf("AluTiming:%u\n",Config::AluTiming); + } + + // Close + nvs_close(handle); } - fclose(f); + + // FILE *f = fopen(DISK_BOOT_FILENAME, "r"); + // if (f==NULL) + // { + // // printf("Error opening %s",DISK_BOOT_FILENAME); + // Config::save(); // Try to create file if doesn't exist + // return; + // } + + // char buf[256]; + // while(fgets(buf, sizeof(buf), f) != NULL) + // { + // string line = buf; + // printf(line.c_str()); + // if (line.find("ram:") != string::npos) { + // ram_file = line.substr(line.find(':') + 1); + // erase_cntrl(ram_file); + // trim(ram_file); + // } else if (line.find("arch:") != string::npos) { + // arch = line.substr(line.find(':') + 1); + // erase_cntrl(arch); + // trim(arch); + // } else if (line.find("romset:") != string::npos) { + // romSet = line.substr(line.find(':') + 1); + // erase_cntrl(romSet); + // trim(romSet); + // } else if (line.find("slog:") != string::npos) { + // line = line.substr(line.find(':') + 1); + // erase_cntrl(line); + // trim(line); + // slog_on = (line == "true" ? true : false); + // } else if (line.find("asp169:") != string::npos) { + // line = line.substr(line.find(':') + 1); + // erase_cntrl(line); + // trim(line); + // aspect_16_9 = (line == "true"); + // } else if (line.find("sdstorage:") != string::npos) { + // if (FileUtils::SDReady) { + // line = line.substr(line.find(':') + 1); + // erase_cntrl(line); + // trim(line); + // FileUtils::MountPoint = (line == "true" ? MOUNT_POINT_SD : MOUNT_POINT_SPIFFS); + // } else + // FileUtils::MountPoint = MOUNT_POINT_SPIFFS; + // } else if (line.find("kbdlayout:") != string::npos) { + // kbd_layout = line.substr(line.find(':') + 1); + // erase_cntrl(kbd_layout); + // trim(kbd_layout); + // } else if (line.find("videomode:") != string::npos) { + // string svmode = line.substr(line.find(':') + 1); + // erase_cntrl(svmode); + // trim(svmode); + // Config::videomode = stoi(svmode); + // } else if (line.find("language:") != string::npos) { + // string slang = line.substr(line.find(':') + 1); + // erase_cntrl(slang); + // trim(slang); + // Config::lang = stoi(slang); + // } else if (line.find("AY48:") != string::npos) { + // line = line.substr(line.find(':') + 1); + // erase_cntrl(line); + // trim(line); + // AY48 = (line == "true"); + // } else if (line.find("joystick:") != string::npos) { + // string sjoy = line.substr(line.find(':') + 1); + // erase_cntrl(sjoy); + // trim(sjoy); + // Config::joystick = stoi(sjoy); + // } + + + // } + // fclose(f); pwm_audio_start(); } -// Dump actual config to FS void Config::save() { + Config::save("all"); +} + +// Dump actual config to FS +void Config::save(string value) { pwm_audio_stop(); - //printf("Saving config file '%s':\n", DISK_BOOT_FILENAME); + // Initialize NVS + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + // NVS partition was truncated and needs to be erased + // Retry nvs_flash_init + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK( err ); - FILE *f = fopen(DISK_BOOT_FILENAME, "w"); - if (f == NULL) - { - printf("Error opening %s\n",DISK_BOOT_FILENAME); - pwm_audio_start(); - return; + // Open + printf("\n"); + printf("Opening Non-Volatile Storage (NVS) handle... "); + nvs_handle_t handle; + err = nvs_open("storage", NVS_READWRITE, &handle); + if (err != ESP_OK) { + printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err)); + } else { + printf("Done\n"); + + + if((value=="arch") || (value=="all")) + nvs_set_str(handle,"arch",arch.c_str()); + + if((value=="romSet") || (value=="all")) + nvs_set_str(handle,"romSet",romSet.c_str()); + + if((value=="ram") || (value=="all")) + nvs_set_str(handle,"ram",ram_file.c_str()); + + if((value=="slog") || (value=="all")) + // nvs_set_str(handle,"slog",slog_on ? "true" : "false"); + nvs_set_str(handle,"slog","true"); + + if((value=="sdstorage") || (value=="all")) + nvs_set_str(handle,"sdstorage",FileUtils::MountPoint == MOUNT_POINT_SD ? "true" : "false"); + + if((value=="asp169") || (value=="all")) + nvs_set_str(handle,"asp169",aspect_16_9 ? "true" : "false"); + + if((value=="videomode") || (value=="all")) + nvs_set_u8(handle,"videomode",Config::videomode); + + if((value=="language") || (value=="all")) + nvs_set_u8(handle,"language",Config::lang); + + if((value=="AY48") || (value=="all")) + nvs_set_str(handle,"AY48",AY48 ? "true" : "false"); + + if((value=="joystick") || (value=="all")) + nvs_set_u8(handle,"joystick",Config::joystick); + + if((value=="AluTiming") || (value=="all")) + nvs_set_u8(handle,"AluTiming",Config::AluTiming); + + printf("Committing updates in NVS ... "); + err = nvs_commit(handle); + printf((err != ESP_OK) ? "Failed!\n" : "Done\n"); + + // Close + nvs_close(handle); } - // Architecture - //printf(("arch:" + arch + "\n").c_str()); - fputs(("arch:" + arch + "\n").c_str(),f); + //printf("Saving config file '%s':\n", DISK_BOOT_FILENAME); + + // FILE *f = fopen(DISK_BOOT_FILENAME, "w"); + // if (f == NULL) + // { + // printf("Error opening %s\n",DISK_BOOT_FILENAME); + // pwm_audio_start(); + // return; + // } + + // // Architecture + // //printf(("arch:" + arch + "\n").c_str()); + // fputs(("arch:" + arch + "\n").c_str(),f); - // ROM set - //printf(("romset:" + romSet + "\n").c_str()); - fputs(("romset:" + romSet + "\n").c_str(),f); + // // ROM set + // //printf(("romset:" + romSet + "\n").c_str()); + // fputs(("romset:" + romSet + "\n").c_str(),f); - // RAM SNA - //printf(("ram:" + ram_file + "\n").c_str()); - fputs(("ram:" + ram_file + "\n").c_str(),f); + // // RAM SNA + // //printf(("ram:" + ram_file + "\n").c_str()); + // fputs(("ram:" + ram_file + "\n").c_str(),f); - // Serial logging - //printf(slog_on ? "slog:true\n" : "slog:false\n"); - fputs(slog_on ? "slog:true\n" : "slog:false\n",f); + // // Serial logging + // //printf(slog_on ? "slog:true\n" : "slog:false\n"); + // fputs(slog_on ? "slog:true\n" : "slog:false\n",f); - // Aspect ratio - //printf(aspect_16_9 ? "asp169:true\n" : "asp169:false\n"); - fputs(aspect_16_9 ? "asp169:true\n" : "asp169:false\n",f); + // // Aspect ratio + // //printf(aspect_16_9 ? "asp169:true\n" : "asp169:false\n"); + // fputs(aspect_16_9 ? "asp169:true\n" : "asp169:false\n",f); - // Mount point - //printf(FileUtils::MountPoint == MOUNT_POINT_SD ? "sdstorage:true\n" : "sdstorage:false\n"); - fputs(FileUtils::MountPoint == MOUNT_POINT_SD ? "sdstorage:true\n" : "sdstorage:false\n",f); + // // Mount point + // //printf(FileUtils::MountPoint == MOUNT_POINT_SD ? "sdstorage:true\n" : "sdstorage:false\n"); + // fputs(FileUtils::MountPoint == MOUNT_POINT_SD ? "sdstorage:true\n" : "sdstorage:false\n",f); - // KBD layout - //printf(("kbdlayout:" + kbd_layout + "\n").c_str()); - // fputs(("kbdlayout:" + kbd_layout + "\n").c_str(),f); + // // KBD layout + // //printf(("kbdlayout:" + kbd_layout + "\n").c_str()); + // // fputs(("kbdlayout:" + kbd_layout + "\n").c_str(),f); - // Videomode - fputs(("videomode:" + std::to_string(Config::videomode) + "\n").c_str(),f); + // // Videomode + // fputs(("videomode:" + std::to_string(Config::videomode) + "\n").c_str(),f); - // Language - //printf("language:%s\n",std::to_string(Config::lang).c_str()); - fputs(("language:" + std::to_string(Config::lang) + "\n").c_str(),f); + // // Language + // //printf("language:%s\n",std::to_string(Config::lang).c_str()); + // fputs(("language:" + std::to_string(Config::lang) + "\n").c_str(),f); - // AY emulation on 48K mode - fputs(AY48 ? "AY48:true\n" : "AY48:false\n",f); + // // AY emulation on 48K mode + // fputs(AY48 ? "AY48:true\n" : "AY48:false\n",f); - // Joystick - fputs(("joystick:" + std::to_string(Config::joystick) + "\n").c_str(),f); + // // Joystick + // fputs(("joystick:" + std::to_string(Config::joystick) + "\n").c_str(),f); - fclose(f); + // fclose(f); printf("Config saved OK\n"); diff --git a/src/ESPectrum.cpp b/src/ESPectrum.cpp index 42062585..66e2a1d8 100644 --- a/src/ESPectrum.cpp +++ b/src/ESPectrum.cpp @@ -60,29 +60,11 @@ visit https://zxespectrum.speccy.org/contacto #include "freertos/task.h" #include "driver/timer.h" #include "soc/timer_group_struct.h" -#include "esp_spiffs.h" #include "esp_timer.h" #include "esp_system.h" #include "esp_spi_flash.h" #endif -// #include -// #include -// #include -// #include "driver/uart.h" - -// #include "esp_bt.h" -// #include "nvs_flash.h" -// #include "esp_bt_device.h" -// #include "esp_gap_ble_api.h" -// #include "esp_gattc_api.h" -// #include "esp_gatt_defs.h" -// #include "esp_bt_main.h" -// #include "esp_system.h" -// #include "esp_gatt_common_api.h" -// #include "esp_log.h" -// #define GATTC_TAG "GATTC_SPP_DEMO" - using namespace std; // works, but not needed for now @@ -182,21 +164,303 @@ printf("------------------------------------------------------------------------ printf("Total currently free in all non-continues blocks: %d\n", info.total_free_bytes); printf("Minimum free ever: %d\n", info.minimum_free_bytes); printf("Largest continues block to allocate big array: %d\n", info.largest_free_block); -printf("Heap caps get free size: %d\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); +printf("Heap caps get free size (MALLOC_CAP_8BIT): %d\n", heap_caps_get_free_size(MALLOC_CAP_8BIT)); +printf("Heap caps get free size (MALLOC_CAP_32BIT): %d\n", heap_caps_get_free_size(MALLOC_CAP_32BIT)); +printf("Heap caps get free size (MALLOC_CAP_INTERNAL): %d\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); printf("=========================================================================\n\n"); -UBaseType_t wm; -wm = uxTaskGetStackHighWaterMark(audioTaskHandle); -printf("Audio Task Stack HWM: %u\n", wm); -// wm = uxTaskGetStackHighWaterMark(loopTaskHandle); -// printf("Loop Task Stack HWM: %u\n", wm); -wm = uxTaskGetStackHighWaterMark(VIDEO::videoTaskHandle); -printf("Video Task Stack HWM: %u\n", wm); +// heap_caps_print_heap_info(MALLOC_CAP_INTERNAL); + +// printf("=========================================================================\n"); +// heap_caps_print_heap_info(MALLOC_CAP_8BIT); + +// printf("=========================================================================\n"); +// heap_caps_print_heap_info(MALLOC_CAP_32BIT); + +// printf("=========================================================================\n"); +// heap_caps_print_heap_info(MALLOC_CAP_DEFAULT); + +// printf("=========================================================================\n"); +// heap_caps_print_heap_info(MALLOC_CAP_DMA); + +// printf("=========================================================================\n"); +// heap_caps_print_heap_info(MALLOC_CAP_EXEC); + +// printf("=========================================================================\n"); +// heap_caps_print_heap_info(MALLOC_CAP_IRAM_8BIT); + +// printf("=========================================================================\n"); +// heap_caps_dump_all(); + +// printf("=========================================================================\n"); + +// UBaseType_t wm; +// wm = uxTaskGetStackHighWaterMark(audioTaskHandle); +// printf("Audio Task Stack HWM: %u\n", wm); +// // wm = uxTaskGetStackHighWaterMark(loopTaskHandle); +// // printf("Loop Task Stack HWM: %u\n", wm); +// wm = uxTaskGetStackHighWaterMark(VIDEO::videoTaskHandle); +// printf("Video Task Stack HWM: %u\n", wm); #endif } +//======================================================================================= +// BOOT KEYBOARD +//======================================================================================= +std::string ESPectrum::bootKeyboard() { + + auto Kbd = PS2Controller.keyboard(); + fabgl::VirtualKeyItem NextKey; + bool r = false; + + // #ifdef ZXKEYB + + if (ZXKeyb::Exists) { + + // Process physical keyboard + ZXKeyb::process(); + // Detect and process physical kbd menu key combinations + + if (!bitRead(ZXKeyb::ZXcols[3], 0)) { // 1 + if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q + return "1Q"; + } else + if (!bitRead(ZXKeyb::ZXcols[2], 1)) { // W + return "1W"; + } + } else + if (!bitRead(ZXKeyb::ZXcols[3], 1)) { // 2 + if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q + return "2Q"; + } else + if (!bitRead(ZXKeyb::ZXcols[2], 1)) { // W + return "2W"; + } + } else + if (!bitRead(ZXKeyb::ZXcols[3], 2)) { // 3 + if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q + return "3Q"; + } else + if (!bitRead(ZXKeyb::ZXcols[2], 1)) { // W + return "3W"; + } + } + + } + + // #endif + + while (Kbd->virtualKeyAvailable()) { + r = Kbd->getNextVirtualKey(&NextKey); + if (r) { + // Check keyboard status + if (PS2Controller.keyboard()->isVKDown(fabgl::VK_1)) return "1"; + if (PS2Controller.keyboard()->isVKDown(fabgl::VK_2)) return "2"; + if (PS2Controller.keyboard()->isVKDown(fabgl::VK_3)) return "3"; + if (PS2Controller.keyboard()->isVKDown(fabgl::VK_Q) || PS2Controller.keyboard()->isVKDown(fabgl::VK_q)) return "Q"; + if (PS2Controller.keyboard()->isVKDown(fabgl::VK_W) || PS2Controller.keyboard()->isVKDown(fabgl::VK_w)) return "W"; + } + } + + return ""; + +} + +// void ESPectrum::bootKeyboard() { + +// std::string b = "00"; + +// #ifdef ZXKEYB +// if (ZXKeyb::Exists) { // START - ZXKeyb Exists + +// // Process physical keyboard +// ZXKeyb::process(); +// // Detect and process physical kbd menu key combinations + +// if (!bitRead(ZXKeyb::ZXcols[3], 0)) { // 1 +// if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q +// b = "1Q"; +// } else +// if (!bitRead(ZXKeyb::ZXcols[2], 1)) { // W +// b = "1W"; +// } +// } else +// if (!bitRead(ZXKeyb::ZXcols[3], 1)) { // 2 +// if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q +// b = "2Q"; +// } else +// if (!bitRead(ZXKeyb::ZXcols[2], 1)) { // W +// b = "2W"; +// } +// } else +// if (!bitRead(ZXKeyb::ZXcols[3], 2)) { // 3 +// if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q +// b = "3Q"; +// } else +// if (!bitRead(ZXKeyb::ZXcols[2], 1)) { // W +// b = "3W"; +// } +// } + +// } // END - ZXKeyb Exists +// #endif + +// //PS2Controller.keyboard()->reset(); + +// if ((PS2Controller.keyboard()->isVKDown(fabgl::VK_q) && PS2Controller.keyboard()->isVKDown(fabgl::VK_1)) || (b == "1Q")) { +// b = "1Q"; +// Config::aspect_16_9=false; +// Config::videomode=0; +// } else +// if ((PS2Controller.keyboard()->isVKDown(fabgl::VK_w) && PS2Controller.keyboard()->isVKDown(fabgl::VK_1)) || (b == "1W")) { +// b = "1W"; +// Config::aspect_16_9=true; +// Config::videomode=0; +// } else +// if ((PS2Controller.keyboard()->isVKDown(fabgl::VK_q) && PS2Controller.keyboard()->isVKDown(fabgl::VK_2)) || (b == "2Q")) { +// b = "2Q"; +// Config::aspect_16_9=false; +// Config::videomode=1; +// } else +// if ((PS2Controller.keyboard()->isVKDown(fabgl::VK_w) && PS2Controller.keyboard()->isVKDown(fabgl::VK_2)) || (b == "2W")) { +// b = "2W"; +// Config::aspect_16_9=true; +// Config::videomode=1; +// } else +// if ((PS2Controller.keyboard()->isVKDown(fabgl::VK_q) && PS2Controller.keyboard()->isVKDown(fabgl::VK_3)) || (b == "3Q")) { +// b = "3Q"; +// Config::aspect_16_9=false; +// Config::videomode=2; +// } else +// if ((PS2Controller.keyboard()->isVKDown(fabgl::VK_w) && PS2Controller.keyboard()->isVKDown(fabgl::VK_3)) || (b == "3W")) { +// b = "3W"; +// Config::aspect_16_9=true; +// Config::videomode=2; +// } + +// if (b != "00") { +// Config::ram_file="none"; +// Config::save(); +// printf("%s\n", b.c_str()); +// } + +// //return b; + + + +// /* +// std:string b = "00"; +// std::string s; +// for (int i=0; i<2000; i++) { +// s = bootKeyboard(); +// if (s!="") { + +// if (s.length()==2) +// b = s; +// else { +// b[0] = b[1]; +// b[1] = s[0]; +// } + +// bool chgRes = true; + +// if (b=="1Q" || b=="Q1") { +// Config::aspect_16_9=false; +// Config::videomode=0; +// } else +// if (b=="1W" || b=="W1") { +// Config::aspect_16_9=true; +// Config::videomode=0; +// } else +// if (b=="2Q" || b=="Q2") { +// Config::aspect_16_9=false; +// Config::videomode=1; +// } else +// if (b=="2W" || b=="W2") { +// Config::aspect_16_9=true; +// Config::videomode=1; +// } else +// if (b=="3Q" || b=="Q3") { +// Config::aspect_16_9=false; +// Config::videomode=2; +// } else +// if (b=="3W" || b=="W3") { +// Config::aspect_16_9=true; +// Config::videomode=2; +// } else chgRes = false; + +// if (chgRes) { +// Config::ram_file="none"; +// Config::save(); +// printf("%s\n", b.c_str()); +// break; +// } + +// } + +// delayMicroseconds(250); + +// } +// */ + + +// /* +// auto Kbd = PS2Controller.keyboard(); +// fabgl::VirtualKeyItem NextKey; +// bool r = false; + +// #ifdef ZXKEYB + +// // Process physical keyboard +// ZXKeyb::process(); +// // Detect and process physical kbd menu key combinations + +// if (!bitRead(ZXKeyb::ZXcols[3], 0)) { // 1 +// if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q +// return "1Q"; +// } else +// if (!bitRead(ZXKeyb::ZXcols[2], 1)) { // W +// return "1W"; +// } +// } else +// if (!bitRead(ZXKeyb::ZXcols[3], 1)) { // 2 +// if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q +// return "2Q"; +// } else +// if (!bitRead(ZXKeyb::ZXcols[2], 1)) { // W +// return "2W"; +// } +// } else +// if (!bitRead(ZXKeyb::ZXcols[3], 2)) { // 3 +// if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q +// return "3Q"; +// } else +// if (!bitRead(ZXKeyb::ZXcols[2], 1)) { // W +// return "3W"; +// } +// } + +// #endif + +// while (Kbd->virtualKeyAvailable()) { +// r = Kbd->getNextVirtualKey(&NextKey); +// if (r) { +// // Check keyboard status +// if (PS2Controller.keyboard()->isVKDown(fabgl::VK_1)) return "1"; +// if (PS2Controller.keyboard()->isVKDown(fabgl::VK_2)) return "2"; +// if (PS2Controller.keyboard()->isVKDown(fabgl::VK_3)) return "3"; +// if (PS2Controller.keyboard()->isVKDown(fabgl::VK_Q) || PS2Controller.keyboard()->isVKDown(fabgl::VK_q)) return "Q"; +// if (PS2Controller.keyboard()->isVKDown(fabgl::VK_W) || PS2Controller.keyboard()->isVKDown(fabgl::VK_w)) return "W"; +// } +// } + +// return ""; +// */ + +// } + //======================================================================================= // SETUP //======================================================================================= @@ -205,24 +469,24 @@ printf("Video Task Stack HWM: %u\n", wm); void ESPectrum::setup() { + #ifdef TESTING_CODE + showMemInfo(); + #endif + //======================================================================================= // KEYBOARD //======================================================================================= PS2Controller.begin(PS2Preset::KeyboardPort0, KbdMode::CreateVirtualKeysQueue); - PS2Controller.keyboard()->setScancodeSet(2); // IBM PC AT - - if (Config::slog_on) { - showMemInfo("Keyboard started"); - } + PS2Controller.keyboard()->reset(); // This is already setting the ScancodeSet 2 //======================================================================================= // PHYSICAL KEYBOARD (SINCLAIR 8 + 5 MEMBRANE KEYBOARD) //======================================================================================= - #ifdef ZXKEYB + // #ifdef ZXKEYB ZXKeyb::setup(); - #endif + // #endif //======================================================================================= // FILESYSTEM @@ -232,6 +496,10 @@ void ESPectrum::setup() #ifndef ESP32_SDL2_WRAPPER + if (Config::slog_on) { + showMemInfo("Keyboard started"); + } + // Get chip information esp_chip_info_t chip_info; esp_chip_info(&chip_info); @@ -305,7 +573,7 @@ void ESPectrum::setup() } else chgRes = false; if (chgRes) { - Config::ram_file="none"; + Config::ram_file="none"; Config::save(); printf("%s\n", b.c_str()); break; @@ -331,6 +599,12 @@ void ESPectrum::setup() MemESP::ram6 = (unsigned char *) heap_caps_malloc(0x4000, MALLOC_CAP_8BIT); MemESP::ram7 = (unsigned char *) heap_caps_malloc(0x4000, MALLOC_CAP_8BIT); + // MemESP::ram1 = (unsigned char *) heap_caps_malloc(0x4000, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + // MemESP::ram3 = (unsigned char *) heap_caps_malloc(0x4000, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + // MemESP::ram4 = (unsigned char *) heap_caps_malloc(0x4000, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + // MemESP::ram6 = (unsigned char *) heap_caps_malloc(0x4000, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + // MemESP::ram7 = (unsigned char *) heap_caps_malloc(0x4000, MALLOC_CAP_8BIT); + if (Config::slog_on) { if (MemESP::ram1 == NULL) printf("ERROR! Unable to allocate ram1\n"); if (MemESP::ram3 == NULL) printf("ERROR! Unable to allocate ram3\n"); @@ -442,7 +716,7 @@ void ESPectrum::setup() // ESP host reset #ifndef SNAPSHOT_LOAD_LAST Config::ram_file = NO_RAM_FILE; - Config::save(); + Config::save("ram"); #endif } @@ -575,47 +849,7 @@ bool IRAM_ATTR ESPectrum::readKbd(fabgl::VirtualKeyItem *Nextkey) { } #ifdef TESTING_CODE else if (Nextkey->vk == fabgl::VK_GRAVEACCENT) { // Show mem info - multi_heap_info_t info; - heap_caps_get_info(&info, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); // internal RAM, memory capable to store data or to create new task - printf("=========================================================================\n"); - printf("Total currently free in all non-continues blocks: %d\n", info.total_free_bytes); - printf("Minimum free ever: %d\n", info.minimum_free_bytes); - printf("Largest continues block to allocate big array: %d\n", info.largest_free_block); - printf("Heap caps get free size: %d\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL)); - - printf("=========================================================================\n\n"); - heap_caps_print_heap_info(MALLOC_CAP_INTERNAL); - - printf("=========================================================================\n"); - heap_caps_print_heap_info(MALLOC_CAP_8BIT); - - printf("=========================================================================\n"); - heap_caps_print_heap_info(MALLOC_CAP_32BIT); - - printf("=========================================================================\n"); - heap_caps_print_heap_info(MALLOC_CAP_DEFAULT); - - printf("=========================================================================\n"); - heap_caps_print_heap_info(MALLOC_CAP_DMA); - - printf("=========================================================================\n"); - heap_caps_print_heap_info(MALLOC_CAP_EXEC); - - printf("=========================================================================\n"); - heap_caps_print_heap_info(MALLOC_CAP_IRAM_8BIT); - - printf("=========================================================================\n"); - heap_caps_dump_all(); - - printf("=========================================================================\n"); - UBaseType_t wm; - wm = uxTaskGetStackHighWaterMark(audioTaskHandle); - printf("Audio Task Stack HWM: %u\n", wm); - // wm = uxTaskGetStackHighWaterMark(loopTaskHandle); - // printf("Loop Task Stack HWM: %u\n", wm); - wm = uxTaskGetStackHighWaterMark(VIDEO::videoTaskHandle); - printf("Video Task Stack HWM: %u\n", wm); - + showMemInfo(); r = false; } #endif @@ -626,9 +860,9 @@ bool IRAM_ATTR ESPectrum::readKbd(fabgl::VirtualKeyItem *Nextkey) { uint8_t ESPectrum::PS2cols[8] = { 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f }; -#ifdef ZXKEYB +// #ifdef ZXKEYB static int zxDelay = 0; -#endif +// #endif void IRAM_ATTR ESPectrum::processKeyboard() { @@ -743,136 +977,92 @@ void IRAM_ATTR ESPectrum::processKeyboard() { } - #ifdef ZXKEYB - - if (zxDelay > 0) - zxDelay--; - else - // Process physical keyboard - ZXKeyb::process(); + // #ifdef ZXKEYB - // Detect and process physical kbd menu key combinations - // CS+SS+N -> FN Keys - // F11 -> CS+SS+Q, F12 -> CS+SS+W - // TO DO: Add delay after special key so keys as vol up vol down or toggles like F8 doesn't get re-pressed too fast. - if ((!bitRead(ZXKeyb::ZXcols[0],0)) && (!bitRead(ZXKeyb::ZXcols[7],1))) { + if (ZXKeyb::Exists) { // START - ZXKeyb Exists - zxDelay = 15; + if (zxDelay > 0) + zxDelay--; + else + // Process physical keyboard + ZXKeyb::process(); - if (!bitRead(ZXKeyb::ZXcols[3],0)) { - OSD::do_OSD(fabgl::VK_F1); - } else - if (!bitRead(ZXKeyb::ZXcols[3],1)) { - OSD::do_OSD(fabgl::VK_F2); - } else - if (!bitRead(ZXKeyb::ZXcols[3],2)) { - OSD::do_OSD(fabgl::VK_F3); - } else - if (!bitRead(ZXKeyb::ZXcols[3],3)) { - OSD::do_OSD(fabgl::VK_F4); - } else - if (!bitRead(ZXKeyb::ZXcols[3],4)) { - OSD::do_OSD(fabgl::VK_F5); - } else - if (!bitRead(ZXKeyb::ZXcols[4],4)) { - OSD::do_OSD(fabgl::VK_F6); - } else - if (!bitRead(ZXKeyb::ZXcols[4],3)) { - OSD::do_OSD(fabgl::VK_F7); - } else - if (!bitRead(ZXKeyb::ZXcols[4],2)) { - OSD::do_OSD(fabgl::VK_F8); - } else - if (!bitRead(ZXKeyb::ZXcols[4],1)) { - OSD::do_OSD(fabgl::VK_F9); - } else - if (!bitRead(ZXKeyb::ZXcols[4],0)) { - OSD::do_OSD(fabgl::VK_F10); - } else - if (!bitRead(ZXKeyb::ZXcols[2],0)) { - CaptureToBmp(); - } else - if (!bitRead(ZXKeyb::ZXcols[2],1)) { - OSD::do_OSD(fabgl::VK_F12); - } else - zxDelay = 0; + // Detect and process physical kbd menu key combinations + // CS+SS+N -> FN Keys + // F11 -> CS+SS+Q, F12 -> CS+SS+W + // TO DO: Add delay after special key so keys as vol up vol down or toggles like F8 doesn't get re-pressed too fast. + if ((!bitRead(ZXKeyb::ZXcols[0],0)) && (!bitRead(ZXKeyb::ZXcols[7],1))) { - if (zxDelay) { - // Set all keys as not pressed - for (uint8_t i = 0; i < 8; i++) ZXKeyb::ZXcols[i] = 0x1f; - return; - } - - } + zxDelay = 15; - // Combine both keyboards - for (uint8_t rowidx = 0; rowidx < 8; rowidx++) { - Ports::port[rowidx] = PS2cols[rowidx] & ZXKeyb::ZXcols[rowidx]; - } - - #else + if (!bitRead(ZXKeyb::ZXcols[3],0)) { + OSD::do_OSD(fabgl::VK_F1); + } else + if (!bitRead(ZXKeyb::ZXcols[3],1)) { + OSD::do_OSD(fabgl::VK_F2); + } else + if (!bitRead(ZXKeyb::ZXcols[3],2)) { + OSD::do_OSD(fabgl::VK_F3); + } else + if (!bitRead(ZXKeyb::ZXcols[3],3)) { + OSD::do_OSD(fabgl::VK_F4); + } else + if (!bitRead(ZXKeyb::ZXcols[3],4)) { + OSD::do_OSD(fabgl::VK_F5); + } else + if (!bitRead(ZXKeyb::ZXcols[4],4)) { + OSD::do_OSD(fabgl::VK_F6); + } else + if (!bitRead(ZXKeyb::ZXcols[4],3)) { + OSD::do_OSD(fabgl::VK_F7); + } else + if (!bitRead(ZXKeyb::ZXcols[4],2)) { + OSD::do_OSD(fabgl::VK_F8); + } else + if (!bitRead(ZXKeyb::ZXcols[4],1)) { + OSD::do_OSD(fabgl::VK_F9); + } else + if (!bitRead(ZXKeyb::ZXcols[4],0)) { + OSD::do_OSD(fabgl::VK_F10); + } else + if (!bitRead(ZXKeyb::ZXcols[2],0)) { + CaptureToBmp(); + } else + if (!bitRead(ZXKeyb::ZXcols[2],1)) { + OSD::do_OSD(fabgl::VK_F12); + } else + zxDelay = 0; - if (r) { - for (uint8_t rowidx = 0; rowidx < 8; rowidx++) { - Ports::port[rowidx] = PS2cols[rowidx]; + if (zxDelay) { + // Set all keys as not pressed + for (uint8_t i = 0; i < 8; i++) ZXKeyb::ZXcols[i] = 0x1f; + return; + } + } - } - #endif - -} - -std::string ESPectrum::bootKeyboard() { - - auto Kbd = PS2Controller.keyboard(); - fabgl::VirtualKeyItem NextKey; - bool r = false; - - #ifdef ZXKEYB - // Process physical keyboard - ZXKeyb::process(); - // Detect and process physical kbd menu key combinations - - if (!bitRead(ZXKeyb::ZXcols[3], 0)) { // 1 - if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q - return "1Q"; - } else - if (!bitRead(ZXKeyb::ZXcols[2], 1)) { // W - return "1W"; - } - } else - if (!bitRead(ZXKeyb::ZXcols[3], 1)) { // 2 - if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q - return "2Q"; - } else - if (!bitRead(ZXKeyb::ZXcols[2], 1)) { // W - return "2W"; - } - } else - if (!bitRead(ZXKeyb::ZXcols[3], 2)) { // 3 - if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q - return "3Q"; - } else - if (!bitRead(ZXKeyb::ZXcols[2], 1)) { // W - return "3W"; + // Combine both keyboards + for (uint8_t rowidx = 0; rowidx < 8; rowidx++) { + Ports::port[rowidx] = PS2cols[rowidx] & ZXKeyb::ZXcols[rowidx]; } - } - #endif + } else { - while (Kbd->virtualKeyAvailable()) { - r = Kbd->getNextVirtualKey(&NextKey); if (r) { - // Check keyboard status - if (PS2Controller.keyboard()->isVKDown(fabgl::VK_1)) return "1"; - if (PS2Controller.keyboard()->isVKDown(fabgl::VK_2)) return "2"; - if (PS2Controller.keyboard()->isVKDown(fabgl::VK_3)) return "3"; - if (PS2Controller.keyboard()->isVKDown(fabgl::VK_Q) || PS2Controller.keyboard()->isVKDown(fabgl::VK_q)) return "Q"; - if (PS2Controller.keyboard()->isVKDown(fabgl::VK_W) || PS2Controller.keyboard()->isVKDown(fabgl::VK_w)) return "W"; + for (uint8_t rowidx = 0; rowidx < 8; rowidx++) { + Ports::port[rowidx] = PS2cols[rowidx]; + } } + } + // #else - return ""; + // if (r) { + // for (uint8_t rowidx = 0; rowidx < 8; rowidx++) { + // Ports::port[rowidx] = PS2cols[rowidx]; + // } + // } + // #endif } diff --git a/src/FileSNA.cpp b/src/FileSNA.cpp index 74ec9bfd..33f14637 100644 --- a/src/FileSNA.cpp +++ b/src/FileSNA.cpp @@ -106,11 +106,6 @@ using namespace std; // /////////////////////////////////////////////////////////////////////////////// -// using internal storage (spi flash) -#include "esp_spiffs.h" - -// /////////////////////////////////////////////////////////////////////////////// - bool FileSNA::load(string sna_fn) { FILE *file; @@ -296,6 +291,11 @@ bool FileSNA::load(string sna_fn) ESPectrum::AY_emu = Config::AY48; ESPectrum::Audio_freq = ESP_AUDIO_FREQ_48; + CPU::latetiming = Config::AluTiming; + + CPU::IntStart = INT_START48; + CPU::IntEnd = INT_END48 + CPU::latetiming; + } else { Z80Ops::is48 = false; @@ -309,6 +309,11 @@ bool FileSNA::load(string sna_fn) ESPectrum::AY_emu = true; ESPectrum::Audio_freq = ESP_AUDIO_FREQ_128; + CPU::latetiming = Config::AluTiming; + + CPU::IntStart = INT_START128; + CPU::IntEnd = INT_END128 + CPU::latetiming; + } VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; diff --git a/src/FileUtils.cpp b/src/FileUtils.cpp index c8c72de7..6539de41 100644 --- a/src/FileUtils.cpp +++ b/src/FileUtils.cpp @@ -49,7 +49,6 @@ visit https://zxespectrum.speccy.org/contacto #include "Video.h" #include "esp_vfs.h" -#include "esp_spiffs.h" #include #include #include "esp_vfs_fat.h" @@ -57,26 +56,15 @@ visit https://zxespectrum.speccy.org/contacto using namespace std; -string FileUtils::MountPoint = MOUNT_POINT_SPIFFS; // Start with SPIFFS +string FileUtils::MountPoint = MOUNT_POINT_SD; // Start with SD bool FileUtils::SDReady = false; sdmmc_card_t *FileUtils::card; void FileUtils::initFileSystem() { - // Initialize SPIFFS file system - esp_vfs_spiffs_conf_t config = { - .base_path = MOUNT_POINT_SPIFFS, - .partition_label = NULL, - .max_files = 3, - .format_if_mount_failed = false, - }; - if (esp_vfs_spiffs_register(&config) != ESP_OK) { - return; - } - SDReady = mountSDCard(); - vTaskDelay(2); + vTaskDelay(20 / portTICK_PERIOD_MS); } diff --git a/src/FileZ80.cpp b/src/FileZ80.cpp index 14f2646d..4633429b 100644 --- a/src/FileZ80.cpp +++ b/src/FileZ80.cpp @@ -54,11 +54,6 @@ visit https://zxespectrum.speccy.org/contacto /////////////////////////////////////////////////////////////////////////////// -// using internal storage (spi flash) -#include "esp_spiffs.h" - -/////////////////////////////////////////////////////////////////////////////// - static uint16_t mkword(uint8_t lobyte, uint8_t hibyte) { return lobyte | (hibyte << 8); } @@ -389,6 +384,12 @@ bool FileZ80::load(string z80_fn) ESPectrum::AY_emu = Config::AY48; ESPectrum::Audio_freq = ESP_AUDIO_FREQ_48; + CPU::latetiming = Config::AluTiming; + + CPU::IntStart = INT_START48; + CPU::IntEnd = INT_END48 + CPU::latetiming; + + } else { Z80Ops::is48 = false; @@ -402,6 +403,11 @@ bool FileZ80::load(string z80_fn) ESPectrum::AY_emu = true; ESPectrum::Audio_freq = ESP_AUDIO_FREQ_128; + CPU::latetiming = Config::AluTiming; + + CPU::IntStart = INT_START128; + CPU::IntEnd = INT_END128 + CPU::latetiming; + } VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; diff --git a/src/OSDMain.cpp b/src/OSDMain.cpp index 98e62155..a9c6a2f9 100644 --- a/src/OSDMain.cpp +++ b/src/OSDMain.cpp @@ -194,7 +194,7 @@ static bool persistLoad(uint8_t slotnumber) } else { Config::ram_file = FileUtils::MountPoint + DISK_PSNA_DIR + "/" + persistfname; #ifdef SNAPSHOT_LOAD_LAST - Config::save(); + Config::save("ram"); #endif Config::last_ram_file = Config::ram_file; OSD::osdCenteredMsg(OSD_PSNA_LOADED, LEVEL_INFO); @@ -205,10 +205,10 @@ static bool persistLoad(uint8_t slotnumber) } -#ifdef ZXKEYB +// #ifdef ZXKEYB #define REPDEL 140 // As in real ZX Spectrum (700 ms.) static int zxDelay = 0; -#endif +// #endif // OSD Main Loop void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { @@ -258,7 +258,9 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { menu_curopt = 1; string mFile = menuFile(FileUtils::MountPoint + DISK_TAP_DIR, MENU_TAP_TITLE[Config::lang],".tap.TAP"); if (mFile != "") { - Tape::tapeFileName=FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile; + // Read and analyze tape file + Tape::Open(FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile); + // Tape::tapeFileName=FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile; } } else if (KeytoESP == fabgl::VK_F6) { @@ -361,7 +363,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { // ESP host reset #ifndef SNAPSHOT_LOAD_LAST Config::ram_file = NO_RAM_FILE; - Config::save(); + Config::save("ram"); #endif esp_hard_reset(); @@ -458,7 +460,9 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { // Select TAP File string mFile = menuFile(FileUtils::MountPoint + DISK_TAP_DIR, MENU_TAP_TITLE[Config::lang],".tap.TAP"); if (mFile != "") { - Tape::tapeFileName=FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile; + // Read and analyze tape file + Tape::Open(FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile); + // Tape::tapeFileName=FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile; return; } } @@ -503,7 +507,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { else if (opt2 == 2) { // Hard Config::ram_file = NO_RAM_FILE; - Config::save(); + Config::save("ram"); Config::last_ram_file = NO_RAM_FILE; ESPectrum::reset(); return; @@ -512,7 +516,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { // ESP host reset #ifndef SNAPSHOT_LOAD_LAST Config::ram_file = NO_RAM_FILE; - Config::save(); + Config::save("ram"); #endif esp_hard_reset(); } else { @@ -538,19 +542,19 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { menu_level = 2; // Storage source string stor_menu = MENU_STORAGE[Config::lang]; - int curopt; - if (FileUtils::MountPoint == MOUNT_POINT_SPIFFS) { - stor_menu.replace(stor_menu.find("[I",0),2,"[*"); - stor_menu.replace(stor_menu.find("[S",0),2,"[ "); - curopt = 1; - } else { - stor_menu.replace(stor_menu.find("[I",0),2,"[ "); - stor_menu.replace(stor_menu.find("[S",0),2,"[*"); - curopt = 2; - } + // int curopt; + // if (FileUtils::MountPoint == MOUNT_POINT_SPIFFS) { + // stor_menu.replace(stor_menu.find("[I",0),2,"[*"); + // stor_menu.replace(stor_menu.find("[S",0),2,"[ "); + // curopt = 1; + // } else { + // stor_menu.replace(stor_menu.find("[I",0),2,"[ "); + // stor_menu.replace(stor_menu.find("[S",0),2,"[*"); + // curopt = 2; + // } uint8_t opt2 = menuRun(stor_menu); if (opt2) { - if (opt2 == 3) { + // if (opt2 == 3) { OSD::osdCenteredMsg("Refreshing snap dir", LEVEL_INFO); int chunks = FileUtils::DirToFile(FileUtils::MountPoint + DISK_SNA_DIR, ".sna.SNA.z80.Z80"); // Prepare sna filelist if (chunks) FileUtils::Mergefiles(FileUtils::MountPoint + DISK_SNA_DIR,chunks); // Merge files @@ -558,15 +562,15 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { chunks = FileUtils::DirToFile(FileUtils::MountPoint + DISK_TAP_DIR, ".tap.TAP"); // Prepare tap filelist if (chunks) FileUtils::Mergefiles(FileUtils::MountPoint + DISK_TAP_DIR,chunks); // Merge files return; - } else if (opt2 != curopt) { - if (opt2 == 1) - FileUtils::MountPoint = MOUNT_POINT_SPIFFS; - else - FileUtils::MountPoint = MOUNT_POINT_SD; - Config::save(); - } - menu_curopt = opt2; - menu_saverect = false; + // } else if (opt2 != curopt) { + // if (opt2 == 1) + // FileUtils::MountPoint = MOUNT_POINT_SPIFFS; + // else + // FileUtils::MountPoint = MOUNT_POINT_SD; + // Config::save(); + // } + // menu_curopt = opt2; + // menu_saverect = false; } else { menu_curopt = 1; break; @@ -653,7 +657,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { if (opt2) { if (Config::joystick != (opt2 - 1)) { Config::joystick = opt2 - 1; - Config::save(); + Config::save("joystick"); } menu_curopt = opt2; menu_saverect = false; @@ -685,7 +689,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { if (opt2) { if (Config::lang != (opt2 - 1)) { Config::lang = opt2 - 1; - Config::save(); + Config::save("language"); return; } menu_curopt = opt2; @@ -726,7 +730,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { Config::AY48 = false; if (Config::AY48 != prev_ay48) { - Config::save(); + Config::save("AY48"); } menu_curopt = opt2; menu_saverect = false; @@ -737,6 +741,40 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { } } } + else if (options_num == 2) { + menu_level = 3; + menu_curopt = 1; + menu_saverect = true; + while (1) { + string alu_menu = MENU_ALUTIMING[Config::lang]; + uint8_t prev_AluTiming = Config::AluTiming; + if (prev_AluTiming == 0) { + alu_menu.replace(alu_menu.find("[E",0),2,"[*"); + alu_menu.replace(alu_menu.find("[L",0),2,"[ "); + } else { + alu_menu.replace(alu_menu.find("[E",0),2,"[ "); + alu_menu.replace(alu_menu.find("[L",0),2,"[*"); + } + uint8_t opt2 = menuRun(alu_menu); + if (opt2) { + if (opt2 == 1) + Config::AluTiming = 0; + else + Config::AluTiming = 1; + + if (Config::AluTiming != prev_AluTiming) { + CPU::latetiming = Config::AluTiming; + Config::save("AluTiming"); + } + menu_curopt = opt2; + menu_saverect = false; + } else { + menu_curopt = 2; + menu_level = 2; + break; + } + } + } } else { menu_curopt = 6; break; @@ -755,39 +793,43 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { VIDEO::vga.setTextColor(OSD::zxColor(7, 0), OSD::zxColor(1, 0)); VIDEO::vga.print(OSD_HELP[Config::lang]); - #ifdef ZXKEYB + // #ifdef ZXKEYB zxDelay = REPDEL; - #endif + // #endif while (1) { - #ifdef ZXKEYB - - ZXKeyb::process(); + // #ifdef ZXKEYB - if ((!bitRead(ZXKeyb::ZXcols[6], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 0))) { // ENTER - if (zxDelay == 0) { - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, false, false); - zxDelay = REPDEL; - } - } else - if ((!bitRead(ZXKeyb::ZXcols[7], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 1))) { // BREAK - if (zxDelay == 0) { - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, false, false); - zxDelay = REPDEL; - } - } else - if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q (Capture screen) - if (zxDelay == 0) { - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, false, false); - zxDelay = REPDEL; + if (ZXKeyb::Exists) { + + ZXKeyb::process(); + + if ((!bitRead(ZXKeyb::ZXcols[6], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 0))) { // ENTER + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, false, false); + zxDelay = REPDEL; + } + } else + if ((!bitRead(ZXKeyb::ZXcols[7], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 1))) { // BREAK + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, false, false); + zxDelay = REPDEL; + } + } else + if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q (Capture screen) + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, false, false); + zxDelay = REPDEL; + } } + } - #endif + // #endif if (ESPectrum::PS2Controller.keyboard()->virtualKeyAvailable()) { if (ESPectrum::readKbd(&Nextkey)) { @@ -798,9 +840,9 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { vTaskDelay(5 / portTICK_PERIOD_MS); - #ifdef ZXKEYB + // #ifdef ZXKEYB if (zxDelay > 0) zxDelay--; - #endif + // #endif } @@ -816,39 +858,43 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { VIDEO::vga.setTextColor(OSD::zxColor(7, 0), OSD::zxColor(1, 0)); VIDEO::vga.print(OSD_ABOUT[Config::lang]); - #ifdef ZXKEYB + // #ifdef ZXKEYB zxDelay = REPDEL; - #endif + // #endif while (1) { - #ifdef ZXKEYB - - ZXKeyb::process(); + // #ifdef ZXKEYB - if ((!bitRead(ZXKeyb::ZXcols[6], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 0))) { // ENTER - if (zxDelay == 0) { - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, false, false); - zxDelay = REPDEL; - } - } else - if ((!bitRead(ZXKeyb::ZXcols[7], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 1))) { // BREAK - if (zxDelay == 0) { - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, false, false); - zxDelay = REPDEL; - } - } else - if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q (Capture screen) - if (zxDelay == 0) { - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, false, false); - zxDelay = REPDEL; + if (ZXKeyb::Exists) { + + ZXKeyb::process(); + + if ((!bitRead(ZXKeyb::ZXcols[6], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 0))) { // ENTER + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, false, false); + zxDelay = REPDEL; + } + } else + if ((!bitRead(ZXKeyb::ZXcols[7], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 1))) { // BREAK + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, false, false); + zxDelay = REPDEL; + } + } else + if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q (Capture screen) + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, false, false); + zxDelay = REPDEL; + } } + } - #endif + // #endif if (ESPectrum::PS2Controller.keyboard()->virtualKeyAvailable()) { if (ESPectrum::readKbd(&Nextkey)) { @@ -859,9 +905,9 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { vTaskDelay(5 / portTICK_PERIOD_MS); - #ifdef ZXKEYB + // #ifdef ZXKEYB if (zxDelay > 0) zxDelay--; - #endif + // #endif } @@ -1025,7 +1071,7 @@ void OSD::changeSnapshot(string filename) Config::ram_file = filename; #ifdef SNAPSHOT_LOAD_LAST - Config::save(); + Config::save("ram"); #endif Config::last_ram_file = filename; diff --git a/src/OSDMenu.cpp b/src/OSDMenu.cpp index 7d671527..24fbe833 100644 --- a/src/OSDMenu.cpp +++ b/src/OSDMenu.cpp @@ -299,12 +299,12 @@ string OSD::getRomsetMenu(string arch) { return menu; } -#ifdef ZXKEYB +// #ifdef ZXKEYB #define REPDEL 140 // As in real ZX Spectrum (700 ms.) #define REPPER 20 // As in real ZX Spectrum (100 ms.) static int zxDelay = 0; static int lastzxKey = 0; -#endif +// #endif // Run a new menu unsigned short OSD::menuRun(string new_menu) { @@ -313,100 +313,104 @@ unsigned short OSD::menuRun(string new_menu) { newMenu(new_menu); - #ifdef ZXKEYB + // #ifdef ZXKEYB zxDelay = REPDEL; lastzxKey = 0; - #endif + // #endif while (1) { - #ifdef ZXKEYB - - ZXKeyb::process(); - - if (!bitRead(ZXKeyb::ZXcols[4], 3)) { // 6 DOWN - if (zxDelay == 0) { - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_UP, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_UP, false, false); - if (lastzxKey == 1) - zxDelay = REPPER; - else - zxDelay = REPDEL; - lastzxKey = 1; - } - } else - if (!bitRead(ZXKeyb::ZXcols[4], 4)) { // 7 UP (Yes, like the drink's name, I know... :D) - if (zxDelay == 0) { - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_DOWN, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_DOWN, false, false); - if (lastzxKey == 2) - zxDelay = REPPER; - else - zxDelay = REPDEL; - lastzxKey = 2; - } - } else - if ((!bitRead(ZXKeyb::ZXcols[6], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 0))) { // ENTER - if (zxDelay == 0) { - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, false, false); - if (lastzxKey == 3) - zxDelay = REPPER; - else - zxDelay = REPDEL; - lastzxKey = 3; - } - } else - if ((!bitRead(ZXKeyb::ZXcols[7], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 1))) { // BREAK - if (zxDelay == 0) { - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, false, false); - if (lastzxKey == 4) - zxDelay = REPPER; - else - zxDelay = REPDEL; - lastzxKey = 4; - } - } else - if (!bitRead(ZXKeyb::ZXcols[3], 4)) { // LEFT - if (zxDelay == 0) { - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEUP, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEUP, false, false); - if (lastzxKey == 5) - zxDelay = REPPER; - else - zxDelay = REPDEL; - lastzxKey = 5; - } - } else - if (!bitRead(ZXKeyb::ZXcols[4], 2)) { // RIGHT - if (zxDelay == 0) { - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEDOWN, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEDOWN, false, false); - if (lastzxKey == 6) - zxDelay = REPPER; - else - zxDelay = REPDEL; - lastzxKey = 6; - } - } else - if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q (Capture screen) - if (zxDelay == 0) { - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, false, false); - if (lastzxKey == 7) - zxDelay = REPPER; - else - zxDelay = REPDEL; - lastzxKey = 7; + // #ifdef ZXKEYB + + if (ZXKeyb::Exists) { + + ZXKeyb::process(); + + if (!bitRead(ZXKeyb::ZXcols[4], 3)) { // 6 DOWN + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_UP, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_UP, false, false); + if (lastzxKey == 1) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 1; + } + } else + if (!bitRead(ZXKeyb::ZXcols[4], 4)) { // 7 UP (Yes, like the drink's name, I know... :D) + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_DOWN, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_DOWN, false, false); + if (lastzxKey == 2) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 2; + } + } else + if ((!bitRead(ZXKeyb::ZXcols[6], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 0))) { // ENTER + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, false, false); + if (lastzxKey == 3) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 3; + } + } else + if ((!bitRead(ZXKeyb::ZXcols[7], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 1))) { // BREAK + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, false, false); + if (lastzxKey == 4) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 4; + } + } else + if (!bitRead(ZXKeyb::ZXcols[3], 4)) { // LEFT + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEUP, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEUP, false, false); + if (lastzxKey == 5) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 5; + } + } else + if (!bitRead(ZXKeyb::ZXcols[4], 2)) { // RIGHT + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEDOWN, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEDOWN, false, false); + if (lastzxKey == 6) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 6; + } + } else + if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q (Capture screen) + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, false, false); + if (lastzxKey == 7) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 7; + } + } else + { + zxDelay = 0; + lastzxKey = 0; } - } else - { - zxDelay = 0; - lastzxKey = 0; + } - #endif + // #endif // Process external keyboard if (ESPectrum::PS2Controller.keyboard()->virtualKeyAvailable()) { @@ -509,9 +513,9 @@ unsigned short OSD::menuRun(string new_menu) { } vTaskDelay(5 / portTICK_PERIOD_MS); - #ifdef ZXKEYB + // #ifdef ZXKEYB if (zxDelay > 0) zxDelay--; - #endif + // #endif } @@ -666,100 +670,104 @@ string OSD::menuFile(string filedir, string title, string extensions) { menuDraw(); - #ifdef ZXKEYB + // #ifdef ZXKEYB zxDelay = REPDEL; lastzxKey = 0; - #endif + // #endif while (1) { - #ifdef ZXKEYB + // #ifdef ZXKEYB - ZXKeyb::process(); + if (ZXKeyb::Exists) { - if (!bitRead(ZXKeyb::ZXcols[4], 3)) { // 6 DOWN - if (zxDelay == 0) { - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_UP, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_UP, false, false); - if (lastzxKey == 1) - zxDelay = REPPER; - else - zxDelay = REPDEL; - lastzxKey = 1; - } - } else - if (!bitRead(ZXKeyb::ZXcols[4], 4)) { // 7 UP (Yes, like the drink's name, I know... :D) - if (zxDelay == 0) { - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_DOWN, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_DOWN, false, false); - if (lastzxKey == 2) - zxDelay = REPPER; - else - zxDelay = REPDEL; - lastzxKey = 2; - } - } else - if ((!bitRead(ZXKeyb::ZXcols[6], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 0))) { // ENTER - if (zxDelay == 0) { - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, false, false); - if (lastzxKey == 3) - zxDelay = REPPER; - else - zxDelay = REPDEL; - lastzxKey = 3; - } - } else - if ((!bitRead(ZXKeyb::ZXcols[7], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 1))) { // BREAK - if (zxDelay == 0) { - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, false, false); - if (lastzxKey == 4) - zxDelay = REPPER; - else - zxDelay = REPDEL; - lastzxKey = 4; - } - } else - if (!bitRead(ZXKeyb::ZXcols[3], 4)) { // LEFT - if (zxDelay == 0) { - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEUP, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEUP, false, false); - if (lastzxKey == 5) - zxDelay = REPPER; - else - zxDelay = REPDEL; - lastzxKey = 5; - } - } else - if (!bitRead(ZXKeyb::ZXcols[4], 2)) { // RIGHT - if (zxDelay == 0) { - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEDOWN, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEDOWN, false, false); - if (lastzxKey == 6) - zxDelay = REPPER; - else - zxDelay = REPDEL; - lastzxKey = 6; - } - } else - if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q (Capture screen) - if (zxDelay == 0) { - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, false, false); - if (lastzxKey == 7) - zxDelay = REPPER; - else - zxDelay = REPDEL; - lastzxKey = 7; + ZXKeyb::process(); + + if (!bitRead(ZXKeyb::ZXcols[4], 3)) { // 6 DOWN + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_UP, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_UP, false, false); + if (lastzxKey == 1) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 1; + } + } else + if (!bitRead(ZXKeyb::ZXcols[4], 4)) { // 7 UP (Yes, like the drink's name, I know... :D) + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_DOWN, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_DOWN, false, false); + if (lastzxKey == 2) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 2; + } + } else + if ((!bitRead(ZXKeyb::ZXcols[6], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 0))) { // ENTER + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, false, false); + if (lastzxKey == 3) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 3; + } + } else + if ((!bitRead(ZXKeyb::ZXcols[7], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 1))) { // BREAK + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, false, false); + if (lastzxKey == 4) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 4; + } + } else + if (!bitRead(ZXKeyb::ZXcols[3], 4)) { // LEFT + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEUP, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEUP, false, false); + if (lastzxKey == 5) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 5; + } + } else + if (!bitRead(ZXKeyb::ZXcols[4], 2)) { // RIGHT + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEDOWN, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEDOWN, false, false); + if (lastzxKey == 6) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 6; + } + } else + if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q (Capture screen) + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, false, false); + if (lastzxKey == 7) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 7; + } + } else + { + zxDelay = 0; + lastzxKey = 0; } - } else - { - zxDelay = 0; - lastzxKey = 0; + } - #endif + // #endif // Process external keyboard if (ESPectrum::PS2Controller.keyboard()->virtualKeyAvailable()) { @@ -873,9 +881,9 @@ string OSD::menuFile(string filedir, string title, string extensions) { vTaskDelay(5 / portTICK_PERIOD_MS); - #ifdef ZXKEYB + // #ifdef ZXKEYB if (zxDelay > 0) zxDelay--; - #endif + // #endif } diff --git a/src/Ports.cpp b/src/Ports.cpp index bd4fe661..25d0cd98 100644 --- a/src/Ports.cpp +++ b/src/Ports.cpp @@ -120,8 +120,10 @@ uint8_t IRAM_ATTR Ports::input(uint16_t address) MemESP::bankLatch = data & 0x7; MemESP::ramCurrent[3] = (unsigned char *)MemESP::ram[MemESP::bankLatch]; MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; - MemESP::videoLatch = bitRead(data, 3); - VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; + if (MemESP::videoLatch != bitRead(data, 3)) { + MemESP::videoLatch = bitRead(data, 3); + VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; + } MemESP::romLatch = bitRead(data, 4); bitWrite(MemESP::romInUse, 0, MemESP::romLatch); MemESP::ramCurrent[0] = (unsigned char *)MemESP::rom[MemESP::romInUse]; @@ -185,22 +187,80 @@ void IRAM_ATTR Ports::output(uint16_t address, uint8_t data) { // 128 ======================================================================= if ((!Z80Ops::is48) && ((address & 0x8002) == 0)) { - if (MemESP::pagingLock) return; + if (!MemESP::pagingLock) { - MemESP::pagingLock = bitRead(data, 5); - - MemESP::bankLatch = data & 0x7; - MemESP::ramCurrent[3] = (unsigned char *)MemESP::ram[MemESP::bankLatch]; - MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; + MemESP::pagingLock = bitRead(data, 5); - MemESP::videoLatch = bitRead(data, 3); - - VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; - - MemESP::romLatch = bitRead(data, 4); - bitWrite(MemESP::romInUse, 0, MemESP::romLatch); - MemESP::ramCurrent[0] = (unsigned char *)MemESP::rom[MemESP::romInUse]; + MemESP::bankLatch = data & 0x7; + MemESP::ramCurrent[3] = (unsigned char *)MemESP::ram[MemESP::bankLatch]; + MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; + + if (MemESP::videoLatch != bitRead(data, 3)) { + MemESP::videoLatch = bitRead(data, 3); + VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; + } + + MemESP::romLatch = bitRead(data, 4); + bitWrite(MemESP::romInUse, 0, MemESP::romLatch); + MemESP::ramCurrent[0] = (unsigned char *)MemESP::rom[MemESP::romInUse]; + + } } - + } + +// void Ports::ContendedIODelay(uint16_t portNumber) +// { + +// uint8_t lowByte = portNumber & 0xff; + +// if (bitRead(lowByte, 0)) { +// if (Z80Ops::is48) { +// if (portNumber >= 0x4000 && portNumber <= 0x7FFF) { +// // Template D +// VIDEO::Draw(1,true); +// VIDEO::Draw(1,true); +// VIDEO::Draw(1,true); +// VIDEO::Draw(1,true); +// } else { +// // Template B +// VIDEO::Draw(4,false); +// } +// } else { +// if ((portNumber >= 0x4000 && portNumber <= 0x7FFF) || ((portNumber >= 0xC000 && portNumber <= 0xFFFF) && (MemESP::ramContended[3]))) { +// // Template D +// VIDEO::Draw(1,true); +// VIDEO::Draw(1,true); +// VIDEO::Draw(1,true); +// VIDEO::Draw(1,true); +// } else { +// // Template B +// VIDEO::Draw(4,false); +// } +// } +// } else { +// if (Z80Ops::is48) { +// if (portNumber >= 0x4000 && portNumber <= 0x7FFF) { +// // Template C +// VIDEO::Draw(1,true); +// VIDEO::Draw(3,true); +// } else { +// // Template A +// VIDEO::Draw(1,false); +// VIDEO::Draw(3,true); +// } +// } else { +// if ((portNumber >= 0x4000 && portNumber <= 0x7FFF) || ((portNumber >= 0xC000 && portNumber <= 0xFFFF) && (MemESP::ramContended[3]))) { +// // Template C +// VIDEO::Draw(1,true); +// VIDEO::Draw(3,true); +// } else { +// // Template A +// VIDEO::Draw(1,false); +// VIDEO::Draw(3,true); +// } + +// } +// } +// } diff --git a/src/Tape.cpp b/src/Tape.cpp index 577ef553..16cb20c7 100644 --- a/src/Tape.cpp +++ b/src/Tape.cpp @@ -73,6 +73,24 @@ void Tape::Init() tape = NULL; } +void Tape::Open(string name) +{ + Tape::tapeFileName = name; + + tape = fopen(Tape::tapeFileName.c_str(), "rb"); + if (tape == NULL) + { + OSD::osdCenteredMsg(OSD_TAPE_LOAD_ERR, LEVEL_ERROR); + return; + } + + // Analyze .tap file + + + fclose(tape); + +} + void Tape::TAP_Play() { @@ -121,7 +139,7 @@ void Tape::TAP_Stop() fclose(tape); } -void Tape::TAP_Read() +void IRAM_ATTR Tape::TAP_Read() { uint64_t tapeCurrent = (CPU::global_tstates + CPU::tstates) - tapeStart; diff --git a/src/Z80_JLS.cpp b/src/Z80_JLS.cpp index 40d1e34f..835ca855 100644 --- a/src/Z80_JLS.cpp +++ b/src/Z80_JLS.cpp @@ -752,7 +752,7 @@ void IRAM_ATTR Z80::ini(void) { } carryFlag = false; - uint16_t tmp = work8 + REG_C + 1; + uint16_t tmp = work8 + ((REG_C + 1) & 255); if (tmp > 0xff) { sz5h3pnFlags |= HALFCARRY_MASK; carryFlag = true; @@ -783,7 +783,7 @@ void IRAM_ATTR Z80::ind(void) { } carryFlag = false; - uint16_t tmp = work8 + (REG_C - 1); + uint16_t tmp = work8 + ((REG_C - 1) & 255); if (tmp > 0xff) { sz5h3pnFlags |= HALFCARRY_MASK; carryFlag = true; @@ -912,13 +912,13 @@ void Z80::bitTest(uint8_t mask, uint8_t reg) { */ void Z80::interrupt(void) { - lastFlagQ = false; + // lastFlagQ = false; // Si estaba en un HALT esperando una INT, lo saca de la espera - if (halted) { + // if (halted) { halted = false; - REG_PC++; - } + // REG_PC++; + // } // Z80Ops::interruptHandlingTime(7); VIDEO::Draw(7, false); @@ -942,36 +942,41 @@ void Z80::interrupt(void) { * M3: 3 T-Estados -> escribe byte bajo de PC y PC=0x0066 */ void Z80::nmi(void) { + + // lastFlagQ = false; + + halted = false; + // Esta lectura consigue dos cosas: // 1.- La lectura del opcode del M1 que se descarta // 2.- Si estaba en un HALT esperando una INT, lo saca de la espera - // Z80Ops::fetchOpcode(REG_PC); - FETCH_OPCODE(uint8_t discardOpCode, REG_PC); - // Z80Ops::interruptHandlingTime(1); + FETCH_OPCODE(uint8_t discardOpCode, REG_PC); VIDEO::Draw(1, false); - if (halted) { - halted = false; - REG_PC++; - } + // if (halted) { + // halted = false; + // REG_PC++; + // } + regR++; ffIFF1 = false; push(REG_PC); // 3+3 t-estados + contended si procede REG_PC = REG_WZ = 0x0066; } -void Z80::checkINT(void) { +void IRAM_ATTR Z80::checkINT(void) { // Comprueba si está activada la señal INT if (ffIFF1 && !pendingEI && Z80Ops::isActiveINT()) { + lastFlagQ = false; interrupt(); } } -void Z80::incRegR(uint8_t inc) { +void IRAM_ATTR Z80::incRegR(uint8_t inc) { regR += inc; @@ -989,41 +994,45 @@ void IRAM_ATTR Z80::execute() { } #endif - REG_PC++; + if (!halted) { - // El prefijo 0xCB no cuenta para esta guerra. - // En CBxx todas las xx producen un código válido - // de instrucción, incluyendo CBCB. - switch (prefixOpcode) { - case 0x00: - flagQ = pendingEI = false; - dcOpcode[opCode](); - break; - case 0xDD: - prefixOpcode = 0; - decodeDDFD(regIX); - break; - case 0xED: - prefixOpcode = 0; - decodeED(); - break; - case 0xFD: - prefixOpcode = 0; - decodeDDFD(regIY); - break; - default: - return; - } - - if (prefixOpcode != 0) return; + REG_PC++; - lastFlagQ = flagQ; + // El prefijo 0xCB no cuenta para esta guerra. + // En CBxx todas las xx producen un código válido + // de instrucción, incluyendo CBCB. + switch (prefixOpcode) { + case 0x00: + flagQ = pendingEI = false; + dcOpcode[opCode](); + break; + case 0xDD: + prefixOpcode = 0; + decodeDDFD(regIX); + break; + case 0xED: + prefixOpcode = 0; + decodeED(); + break; + case 0xFD: + prefixOpcode = 0; + decodeDDFD(regIY); + break; + default: + return; + } + + if (prefixOpcode != 0) return; + + lastFlagQ = flagQ; + + #ifdef WITH_EXEC_DONE + if (execDone) { + Z80Ops::execDone(); + } + #endif - #ifdef WITH_EXEC_DONE - if (execDone) { - Z80Ops::execDone(); } - #endif // Primero se comprueba NMI // Si se activa NMI no se comprueba INT porque la siguiente @@ -1036,9 +1045,12 @@ void IRAM_ATTR Z80::execute() { // } // Ahora se comprueba si está activada la señal INT - if (ffIFF1 && !pendingEI && Z80Ops::isActiveINT()) { - interrupt(); - } + checkINT(); + + // if (ffIFF1 && !pendingEI && Z80Ops::isActiveINT()) { + // lastFlagQ = false; + // interrupt(); + // } } @@ -1803,12 +1815,14 @@ void Z80::decodeOpcode75() void Z80::decodeOpcode76() { /* HALT */ - REG_PC--; + + // REG_PC--; // Signal HALT to CPU Loop - CPU::tstates |= 0xFF000000; + if (!CPU::latetiming) CPU::tstates |= 0xFF000000; halted = true; + } void Z80::decodeOpcode77() @@ -5771,6 +5785,8 @@ void Z80::decodeED(void) { REG_PC = REG_PC - 2; REG_WZ = REG_PC + 1; Z80Ops::addressOnBus(REG_DE - 1, 5); + sz5h3pnFlags &= ~FLAG_53_MASK; + sz5h3pnFlags |= (REG_PCh & FLAG_53_MASK); } break; } @@ -5782,6 +5798,8 @@ void Z80::decodeED(void) { REG_PC = REG_PC - 2; REG_WZ = REG_PC + 1; Z80Ops::addressOnBus(REG_HL - 1, 5); + sz5h3pnFlags &= ~FLAG_53_MASK; + sz5h3pnFlags |= (REG_PCh & FLAG_53_MASK); } break; } @@ -5791,6 +5809,7 @@ void Z80::decodeED(void) { if (REG_B != 0) { REG_PC = REG_PC - 2; Z80Ops::addressOnBus(REG_HL - 1, 5); + SetAbortedINxR_OTxRFlags(); } break; } @@ -5800,6 +5819,7 @@ void Z80::decodeED(void) { if (REG_B != 0) { REG_PC = REG_PC - 2; Z80Ops::addressOnBus(REG_BC, 5); + SetAbortedINxR_OTxRFlags(); } break; } @@ -5810,6 +5830,8 @@ void Z80::decodeED(void) { REG_PC = REG_PC - 2; REG_WZ = REG_PC + 1; Z80Ops::addressOnBus(REG_DE + 1, 5); + sz5h3pnFlags &= ~FLAG_53_MASK; + sz5h3pnFlags |= (REG_PCh & FLAG_53_MASK); } break; } @@ -5821,6 +5843,8 @@ void Z80::decodeED(void) { REG_PC = REG_PC - 2; REG_WZ = REG_PC + 1; Z80Ops::addressOnBus(REG_HL + 1, 5); + sz5h3pnFlags &= ~FLAG_53_MASK; + sz5h3pnFlags |= (REG_PCh & FLAG_53_MASK); } break; } @@ -5830,6 +5854,7 @@ void Z80::decodeED(void) { if (REG_B != 0) { REG_PC = REG_PC - 2; Z80Ops::addressOnBus(REG_HL + 1, 5); + SetAbortedINxR_OTxRFlags(); } break; } @@ -5839,6 +5864,7 @@ void Z80::decodeED(void) { if (REG_B != 0) { REG_PC = REG_PC - 2; Z80Ops::addressOnBus(REG_BC, 5); + SetAbortedINxR_OTxRFlags(); } break; } @@ -5884,3 +5910,38 @@ void Z80::copyToRegister(uint8_t value) break; } } + +void Z80::SetAbortedINxR_OTxRFlags() { + + sz5h3pnFlags &= ~FLAG_53_MASK; + sz5h3pnFlags |= (REG_PCh & FLAG_53_MASK); + + // // 1st implementation + // uint8_t pf = sz5h3pnFlags & PARITY_MASK; + // if (carryFlag) { + // int addsub = 1 - (sz5h3pnFlags & ADDSUB_MASK); + // pf = pf ^ sz53pn_addTable[(REG_B + addsub) & 0x07] ^ PARITY_MASK; + // if ((REG_B & 0x0F) == (addsub != 1 ? 0x00 : 0x0F )) sz5h3pnFlags |= HALFCARRY_MASK; else sz5h3pnFlags &= ~HALFCARRY_MASK; + // } else { + // pf = pf ^ sz53pn_addTable[REG_B & 0x07] ^ PARITY_MASK; + // } + // if (pf & PARITY_MASK) sz5h3pnFlags |= PARITY_MASK; else sz5h3pnFlags &= ~PARITY_MASK; + + // // 2nd implementation + // uint8_t pf = sz5h3pnFlags & PARITY_MASK; + // int addsub = carryFlag ? 1 - (sz5h3pnFlags & ADDSUB_MASK): 0; + // if (addsub) + // if ((REG_B & 0x0F) == (addsub > 0 ? 0xF : 0x0 )) sz5h3pnFlags |= HALFCARRY_MASK; else sz5h3pnFlags &= ~HALFCARRY_MASK; + // pf ^= sz53pn_addTable[(REG_B + addsub) & 0x07] ^ PARITY_MASK; + // if (pf & PARITY_MASK) sz5h3pnFlags |= PARITY_MASK; else sz5h3pnFlags &= ~PARITY_MASK; + + // 3rd implementation + uint8_t cpyB = REG_B; + if (carryFlag) { + cpyB += sz5h3pnFlags & ADDSUB_MASK ? -1 : 1; + sz5h3pnFlags = (cpyB ^ REG_B) & HALFCARRY_MASK ? sz5h3pnFlags | HALFCARRY_MASK : sz5h3pnFlags & ~HALFCARRY_MASK; + } + uint8_t pf = (sz5h3pnFlags & PARITY_MASK) ^ sz53pn_addTable[cpyB & 0x07] ^ PARITY_MASK; + sz5h3pnFlags = pf & PARITY_MASK ? sz5h3pnFlags | PARITY_MASK : sz5h3pnFlags & ~PARITY_MASK; + +} diff --git a/src/ZXKeyb.cpp b/src/ZXKeyb.cpp index a9498c21..3bfdcb21 100644 --- a/src/ZXKeyb.cpp +++ b/src/ZXKeyb.cpp @@ -38,6 +38,7 @@ visit https://zxespectrum.speccy.org/contacto #include "Ports.h" uint8_t ZXKeyb::ZXcols[8]; +bool ZXKeyb::Exists; void ZXKeyb::setup() { @@ -53,8 +54,13 @@ void ZXKeyb::setup() gpio_set_direction((gpio_num_t)KM_COL_3, (gpio_mode_t)GPIO_MODE_INPUT); gpio_set_direction((gpio_num_t)KM_COL_4, (gpio_mode_t)GPIO_MODE_INPUT); + // Check if membrane keyboard is present + ZXKeyb::putRows(0xFF); + ZXKeyb::Exists = gpio_get_level((gpio_num_t)KM_COL_1) && gpio_get_level((gpio_num_t)KM_COL_2) && gpio_get_level((gpio_num_t)KM_COL_4); + // set all keys as not pressed - for (uint8_t i = 0; i < 8; i++) ZXcols[i] = 0x1f; + if (ZXKeyb::Exists) for (uint8_t i = 0; i < 8; i++) ZXcols[i] = 0x1f; + } // row order depends on actual row association with address lines, see From 0f8544a394c333949b7573e3355df5c7ae95d8c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Wed, 5 Jul 2023 11:14:44 +0200 Subject: [PATCH 02/29] ptime and ptime-128 tests fixes --- src/Ports.cpp | 28 ++++++++++++++++++++++------ src/Video.cpp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/Ports.cpp b/src/Ports.cpp index 25d0cd98..d3d7646e 100644 --- a/src/Ports.cpp +++ b/src/Ports.cpp @@ -41,6 +41,7 @@ visit https://zxespectrum.speccy.org/contacto #include "Video.h" #include "AySound.h" #include "Tape.h" +#include "CPU.h" #pragma GCC optimize ("O3") @@ -122,6 +123,11 @@ uint8_t IRAM_ATTR Ports::input(uint16_t address) MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; if (MemESP::videoLatch != bitRead(data, 3)) { MemESP::videoLatch = bitRead(data, 3); + // This, or using the two states at a time video paper draw version, fixs ptime and ptime128 + if (((address & 0x0001) != 0) && (MemESP::ramContended[address >> 14])) { + VIDEO::Draw(2, false); + CPU::tstates -= 2; + } VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; } MemESP::romLatch = bitRead(data, 4); @@ -175,15 +181,20 @@ void IRAM_ATTR Ports::output(uint16_t address, uint8_t data) { // ** I/O Contention (Late) ************************** if ((address & 0x0001) == 0) { VIDEO::Draw(3, true); + // printf("Case 1\n"); } else { if (MemESP::ramContended[address >> 14]) { VIDEO::Draw(1, true); VIDEO::Draw(1, true); VIDEO::Draw(1, true); - } else VIDEO::Draw(3, false); + // printf("Case 2\n"); + } else { + // printf("Case 3\n"); + VIDEO::Draw(3, false); + } } // ** I/O Contention (Late) ************************** - + // 128 ======================================================================= if ((!Z80Ops::is48) && ((address & 0x8002) == 0)) { @@ -195,15 +206,20 @@ void IRAM_ATTR Ports::output(uint16_t address, uint8_t data) { MemESP::ramCurrent[3] = (unsigned char *)MemESP::ram[MemESP::bankLatch]; MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; + MemESP::romLatch = bitRead(data, 4); + bitWrite(MemESP::romInUse, 0, MemESP::romLatch); + MemESP::ramCurrent[0] = (unsigned char *)MemESP::rom[MemESP::romInUse]; + if (MemESP::videoLatch != bitRead(data, 3)) { MemESP::videoLatch = bitRead(data, 3); + // This, or using the two states at a time video paper draw version, fixs ptime and ptime128 + if (((address & 0x0001) != 0) && (MemESP::ramContended[address >> 14])) { + VIDEO::Draw(2, false); + CPU::tstates -= 2; + } VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; } - MemESP::romLatch = bitRead(data, 4); - bitWrite(MemESP::romInUse, 0, MemESP::romLatch); - MemESP::ramCurrent[0] = (unsigned char *)MemESP::rom[MemESP::romInUse]; - } } diff --git a/src/Video.cpp b/src/Video.cpp index 28e6eaab..6b5015ef 100644 --- a/src/Video.cpp +++ b/src/Video.cpp @@ -496,6 +496,38 @@ void IRAM_ATTR VIDEO::MainScreen(unsigned int statestoadd, bool contended) { } + // // 2 T-states at a time version + + // static uint8_t att, bmp; + + // if (contended) + // statestoadd += Z80Ops::is48 ? wait_st[(CPU::tstates + 1) % 224] : wait_st[(CPU::tstates + 3) % 228]; + + // CPU::tstates += statestoadd; + + // statestoadd += video_rest; + // video_rest = statestoadd & 0x01; // Mod 2 + + // for (int i=0; i < (statestoadd >> 1); i++) { + + // if((coldraw_cnt & 0x01) == 0) { + // att = grmem[attOffset++]; // get attribute byte + // bmp = (att & flashing) ? ~grmem[bmpOffset++] : grmem[bmpOffset++]; + // *lineptr32++ = AluBytes[bmp >> 4][att]; + // } else { + // *lineptr32++ = AluBytes[bmp & 0xF][att]; + // } + + // if (++coldraw_cnt > 67) { + // coldraw_cnt = 36; + // Draw = MainScreenRB; + // video_rest += ((statestoadd >> 1) - (i + 1)) << 1; + // MainScreenRB(0,false); + // return; + // } + + // } + } void IRAM_ATTR VIDEO::MainScreen_OSD(unsigned int statestoadd, bool contended) { From e7d828e93851207680e921ace17453ca219ce90e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Wed, 5 Jul 2023 11:41:40 +0200 Subject: [PATCH 03/29] ptime and ptime128 fixes --- include/Video.h | 3 ++- src/Ports.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/Video.h b/include/Video.h index 25d61d78..5fbfc6af 100644 --- a/include/Video.h +++ b/include/Video.h @@ -71,10 +71,11 @@ visit https://zxespectrum.speccy.org/contacto #define TS_SCREEN_320x240 8944 // START OF VISIBLE ULA DRAW 48K @ 320x240, SCANLINE 40, -16 FROM BORDER #define TS_SCREEN_320x240_128 8874 // START OF VISIBLE ULA DRAW 128K @ 320x240, SCANLINE 39, -16 FROM BORDER + // ( ADDITIONAL -2 SEEMS NEEDED IF NOT USING 2 TSTATES AT A TIME PAPER DRAWING VERSION) #define TS_SCREEN_360x200 13424 // START OF VISIBLE ULA DRAW 48K @ 360x200, SCANLINE 60, -16 FROM BORDER #define TS_SCREEN_360x200_128 13434 // START OF VISIBLE ULA DRAW 128K @ 360x200, SCANLINE 59, -16 FROM BORDER - + // ( ADDITIONAL -2 SEEMS NEEDED IF NOT USING 2 TSTATES AT A TIME PAPER DRAWING VERSION) class VIDEO { public: diff --git a/src/Ports.cpp b/src/Ports.cpp index d3d7646e..ade4a5aa 100644 --- a/src/Ports.cpp +++ b/src/Ports.cpp @@ -123,7 +123,7 @@ uint8_t IRAM_ATTR Ports::input(uint16_t address) MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; if (MemESP::videoLatch != bitRead(data, 3)) { MemESP::videoLatch = bitRead(data, 3); - // This, or using the two states at a time video paper draw version, fixs ptime and ptime128 + // This, if not using the two states at a time video paper draw version, fixs ptime and ptime128 if (((address & 0x0001) != 0) && (MemESP::ramContended[address >> 14])) { VIDEO::Draw(2, false); CPU::tstates -= 2; @@ -212,7 +212,7 @@ void IRAM_ATTR Ports::output(uint16_t address, uint8_t data) { if (MemESP::videoLatch != bitRead(data, 3)) { MemESP::videoLatch = bitRead(data, 3); - // This, or using the two states at a time video paper draw version, fixs ptime and ptime128 + // This, if not using the two states at a time video paper draw version, fixs ptime and ptime128 if (((address & 0x0001) != 0) && (MemESP::ramContended[address >> 14])) { VIDEO::Draw(2, false); CPU::tstates -= 2; From 8903b28ae3a35873f5740f7a75172cd499fb2b91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Fri, 7 Jul 2023 02:12:00 +0200 Subject: [PATCH 04/29] Float bus & contention optimized, ptime128 working --- include/Video.h | 5 + src/FileSNA.cpp | 6 ++ src/FileZ80.cpp | 5 + src/Ports.cpp | 4 +- src/Video.cpp | 252 +++++++++++++++++++++++++++++++----------------- 5 files changed, 181 insertions(+), 91 deletions(-) diff --git a/include/Video.h b/include/Video.h index 5fbfc6af..b39b54e2 100644 --- a/include/Video.h +++ b/include/Video.h @@ -127,6 +127,11 @@ class VIDEO static uint8_t flashing; static uint8_t flash_ctr; + static uint8_t dispUpdCycle; + + static uint8_t contendOffset; + static uint8_t contendMod; + static bool OSD; static uint32_t* SaveRect; diff --git a/src/FileSNA.cpp b/src/FileSNA.cpp index 33f14637..ac2ea8d6 100644 --- a/src/FileSNA.cpp +++ b/src/FileSNA.cpp @@ -296,6 +296,9 @@ bool FileSNA::load(string sna_fn) CPU::IntStart = INT_START48; CPU::IntEnd = INT_END48 + CPU::latetiming; + VIDEO::contendMod=224; + VIDEO::contendOffset=1; + } else { Z80Ops::is48 = false; @@ -314,6 +317,9 @@ bool FileSNA::load(string sna_fn) CPU::IntStart = INT_START128; CPU::IntEnd = INT_END128 + CPU::latetiming; + VIDEO::contendMod=228; + VIDEO::contendOffset=3; + } VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; diff --git a/src/FileZ80.cpp b/src/FileZ80.cpp index 4633429b..5f25739a 100644 --- a/src/FileZ80.cpp +++ b/src/FileZ80.cpp @@ -389,6 +389,8 @@ bool FileZ80::load(string z80_fn) CPU::IntStart = INT_START48; CPU::IntEnd = INT_END48 + CPU::latetiming; + VIDEO::contendMod=224; + VIDEO::contendOffset=1; } else { @@ -408,6 +410,9 @@ bool FileZ80::load(string z80_fn) CPU::IntStart = INT_START128; CPU::IntEnd = INT_END128 + CPU::latetiming; + VIDEO::contendMod=228; + VIDEO::contendOffset=3; + } VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; diff --git a/src/Ports.cpp b/src/Ports.cpp index ade4a5aa..99030493 100644 --- a/src/Ports.cpp +++ b/src/Ports.cpp @@ -123,7 +123,7 @@ uint8_t IRAM_ATTR Ports::input(uint16_t address) MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; if (MemESP::videoLatch != bitRead(data, 3)) { MemESP::videoLatch = bitRead(data, 3); - // This, if not using the two states at a time video paper draw version, fixs ptime and ptime128 + // This, if not using the ptime128 draw version, fixs ptime and ptime128 if (((address & 0x0001) != 0) && (MemESP::ramContended[address >> 14])) { VIDEO::Draw(2, false); CPU::tstates -= 2; @@ -212,7 +212,7 @@ void IRAM_ATTR Ports::output(uint16_t address, uint8_t data) { if (MemESP::videoLatch != bitRead(data, 3)) { MemESP::videoLatch = bitRead(data, 3); - // This, if not using the two states at a time video paper draw version, fixs ptime and ptime128 + // This, if not using the ptime128 draw version, fixs ptime and ptime128 if (((address & 0x0001) != 0) && (MemESP::ramContended[address >> 14])) { VIDEO::Draw(2, false); CPU::tstates -= 2; diff --git a/src/Video.cpp b/src/Video.cpp index 6b5015ef..6ba25910 100644 --- a/src/Video.cpp +++ b/src/Video.cpp @@ -55,6 +55,9 @@ int VIDEO::tStatesScreen; uint8_t* VIDEO::grmem; uint32_t* VIDEO::SaveRect; int VIDEO::VsyncFinetune[2]; +uint8_t VIDEO::dispUpdCycle; +uint8_t VIDEO::contendOffset; +uint8_t VIDEO::contendMod; void IRAM_ATTR VGA6Bit::interrupt(void *arg) { @@ -252,6 +255,8 @@ void VIDEO::Init() { VsyncFinetune[0] = is169 ? 0 : 0; VsyncFinetune[1] = is169 ? 0 : 0; } + VIDEO::contendMod=224; + VIDEO::contendOffset=1; } else { tStatesPerLine = TSTATES_PER_LINE_128; tStatesScreen = is169 ? TS_SCREEN_360x200_128 : TS_SCREEN_320x240_128; @@ -262,6 +267,8 @@ void VIDEO::Init() { VsyncFinetune[0] = is169 ? 0 : 0; VsyncFinetune[1] = is169 ? 0 : 0; } + VIDEO::contendMod=228; + VIDEO::contendOffset=3; } #ifdef NO_VIDEO @@ -289,6 +296,8 @@ void VIDEO::Reset() { VsyncFinetune[0] = is169 ? 0 : 0; VsyncFinetune[1] = is169 ? 0 : 0; } + VIDEO::contendMod=224; + VIDEO::contendOffset=1; } else { tStatesPerLine = TSTATES_PER_LINE_128; tStatesScreen = is169 ? TS_SCREEN_360x200_128 : TS_SCREEN_320x240_128; @@ -299,6 +308,8 @@ void VIDEO::Reset() { VsyncFinetune[0] = is169 ? 0 : 0; VsyncFinetune[1] = is169 ? 0 : 0; } + VIDEO::contendMod=228; + VIDEO::contendOffset=3; } grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; @@ -311,79 +322,115 @@ void VIDEO::Reset() { } +// uint8_t IRAM_ATTR VIDEO::getFloatBusData48() { + +// unsigned int currentTstates = CPU::tstates; + +// unsigned short int line = currentTstates / 224; // int line +// if (line < 64 || line >= 256) return 0xFF; + +// unsigned char halfpix = currentTstates % 224; +// if (halfpix >= 128) return 0xFF; + +// switch (halfpix & 0x07) { +// case 3: { // Bitmap +// unsigned int bmpOffset = offBmp[line - 64]; +// int hpoffset = (halfpix - 3) >> 2; +// return(grmem[bmpOffset + hpoffset]); +// } +// case 4: { // Attr +// unsigned int attOffset = offAtt[line - 64]; +// int hpoffset = (halfpix - 3) >> 2; +// return(grmem[attOffset + hpoffset]); +// } +// case 5: { // Bitmap + 1 +// unsigned int bmpOffset = offBmp[line - 64]; +// int hpoffset = ((halfpix - 3) >> 2) + 1; +// return(grmem[bmpOffset + hpoffset]); +// } +// case 6: { // Attr + 1 +// unsigned int attOffset = offAtt[line - 64]; +// int hpoffset = ((halfpix - 3) >> 2) + 1; +// return(grmem[attOffset + hpoffset]); +// } +// } + +// return(0xFF); + +// } + +// uint8_t IRAM_ATTR VIDEO::getFloatBusData128() { + +// unsigned int currentTstates = CPU::tstates; + +// currentTstates--; + +// unsigned short int line = currentTstates / 228; // int line +// if (line < 63 || line >= 255) return 0xFF; + +// unsigned char halfpix = currentTstates % 228; +// if (halfpix >= 128) return 0xFF; + +// switch (halfpix & 0x07) { +// case 0: { // Bitmap +// unsigned int bmpOffset = offBmp[line - 63]; +// int hpoffset = (halfpix) >> 2; +// return(grmem[bmpOffset + hpoffset]); +// } +// case 1: { // Attr +// unsigned int attOffset = offAtt[line - 63]; +// int hpoffset = (halfpix) >> 2; +// return(grmem[attOffset + hpoffset]); +// } +// case 2: { // Bitmap + 1 +// unsigned int bmpOffset = offBmp[line - 63]; +// int hpoffset = ((halfpix) >> 2) + 1; +// return(grmem[bmpOffset + hpoffset]); +// } +// case 3: { // Attr + 1 +// unsigned int attOffset = offAtt[line - 63]; +// int hpoffset = ((halfpix) >> 2) + 1; +// return(grmem[attOffset + hpoffset]); +// } +// } + +// return(0xFF); + +// } + uint8_t IRAM_ATTR VIDEO::getFloatBusData48() { unsigned int currentTstates = CPU::tstates; - unsigned short int line = currentTstates / 224; // int line - if (line < 64 || line >= 256) return 0xFF; + unsigned int line = (currentTstates / 224) - 64; + if (line >= 192) return 0xFF; - unsigned char halfpix = currentTstates % 224; - if (halfpix >= 128) return 0xFF; + unsigned char halfpix = (currentTstates % 224) - 3; + if ((halfpix >= 125) || (halfpix & 0x04)) return 0xFF; - switch (halfpix & 0x07) { - case 3: { // Bitmap - unsigned int bmpOffset = offBmp[line - 64]; - int hpoffset = (halfpix - 3) >> 2; - return(grmem[bmpOffset + hpoffset]); - } - case 4: { // Attr - unsigned int attOffset = offAtt[line - 64]; - int hpoffset = (halfpix - 3) >> 2; - return(grmem[attOffset + hpoffset]); - } - case 5: { // Bitmap + 1 - unsigned int bmpOffset = offBmp[line - 64]; - int hpoffset = ((halfpix - 3) >> 2) + 1; - return(grmem[bmpOffset + hpoffset]); - } - case 6: { // Attr + 1 - unsigned int attOffset = offAtt[line - 64]; - int hpoffset = ((halfpix - 3) >> 2) + 1; - return(grmem[attOffset + hpoffset]); - } - } + int hpoffset = ((halfpix) >> 2) + ((halfpix >> 1) & 0x01);; + + if (halfpix & 0x01) return(grmem[offAtt[line] + hpoffset]); - return(0xFF); + return(grmem[offBmp[line] + hpoffset]); } uint8_t IRAM_ATTR VIDEO::getFloatBusData128() { - unsigned int currentTstates = CPU::tstates; - - currentTstates--; + unsigned int currentTstates = CPU::tstates - 1; - unsigned short int line = currentTstates / 228; // int line - if (line < 63 || line >= 255) return 0xFF; + unsigned int line = (currentTstates / 228) - 63; + if (line >= 192) return 0xFF; unsigned char halfpix = currentTstates % 228; - if (halfpix >= 128) return 0xFF; + if ((halfpix >= 128) || (halfpix & 0x04)) return 0xFF; - switch (halfpix & 0x07) { - case 0: { // Bitmap - unsigned int bmpOffset = offBmp[line - 63]; - int hpoffset = (halfpix) >> 2; - return(grmem[bmpOffset + hpoffset]); - } - case 1: { // Attr - unsigned int attOffset = offAtt[line - 63]; - int hpoffset = (halfpix) >> 2; - return(grmem[attOffset + hpoffset]); - } - case 2: { // Bitmap + 1 - unsigned int bmpOffset = offBmp[line - 63]; - int hpoffset = ((halfpix) >> 2) + 1; - return(grmem[bmpOffset + hpoffset]); - } - case 3: { // Attr + 1 - unsigned int attOffset = offAtt[line - 63]; - int hpoffset = ((halfpix) >> 2) + 1; - return(grmem[attOffset + hpoffset]); - } - } + int hpoffset = ((halfpix) >> 2) + ((halfpix >> 1) & 0x01);; + + if (halfpix & 0x01) return(grmem[offAtt[line] + hpoffset]); - return(0xFF); + return(grmem[offBmp[line] + hpoffset]); } @@ -446,8 +493,7 @@ void IRAM_ATTR VIDEO::MainScreen_Blank(unsigned int statestoadd, bool contended) void IRAM_ATTR VIDEO::MainScreenLB(unsigned int statestoadd, bool contended) { - if (contended) - statestoadd += Z80Ops::is48 ? wait_st[(CPU::tstates + 1) % 224] : wait_st[(CPU::tstates + 3) % 228]; + if (contended) statestoadd += wait_st[(CPU::tstates + contendOffset) % contendMod]; CPU::tstates += statestoadd; statestoadd += video_rest; @@ -459,20 +505,33 @@ void IRAM_ATTR VIDEO::MainScreenLB(unsigned int statestoadd, bool contended) { if (++coldraw_cnt > 3) { Draw = DrawOSD169; video_rest += ((statestoadd >> 2) - (i + 1)) << 2; + + // ------------------------------- + // Non ptime-128 compliant version Draw(0,false); + // ------------------------------- + + // // --------------------------- + // // ptime-128 compliant version + // dispUpdCycle = 6 + CPU::latetiming; + // Draw(0,false); + // video_rest = 0; + // // --------------------------- + return; } } } - +// ------------------------------- +// Non ptime-128 compliant version +// ------------------------------- void IRAM_ATTR VIDEO::MainScreen(unsigned int statestoadd, bool contended) { uint8_t att, bmp; - if (contended) - statestoadd += Z80Ops::is48 ? wait_st[(CPU::tstates + 1) % 224] : wait_st[(CPU::tstates + 3) % 228]; + if (contended) statestoadd += wait_st[(CPU::tstates + contendOffset) % contendMod]; CPU::tstates += statestoadd; @@ -496,46 +555,62 @@ void IRAM_ATTR VIDEO::MainScreen(unsigned int statestoadd, bool contended) { } - // // 2 T-states at a time version +} - // static uint8_t att, bmp; +// // --------------------------- +// // ptime-128 compliant version +// // --------------------------- +// void IRAM_ATTR VIDEO::MainScreen(unsigned int statestoadd, bool contended) { - // if (contended) - // statestoadd += Z80Ops::is48 ? wait_st[(CPU::tstates + 1) % 224] : wait_st[(CPU::tstates + 3) % 228]; +// static uint8_t att1,bmp1; - // CPU::tstates += statestoadd; +// if (contended) +// statestoadd += Z80Ops::is48 ? wait_st[(CPU::tstates + 1) % 224] : wait_st[(CPU::tstates + 3) % 228]; - // statestoadd += video_rest; - // video_rest = statestoadd & 0x01; // Mod 2 +// CPU::tstates += statestoadd; - // for (int i=0; i < (statestoadd >> 1); i++) { +// statestoadd += video_rest; + +// for (int i=0; i < statestoadd; i++) { - // if((coldraw_cnt & 0x01) == 0) { - // att = grmem[attOffset++]; // get attribute byte - // bmp = (att & flashing) ? ~grmem[bmpOffset++] : grmem[bmpOffset++]; - // *lineptr32++ = AluBytes[bmp >> 4][att]; - // } else { - // *lineptr32++ = AluBytes[bmp & 0xF][att]; - // } +// switch(dispUpdCycle) { +// case 0: +// case 2: +// bmp1 = grmem[bmpOffset++]; +// break; +// case 1: +// att1 = grmem[attOffset++]; // get attribute byte +// case 5: - // if (++coldraw_cnt > 67) { - // coldraw_cnt = 36; - // Draw = MainScreenRB; - // video_rest += ((statestoadd >> 1) - (i + 1)) << 1; - // MainScreenRB(0,false); - // return; - // } +// if (att1 & flashing) bmp1 = ~bmp1; +// *lineptr32++ = AluBytes[bmp1 >> 4][att1]; +// *lineptr32++ = AluBytes[bmp1 & 0xF][att1]; - // } +// if (++coldraw_cnt > 35) { +// Draw = MainScreenRB; +// video_rest += statestoadd - (i + 1); +// MainScreenRB(0,false); +// return; +// } -} +// break; +// case 3: +// att1 = grmem[attOffset++]; // get attribute byte +// break; +// } + +// // Update the cycle counter. +// ++dispUpdCycle &= 0x07; + +// } + +// } void IRAM_ATTR VIDEO::MainScreen_OSD(unsigned int statestoadd, bool contended) { uint8_t att, bmp; - if (contended) - statestoadd += Z80Ops::is48 ? wait_st[(CPU::tstates + 1) % 224] : wait_st[(CPU::tstates + 3) % 228]; + if (contended) statestoadd += wait_st[(CPU::tstates + contendOffset) % contendMod]; CPU::tstates += statestoadd; @@ -575,8 +650,7 @@ void IRAM_ATTR VIDEO::MainScreen_OSD(unsigned int statestoadd, bool contended) { void IRAM_ATTR VIDEO::MainScreenRB(unsigned int statestoadd, bool contended) { - if (contended) - statestoadd += Z80Ops::is48 ? wait_st[(CPU::tstates + 1) % 224] : wait_st[(CPU::tstates + 3) % 228]; + if (contended) statestoadd += wait_st[(CPU::tstates + contendOffset) % contendMod]; CPU::tstates += statestoadd; statestoadd += video_rest; From 641781efa083dadc34b8b03993472bae4282315e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Fri, 7 Jul 2023 15:25:32 +0200 Subject: [PATCH 05/29] Kempston 0xDF port fix --- src/Ports.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Ports.cpp b/src/Ports.cpp index 99030493..e6d5f5ef 100644 --- a/src/Ports.cpp +++ b/src/Ports.cpp @@ -56,7 +56,7 @@ visit https://zxespectrum.speccy.org/contacto // 6: ula <= 8'hF8; // 7: ula <= 8'hFF; // and adjusted for BEEPER_MAX_VOLUME = 97 -int speaker_values[8]={ 0, 19, 34, 53, 97, 101, 130, 134 }; +uint8_t speaker_values[8]={ 0, 19, 34, 53, 97, 101, 130, 134 }; uint8_t Ports::port[128]; @@ -79,10 +79,11 @@ uint8_t IRAM_ATTR Ports::input(uint16_t address) } // ** I/O Contention (Late) ************************** - if (((address & 0xff) == 0x1f) && (Config::joystick)) return port[0x1f]; // Kempston port + // Kempston Joystick + if ((Config::joystick) && ((address & 0x00E0) == 0 || (address & 0xFF) == 0xDF)) return port[0x1f]; - if ((address & 0xff) == 0xfe) // ULA PORT - { + // ULA PORT + if ((address & 0x0001) == 0) { uint8_t result = 0xbf; @@ -98,20 +99,19 @@ uint8_t IRAM_ATTR Ports::input(uint16_t address) bitWrite(result,6,Tape::tapeEarBit); } - return result | (0xa0); // OR 0xa0 -> ISSUE 2 } // Sound (AY-3-8912) if (ESPectrum::AY_emu) { - if ( (((address >> 8) & 0xC0) == 0xC0) && (((address & 0xff) & 0x02) == 0x00) ) + if ((address & 0xC002) == 0xC000) return AySound::getRegisterData(); } uint8_t data = VIDEO::getFloatBusData(); - if (((address & 0x8002) == 0) && (!Z80Ops::is48)) { + if ((!Z80Ops::is48) || ((address & 0x8002) == 0)) { // // Solo en el modelo 128K, pero no en los +2/+2A/+3, si se lee el puerto // // 0x7ffd, el valor leído es reescrito en el puerto 0x7ffd. From 419cee0566d7909910d58361a88899c16391deab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Mon, 10 Jul 2023 02:53:45 +0200 Subject: [PATCH 06/29] Flushonhalt for all timings, faster contention --- include/CPU.h | 3 +- include/messages.h | 3 +- src/CPU.cpp | 101 +++++++++++++++++++++------------------------ src/OSDMain.cpp | 10 ++--- src/Ports.cpp | 2 +- src/Video.cpp | 26 +++++++----- src/Z80_JLS.cpp | 92 ++++++++++++++++++++++++++++++----------- 7 files changed, 141 insertions(+), 96 deletions(-) diff --git a/include/CPU.h b/include/CPU.h index d8fbb1c4..a17807b3 100644 --- a/include/CPU.h +++ b/include/CPU.h @@ -92,7 +92,8 @@ class CPU }; -static const unsigned char wait_st[228] = { +static const unsigned char DRAM_ATTR wait_st[243] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 5, 4, 3, 2, 1, 0, 0, 6, 5, 4, 3, 2, 1, 0, 0, 6, 5, 4, 3, 2, 1, 0, 0, 6, 5, 4, 3, 2, 1, 0, 0, 6, 5, 4, 3, 2, 1, 0, 0, 6, 5, 4, 3, 2, 1, 0, 0, diff --git a/include/messages.h b/include/messages.h index 4967bdf6..de0e4239 100644 --- a/include/messages.h +++ b/include/messages.h @@ -41,6 +41,7 @@ visit https://zxespectrum.speccy.org/contacto #define MSG_LOADING_Z80 "Loading Z80 file" #define MSG_SAVE_CONFIG "Saving config file" #define MSG_VGA_INIT "Initializing VGA" +#define EMU_VERSION " v1.0rc2pr " // Error #define ERROR_TITLE " !!! ERROR - CLIVE MEDITATION !!! " @@ -54,7 +55,7 @@ visit https://zxespectrum.speccy.org/contacto // OSD #define OSD_TITLE " ESPectrum - The ESP32 powered emulator " // #define OSD_BOTTOM " SCIENCE LEADS TO PROGRESS v1.0rc1 " -#define OSD_BOTTOM " zxespectrum.speccy.org v1.0rc1 " +#define OSD_BOTTOM " zxespectrum.speccy.org " EMU_VERSION #define OSD_PAUSE_EN " --=[PAUSED]=-- " #define OSD_PAUSE_ES "--=[EN PAUSA]=--" diff --git a/src/CPU.cpp b/src/CPU.cpp index 0d8d3ece..4abf2c08 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -164,50 +164,58 @@ void CPU::FlushOnHalt() { tstates &= 0x00FFFFFF; - uint32_t pre_tstates = tstates; - - VIDEO::Flush(); // Draw the rest of the frame - - tstates = pre_tstates; - - uint8_t page = (Z80::getRegPC() + 1) >> 14; - if ((page == 1) || ((page == 3) && (!Z80Ops::is48) && (MemESP::bankLatch & 0x01))) { + uint8_t page = Z80::getRegPC() >> 14; + if (MemESP::ramContended[page]) { - if (Z80Ops::is48) { + uint32_t stFrame = statesInFrame - latetiming; + while (tstates < stFrame ) { + VIDEO::Draw(4,true); + Z80::incRegR(1); + } + + // if (Z80Ops::is48) { - while (tstates < statesInFrame ) { - uint32_t currentTstates = CPU::tstates + 1; - unsigned short int line = currentTstates / 224; - if (line >= 64 && line < 256) tstates += wait_st[currentTstates % 224]; - tstates += 4; - Z80::incRegR(1); - } + // while (tstates < statesInFrame ) { + // uint32_t currentTstates = CPU::tstates + 1; + // unsigned short int line = currentTstates / 224; + // if (line >= 64 && line < 256) tstates += wait_st[currentTstates % 224]; + // tstates += 4; + // Z80::incRegR(1); + // } - } else { + // } else { - while (tstates < statesInFrame ) { - uint32_t currentTstates = CPU::tstates + 3; - unsigned short int line = currentTstates / 228; - if (line >= 63 && line < 255) tstates += wait_st[currentTstates % 228]; - tstates += 4; - Z80::incRegR(1); - } + // while (tstates < statesInFrame ) { + // uint32_t currentTstates = CPU::tstates + 3; + // unsigned short int line = currentTstates / 228; + // if (line >= 63 && line < 255) tstates += wait_st[currentTstates % 228]; + // tstates += 4; + // Z80::incRegR(1); + // } - } + // } } else { - // tstates + uint32_t pre_tstates = tstates; + VIDEO::Flush(); // Draw the rest of the frame + tstates = pre_tstates; + + // uint32_t stFrame = statesInFrame - latetiming; + // while (tstates < stFrame ) { + // tstates += 4; + // Z80::incRegR(1); + // } + + pre_tstates += latetiming; uint32_t incr = (statesInFrame - pre_tstates) >> 2; - if (tstates & 0x03) incr++; + if (pre_tstates & 0x03) incr++; tstates += (incr << 2); - - // RegR Z80::incRegR(incr & 0x000000FF); } - Z80::checkINT(); // I think I can put this out of the "while (tstates .. ". Study + Z80::checkINT(); } @@ -215,22 +223,21 @@ void CPU::FlushOnHalt() { // Z80Ops /////////////////////////////////////////////////////////////////////////////// -/* Read byte from RAM */ +// Read byte from RAM uint8_t IRAM_ATTR Z80Ops::peek8(uint16_t address) { uint8_t page = address >> 14; VIDEO::Draw(3,MemESP::ramContended[page]); - return MemESP::ramCurrent[page][address & 0x3fff]; + return MemESP::ramCurrent[page][address & 0x3fff]; } -/* Write byte to RAM */ +// Write byte to RAM void IRAM_ATTR Z80Ops::poke8(uint16_t address, uint8_t value) { uint8_t page = address >> 14; VIDEO::Draw(3, MemESP::ramContended[page]); if (page != 0) MemESP::ramCurrent[page][address & 0x3fff] = value; - return; } -/* Read/Write word from/to RAM */ +// Read word from RAM uint16_t IRAM_ATTR Z80Ops::peek16(uint16_t address) { uint8_t page = address >> 14; @@ -245,6 +252,7 @@ uint16_t IRAM_ATTR Z80Ops::peek16(uint16_t address) { } +// Write word to RAM void IRAM_ATTR Z80Ops::poke16(uint16_t address, RegisterPair word) { uint8_t page = address >> 14; @@ -263,35 +271,18 @@ void IRAM_ATTR Z80Ops::poke16(uint16_t address, RegisterPair word) { } /* Put an address on bus lasting 'tstates' cycles */ -void IRAM_ATTR Z80Ops::addressOnBus(uint16_t address, int32_t wstates){ - +void IRAM_ATTR Z80Ops::addressOnBus(uint16_t address, int32_t wstates) { if (MemESP::ramContended[address >> 14]) { for (int idx = 0; idx < wstates; idx++) - VIDEO::Draw(1, true); - } else { + VIDEO::Draw(1, true); + } else VIDEO::Draw(wstates, false); - } - } /* Callback to know when the INT signal is active */ bool IRAM_ATTR Z80Ops::isActiveINT(void) { - - - // Early timing - // int tmp = CPU::tstates; - // if (tmp >= CPU::statesInFrame) tmp -= CPU::statesInFrame; - // return ((tmp >= 0) && (tmp < (is48 ? 32 : 36))); - - // // Late timing - // int tmp = CPU::tstates + 1; - // if (tmp >= CPU::statesInFrame) tmp -= CPU::statesInFrame; - // return ((tmp >= 0) && (tmp <= (is48 ? 32 : 36))); - int tmp = CPU::tstates + CPU::latetiming; if (tmp >= CPU::statesInFrame) tmp -= CPU::statesInFrame; - // return ((tmp >= 0) && (tmp < (is48 ? 32 + CPU::latetiming: 36 + CPU::latetiming))); return ((tmp >= CPU::IntStart) && (tmp < CPU::IntEnd)); - } diff --git a/src/OSDMain.cpp b/src/OSDMain.cpp index a9c6a2f9..fa61b486 100644 --- a/src/OSDMain.cpp +++ b/src/OSDMain.cpp @@ -121,7 +121,6 @@ void OSD::osdAt(uint8_t row, uint8_t col) { } void OSD::drawOSD(bool bottom_info) { - static char bottom_info_str[41]; unsigned short x = scrAlignCenterX(OSD_W); unsigned short y = scrAlignCenterY(OSD_H); VIDEO::vga.fillRect(x, y, OSD_W, OSD_H, OSD::zxColor(1, 0)); @@ -133,12 +132,13 @@ void OSD::drawOSD(bool bottom_info) { VIDEO::vga.print(OSD_TITLE); osdAt(21, 0); if (bottom_info) { + string bottom_line; switch(Config::videomode) { - case 0: snprintf(bottom_info_str,sizeof(bottom_info_str)," Video mode: Standard VGA v1.0rc1 "); break; - case 1: snprintf(bottom_info_str,sizeof(bottom_info_str)," Video mode: VGA 50hz v1.0rc1 "); break; - case 2: snprintf(bottom_info_str,sizeof(bottom_info_str)," Video mode: CRT 50hz v1.0rc1 "); break; + case 0: bottom_line = " Video mode: Standard VGA "; break; + case 1: bottom_line = " Video mode: VGA 50hz "; break; + case 2: bottom_line = " Video mode: CRT 50hz "; break; } - VIDEO::vga.print(bottom_info_str); + VIDEO::vga.print(bottom_line.append(EMU_VERSION).c_str()); } else VIDEO::vga.print(OSD_BOTTOM); osdHome(); } diff --git a/src/Ports.cpp b/src/Ports.cpp index e6d5f5ef..32e116a0 100644 --- a/src/Ports.cpp +++ b/src/Ports.cpp @@ -111,7 +111,7 @@ uint8_t IRAM_ATTR Ports::input(uint16_t address) uint8_t data = VIDEO::getFloatBusData(); - if ((!Z80Ops::is48) || ((address & 0x8002) == 0)) { + if ((!Z80Ops::is48) && ((address & 0x8002) == 0)) { // // Solo en el modelo 128K, pero no en los +2/+2A/+3, si se lee el puerto // // 0x7ffd, el valor leído es reescrito en el puerto 0x7ffd. diff --git a/src/Video.cpp b/src/Video.cpp index 6ba25910..9fc34883 100644 --- a/src/Video.cpp +++ b/src/Video.cpp @@ -478,8 +478,9 @@ void IRAM_ATTR VIDEO::MainScreen_Blank(unsigned int statestoadd, bool contended) CPU::tstates += statestoadd; if (CPU::tstates > tstateDraw) { + // printf("Tstate Draw: %d\n",tstateDraw); video_rest = CPU::tstates - tstateDraw; - tstateDraw += tStatesPerLine; + // tstateDraw += tStatesPerLine; lineptr32 = (uint32_t *)(vga.frameBuffers[0][linedraw_cnt]); if (is169) lineptr32 += 5; coldraw_cnt = 0; @@ -493,7 +494,8 @@ void IRAM_ATTR VIDEO::MainScreen_Blank(unsigned int statestoadd, bool contended) void IRAM_ATTR VIDEO::MainScreenLB(unsigned int statestoadd, bool contended) { - if (contended) statestoadd += wait_st[(CPU::tstates + contendOffset) % contendMod]; + // if (contended) statestoadd += wait_st[(CPU::tstates + contendOffset) % contendMod]; + if (contended) statestoadd += wait_st[CPU::tstates - tstateDraw]; CPU::tstates += statestoadd; statestoadd += video_rest; @@ -531,13 +533,15 @@ void IRAM_ATTR VIDEO::MainScreen(unsigned int statestoadd, bool contended) { uint8_t att, bmp; - if (contended) statestoadd += wait_st[(CPU::tstates + contendOffset) % contendMod]; + // if (contended) statestoadd += wait_st[(CPU::tstates + contendOffset) % contendMod]; + if (contended) statestoadd += wait_st[CPU::tstates - tstateDraw]; CPU::tstates += statestoadd; statestoadd += video_rest; - video_rest = statestoadd & 0x03; // Mod 4 + video_rest = statestoadd & 0x03; // Mod 4 + for (int i=0; i < (statestoadd >> 2); i++) { att = grmem[attOffset++]; // get attribute byte @@ -564,8 +568,7 @@ void IRAM_ATTR VIDEO::MainScreen(unsigned int statestoadd, bool contended) { // static uint8_t att1,bmp1; -// if (contended) -// statestoadd += Z80Ops::is48 ? wait_st[(CPU::tstates + 1) % 224] : wait_st[(CPU::tstates + 3) % 228]; +// if (contended) statestoadd += wait_st[CPU::tstates - tstateDraw]; // CPU::tstates += statestoadd; @@ -579,7 +582,7 @@ void IRAM_ATTR VIDEO::MainScreen(unsigned int statestoadd, bool contended) { // bmp1 = grmem[bmpOffset++]; // break; // case 1: -// att1 = grmem[attOffset++]; // get attribute byte +// att1 = grmem[attOffset++]; // get attribute byte // case 5: // if (att1 & flashing) bmp1 = ~bmp1; @@ -595,7 +598,7 @@ void IRAM_ATTR VIDEO::MainScreen(unsigned int statestoadd, bool contended) { // break; // case 3: -// att1 = grmem[attOffset++]; // get attribute byte +// att1 = grmem[attOffset++]; // get attribute byte // break; // } @@ -610,7 +613,8 @@ void IRAM_ATTR VIDEO::MainScreen_OSD(unsigned int statestoadd, bool contended) { uint8_t att, bmp; - if (contended) statestoadd += wait_st[(CPU::tstates + contendOffset) % contendMod]; + // if (contended) statestoadd += wait_st[(CPU::tstates + contendOffset) % contendMod]; + if (contended) statestoadd += wait_st[CPU::tstates - tstateDraw]; CPU::tstates += statestoadd; @@ -650,7 +654,8 @@ void IRAM_ATTR VIDEO::MainScreen_OSD(unsigned int statestoadd, bool contended) { void IRAM_ATTR VIDEO::MainScreenRB(unsigned int statestoadd, bool contended) { - if (contended) statestoadd += wait_st[(CPU::tstates + contendOffset) % contendMod]; + // if (contended) statestoadd += wait_st[(CPU::tstates + contendOffset) % contendMod]; + if (contended) statestoadd += wait_st[CPU::tstates - tstateDraw]; CPU::tstates += statestoadd; statestoadd += video_rest; @@ -661,6 +666,7 @@ void IRAM_ATTR VIDEO::MainScreenRB(unsigned int statestoadd, bool contended) { *lineptr32++ = brd; if (++coldraw_cnt == 40) { + tstateDraw += tStatesPerLine; Draw = ++linedraw_cnt == (is169 ? 196 : 216) ? &BottomBorder_Blank : &MainScreen_Blank; return; } diff --git a/src/Z80_JLS.cpp b/src/Z80_JLS.cpp index 835ca855..c269df27 100644 --- a/src/Z80_JLS.cpp +++ b/src/Z80_JLS.cpp @@ -984,17 +984,13 @@ void IRAM_ATTR Z80::incRegR(uint8_t inc) { void IRAM_ATTR Z80::execute() { - // opCode = Z80Ops::fetchOpcode(REG_PC); - FETCH_OPCODE(opCode,REG_PC); + uint8_t pg = REG_PC >> 14; + VIDEO::Draw(4,MemESP::ramContended[pg]); + opCode = MemESP::ramCurrent[pg][REG_PC & 0x3fff]; + regR++; - #ifdef WITH_BREAKPOINT_SUPPORT - if (breakpointEnabled && prefixOpcode == 0) { - opCode = Z80Ops::breakpoint(REG_PC, opCode); - } - #endif - - if (!halted) { + // if (!halted) { REG_PC++; @@ -1026,13 +1022,7 @@ void IRAM_ATTR Z80::execute() { lastFlagQ = flagQ; - #ifdef WITH_EXEC_DONE - if (execDone) { - Z80Ops::execDone(); - } - #endif - - } + // } // Primero se comprueba NMI // Si se activa NMI no se comprueba INT porque la siguiente @@ -1047,13 +1037,69 @@ void IRAM_ATTR Z80::execute() { // Ahora se comprueba si está activada la señal INT checkINT(); - // if (ffIFF1 && !pendingEI && Z80Ops::isActiveINT()) { - // lastFlagQ = false; - // interrupt(); - // } - } +// void IRAM_ATTR Z80::execute() { + +// regR++; + +// if (!halted) { + +// page = REG_PC >> 14; +// VIDEO::Draw(4,MemESP::ramContended[page]); +// opCode = MemESP::ramCurrent[page][REG_PC & 0x3fff]; + +// REG_PC++; + +// // El prefijo 0xCB no cuenta para esta guerra. +// // En CBxx todas las xx producen un código válido +// // de instrucción, incluyendo CBCB. +// switch (prefixOpcode) { +// case 0x00: +// flagQ = pendingEI = false; +// dcOpcode[opCode](); +// break; +// case 0xDD: +// prefixOpcode = 0; +// decodeDDFD(regIX); +// break; +// case 0xED: +// prefixOpcode = 0; +// decodeED(); +// break; +// case 0xFD: +// prefixOpcode = 0; +// decodeDDFD(regIY); +// break; +// default: +// return; +// } + +// if (prefixOpcode != 0) return; + +// lastFlagQ = flagQ; + +// } else { + +// VIDEO::Draw(4,MemESP::ramContended[REG_PC >> 14]); + +// } + +// // Primero se comprueba NMI +// // Si se activa NMI no se comprueba INT porque la siguiente +// // instrucción debe ser la de 0x0066. +// // if (activeNMI) { +// // activeNMI = false; +// // lastFlagQ = false; +// // nmi(); +// // return; +// // } + +// // Ahora se comprueba si está activada la señal INT +// checkINT(); + +// } + void Z80::decodeOpcode00() { /* NOP */ } @@ -1819,8 +1865,8 @@ void Z80::decodeOpcode76() // REG_PC--; // Signal HALT to CPU Loop - if (!CPU::latetiming) CPU::tstates |= 0xFF000000; - + CPU::tstates |= 0xFF000000; + halted = true; } From 7a3e65c359c42c6bf4b875cac5ab4285ecb740a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Mon, 10 Jul 2023 14:30:19 +0200 Subject: [PATCH 07/29] CPU loop great boost --- src/CPU.cpp | 58 ++++++++++++++++++++++++++++----------------- src/Z80_JLS.cpp | 63 +------------------------------------------------ 2 files changed, 37 insertions(+), 84 deletions(-) diff --git a/src/CPU.cpp b/src/CPU.cpp index 4abf2c08..300f7a38 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -129,27 +129,41 @@ void CPU::reset() { void IRAM_ATTR CPU::loop() { - while (tstates < statesInFrame ) { - - Z80::execute(); - - // - // PRELIMINARY TAPE SAVE TEST - // - // // if PC is 0x970, a call to SA_CONTRL has been made: - // // remove .tap output file if exists - // if(Z80::getRegPC() == 0x970) { - // remove("/sd/tap/cinta1.tap"); - // } - // // if PC is 0x04C2, a call to SA_BYTES has been made: - // // Call Save function - // if(Z80::getRegPC() == 0x04C2) { - // Tape::Save(); - // // printf("Save in ROM called\n"); - // Z80::setRegPC(0x555); - // } - - } + while (tstates < IntEnd) { + Z80::execute(); + Z80::checkINT(); + } + + uint32_t stFrame = statesInFrame - IntEnd; + while (tstates < stFrame) Z80::execute(); + + while (tstates < statesInFrame) { + Z80::execute(); + Z80::checkINT(); + } + + // while (tstates < statesInFrame) { + + // Z80::execute(); + + // PRELIMINARY TAPE SAVE TEST + // + // // if PC is 0x970, a call to SA_CONTRL has been made: + // // remove .tap output file if exists + // if(Z80::getRegPC() == 0x970) { + // remove("/sd/tap/cinta1.tap"); + // } + // // if PC is 0x04C2, a call to SA_BYTES has been made: + // // Call Save function + // if(Z80::getRegPC() == 0x04C2) { + // Tape::Save(); + // // printf("Save in ROM called\n"); + // Z80::setRegPC(0x555); + // } + + // Z80::checkINT(); + + // } if (tstates & 0xFF000000) FlushOnHalt(); // If we're halted flush screen and update registers as needed @@ -283,6 +297,6 @@ void IRAM_ATTR Z80Ops::addressOnBus(uint16_t address, int32_t wstates) { bool IRAM_ATTR Z80Ops::isActiveINT(void) { int tmp = CPU::tstates + CPU::latetiming; if (tmp >= CPU::statesInFrame) tmp -= CPU::statesInFrame; - return ((tmp >= CPU::IntStart) && (tmp < CPU::IntEnd)); + return ((tmp >= CPU::IntStart) && (tmp < CPU::IntEnd)); } diff --git a/src/Z80_JLS.cpp b/src/Z80_JLS.cpp index c269df27..9b6f3c7c 100644 --- a/src/Z80_JLS.cpp +++ b/src/Z80_JLS.cpp @@ -1035,71 +1035,10 @@ void IRAM_ATTR Z80::execute() { // } // Ahora se comprueba si está activada la señal INT - checkINT(); + // checkINT(); } -// void IRAM_ATTR Z80::execute() { - -// regR++; - -// if (!halted) { - -// page = REG_PC >> 14; -// VIDEO::Draw(4,MemESP::ramContended[page]); -// opCode = MemESP::ramCurrent[page][REG_PC & 0x3fff]; - -// REG_PC++; - -// // El prefijo 0xCB no cuenta para esta guerra. -// // En CBxx todas las xx producen un código válido -// // de instrucción, incluyendo CBCB. -// switch (prefixOpcode) { -// case 0x00: -// flagQ = pendingEI = false; -// dcOpcode[opCode](); -// break; -// case 0xDD: -// prefixOpcode = 0; -// decodeDDFD(regIX); -// break; -// case 0xED: -// prefixOpcode = 0; -// decodeED(); -// break; -// case 0xFD: -// prefixOpcode = 0; -// decodeDDFD(regIY); -// break; -// default: -// return; -// } - -// if (prefixOpcode != 0) return; - -// lastFlagQ = flagQ; - -// } else { - -// VIDEO::Draw(4,MemESP::ramContended[REG_PC >> 14]); - -// } - -// // Primero se comprueba NMI -// // Si se activa NMI no se comprueba INT porque la siguiente -// // instrucción debe ser la de 0x0066. -// // if (activeNMI) { -// // activeNMI = false; -// // lastFlagQ = false; -// // nmi(); -// // return; -// // } - -// // Ahora se comprueba si está activada la señal INT -// checkINT(); - -// } - void Z80::decodeOpcode00() { /* NOP */ } From 877bd59ec39bbb1ac0d3656b165e4a0c6c9bd3ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Tue, 11 Jul 2023 21:43:56 +0200 Subject: [PATCH 08/29] Issue 2 selectable, cpu optimizations --- include/Config.h | 1 + include/Ports.h | 1 + include/Video.h | 2 +- include/messages.h | 14 +++- src/Config.cpp | 13 ++++ src/ESPectrum.cpp | 8 +-- src/FileSNA.cpp | 2 +- src/FileZ80.cpp | 2 +- src/OSDMain.cpp | 33 +++++++++ src/Ports.cpp | 165 ++++++++++++++++++++++++++++++++++----------- src/Video.cpp | 2 +- src/ZXKeyb.cpp | 2 +- 12 files changed, 193 insertions(+), 52 deletions(-) diff --git a/include/Config.h b/include/Config.h index 5a195b13..ba75a9d0 100644 --- a/include/Config.h +++ b/include/Config.h @@ -61,6 +61,7 @@ class Config // static string kbd_layout; static uint8_t lang; static bool AY48; + static bool Issue2; static uint8_t joystick; static uint8_t videomode; static uint8_t AluTiming; diff --git a/include/Ports.h b/include/Ports.h index e42d8fd8..d3ea5fa4 100644 --- a/include/Ports.h +++ b/include/Ports.h @@ -43,6 +43,7 @@ class Ports { public: static uint8_t port[128]; + static uint8_t port254; static uint8_t IRAM_ATTR input(uint16_t address); static void IRAM_ATTR output(uint16_t address, uint8_t data); // static void ContendedIODelay(uint16_t portNumber); diff --git a/include/Video.h b/include/Video.h index b39b54e2..01a70b75 100644 --- a/include/Video.h +++ b/include/Video.h @@ -90,7 +90,7 @@ class VIDEO static void IRAM_ATTR TopBorder_Blank(unsigned int statestoadd, bool contended); static void IRAM_ATTR TopBorder(unsigned int statestoadd, bool contended); static void IRAM_ATTR MainScreen_Blank(unsigned int statestoadd, bool contended); - static void IRAM_ATTR MainScreen(unsigned int statestoadd, bool contended); + static void MainScreen(unsigned int statestoadd, bool contended); static void IRAM_ATTR MainScreen_OSD(unsigned int statestoadd, bool contended); static void IRAM_ATTR BottomBorder_Blank(unsigned int statestoadd, bool contended); static void IRAM_ATTR BottomBorder(unsigned int statestoadd, bool contended); diff --git a/include/messages.h b/include/messages.h index de0e4239..f9812d99 100644 --- a/include/messages.h +++ b/include/messages.h @@ -216,10 +216,12 @@ static const char *MENU_STORAGE[2] = { MENU_STORAGE_EN, MENU_STORAGE_ES }; #define MENU_OTHER_EN "Other\n"\ "AY on 48K\t>\n"\ - "ALU Timing\t>\n" + "ALU Timing\t>\n"\ + "48K Issue 2\t>\n" #define MENU_OTHER_ES "Otros\n"\ "AY en 48K\t>\n"\ - "Timing ULA\t>\n" + "Timing ULA\t>\n"\ + "48K Issue 2\t>\n" static const char *MENU_OTHER[2] = { MENU_OTHER_EN, MENU_OTHER_ES }; #define MENU_AY48_EN "AY on 48K\n"\ @@ -238,6 +240,14 @@ static const char *MENU_AY48[2] = { MENU_AY48_EN, MENU_AY48_ES }; "Late\t[L]\n" static const char *MENU_ALUTIMING[2] = { MENU_ALUTIMING_EN, MENU_ALUTIMING_ES }; +#define MENU_ISSUE2_EN "48K Issue 2\n"\ + "Yes\t[Y]\n"\ + "No\t[N]\n" +#define MENU_ISSUE2_ES "48K Issue 2\n"\ + "Si\t[Y]\n"\ + "No\t[N]\n" +static const char *MENU_ISSUE2[2] = { MENU_ISSUE2_EN, MENU_ISSUE2_ES }; + #define MENU_ARCH_EN "Select machine\n"\ "ZX Spectrum 48K\n"\ "ZX Spectrum 128K\n" diff --git a/src/Config.cpp b/src/Config.cpp index 852e6bff..5f37234c 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -62,6 +62,7 @@ uint8_t Config::esp32rev = 0; // string Config::kbd_layout = "US"; uint8_t Config::lang = 0; bool Config::AY48 = false; +bool Config::Issue2 = true; uint8_t Config::joystick = 0; // 0 -> Cursor, 1 -> Kempston uint8_t Config::AluTiming = 0; @@ -213,6 +214,15 @@ void Config::load() { free(str_data); } + err = nvs_get_str(handle, "Issue2", NULL, &required_size); + if (err == ESP_OK) { + str_data = (char *)malloc(required_size); + nvs_get_str(handle, "Issue2", str_data, &required_size); + printf("Issue2:%s\n",str_data); + Issue2 = strcmp(str_data, "false"); + free(str_data); + } + err = nvs_get_u8(handle, "joystick", &Config::joystick); if (err == ESP_OK) { printf("joystick:%u\n",Config::joystick); @@ -362,6 +372,9 @@ void Config::save(string value) { if((value=="AY48") || (value=="all")) nvs_set_str(handle,"AY48",AY48 ? "true" : "false"); + if((value=="Issue2") || (value=="all")) + nvs_set_str(handle,"Issue2",Issue2 ? "true" : "false"); + if((value=="joystick") || (value=="all")) nvs_set_u8(handle,"joystick",Config::joystick); diff --git a/src/ESPectrum.cpp b/src/ESPectrum.cpp index 66e2a1d8..a0dff546 100644 --- a/src/ESPectrum.cpp +++ b/src/ESPectrum.cpp @@ -694,7 +694,7 @@ void ESPectrum::setup() CPU::setup(); // Set Ports starting values - for (int i = 0; i < 128; i++) Ports::port[i] = 0x1F; + for (int i = 0; i < 128; i++) Ports::port[i] = 0xBF; if (Config::joystick) Ports::port[0x1f] = 0; // Kempston // Set emulation loop sync target @@ -735,7 +735,7 @@ void ESPectrum::reset() { // Ports - for (int i = 0; i < 128; i++) Ports::port[i] = 0x1F; + for (int i = 0; i < 128; i++) Ports::port[i] = 0xBF; if (Config::joystick) Ports::port[0x1f] = 0; // Kempston // Memory @@ -858,7 +858,7 @@ bool IRAM_ATTR ESPectrum::readKbd(fabgl::VirtualKeyItem *Nextkey) { return r; } -uint8_t ESPectrum::PS2cols[8] = { 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f }; +uint8_t ESPectrum::PS2cols[8] = { 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf }; // #ifdef ZXKEYB static int zxDelay = 0; @@ -1035,7 +1035,7 @@ void IRAM_ATTR ESPectrum::processKeyboard() { if (zxDelay) { // Set all keys as not pressed - for (uint8_t i = 0; i < 8; i++) ZXKeyb::ZXcols[i] = 0x1f; + for (uint8_t i = 0; i < 8; i++) ZXKeyb::ZXcols[i] = 0xbf; return; } diff --git a/src/FileSNA.cpp b/src/FileSNA.cpp index ac2ea8d6..a1aa0c9d 100644 --- a/src/FileSNA.cpp +++ b/src/FileSNA.cpp @@ -269,7 +269,7 @@ bool FileSNA::load(string sna_fn) } // Ports - for (int i = 0; i < 128; i++) Ports::port[i] = 0x1F; + for (int i = 0; i < 128; i++) Ports::port[i] = 0xBF; if (Config::joystick) Ports::port[0x1f] = 0; // Kempston CPU::statesInFrame = CPU::statesPerFrame(); diff --git a/src/FileZ80.cpp b/src/FileZ80.cpp index 5f25739a..b3184771 100644 --- a/src/FileZ80.cpp +++ b/src/FileZ80.cpp @@ -362,7 +362,7 @@ bool FileZ80::load(string z80_fn) } // Ports - for (int i = 0; i < 128; i++) Ports::port[i] = 0x1F; + for (int i = 0; i < 128; i++) Ports::port[i] = 0xBF; if (Config::joystick) Ports::port[0x1f] = 0; // Kempston CPU::statesInFrame = CPU::statesPerFrame(); diff --git a/src/OSDMain.cpp b/src/OSDMain.cpp index fa61b486..cd6dc14e 100644 --- a/src/OSDMain.cpp +++ b/src/OSDMain.cpp @@ -775,6 +775,39 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { } } } + else if (options_num == 3) { + menu_level = 3; + menu_curopt = 1; + menu_saverect = true; + while (1) { + string iss_menu = MENU_ISSUE2[Config::lang]; + bool prev_iss = Config::Issue2; + if (prev_iss) { + iss_menu.replace(iss_menu.find("[Y",0),2,"[*"); + iss_menu.replace(iss_menu.find("[N",0),2,"[ "); + } else { + iss_menu.replace(iss_menu.find("[Y",0),2,"[ "); + iss_menu.replace(iss_menu.find("[N",0),2,"[*"); + } + uint8_t opt2 = menuRun(iss_menu); + if (opt2) { + if (opt2 == 1) + Config::Issue2 = true; + else + Config::Issue2 = false; + + if (Config::Issue2 != prev_iss) { + Config::save("Issue2"); + } + menu_curopt = opt2; + menu_saverect = false; + } else { + menu_curopt = 3; + menu_level = 2; + break; + } + } + } } else { menu_curopt = 6; break; diff --git a/src/Ports.cpp b/src/Ports.cpp index 32e116a0..0570b1b0 100644 --- a/src/Ports.cpp +++ b/src/Ports.cpp @@ -59,6 +59,7 @@ visit https://zxespectrum.speccy.org/contacto uint8_t speaker_values[8]={ 0, 19, 34, 53, 97, 101, 130, 134 }; uint8_t Ports::port[128]; +uint8_t Ports::port254 = 0; uint8_t IRAM_ATTR Ports::input(uint16_t address) { @@ -79,13 +80,11 @@ uint8_t IRAM_ATTR Ports::input(uint16_t address) } // ** I/O Contention (Late) ************************** - // Kempston Joystick - if ((Config::joystick) && ((address & 0x00E0) == 0 || (address & 0xFF) == 0xDF)) return port[0x1f]; + // The default port value is 0xBF. + uint8_t result = 0xbf; - // ULA PORT + // The ULA functions (keybord and audio in) are accessible via all even numbered ports. if ((address & 0x0001) == 0) { - - uint8_t result = 0xbf; uint8_t portHigh = ~(address >> 8) & 0xff; for (int row = 0, mask = 0x01; row < 8; row++, mask <<= 1) { @@ -96,48 +95,130 @@ uint8_t IRAM_ATTR Ports::input(uint16_t address) if (Tape::tapeStatus==TAPE_LOADING) { Tape::TAP_Read(); - bitWrite(result,6,Tape::tapeEarBit); - } + bitWrite(result,6,Tape::tapeEarBit); + } else { + // Issue 2 behaviour only on Spectrum 48K + if ((Z80Ops::is48) && (Config::Issue2)) { + if (port254 & 0x18) result |= 0x40; + } else { + if (port254 & 0x10) result |= 0x40; + } + } + + } else { - return result | (0xa0); // OR 0xa0 -> ISSUE 2 - - } - - // Sound (AY-3-8912) - if (ESPectrum::AY_emu) { - if ((address & 0xC002) == 0xC000) - return AySound::getRegisterData(); - } + // Handle non ULA ports. + switch (address & 0xFF) { + case 0x1F: + // Kempston joystick interface. + if (Config::joystick) result = port[0x1f]; + break; + case 0xFD: + // AY Register + if ((address == 0xFFFD) && (ESPectrum::AY_emu)) result = AySound::getRegisterData(); + break; + case 0xDF: + // Normally, the Kempston joystick interface + // uses port 0x1F, but some games checks port + // 0xDF instead, which the emulator reserves for + // the Kempston mouse if it is enabled, but if + // there is no mouse, port 0xDF will be connected + // to the joystick. + if (Config::joystick) result = port[0x1f]; + break; + default: + // Unattached ports. + result = VIDEO::getFloatBusData(); + if ((!Z80Ops::is48) && ((address & 0x8002) == 0)) { + + // // Solo en el modelo 128K, pero no en los +2/+2A/+3, si se lee el puerto + // // 0x7ffd, el valor leído es reescrito en el puerto 0x7ffd. + // // http://www.speccy.org/foro/viewtopic.php?f=8&t=2374 + if (!MemESP::pagingLock) { + MemESP::pagingLock = bitRead(result, 5); + MemESP::bankLatch = result & 0x7; + MemESP::ramCurrent[3] = (unsigned char *)MemESP::ram[MemESP::bankLatch]; + MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; + if (MemESP::videoLatch != bitRead(result, 3)) { + MemESP::videoLatch = bitRead(result, 3); + // This, if not using the ptime128 draw version, fixs ptime and ptime128 + if (((address & 0x0001) != 0) && (MemESP::ramContended[address >> 14])) { + VIDEO::Draw(2, false); + CPU::tstates -= 2; + } + VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; + } + MemESP::romLatch = bitRead(result, 4); + bitWrite(MemESP::romInUse, 0, MemESP::romLatch); + MemESP::ramCurrent[0] = (unsigned char *)MemESP::rom[MemESP::romInUse]; + } - uint8_t data = VIDEO::getFloatBusData(); - - if ((!Z80Ops::is48) && ((address & 0x8002) == 0)) { - - // // Solo en el modelo 128K, pero no en los +2/+2A/+3, si se lee el puerto - // // 0x7ffd, el valor leído es reescrito en el puerto 0x7ffd. - // // http://www.speccy.org/foro/viewtopic.php?f=8&t=2374 - if (!MemESP::pagingLock) { - MemESP::pagingLock = bitRead(data, 5); - MemESP::bankLatch = data & 0x7; - MemESP::ramCurrent[3] = (unsigned char *)MemESP::ram[MemESP::bankLatch]; - MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; - if (MemESP::videoLatch != bitRead(data, 3)) { - MemESP::videoLatch = bitRead(data, 3); - // This, if not using the ptime128 draw version, fixs ptime and ptime128 - if (((address & 0x0001) != 0) && (MemESP::ramContended[address >> 14])) { - VIDEO::Draw(2, false); - CPU::tstates -= 2; } - VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; - } - MemESP::romLatch = bitRead(data, 4); - bitWrite(MemESP::romInUse, 0, MemESP::romLatch); - MemESP::ramCurrent[0] = (unsigned char *)MemESP::rom[MemESP::romInUse]; + break; } - } - return data & 0xff; + return result; + + // // Kempston Joystick + // if ((Config::joystick) && ((address & 0x00E0) == 0 || (address & 0xFF) == 0xDF)) return port[0x1f]; + + // // ULA PORT + // if ((address & 0x0001) == 0) { + + // uint8_t result = 0xbf; + + // uint8_t portHigh = ~(address >> 8) & 0xff; + // for (int row = 0, mask = 0x01; row < 8; row++, mask <<= 1) { + // if ((portHigh & mask) != 0) { + // result &= port[row]; + // } + // } + + // if (Tape::tapeStatus==TAPE_LOADING) { + // Tape::TAP_Read(); + // bitWrite(result,6,Tape::tapeEarBit); + // } + + // return result | (0xa0); // OR 0xa0 -> ISSUE 2 + + // } + + // // Sound (AY-3-8912) + // if (ESPectrum::AY_emu) { + // if ((address & 0xC002) == 0xC000) + // return AySound::getRegisterData(); + // } + + // uint8_t data = VIDEO::getFloatBusData(); + + // if ((!Z80Ops::is48) && ((address & 0x8002) == 0)) { + + // // // Solo en el modelo 128K, pero no en los +2/+2A/+3, si se lee el puerto + // // // 0x7ffd, el valor leído es reescrito en el puerto 0x7ffd. + // // // http://www.speccy.org/foro/viewtopic.php?f=8&t=2374 + // if (!MemESP::pagingLock) { + // MemESP::pagingLock = bitRead(data, 5); + // MemESP::bankLatch = data & 0x7; + // MemESP::ramCurrent[3] = (unsigned char *)MemESP::ram[MemESP::bankLatch]; + // MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; + // if (MemESP::videoLatch != bitRead(data, 3)) { + // MemESP::videoLatch = bitRead(data, 3); + // // This, if not using the ptime128 draw version, fixs ptime and ptime128 + // if (((address & 0x0001) != 0) && (MemESP::ramContended[address >> 14])) { + // VIDEO::Draw(2, false); + // CPU::tstates -= 2; + // } + // VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; + // } + // MemESP::romLatch = bitRead(data, 4); + // bitWrite(MemESP::romInUse, 0, MemESP::romLatch); + // MemESP::ramCurrent[0] = (unsigned char *)MemESP::rom[MemESP::romInUse]; + // } + + // } + + // return data & 0xff; } @@ -152,6 +233,8 @@ void IRAM_ATTR Ports::output(uint16_t address, uint8_t data) { // ULA ======================================================================= if ((address & 0x0001) == 0) { + port254 = data; + // Border color if (VIDEO::borderColor != data & 0x07) { VIDEO::borderColor = data & 0x07; diff --git a/src/Video.cpp b/src/Video.cpp index 9fc34883..d3e7bf96 100644 --- a/src/Video.cpp +++ b/src/Video.cpp @@ -529,7 +529,7 @@ void IRAM_ATTR VIDEO::MainScreenLB(unsigned int statestoadd, bool contended) { // ------------------------------- // Non ptime-128 compliant version // ------------------------------- -void IRAM_ATTR VIDEO::MainScreen(unsigned int statestoadd, bool contended) { +void VIDEO::MainScreen(unsigned int statestoadd, bool contended) { uint8_t att, bmp; diff --git a/src/ZXKeyb.cpp b/src/ZXKeyb.cpp index 3bfdcb21..88a8a283 100644 --- a/src/ZXKeyb.cpp +++ b/src/ZXKeyb.cpp @@ -59,7 +59,7 @@ void ZXKeyb::setup() ZXKeyb::Exists = gpio_get_level((gpio_num_t)KM_COL_1) && gpio_get_level((gpio_num_t)KM_COL_2) && gpio_get_level((gpio_num_t)KM_COL_4); // set all keys as not pressed - if (ZXKeyb::Exists) for (uint8_t i = 0; i < 8; i++) ZXcols[i] = 0x1f; + if (ZXKeyb::Exists) for (uint8_t i = 0; i < 8; i++) ZXcols[i] = 0xbf; } From 39346aeb3966d3c2e6ab2a66fed75baf43861c55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Fri, 14 Jul 2023 02:02:31 +0200 Subject: [PATCH 09/29] New tape browser --- include/CPU.h | 8 +- include/OSDMain.h | 2 + include/Tape.h | 26 ++++ include/Video.h | 6 +- include/messages.h | 12 +- src/CPU.cpp | 4 +- src/FileSNA.cpp | 8 +- src/FileZ80.cpp | 8 +- src/OSDMain.cpp | 50 ++++--- src/OSDMenu.cpp | 352 ++++++++++++++++++++++++++++++++++++++++++++- src/Tape.cpp | 208 ++++++++++++++++++++++++--- src/Video.cpp | 22 +-- 12 files changed, 640 insertions(+), 66 deletions(-) diff --git a/include/CPU.h b/include/CPU.h index a17807b3..ac992601 100644 --- a/include/CPU.h +++ b/include/CPU.h @@ -57,7 +57,13 @@ class CPU static void setup(); // call this for executing a frame's worth of instructions - static void IRAM_ATTR loop(); + static void IRAM_ATTR loop_fast(); + + // call this for executing a frame's worth of instructions + static void IRAM_ATTR loop_trap(); + + // call this for executing a frame's worth of instructions + static void IRAM_ATTR (*loop)(); // call this for resetting the CPU static void reset(); diff --git a/include/OSDMain.h b/include/OSDMain.h index c54b0a16..023972fa 100644 --- a/include/OSDMain.h +++ b/include/OSDMain.h @@ -94,8 +94,10 @@ class OSD static string getRomsetMenu(string arch); static unsigned short menuRun(string new_menu); static string menuFile(string new_menu, string title, string extensions); + static int menuTape(string title); static void menuScroll(bool up); static void filemenuRedraw(string title); + static void tapemenuRedraw(string title); static void filemenuPrintRow(uint8_t virtual_row_num, uint8_t line_type); static void menuAt(short int row, short int col); static void menuScrollBar(); diff --git a/include/Tape.h b/include/Tape.h index 8f196167..4053bd66 100644 --- a/include/Tape.h +++ b/include/Tape.h @@ -37,6 +37,7 @@ visit https://zxespectrum.speccy.org/contacto #define Tape_h #include +#include #include using namespace std; @@ -72,6 +73,28 @@ using namespace std; #define TAPE_BLK_PAUSELEN 1750000UL // 1/2 second of pause between blocks //#define TAPE_BLK_PAUSELEN 875000UL // 1/4 second of pause between blocks +class TapeBlock +{ +public: + enum BlockType { + Program_header, + Number_array_header, + Character_array_header, + Code_header, + Data_block, + Info, + Unassigned + }; + uint8_t Index; // Index (position) of the tape block in the tape file. + BlockType Type; // Type of tape block (enum). + char FileName[11]; // File name in header block. + bool IsHeaderless; // Set to true for data blocks without a header. + uint8_t Checksum; // Header checksum byte. + uint8_t BlockTypeNum; // Block type, 0x00 = header; 0xFF = data block. + uint32_t StartPosition; // Where in the translated tape data is the start point of this block? + uint16_t BlockLength; +}; + class Tape { public: @@ -83,7 +106,10 @@ class Tape static uint8_t tapeStatus; static uint8_t SaveStatus; static uint8_t romLoading; + static uint16_t tapeCurBlock; + static std::vector TapeListing; + static void Init(); static void Open(string name); static void TAP_Play(); diff --git a/include/Video.h b/include/Video.h index 01a70b75..3e7daa5f 100644 --- a/include/Video.h +++ b/include/Video.h @@ -127,10 +127,10 @@ class VIDEO static uint8_t flashing; static uint8_t flash_ctr; - static uint8_t dispUpdCycle; + // static uint8_t dispUpdCycle; - static uint8_t contendOffset; - static uint8_t contendMod; + // static uint8_t contendOffset; + // static uint8_t contendMod; static bool OSD; diff --git a/include/messages.h b/include/messages.h index f9812d99..76da945d 100644 --- a/include/messages.h +++ b/include/messages.h @@ -97,14 +97,14 @@ static const char *MENU_SNA[2] = { MENU_SNA_EN,MENU_SNA_ES }; #define MENU_TAPE_EN \ "Tape menu\n"\ - "Select TAP \t[F5] >\n"\ - "Play/Pause \t[F6] \n"\ - "Stop \t[F7] \n" + "Select TAP \t[F5] >\n"\ + "Play/Stop \t[F6] \n"\ + "Tape browser \t[F7] \n" #define MENU_TAPE_ES \ "Casete\n"\ - "Elegir TAP \t[F5] >\n"\ - "Play/Pausa \t[F6] \n"\ - "Stop \t[F7] \n" + "Elegir TAP \t[F5] >\n"\ + "Play/Stop \t[F6] \n"\ + "Navegador cinta \t[F7] \n" static const char *MENU_TAPE[2] = { MENU_TAPE_EN,MENU_TAPE_ES }; #define MENU_MAIN_EN /*"Main Menu\n"*/ \ diff --git a/src/CPU.cpp b/src/CPU.cpp index 300f7a38..1cb98c89 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -47,6 +47,8 @@ visit https://zxespectrum.speccy.org/contacto static bool createCalled = false; +void (*CPU::loop)() = &CPU::loop_fast; + uint32_t CPU::statesPerFrame() { if (Config::getArch() == "48K") return 69888; @@ -126,7 +128,7 @@ void CPU::reset() { /////////////////////////////////////////////////////////////////////////////// -void IRAM_ATTR CPU::loop() +void IRAM_ATTR CPU::loop_fast() { while (tstates < IntEnd) { diff --git a/src/FileSNA.cpp b/src/FileSNA.cpp index a1aa0c9d..662e7d26 100644 --- a/src/FileSNA.cpp +++ b/src/FileSNA.cpp @@ -296,8 +296,8 @@ bool FileSNA::load(string sna_fn) CPU::IntStart = INT_START48; CPU::IntEnd = INT_END48 + CPU::latetiming; - VIDEO::contendMod=224; - VIDEO::contendOffset=1; + // VIDEO::contendMod=224; + // VIDEO::contendOffset=1; } else { @@ -317,8 +317,8 @@ bool FileSNA::load(string sna_fn) CPU::IntStart = INT_START128; CPU::IntEnd = INT_END128 + CPU::latetiming; - VIDEO::contendMod=228; - VIDEO::contendOffset=3; + // VIDEO::contendMod=228; + // VIDEO::contendOffset=3; } diff --git a/src/FileZ80.cpp b/src/FileZ80.cpp index b3184771..76ccef8a 100644 --- a/src/FileZ80.cpp +++ b/src/FileZ80.cpp @@ -389,8 +389,8 @@ bool FileZ80::load(string z80_fn) CPU::IntStart = INT_START48; CPU::IntEnd = INT_END48 + CPU::latetiming; - VIDEO::contendMod=224; - VIDEO::contendOffset=1; + // VIDEO::contendMod=224; + // VIDEO::contendOffset=1; } else { @@ -410,8 +410,8 @@ bool FileZ80::load(string z80_fn) CPU::IntStart = INT_START128; CPU::IntEnd = INT_END128 + CPU::latetiming; - VIDEO::contendMod=228; - VIDEO::contendOffset=3; + // VIDEO::contendMod=228; + // VIDEO::contendOffset=3; } diff --git a/src/OSDMain.cpp b/src/OSDMain.cpp index cd6dc14e..236a7152 100644 --- a/src/OSDMain.cpp +++ b/src/OSDMain.cpp @@ -258,27 +258,34 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { menu_curopt = 1; string mFile = menuFile(FileUtils::MountPoint + DISK_TAP_DIR, MENU_TAP_TITLE[Config::lang],".tap.TAP"); if (mFile != "") { + Tape::TAP_Stop(); // Read and analyze tape file Tape::Open(FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile); // Tape::tapeFileName=FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile; } } else if (KeytoESP == fabgl::VK_F6) { + // Start / Stop .tap reproduction + Tape::TAP_Play(); + click(); + } + else if (KeytoESP == fabgl::VK_F7) { - // Start .tap reproduction + // Tape Browser if (Tape::tapeFileName=="none") { OSD::osdCenteredMsg(OSD_TAPE_SELECT_ERR[Config::lang], LEVEL_WARN); } else { - Tape::TAP_Play(); - click(); + menu_level = 0; + menu_curopt = 1; + int tBlock = menuTape(Tape::tapeFileName.substr(6,28)); + if (tBlock >= 0) { + Tape::tapeCurBlock = tBlock; + Tape::TAP_Stop(); + Tape::TAP_Play(); + } } } - else if (KeytoESP == fabgl::VK_F7) { - // Stop .tap reproduction - Tape::TAP_Stop(); - click(); - } else if (KeytoESP == fabgl::VK_F8) { // Show / hide OnScreen Stats if (VIDEO::OSD) { @@ -453,34 +460,43 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { // Tape menu uint8_t tap_num = menuRun(MENU_TAPE[Config::lang]); if (tap_num > 0) { + menu_level = 2; + menu_saverect = true; if (tap_num == 1) { - menu_level = 2; - menu_saverect = true; menu_curopt = 1; // Select TAP File string mFile = menuFile(FileUtils::MountPoint + DISK_TAP_DIR, MENU_TAP_TITLE[Config::lang],".tap.TAP"); if (mFile != "") { + Tape::TAP_Stop(); // Read and analyze tape file Tape::Open(FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile); - // Tape::tapeFileName=FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile; return; } } else if (tap_num == 2) { - // Start .tap reproduction + // Start / Stop .tap reproduction + Tape::TAP_Play(); + return; + } + else if (tap_num == 3) { + // Tape Browser if (Tape::tapeFileName=="none") { OSD::osdCenteredMsg(OSD_TAPE_SELECT_ERR[Config::lang], LEVEL_WARN); menu_curopt = 2; menu_saverect = false; } else { - Tape::TAP_Play(); + menu_level = 0; + menu_saverect = false; + menu_curopt = 1; + int tBlock = menuTape(Tape::tapeFileName.substr(6,28)); + if (tBlock >= 0) { + Tape::tapeCurBlock = tBlock; + Tape::TAP_Stop(); + Tape::TAP_Play(); + } return; } } - else if (tap_num == 3) { - Tape::TAP_Stop(); - return; - } } else { menu_curopt = 2; break; diff --git a/src/OSDMenu.cpp b/src/OSDMenu.cpp index 24fbe833..ebd95ce2 100644 --- a/src/OSDMenu.cpp +++ b/src/OSDMenu.cpp @@ -52,6 +52,7 @@ using namespace std; #include "ZXKeyb.h" #include "pwm_audio.h" #include "Z80_JLS/z80.h" +#include "Tape.h" #define MENU_MAX_ROWS 18 // Line type @@ -188,7 +189,10 @@ void OSD::menuPrintRow(uint8_t virtual_row_num, uint8_t line_type) { uint8_t margin; - string line = rowGet(menu, menuRealRowFor(virtual_row_num)); + // string line = rowGet(menu, menuRealRowFor(virtual_row_num)); + string line = rowGet(menu, virtual_row_num); + + printf("%s\n",line.c_str()); switch (line_type) { case IS_TITLE: @@ -958,3 +962,349 @@ void OSD::filemenuRedraw(string title) { last_begin_row = begin_row; } } + +// Redraw inside rows +void OSD::tapemenuRedraw(string title) { + if ((focus != last_focus) || (begin_row != last_begin_row)) { + + // Read bunch of rows + menu = title + "\n"; + char buf[256]; + for (int i = begin_row - 1; i < virtual_rows + begin_row - 2; i++) { + if (i > Tape::TapeListing.size()) break; + + string blktype; + switch (Tape::TapeListing[i].Type) { + case 0: + blktype = "Program "; + break; + case 1: + blktype = "Number array "; + break; + case 2: + blktype = "Char array "; + break; + case 3: + blktype = "Code "; + break; + case 4: + blktype = "Data block "; + break; + case 5: + blktype = "Info "; + break; + case 6: + blktype = "Unassigned "; + break; + } + + snprintf(buf, sizeof(buf), "%02d %s %10s % 6d\n", Tape::TapeListing[i].Index, blktype.c_str(), Tape::TapeListing[i].FileName, Tape::TapeListing[i].BlockLength); + + menu += buf; + + } + + for (uint8_t row = 1; row < virtual_rows; row++) { + if (row == focus) { + filemenuPrintRow(row, IS_FOCUSED); + } else { + filemenuPrintRow(row, IS_NORMAL); + } + } + + menuScrollBar(); + + last_focus = focus; + last_begin_row = begin_row; + } +} + +// Run a new file menu +int OSD::menuTape(string title) { + + fabgl::VirtualKeyItem Menukey; + + // Tape::TapeListing.erase(Tape::TapeListing.begin(),Tape::TapeListing.begin() + 2); + + real_rows = Tape::TapeListing.size() + 1; + virtual_rows = (real_rows > 19 ? 19 : real_rows); + begin_row = last_begin_row = last_focus = focus = 1; + + if (Tape::tapeCurBlock > 17) { + begin_row = Tape::tapeCurBlock - 16; + focus = 18; + } else{ + begin_row = 1; + focus = Tape::tapeCurBlock + 1; + } + last_focus = focus; + last_begin_row = begin_row; + menu_curopt = focus; + + // Get first bunch of rows + menu = title + "\n"; + char buf[256]; + for (int i = (begin_row - 1); i < (begin_row - 1) + (virtual_rows - 1); i++) { + + if (i > Tape::TapeListing.size()) break; + + string blktype; + switch (Tape::TapeListing[i].Type) { + case 0: + blktype = "Program "; + break; + case 1: + blktype = "Number array "; + break; + case 2: + blktype = "Char array "; + break; + case 3: + blktype = "Code "; + break; + case 4: + blktype = "Data block "; + break; + case 5: + blktype = "Info "; + break; + case 6: + blktype = "Unassigned "; + break; + } + + snprintf(buf, sizeof(buf), "%02d %s %10s % 6d\n", Tape::TapeListing[i].Index, blktype.c_str(), Tape::TapeListing[i].FileName, Tape::TapeListing[i].BlockLength); + + // printf("%02d %s %10s % 6d\n", Tape::TapeListing[i].Index, blktype.c_str(), Tape::TapeListing[i].FileName, Tape::TapeListing[i].BlockLength); + + menu += buf; + + } + + printf(menu.c_str()); + + // Position + if (menu_level == 0) { + x = (Config::aspect_16_9 ? 24 : 8); + y = 8; + } else { + x = (Config::aspect_16_9 ? 24 : 8) + (60 * menu_level); + y = 8 + (16 * menu_level); + } + + // Columns + cols = 37; // 34 for block info + 2 pre and post space + 1 for scrollbar + + // Size + w = (cols * OSD_FONT_W) + 2; + h = (virtual_rows * OSD_FONT_H) + 2; + + menuDraw(); + + zxDelay = REPDEL; + lastzxKey = 0; + + while (1) { + + if (ZXKeyb::Exists) { + + ZXKeyb::process(); + + if (!bitRead(ZXKeyb::ZXcols[4], 3)) { // 6 DOWN + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_UP, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_UP, false, false); + if (lastzxKey == 1) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 1; + } + } else + if (!bitRead(ZXKeyb::ZXcols[4], 4)) { // 7 UP (Yes, like the drink's name, I know... :D) + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_DOWN, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_DOWN, false, false); + if (lastzxKey == 2) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 2; + } + } else + if ((!bitRead(ZXKeyb::ZXcols[6], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 0))) { // ENTER + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, false, false); + if (lastzxKey == 3) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 3; + } + } else + if ((!bitRead(ZXKeyb::ZXcols[7], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 1))) { // BREAK + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, false, false); + if (lastzxKey == 4) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 4; + } + } else + if (!bitRead(ZXKeyb::ZXcols[3], 4)) { // LEFT + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEUP, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEUP, false, false); + if (lastzxKey == 5) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 5; + } + } else + if (!bitRead(ZXKeyb::ZXcols[4], 2)) { // RIGHT + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEDOWN, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEDOWN, false, false); + if (lastzxKey == 6) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 6; + } + } else + if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q (Capture screen) + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, false, false); + if (lastzxKey == 7) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 7; + } + } else + { + zxDelay = 0; + lastzxKey = 0; + } + + } + + // Process external keyboard + if (ESPectrum::PS2Controller.keyboard()->virtualKeyAvailable()) { + if (ESPectrum::readKbd(&Menukey)) { + + if (!Menukey.down) continue; + + if (Menukey.vk == fabgl::VK_UP) { + if (focus == 1 and begin_row > 1) { + if (begin_row > 1) { + last_begin_row = begin_row; + begin_row--; + } + tapemenuRedraw(title); + click(); + } else if (focus > 1) { + last_focus = focus; + focus--; + filemenuPrintRow(focus, IS_FOCUSED); + filemenuPrintRow(focus + 1, IS_NORMAL); + click(); + } + } else if (Menukey.vk == fabgl::VK_DOWN) { + if (focus == virtual_rows - 1) { + if ((begin_row + virtual_rows - 1) < real_rows) { + last_begin_row = begin_row; + begin_row++; + tapemenuRedraw(title); + click(); + } + } else if (focus < virtual_rows - 1) { + last_focus = focus; + focus++; + filemenuPrintRow(focus, IS_FOCUSED); + filemenuPrintRow(focus - 1, IS_NORMAL); + click(); + } + } else if ((Menukey.vk == fabgl::VK_PAGEUP) || (Menukey.vk == fabgl::VK_LEFT)) { + // printf("%u\n",begin_row); + if (begin_row > virtual_rows) { + last_focus = focus; + last_begin_row = begin_row; + focus = 1; + begin_row -= virtual_rows - 1; + tapemenuRedraw(title); + click(); + } else { + last_focus = focus; + last_begin_row = begin_row; + focus = 1; + begin_row = 1; + tapemenuRedraw(title); + click(); + } + } else if ((Menukey.vk == fabgl::VK_PAGEDOWN) || (Menukey.vk == fabgl::VK_RIGHT)) { + if (real_rows - begin_row - virtual_rows > virtual_rows) { + last_focus = focus; + last_begin_row = begin_row; + focus = 1; + begin_row += virtual_rows - 1; + tapemenuRedraw(title); + click(); + } else { + last_focus = focus; + last_begin_row = begin_row; + focus = virtual_rows - 1; + begin_row = real_rows - virtual_rows + 1; + tapemenuRedraw(title); + click(); + } + } else if (Menukey.vk == fabgl::VK_HOME) { + last_focus = focus; + last_begin_row = begin_row; + focus = 1; + begin_row = 1; + tapemenuRedraw(title); + click(); + } else if (Menukey.vk == fabgl::VK_END) { + last_focus = focus; + last_begin_row = begin_row; + focus = virtual_rows - 1; + begin_row = real_rows - virtual_rows + 1; + tapemenuRedraw(title); + click(); + } else if (Menukey.vk == fabgl::VK_RETURN) { + click(); + return (begin_row + focus - 2); + } else if (Menukey.vk == fabgl::VK_ESCAPE) { + + if (menu_level!=0) { + // Restore backbuffer data + int j = SaveRectpos - (((w >> 2) + 1) * h); + SaveRectpos = j - 4; + for (int m = y; m < y + h; m++) { + uint32_t *backbuffer32 = (uint32_t *)(VIDEO::vga.backBuffer[m]); + for (int n = x >> 2; n < ((x + w) >> 2) + 1; n++) { + backbuffer32[n] = VIDEO::SaveRect[j]; + j++; + } + } + menu_saverect = false; + } + click(); + return -1; + } + } + } + + vTaskDelay(5 / portTICK_PERIOD_MS); + + if (zxDelay > 0) zxDelay--; + + } +} + diff --git a/src/Tape.cpp b/src/Tape.cpp index 16cb20c7..9dcac246 100644 --- a/src/Tape.cpp +++ b/src/Tape.cpp @@ -35,6 +35,7 @@ visit https://zxespectrum.speccy.org/contacto #include #include +#include #include using namespace std; @@ -54,6 +55,8 @@ uint8_t Tape::tapeStatus = TAPE_STOPPED; uint8_t Tape::SaveStatus = SAVE_STOPPED; uint8_t Tape::romLoading = false; uint8_t Tape::tapeEarBit; +std::vector Tape::TapeListing; +uint16_t Tape::tapeCurBlock; static uint8_t tapeCurByte; static uint8_t tapePhase; @@ -65,7 +68,8 @@ static uint32_t tapebufByteCount; static uint16_t tapeHdrPulses; static uint32_t tapeBlockLen; static size_t tapeFileSize; -static uint8_t tapeBitMask; +static uint8_t tapeBitMask; + // static uint8_t tapeReadBuf[4096] = { 0 }; void Tape::Init() @@ -73,21 +77,184 @@ void Tape::Init() tape = NULL; } -void Tape::Open(string name) -{ - Tape::tapeFileName = name; +void Tape::Open(string name) { + + FILE *file; - tape = fopen(Tape::tapeFileName.c_str(), "rb"); - if (tape == NULL) - { + file = fopen(name.c_str(), "rb"); + if (file == NULL) { OSD::osdCenteredMsg(OSD_TAPE_LOAD_ERR, LEVEL_ERROR); return; } + + fseek(file,0,SEEK_END); + long tSize = ftell(file); + rewind(file); + if (tSize == 0) return; - // Analyze .tap file - + tapeFileName = name; - fclose(tape); + Tape::TapeListing.clear(); // Clear TapeListing vector + std::vector().swap(TapeListing); // free memory + + int tapeListIndex=0; + int tapeContentIndex=0; + int tapeBlkLen=0; + TapeBlock block; + do { + + // Analyze .tap file + tapeBlkLen=(readByteFile(file) | (readByteFile(file) << 8)); + + // printf("Analyzing block %d\n",tapeListIndex); + // printf(" Block Len: %d\n",tapeBlockLen - 2); + + // Read the flag byte from the block. + // If the last block is a fragmented data block, there is no flag byte, so set the flag to 255 + // to indicate a data block. + uint8_t flagByte; + if (tapeContentIndex + 2 < tSize) { + flagByte = readByteFile(file); + } else { + flagByte = 255; + } + + // Process the block depending on if it is a header or a data block. + // Block type 0 should be a header block, but it happens that headerless blocks also + // have block type 0, so we need to check the block length as well. + if (flagByte == 0 && tapeBlkLen == 19) { // This is a header. + + // Get the block type. + TapeBlock::BlockType dataBlockType; + uint8_t blocktype = readByteFile(file); + switch (blocktype) + { + case 0: + dataBlockType = TapeBlock::BlockType::Program_header; + break; + case 1: + dataBlockType = TapeBlock::BlockType::Number_array_header; + break; + case 2: + dataBlockType = TapeBlock::BlockType::Character_array_header; + break; + case 3: + dataBlockType = TapeBlock::BlockType::Code_header; + break; + default: + dataBlockType = TapeBlock::BlockType::Unassigned; + break; + } + + // Get the filename. + for (int i = 0; i < 10; i++) { + block.FileName[i] = readByteFile(file); + } + block.FileName[10]='\0'; + + fseek(file,6,SEEK_CUR); + + // Get the checksum. + uint8_t checksum = readByteFile(file); + + block.Type = dataBlockType; + block.Index = tapeListIndex; + block.IsHeaderless = false; + block.Checksum = checksum; + block.BlockLength = 19; + block.BlockTypeNum = 0; + block.StartPosition = tapeContentIndex; + + TapeListing.push_back(block); + + } else { + + // Get the block content length. + int contentLength; + int contentOffset; + if (tapeBlkLen >= 2) { + // Normally the content length equals the block length minus two + // (the flag byte and the checksum are not included in the content). + contentLength = tapeBlkLen - 2; + // The content is found at an offset of 3 (two byte block size + one flag byte). + contentOffset = 3; + } else { + // Fragmented data doesn't have a flag byte or a checksum. + contentLength = tapeBlkLen; + // The content is found at an offset of 2 (two byte block size). + contentOffset = 2; + } + + // If the preceeding block is a data block, this is a headerless block. + bool isHeaderless; + if (tapeListIndex > 0 && TapeListing[tapeListIndex - 1].Type == TapeBlock::BlockType::Data_block) { + isHeaderless = true; + } else { + isHeaderless = false; + } + + fseek(file,contentLength,SEEK_CUR); + + // Get the checksum. + uint8_t checksum = readByteFile(file); + + block.FileName[0]='\0'; + block.Type = TapeBlock::BlockType::Data_block; + block.Index = tapeListIndex; + block.IsHeaderless = isHeaderless; + block.Checksum = checksum; + block.BlockLength = tapeBlkLen; + block.BlockTypeNum = flagByte; + block.StartPosition = tapeContentIndex; + + TapeListing.push_back(block); + + } + + tapeListIndex++; + + tapeContentIndex += tapeBlkLen + 2; + + } while(tapeContentIndex < tSize); + + // printf("------------------------------------\n"); + // for (int i = 0; i < tapeListIndex; i++) { + // printf("Block Index: %d\n",TapeListing[i].Index); + + // string blktype; + // switch (TapeListing[i].Type) { + // case 0: + // blktype = "Program header"; + // break; + // case 1: + // blktype = "Number array header"; + // break; + // case 2: + // blktype = "Character array header"; + // break; + // case 3: + // blktype = "Code header"; + // break; + // case 4: + // blktype = "Data block"; + // break; + // case 5: + // blktype = "Info"; + // break; + // case 6: + // blktype = "Unassigned"; + // break; + // } + // printf("Block Type : %s\n",blktype.c_str()); + + // printf("Filename : %s\n",(char *)TapeListing[i].FileName); + // printf("Lenght : %d\n",TapeListing[i].BlockLength); + // printf("Start Pos. : %d\n",TapeListing[i].StartPosition); + // printf("------------------------------------\n"); + + // } + + fclose(file); } @@ -109,34 +276,38 @@ void Tape::TAP_Play() tapeFileSize = ftell(tape); rewind (tape); + // Move to selected block position + fseek(tape,TapeListing[Tape::tapeCurBlock].StartPosition,SEEK_SET); + tapePhase=TAPE_PHASE_SYNC; tapePulseCount=0; tapeEarBit=0; tapeBitMask=0x80; tapeBitPulseCount=0; tapeBitPulseLen=TAPE_BIT0_PULSELEN; - tapeHdrPulses=TAPE_HDR_LONG; tapeBlockLen=(readByteFile(tape) | (readByteFile(tape) <<8)) + 2; tapeCurByte = readByteFile(tape); + if (tapeCurByte) tapeHdrPulses=TAPE_HDR_SHORT; else tapeHdrPulses=TAPE_HDR_LONG; tapebufByteCount=2; tapeStart=CPU::global_tstates + CPU::tstates; Tape::tapeStatus=TAPE_LOADING; break; case TAPE_LOADING: - Tape::tapeStatus=TAPE_PAUSED; + TAP_Stop(); break; - case TAPE_PAUSED: - tapeStart=CPU::global_tstates + CPU::tstates; - Tape::tapeStatus=TAPE_LOADING; + // case TAPE_PAUSED: + // tapeStart=CPU::global_tstates + CPU::tstates; + // Tape::tapeStatus=TAPE_LOADING; } } void Tape::TAP_Stop() { - Tape::tapeStatus=TAPE_STOPPED; + tapeStatus=TAPE_STOPPED; fclose(tape); + tape = NULL; } void IRAM_ATTR Tape::TAP_Read() @@ -183,6 +354,7 @@ void IRAM_ATTR Tape::TAP_Read() tapebufByteCount++; if (tapebufByteCount == tapeBlockLen) { tapePhase=TAPE_PHASE_PAUSE; + tapeCurBlock++; tapeEarBit=0; break; } @@ -203,8 +375,8 @@ void IRAM_ATTR Tape::TAP_Read() if (tapeCurByte) tapeHdrPulses=TAPE_HDR_SHORT; else tapeHdrPulses=TAPE_HDR_LONG; } } else { - Tape::tapeStatus=TAPE_STOPPED; - fclose(tape); + tapeCurBlock--; + TAP_Stop(); } } diff --git a/src/Video.cpp b/src/Video.cpp index d3e7bf96..63661d2b 100644 --- a/src/Video.cpp +++ b/src/Video.cpp @@ -55,9 +55,9 @@ int VIDEO::tStatesScreen; uint8_t* VIDEO::grmem; uint32_t* VIDEO::SaveRect; int VIDEO::VsyncFinetune[2]; -uint8_t VIDEO::dispUpdCycle; -uint8_t VIDEO::contendOffset; -uint8_t VIDEO::contendMod; +// uint8_t VIDEO::dispUpdCycle; +// uint8_t VIDEO::contendOffset; +// uint8_t VIDEO::contendMod; void IRAM_ATTR VGA6Bit::interrupt(void *arg) { @@ -255,8 +255,8 @@ void VIDEO::Init() { VsyncFinetune[0] = is169 ? 0 : 0; VsyncFinetune[1] = is169 ? 0 : 0; } - VIDEO::contendMod=224; - VIDEO::contendOffset=1; + // VIDEO::contendMod=224; + // VIDEO::contendOffset=1; } else { tStatesPerLine = TSTATES_PER_LINE_128; tStatesScreen = is169 ? TS_SCREEN_360x200_128 : TS_SCREEN_320x240_128; @@ -267,8 +267,8 @@ void VIDEO::Init() { VsyncFinetune[0] = is169 ? 0 : 0; VsyncFinetune[1] = is169 ? 0 : 0; } - VIDEO::contendMod=228; - VIDEO::contendOffset=3; + // VIDEO::contendMod=228; + // VIDEO::contendOffset=3; } #ifdef NO_VIDEO @@ -296,8 +296,8 @@ void VIDEO::Reset() { VsyncFinetune[0] = is169 ? 0 : 0; VsyncFinetune[1] = is169 ? 0 : 0; } - VIDEO::contendMod=224; - VIDEO::contendOffset=1; + // VIDEO::contendMod=224; + // VIDEO::contendOffset=1; } else { tStatesPerLine = TSTATES_PER_LINE_128; tStatesScreen = is169 ? TS_SCREEN_360x200_128 : TS_SCREEN_320x240_128; @@ -308,8 +308,8 @@ void VIDEO::Reset() { VsyncFinetune[0] = is169 ? 0 : 0; VsyncFinetune[1] = is169 ? 0 : 0; } - VIDEO::contendMod=228; - VIDEO::contendOffset=3; + // VIDEO::contendMod=228; + // VIDEO::contendOffset=3; } grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; From eb734ed42302229017f797fd9f4e3bafc8eec301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Fri, 14 Jul 2023 02:33:14 +0200 Subject: [PATCH 10/29] Tape load data in OSD --- src/ESPectrum.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ESPectrum.cpp b/src/ESPectrum.cpp index a0dff546..62e532be 100644 --- a/src/ESPectrum.cpp +++ b/src/ESPectrum.cpp @@ -1300,8 +1300,13 @@ for(;;) { #else - snprintf(linea1, sizeof(linea1), "CPU: %05d / IDL: %05d ", (int)(elapsed), (int)(idle)); - snprintf(linea2, sizeof(linea2), "FPS:%6.2f / FND:%6.2f ", CPU::framecnt / (totalseconds / 1000000), CPU::framecnt / (totalsecondsnodelay / 1000000)); + if (Tape::tapeStatus==TAPE_LOADING) { + snprintf(linea1, sizeof(linea1), "%02d/%02d %10s % 6d ", Tape::TapeListing[Tape::tapeCurBlock].Index, Tape::TapeListing.size() - 1, Tape::TapeListing[Tape::tapeCurBlock].FileName, Tape::TapeListing[Tape::tapeCurBlock].BlockLength); + snprintf(linea2, sizeof(linea2), "FPS:%6.2f / FND:%6.2f ", CPU::framecnt / (totalseconds / 1000000), CPU::framecnt / (totalsecondsnodelay / 1000000)); + } else { + snprintf(linea1, sizeof(linea1), "CPU: %05d / IDL: %05d ", (int)(elapsed), (int)(idle)); + snprintf(linea2, sizeof(linea2), "FPS:%6.2f / FND:%6.2f ", CPU::framecnt / (totalseconds / 1000000), CPU::framecnt / (totalsecondsnodelay / 1000000)); + } #endif } From 9f5ae56d72d4d7fa0452ed1d38417e79aa4a746a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Fri, 14 Jul 2023 02:39:26 +0200 Subject: [PATCH 11/29] Tape browser fix --- src/Tape.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Tape.cpp b/src/Tape.cpp index 9dcac246..393bd370 100644 --- a/src/Tape.cpp +++ b/src/Tape.cpp @@ -217,6 +217,8 @@ void Tape::Open(string name) { } while(tapeContentIndex < tSize); + tapeCurBlock = 0; + // printf("------------------------------------\n"); // for (int i = 0; i < tapeListIndex; i++) { // printf("Block Index: %d\n",TapeListing[i].Index); From 8e609d16e00827446e55ede4b800f5ac109cb83e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Fri, 14 Jul 2023 15:26:46 +0200 Subject: [PATCH 12/29] ZX Kbd Issue 2 fix --- src/OSDMenu.cpp | 2 +- src/ZXKeyb.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/OSDMenu.cpp b/src/OSDMenu.cpp index ebd95ce2..5c5e5066 100644 --- a/src/OSDMenu.cpp +++ b/src/OSDMenu.cpp @@ -192,7 +192,7 @@ void OSD::menuPrintRow(uint8_t virtual_row_num, uint8_t line_type) { // string line = rowGet(menu, menuRealRowFor(virtual_row_num)); string line = rowGet(menu, virtual_row_num); - printf("%s\n",line.c_str()); + // printf("%s\n",line.c_str()); switch (line_type) { case IS_TITLE: diff --git a/src/ZXKeyb.cpp b/src/ZXKeyb.cpp index 88a8a283..fffa2e39 100644 --- a/src/ZXKeyb.cpp +++ b/src/ZXKeyb.cpp @@ -159,7 +159,8 @@ uint8_t ZXKeyb::getCols() cols <<= 1; cols |= gpio_get_level((gpio_num_t)KM_COL_0); - // cols |= 0xE0; + // Keep bits 5,7 up + cols |= 0xa0; return cols; } From 9503617d32de65295061fb3b2da73b58e0249c0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Fri, 14 Jul 2023 20:37:40 +0200 Subject: [PATCH 13/29] Tape OSD done, fixes to tape logic & Ports::input --- include/Tape.h | 3 + src/ESPectrum.cpp | 3 +- src/Ports.cpp | 225 +++++++++++++++++++++++----------------------- src/Tape.cpp | 8 +- 4 files changed, 125 insertions(+), 114 deletions(-) diff --git a/include/Tape.h b/include/Tape.h index 4053bd66..faeed6f1 100644 --- a/include/Tape.h +++ b/include/Tape.h @@ -107,6 +107,9 @@ class Tape static uint8_t SaveStatus; static uint8_t romLoading; static uint16_t tapeCurBlock; + static uint32_t tapebufByteCount; + static uint32_t tapePlayOffset; + static size_t tapeFileSize; static std::vector TapeListing; diff --git a/src/ESPectrum.cpp b/src/ESPectrum.cpp index 62e532be..f08350fc 100644 --- a/src/ESPectrum.cpp +++ b/src/ESPectrum.cpp @@ -1302,7 +1302,8 @@ for(;;) { if (Tape::tapeStatus==TAPE_LOADING) { snprintf(linea1, sizeof(linea1), "%02d/%02d %10s % 6d ", Tape::TapeListing[Tape::tapeCurBlock].Index, Tape::TapeListing.size() - 1, Tape::TapeListing[Tape::tapeCurBlock].FileName, Tape::TapeListing[Tape::tapeCurBlock].BlockLength); - snprintf(linea2, sizeof(linea2), "FPS:%6.2f / FND:%6.2f ", CPU::framecnt / (totalseconds / 1000000), CPU::framecnt / (totalsecondsnodelay / 1000000)); + float percent = (float)((Tape::tapebufByteCount + Tape::tapePlayOffset) * 100) / (float)Tape::tapeFileSize; + snprintf(linea2, sizeof(linea2), "%5.2f%% %06d of %06d ", percent, Tape::tapebufByteCount + Tape::tapePlayOffset, Tape::tapeFileSize); } else { snprintf(linea1, sizeof(linea1), "CPU: %05d / IDL: %05d ", (int)(elapsed), (int)(idle)); snprintf(linea2, sizeof(linea2), "FPS:%6.2f / FND:%6.2f ", CPU::framecnt / (totalseconds / 1000000), CPU::framecnt / (totalsecondsnodelay / 1000000)); diff --git a/src/Ports.cpp b/src/Ports.cpp index 0570b1b0..be1270f0 100644 --- a/src/Ports.cpp +++ b/src/Ports.cpp @@ -83,9 +83,89 @@ uint8_t IRAM_ATTR Ports::input(uint16_t address) // The default port value is 0xBF. uint8_t result = 0xbf; - // The ULA functions (keybord and audio in) are accessible via all even numbered ports. - if ((address & 0x0001) == 0) { + // // The ULA functions (keybord and audio in) are accessible via all even numbered ports. + // if ((address & 0x0001) == 0) { + + // uint8_t portHigh = ~(address >> 8) & 0xff; + // for (int row = 0, mask = 0x01; row < 8; row++, mask <<= 1) { + // if ((portHigh & mask) != 0) { + // result &= port[row]; + // } + // } + + // if (Tape::tapeStatus==TAPE_LOADING) { + // Tape::TAP_Read(); + // bitWrite(result,6,Tape::tapeEarBit); + // } else { + // // Issue 2 behaviour only on Spectrum 48K + // if ((Z80Ops::is48) && (Config::Issue2)) { + // if (port254 & 0x18) result |= 0x40; + // } else { + // if (port254 & 0x10) result |= 0x40; + // } + // } + + // } else { + + // // Handle non ULA ports. + // switch (address & 0xFF) { + // case 0x1F: + // // Kempston joystick interface. + // if (Config::joystick) result = port[0x1f]; + // break; + // case 0xFD: + // // AY Register + // if ((address == 0xFFFD) && (ESPectrum::AY_emu)) result = AySound::getRegisterData(); + // break; + // case 0xDF: + // // Normally, the Kempston joystick interface + // // uses port 0x1F, but some games checks port + // // 0xDF instead, which the emulator reserves for + // // the Kempston mouse if it is enabled, but if + // // there is no mouse, port 0xDF will be connected + // // to the joystick. + // if (Config::joystick) result = port[0x1f]; + // break; + // default: + // // Unattached ports. + // result = VIDEO::getFloatBusData(); + // if ((!Z80Ops::is48) && ((address & 0x8002) == 0)) { + + // // // Solo en el modelo 128K, pero no en los +2/+2A/+3, si se lee el puerto + // // // 0x7ffd, el valor leído es reescrito en el puerto 0x7ffd. + // // // http://www.speccy.org/foro/viewtopic.php?f=8&t=2374 + // if (!MemESP::pagingLock) { + // MemESP::pagingLock = bitRead(result, 5); + // MemESP::bankLatch = result & 0x7; + // MemESP::ramCurrent[3] = (unsigned char *)MemESP::ram[MemESP::bankLatch]; + // MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; + // if (MemESP::videoLatch != bitRead(result, 3)) { + // MemESP::videoLatch = bitRead(result, 3); + // // This, if not using the ptime128 draw version, fixs ptime and ptime128 + // if (((address & 0x0001) != 0) && (MemESP::ramContended[address >> 14])) { + // VIDEO::Draw(2, false); + // CPU::tstates -= 2; + // } + // VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; + // } + // MemESP::romLatch = bitRead(result, 4); + // bitWrite(MemESP::romInUse, 0, MemESP::romLatch); + // MemESP::ramCurrent[0] = (unsigned char *)MemESP::rom[MemESP::romInUse]; + // } + + // } + // break; + // } + // } + + // return result; + // Kempston Joystick + if ((Config::joystick) && ((address & 0x00E0) == 0 || (address & 0xFF) == 0xDF)) return port[0x1f]; + + // ULA PORT + if ((address & 0x0001) == 0) { + uint8_t portHigh = ~(address >> 8) & 0xff; for (int row = 0, mask = 0x01; row < 8; row++, mask <<= 1) { if ((portHigh & mask) != 0) { @@ -104,121 +184,46 @@ uint8_t IRAM_ATTR Ports::input(uint16_t address) if (port254 & 0x10) result |= 0x40; } } - - } else { - - // Handle non ULA ports. - switch (address & 0xFF) { - case 0x1F: - // Kempston joystick interface. - if (Config::joystick) result = port[0x1f]; - break; - case 0xFD: - // AY Register - if ((address == 0xFFFD) && (ESPectrum::AY_emu)) result = AySound::getRegisterData(); - break; - case 0xDF: - // Normally, the Kempston joystick interface - // uses port 0x1F, but some games checks port - // 0xDF instead, which the emulator reserves for - // the Kempston mouse if it is enabled, but if - // there is no mouse, port 0xDF will be connected - // to the joystick. - if (Config::joystick) result = port[0x1f]; - break; - default: - // Unattached ports. - result = VIDEO::getFloatBusData(); - if ((!Z80Ops::is48) && ((address & 0x8002) == 0)) { - - // // Solo en el modelo 128K, pero no en los +2/+2A/+3, si se lee el puerto - // // 0x7ffd, el valor leído es reescrito en el puerto 0x7ffd. - // // http://www.speccy.org/foro/viewtopic.php?f=8&t=2374 - if (!MemESP::pagingLock) { - MemESP::pagingLock = bitRead(result, 5); - MemESP::bankLatch = result & 0x7; - MemESP::ramCurrent[3] = (unsigned char *)MemESP::ram[MemESP::bankLatch]; - MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; - if (MemESP::videoLatch != bitRead(result, 3)) { - MemESP::videoLatch = bitRead(result, 3); - // This, if not using the ptime128 draw version, fixs ptime and ptime128 - if (((address & 0x0001) != 0) && (MemESP::ramContended[address >> 14])) { - VIDEO::Draw(2, false); - CPU::tstates -= 2; - } - VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; - } - MemESP::romLatch = bitRead(result, 4); - bitWrite(MemESP::romInUse, 0, MemESP::romLatch); - MemESP::ramCurrent[0] = (unsigned char *)MemESP::rom[MemESP::romInUse]; - } - - } - break; - } - } - - return result; - - // // Kempston Joystick - // if ((Config::joystick) && ((address & 0x00E0) == 0 || (address & 0xFF) == 0xDF)) return port[0x1f]; - - // // ULA PORT - // if ((address & 0x0001) == 0) { - - // uint8_t result = 0xbf; - - // uint8_t portHigh = ~(address >> 8) & 0xff; - // for (int row = 0, mask = 0x01; row < 8; row++, mask <<= 1) { - // if ((portHigh & mask) != 0) { - // result &= port[row]; - // } - // } - // if (Tape::tapeStatus==TAPE_LOADING) { - // Tape::TAP_Read(); - // bitWrite(result,6,Tape::tapeEarBit); - // } - - // return result | (0xa0); // OR 0xa0 -> ISSUE 2 + return result; - // } + } - // // Sound (AY-3-8912) - // if (ESPectrum::AY_emu) { - // if ((address & 0xC002) == 0xC000) - // return AySound::getRegisterData(); - // } + // Sound (AY-3-8912) + if (ESPectrum::AY_emu) { + if ((address & 0xC002) == 0xC000) + return AySound::getRegisterData(); + } - // uint8_t data = VIDEO::getFloatBusData(); + uint8_t data = VIDEO::getFloatBusData(); - // if ((!Z80Ops::is48) && ((address & 0x8002) == 0)) { - - // // // Solo en el modelo 128K, pero no en los +2/+2A/+3, si se lee el puerto - // // // 0x7ffd, el valor leído es reescrito en el puerto 0x7ffd. - // // // http://www.speccy.org/foro/viewtopic.php?f=8&t=2374 - // if (!MemESP::pagingLock) { - // MemESP::pagingLock = bitRead(data, 5); - // MemESP::bankLatch = data & 0x7; - // MemESP::ramCurrent[3] = (unsigned char *)MemESP::ram[MemESP::bankLatch]; - // MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; - // if (MemESP::videoLatch != bitRead(data, 3)) { - // MemESP::videoLatch = bitRead(data, 3); - // // This, if not using the ptime128 draw version, fixs ptime and ptime128 - // if (((address & 0x0001) != 0) && (MemESP::ramContended[address >> 14])) { - // VIDEO::Draw(2, false); - // CPU::tstates -= 2; - // } - // VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; - // } - // MemESP::romLatch = bitRead(data, 4); - // bitWrite(MemESP::romInUse, 0, MemESP::romLatch); - // MemESP::ramCurrent[0] = (unsigned char *)MemESP::rom[MemESP::romInUse]; - // } + if ((!Z80Ops::is48) && ((address & 0x8002) == 0)) { - // } + // // Solo en el modelo 128K, pero no en los +2/+2A/+3, si se lee el puerto + // // 0x7ffd, el valor leído es reescrito en el puerto 0x7ffd. + // // http://www.speccy.org/foro/viewtopic.php?f=8&t=2374 + if (!MemESP::pagingLock) { + MemESP::pagingLock = bitRead(data, 5); + MemESP::bankLatch = data & 0x7; + MemESP::ramCurrent[3] = (unsigned char *)MemESP::ram[MemESP::bankLatch]; + MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; + if (MemESP::videoLatch != bitRead(data, 3)) { + MemESP::videoLatch = bitRead(data, 3); + // This, if not using the ptime128 draw version, fixs ptime and ptime128 + if (((address & 0x0001) != 0) && (MemESP::ramContended[address >> 14])) { + VIDEO::Draw(2, false); + CPU::tstates -= 2; + } + VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; + } + MemESP::romLatch = bitRead(data, 4); + bitWrite(MemESP::romInUse, 0, MemESP::romLatch); + MemESP::ramCurrent[0] = (unsigned char *)MemESP::rom[MemESP::romInUse]; + } + + } - // return data & 0xff; + return data; } diff --git a/src/Tape.cpp b/src/Tape.cpp index 393bd370..dc7aae36 100644 --- a/src/Tape.cpp +++ b/src/Tape.cpp @@ -57,6 +57,9 @@ uint8_t Tape::romLoading = false; uint8_t Tape::tapeEarBit; std::vector Tape::TapeListing; uint16_t Tape::tapeCurBlock; +uint32_t Tape::tapebufByteCount; +uint32_t Tape::tapePlayOffset; +size_t Tape::tapeFileSize; static uint8_t tapeCurByte; static uint8_t tapePhase; @@ -64,10 +67,8 @@ static uint64_t tapeStart; static uint32_t tapePulseCount; static uint16_t tapeBitPulseLen; static uint8_t tapeBitPulseCount; -static uint32_t tapebufByteCount; static uint16_t tapeHdrPulses; static uint32_t tapeBlockLen; -static size_t tapeFileSize; static uint8_t tapeBitMask; // static uint8_t tapeReadBuf[4096] = { 0 }; @@ -280,6 +281,7 @@ void Tape::TAP_Play() // Move to selected block position fseek(tape,TapeListing[Tape::tapeCurBlock].StartPosition,SEEK_SET); + tapePlayOffset = TapeListing[Tape::tapeCurBlock].StartPosition; tapePhase=TAPE_PHASE_SYNC; tapePulseCount=0; @@ -366,7 +368,7 @@ void IRAM_ATTR Tape::TAP_Read() } break; case TAPE_PHASE_PAUSE: - if (tapebufByteCount < tapeFileSize) { + if ((tapebufByteCount + tapePlayOffset) < tapeFileSize) { if (tapeCurrent > TAPE_BLK_PAUSELEN) { tapeStart=CPU::global_tstates + CPU::tstates; tapePulseCount=0; From c3b90b8a0daf5eac1679d09c7d40f480252ab1f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Wed, 19 Jul 2023 11:30:18 +0200 Subject: [PATCH 14/29] AY reg 15 emulation, Tape Save traps test --- include/AySound.h | 11 ++-- include/CPU.h | 2 + include/Tape.h | 1 + include/messages.h | 3 ++ src/AySound.cpp | 50 ++++++++--------- src/CPU.cpp | 99 +++++++++++++++++++++++++++------- src/ESPectrum.cpp | 2 +- src/Ports.cpp | 132 --------------------------------------------- src/Tape.cpp | 12 +++-- src/Video.cpp | 4 +- 10 files changed, 130 insertions(+), 186 deletions(-) diff --git a/include/AySound.h b/include/AySound.h index 8c68b428..2c4bc078 100644 --- a/include/AySound.h +++ b/include/AySound.h @@ -114,6 +114,8 @@ typedef struct int env_c; /**< R10 bit 4 */ int env_freq; /**< R11, R12 */ int env_style; /**< R13 */ + int IOPortA; /**< R14 */ + int IOPortB; /**< R15 */ } ayemu_regdata_t; @@ -140,7 +142,9 @@ class AySound static void updVolC(); static void updEnvFreq(); static void updEnvType(); - + static void updIOPortA(); + static void updIOPortB(); + static void reset(); static uint8_t getRegisterData(); static void selectRegister(uint8_t data); @@ -153,9 +157,8 @@ class AySound static int set_sound_format(int freq, int chans, int bits); static void prepare_generation(); static void gen_sound(int bufsize, int bufpos); - static void gen_sound_speech_test(unsigned char *buff, size_t sound_bufsize, int bufpos); - static void(*updateReg[14])(); + static void(*updateReg[16])(); static uint8_t SamplebufAY[ESP_AUDIO_SAMPLES_48]; @@ -196,7 +199,7 @@ class AySound static int env_pos; /**< current position in envelop (0...127) */ static int Cur_Seed; /**< random numbers counter */ - static uint8_t regs[14]; + static uint8_t regs[16]; static uint8_t selectedRegister; }; diff --git a/include/CPU.h b/include/CPU.h index ac992601..58542601 100644 --- a/include/CPU.h +++ b/include/CPU.h @@ -65,6 +65,8 @@ class CPU // call this for executing a frame's worth of instructions static void IRAM_ATTR (*loop)(); + static void IRAM_ATTR checkTraps(); + // call this for resetting the CPU static void reset(); diff --git a/include/Tape.h b/include/Tape.h index faeed6f1..dac9b579 100644 --- a/include/Tape.h +++ b/include/Tape.h @@ -102,6 +102,7 @@ class Tape // Tape static FILE *tape; static string tapeFileName; + static string tapeSaveName; static uint8_t tapeEarBit; static uint8_t tapeStatus; static uint8_t SaveStatus; diff --git a/include/messages.h b/include/messages.h index 76da945d..2e4a1d34 100644 --- a/include/messages.h +++ b/include/messages.h @@ -70,6 +70,7 @@ static const char *OSD_PAUSE[2] = { OSD_PAUSE_EN,OSD_PAUSE_ES }; #define OSD_PSNA_LOAD_ERR "ERROR Loading Persist Snapshot" #define OSD_PSNA_SAVED " Persist Snapshot Saved " #define OSD_TAPE_LOAD_ERR "ERROR Loading TAP file" +#define OSD_TAPE_SAVE_ERR "ERROR Saving TAP file" #define OSD_TAPE_SELECT_ERR_EN "No TAP selected" #define OSD_TAPE_SELECT_ERR_ES "TAP no seleccionado" @@ -388,4 +389,6 @@ static const char *OSD_ABOUT[2] = { OSD_ABOUT_EN, OSD_ABOUT_ES }; " [ImpPant] Captura BMP (Carpeta SD /c)\n" static const char *OSD_HELP[2] = { OSD_HELP_EN, OSD_HELP_ES }; +static const char *OSD_TAPE_OF[2] = { "of", "de" }; + #endif // ESPECTRUM_MESSAGES_h diff --git a/src/AySound.cpp b/src/AySound.cpp index 2b1b5ce5..da6eee57 100644 --- a/src/AySound.cpp +++ b/src/AySound.cpp @@ -77,14 +77,14 @@ int AySound::EnvNum; /**< number of current envilopment (0... int AySound::env_pos; /**< current position in envelop (0...127) */ int AySound::Cur_Seed; /**< random numbers counter */ -uint8_t AySound::regs[14]; +uint8_t AySound::regs[16]; uint8_t AySound::SamplebufAY[ESP_AUDIO_SAMPLES_48] = { 0 }; -void (*AySound::updateReg[14])() = { +void (*AySound::updateReg[16])() = { &updToneA,&updToneA,&updToneB,&updToneB,&updToneC, &updToneC,&updNoisePitch,&updMixer,&updVolA,&updVolB, - &updVolC,&updEnvFreq,&updEnvFreq,&updEnvType + &updVolC,&updEnvFreq,&updEnvFreq,&updEnvType,&updIOPortA,&updIOPortB }; // Status @@ -477,9 +477,22 @@ void AySound::updEnvType() { } +void AySound::updIOPortA() { + ayregs.IOPortA = regs[14] & 0xff; +} + +void AySound::updIOPortB() { + ayregs.IOPortB = regs[15] & 0xff; +} + uint8_t AySound::getRegisterData() { + if ((selectedRegister >= 14) && ((regs[7] >> (selectedRegister - 8)) & 1) == 0) { + printf("getAYRegister %d: %02X\n", selectedRegister, 0xFF); + return 0xFF; + } + switch(selectedRegister) { case 0x00: return ayregs.tone_a & 0xff; case 0x01: return (ayregs.tone_a >> 8) & 0x0f; @@ -495,8 +508,8 @@ uint8_t AySound::getRegisterData() case 0x0b: return ayregs.env_freq & 0x00ff; case 0x0c: return ayregs.env_freq >> 8; case 0x0d: return ayregs.env_style & 0x0f; - case 0x0e: return 0xff; - case 0x0f: return 0xff; + case 0x0e: return ayregs.IOPortA; + case 0x0f: return ayregs.IOPortB; } return 0; @@ -511,10 +524,8 @@ void AySound::selectRegister(uint8_t registerNumber) void AySound::setRegisterData(uint8_t data) { - if (selectedRegister < 14) { - regs[selectedRegister] = data; - updateReg[selectedRegister](); - } + regs[selectedRegister] = data; + updateReg[selectedRegister](); } @@ -537,23 +548,12 @@ void AySound::reset() prepare_generation(); - for (int i=0;i<14;i++) regs[i] = 0; - // regs[7] = 0xff; // More correct ? (Setting here as 0xff produces artifacts in Overscan loader i.e.) + for (int i=0;i<16;i++) regs[i] = 0; // All registers are set to 0 + + regs[7] = 0xff; // Mixer register selectedRegister = 0xff; - for(int i=0; i<14; i++) updateReg[i](); -} + for(int i=0; i < 16; i++) updateReg[i](); // Update all registers -void AySound::gen_sound_speech_test(unsigned char *buff, size_t sound_bufsize, int bufpos) -{ - unsigned char *sound_buf = buff; - sound_buf += bufpos; - - while (sound_bufsize-- > 0) { - // *sound_buf++ = table[(regs[8] & 0x0f) * 2 + 1]; - *sound_buf++ = (vols[0][(regs[8] & 0x0f) * 2 + 1]) >> 8; - // *sound_buf++ = (vols[0][ayregs.vol_a * 2 + 1]) >> 8; - // *sound_buf++ = ayregs.vol_a << 4; - } -} \ No newline at end of file +} diff --git a/src/CPU.cpp b/src/CPU.cpp index 1cb98c89..4bb32a1d 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -33,6 +33,9 @@ visit https://zxespectrum.speccy.org/contacto */ +#include +#include + #include "CPU.h" #include "ESPectrum.h" #include "MemESP.h" @@ -47,7 +50,7 @@ visit https://zxespectrum.speccy.org/contacto static bool createCalled = false; -void (*CPU::loop)() = &CPU::loop_fast; +void (*CPU::loop)() = &CPU::loop_trap; uint32_t CPU::statesPerFrame() { @@ -144,28 +147,36 @@ void IRAM_ATTR CPU::loop_fast() Z80::checkINT(); } - // while (tstates < statesInFrame) { + if (tstates & 0xFF000000) FlushOnHalt(); // If we're halted flush screen and update registers as needed - // Z80::execute(); + global_tstates += statesInFrame; // increase global Tstates + tstates -= statesInFrame; - // PRELIMINARY TAPE SAVE TEST - // - // // if PC is 0x970, a call to SA_CONTRL has been made: - // // remove .tap output file if exists - // if(Z80::getRegPC() == 0x970) { - // remove("/sd/tap/cinta1.tap"); - // } - // // if PC is 0x04C2, a call to SA_BYTES has been made: - // // Call Save function - // if(Z80::getRegPC() == 0x04C2) { - // Tape::Save(); - // // printf("Save in ROM called\n"); - // Z80::setRegPC(0x555); - // } + framecnt++; - // Z80::checkINT(); +} + +void IRAM_ATTR CPU::loop_trap() +{ + + while (tstates < IntEnd) { + Z80::execute(); + CPU::checkTraps(); + Z80::checkINT(); + } + + uint32_t stFrame = statesInFrame - IntEnd; + while (tstates < stFrame) { + Z80::execute(); + CPU::checkTraps(); + } + + while (tstates < statesInFrame) { + Z80::execute(); + CPU::checkTraps(); + Z80::checkINT(); + } - // } if (tstates & 0xFF000000) FlushOnHalt(); // If we're halted flush screen and update registers as needed @@ -176,6 +187,56 @@ void IRAM_ATTR CPU::loop_fast() } +// trim from end (in place) +static inline void rtrim(std::string &s) { + s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { + return !std::isspace(ch); + }).base(), s.end()); +} + +void IRAM_ATTR CPU::checkTraps() { + + // PRELIMINARY TAPE SAVE TEST + + // // if PC is 0x970, a call to SA_CONTRL has been made: + // // remove .tap output file if exists + if(Z80::getRegPC() == 0x970) { + + // Get save name + string name; + uint16_t header_data = Z80::getRegIX(); + for (int i=0; i < 10; i++) + name += MemESP::ramCurrent[header_data++ >> 14][header_data & 0x3fff]; + rtrim(name); + Tape::tapeSaveName = "/sd/t/" + name + ".tap"; + + // TO DO: Check existence of file and ask for overwrite or append + + printf("Removing previuous tap file.\n"); + int result = remove(Tape::tapeSaveName.c_str()); + + // check if file has been deleted successfully + // if (result != 0) { + // // print error message + // printf("File deletion failed\n"); + // } + // else { + // printf("File deleted succesfully\n"); + // } + + printf("%s\n",Tape::tapeSaveName.c_str()); + + } else + // if PC is 0x04C2, a call to SA_BYTES has been made: + // Call Save function + if(Z80::getRegPC() == 0x04C2) { + printf("Saving %s block.\n",Tape::tapeSaveName.c_str()); + Tape::Save(); + Z80::setRegPC(0x555); + } + +} + void CPU::FlushOnHalt() { tstates &= 0x00FFFFFF; diff --git a/src/ESPectrum.cpp b/src/ESPectrum.cpp index f08350fc..65ae300c 100644 --- a/src/ESPectrum.cpp +++ b/src/ESPectrum.cpp @@ -1303,7 +1303,7 @@ for(;;) { if (Tape::tapeStatus==TAPE_LOADING) { snprintf(linea1, sizeof(linea1), "%02d/%02d %10s % 6d ", Tape::TapeListing[Tape::tapeCurBlock].Index, Tape::TapeListing.size() - 1, Tape::TapeListing[Tape::tapeCurBlock].FileName, Tape::TapeListing[Tape::tapeCurBlock].BlockLength); float percent = (float)((Tape::tapebufByteCount + Tape::tapePlayOffset) * 100) / (float)Tape::tapeFileSize; - snprintf(linea2, sizeof(linea2), "%5.2f%% %06d of %06d ", percent, Tape::tapebufByteCount + Tape::tapePlayOffset, Tape::tapeFileSize); + snprintf(linea2, sizeof(linea2), "%5.2f%% %06d %s %06d ", percent, Tape::tapebufByteCount + Tape::tapePlayOffset, OSD_TAPE_OF[Config::lang] , Tape::tapeFileSize); } else { snprintf(linea1, sizeof(linea1), "CPU: %05d / IDL: %05d ", (int)(elapsed), (int)(idle)); snprintf(linea2, sizeof(linea2), "FPS:%6.2f / FND:%6.2f ", CPU::framecnt / (totalseconds / 1000000), CPU::framecnt / (totalsecondsnodelay / 1000000)); diff --git a/src/Ports.cpp b/src/Ports.cpp index be1270f0..5ea53ac6 100644 --- a/src/Ports.cpp +++ b/src/Ports.cpp @@ -83,83 +83,6 @@ uint8_t IRAM_ATTR Ports::input(uint16_t address) // The default port value is 0xBF. uint8_t result = 0xbf; - // // The ULA functions (keybord and audio in) are accessible via all even numbered ports. - // if ((address & 0x0001) == 0) { - - // uint8_t portHigh = ~(address >> 8) & 0xff; - // for (int row = 0, mask = 0x01; row < 8; row++, mask <<= 1) { - // if ((portHigh & mask) != 0) { - // result &= port[row]; - // } - // } - - // if (Tape::tapeStatus==TAPE_LOADING) { - // Tape::TAP_Read(); - // bitWrite(result,6,Tape::tapeEarBit); - // } else { - // // Issue 2 behaviour only on Spectrum 48K - // if ((Z80Ops::is48) && (Config::Issue2)) { - // if (port254 & 0x18) result |= 0x40; - // } else { - // if (port254 & 0x10) result |= 0x40; - // } - // } - - // } else { - - // // Handle non ULA ports. - // switch (address & 0xFF) { - // case 0x1F: - // // Kempston joystick interface. - // if (Config::joystick) result = port[0x1f]; - // break; - // case 0xFD: - // // AY Register - // if ((address == 0xFFFD) && (ESPectrum::AY_emu)) result = AySound::getRegisterData(); - // break; - // case 0xDF: - // // Normally, the Kempston joystick interface - // // uses port 0x1F, but some games checks port - // // 0xDF instead, which the emulator reserves for - // // the Kempston mouse if it is enabled, but if - // // there is no mouse, port 0xDF will be connected - // // to the joystick. - // if (Config::joystick) result = port[0x1f]; - // break; - // default: - // // Unattached ports. - // result = VIDEO::getFloatBusData(); - // if ((!Z80Ops::is48) && ((address & 0x8002) == 0)) { - - // // // Solo en el modelo 128K, pero no en los +2/+2A/+3, si se lee el puerto - // // // 0x7ffd, el valor leído es reescrito en el puerto 0x7ffd. - // // // http://www.speccy.org/foro/viewtopic.php?f=8&t=2374 - // if (!MemESP::pagingLock) { - // MemESP::pagingLock = bitRead(result, 5); - // MemESP::bankLatch = result & 0x7; - // MemESP::ramCurrent[3] = (unsigned char *)MemESP::ram[MemESP::bankLatch]; - // MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; - // if (MemESP::videoLatch != bitRead(result, 3)) { - // MemESP::videoLatch = bitRead(result, 3); - // // This, if not using the ptime128 draw version, fixs ptime and ptime128 - // if (((address & 0x0001) != 0) && (MemESP::ramContended[address >> 14])) { - // VIDEO::Draw(2, false); - // CPU::tstates -= 2; - // } - // VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; - // } - // MemESP::romLatch = bitRead(result, 4); - // bitWrite(MemESP::romInUse, 0, MemESP::romLatch); - // MemESP::ramCurrent[0] = (unsigned char *)MemESP::rom[MemESP::romInUse]; - // } - - // } - // break; - // } - // } - - // return result; - // Kempston Joystick if ((Config::joystick) && ((address & 0x00E0) == 0 || (address & 0xFF) == 0xDF)) return port[0x1f]; @@ -313,58 +236,3 @@ void IRAM_ATTR Ports::output(uint16_t address, uint8_t data) { } } - -// void Ports::ContendedIODelay(uint16_t portNumber) -// { - -// uint8_t lowByte = portNumber & 0xff; - -// if (bitRead(lowByte, 0)) { -// if (Z80Ops::is48) { -// if (portNumber >= 0x4000 && portNumber <= 0x7FFF) { -// // Template D -// VIDEO::Draw(1,true); -// VIDEO::Draw(1,true); -// VIDEO::Draw(1,true); -// VIDEO::Draw(1,true); -// } else { -// // Template B -// VIDEO::Draw(4,false); -// } -// } else { -// if ((portNumber >= 0x4000 && portNumber <= 0x7FFF) || ((portNumber >= 0xC000 && portNumber <= 0xFFFF) && (MemESP::ramContended[3]))) { -// // Template D -// VIDEO::Draw(1,true); -// VIDEO::Draw(1,true); -// VIDEO::Draw(1,true); -// VIDEO::Draw(1,true); -// } else { -// // Template B -// VIDEO::Draw(4,false); -// } -// } -// } else { -// if (Z80Ops::is48) { -// if (portNumber >= 0x4000 && portNumber <= 0x7FFF) { -// // Template C -// VIDEO::Draw(1,true); -// VIDEO::Draw(3,true); -// } else { -// // Template A -// VIDEO::Draw(1,false); -// VIDEO::Draw(3,true); -// } -// } else { -// if ((portNumber >= 0x4000 && portNumber <= 0x7FFF) || ((portNumber >= 0xC000 && portNumber <= 0xFFFF) && (MemESP::ramContended[3]))) { -// // Template C -// VIDEO::Draw(1,true); -// VIDEO::Draw(3,true); -// } else { -// // Template A -// VIDEO::Draw(1,false); -// VIDEO::Draw(3,true); -// } - -// } -// } -// } diff --git a/src/Tape.cpp b/src/Tape.cpp index dc7aae36..19cf460c 100644 --- a/src/Tape.cpp +++ b/src/Tape.cpp @@ -34,9 +34,9 @@ visit https://zxespectrum.speccy.org/contacto */ #include -#include #include #include +#include using namespace std; @@ -51,6 +51,7 @@ using namespace std; FILE *Tape::tape; string Tape::tapeFileName = "none"; +string Tape::tapeSaveName = "none"; uint8_t Tape::tapeStatus = TAPE_STOPPED; uint8_t Tape::SaveStatus = SAVE_STOPPED; uint8_t Tape::romLoading = false; @@ -393,10 +394,15 @@ void Tape::Save() { uint8_t dato; int longitud; - fichero = fopen("/sd/tap/cinta1.tap", "ab"); + // if (tapeSaveName == "none") { + // OSD::osdCenteredMsg(OSD_TAPE_SAVE_ERR, LEVEL_ERROR); + // return; + // } + + fichero = fopen(tapeSaveName.c_str(), "ab"); if (fichero == NULL) { - OSD::osdCenteredMsg(OSD_TAPE_LOAD_ERR, LEVEL_ERROR); + OSD::osdCenteredMsg(OSD_TAPE_SAVE_ERR, LEVEL_ERROR); return; } diff --git a/src/Video.cpp b/src/Video.cpp index 63661d2b..69ae3d25 100644 --- a/src/Video.cpp +++ b/src/Video.cpp @@ -408,7 +408,7 @@ uint8_t IRAM_ATTR VIDEO::getFloatBusData48() { unsigned char halfpix = (currentTstates % 224) - 3; if ((halfpix >= 125) || (halfpix & 0x04)) return 0xFF; - int hpoffset = ((halfpix) >> 2) + ((halfpix >> 1) & 0x01);; + int hpoffset = (halfpix >> 2) + ((halfpix >> 1) & 0x01);; if (halfpix & 0x01) return(grmem[offAtt[line] + hpoffset]); @@ -426,7 +426,7 @@ uint8_t IRAM_ATTR VIDEO::getFloatBusData128() { unsigned char halfpix = currentTstates % 228; if ((halfpix >= 128) || (halfpix & 0x04)) return 0xFF; - int hpoffset = ((halfpix) >> 2) + ((halfpix >> 1) & 0x01);; + int hpoffset = (halfpix >> 2) + ((halfpix >> 1) & 0x01);; if (halfpix & 0x01) return(grmem[offAtt[line] + hpoffset]); From 9de08edd407709d67a95a2a0f702c1eb2c2443ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Wed, 19 Jul 2023 18:53:46 +0200 Subject: [PATCH 15/29] Fast Tape Loading, 1st (and buggy) version --- include/Tape.h | 2 + include/Z80_JLS/z80.h | 4 + src/AySound.cpp | 6 +- src/CPU.cpp | 51 +++-- src/Tape.cpp | 443 ++++++++++++++++++++++++++++++++++++++++++ src/Z80_JLS.cpp | 8 + 6 files changed, 501 insertions(+), 13 deletions(-) diff --git a/include/Tape.h b/include/Tape.h index dac9b579..d379f466 100644 --- a/include/Tape.h +++ b/include/Tape.h @@ -119,6 +119,8 @@ class Tape static void TAP_Play(); static void TAP_Stop(); static void IRAM_ATTR TAP_Read(); + static bool FlashLoad(); + // static bool FlashLoad2(); static void Save(); }; diff --git a/include/Z80_JLS/z80.h b/include/Z80_JLS/z80.h index d339d8c8..f0550593 100644 --- a/include/Z80_JLS/z80.h +++ b/include/Z80_JLS/z80.h @@ -397,6 +397,10 @@ class Z80 { static void IRAM_ATTR incRegR(uint8_t inc); + static void Xor(uint8_t oper8); + + static void Cp(uint8_t oper8); + #ifdef WITH_BREAKPOINT_SUPPORT static bool isBreakpoint(void) { return breakpointEnabled; } static void setBreakpoint(bool state) { breakpointEnabled = state; } diff --git a/src/AySound.cpp b/src/AySound.cpp index da6eee57..cc5ab847 100644 --- a/src/AySound.cpp +++ b/src/AySound.cpp @@ -524,8 +524,10 @@ void AySound::selectRegister(uint8_t registerNumber) void AySound::setRegisterData(uint8_t data) { - regs[selectedRegister] = data; - updateReg[selectedRegister](); + if (selectedRegister < 16) { + regs[selectedRegister] = data; + updateReg[selectedRegister](); + } } diff --git a/src/CPU.cpp b/src/CPU.cpp index 4bb32a1d..b48afcc4 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -196,15 +196,19 @@ static inline void rtrim(std::string &s) { void IRAM_ATTR CPU::checkTraps() { - // PRELIMINARY TAPE SAVE TEST - - // // if PC is 0x970, a call to SA_CONTRL has been made: - // // remove .tap output file if exists - if(Z80::getRegPC() == 0x970) { + string name; + int result; + uint16_t header_data; + + switch(Z80::getRegPC()) { + + case 0x970 : + // if PC is 0x970, a call to SA_CONTRL has been made: + // remove .tap output file if exists // Get save name - string name; - uint16_t header_data = Z80::getRegIX(); + + header_data = Z80::getRegIX(); for (int i=0; i < 10; i++) name += MemESP::ramCurrent[header_data++ >> 14][header_data & 0x3fff]; rtrim(name); @@ -213,7 +217,7 @@ void IRAM_ATTR CPU::checkTraps() { // TO DO: Check existence of file and ask for overwrite or append printf("Removing previuous tap file.\n"); - int result = remove(Tape::tapeSaveName.c_str()); + result = remove(Tape::tapeSaveName.c_str()); // check if file has been deleted successfully // if (result != 0) { @@ -226,14 +230,39 @@ void IRAM_ATTR CPU::checkTraps() { printf("%s\n",Tape::tapeSaveName.c_str()); - } else + break; + + case 0x4C2 : // if PC is 0x04C2, a call to SA_BYTES has been made: // Call Save function - if(Z80::getRegPC() == 0x04C2) { + printf("Saving %s block.\n",Tape::tapeSaveName.c_str()); Tape::Save(); Z80::setRegPC(0x555); - } + + break; + + // case 0x556 : // Jspeccy + case 0x56A : // SoftSpectrum + + // LD_BYTES routine in Spectrum ROM at address 0x0556 + + // if (loadTrap && memory.isSpectrumRom() && tape.isTapeReady()) { + // if (flashload && tape.flashLoad(memory)) { + // invalidateScreen(true); // thanks Andrew Owen + // return 0xC9; // RET opcode + // } else { + // tape.play(false); + // } + // } + + if (Tape::tapeFileName != "none" && Tape::tapeStatus != TAPE_LOADING) { + if (Tape::FlashLoad()) Z80::setRegPC(0x5e2); + } + + break; + + } } diff --git a/src/Tape.cpp b/src/Tape.cpp index 19cf460c..01067a0c 100644 --- a/src/Tape.cpp +++ b/src/Tape.cpp @@ -438,3 +438,446 @@ void Tape::Save() { fclose(fichero); } + +bool Tape::FlashLoad() { + + // if (tapeCurBlock >= (TapeListing.size() - 1)) { + // Z80::setCarryFlag(false); + // return false; + // } + FILE *flashtape; + + flashtape = fopen(Tape::tapeFileName.c_str(), "rb"); + if (flashtape == NULL) + { + OSD::osdCenteredMsg(OSD_TAPE_LOAD_ERR, LEVEL_ERROR); + Z80::setCarryFlag(false); + return false; + } + // fseek(tape,0,SEEK_END); + // tapeFileSize = ftell(tape); + // rewind (tape); + + // Move to selected block position + fseek(flashtape,TapeListing[Tape::tapeCurBlock].StartPosition,SEEK_SET); + + // tapePlayOffset = TapeListing[Tape::tapeCurBlock].StartPosition + 2; + +// tapePos = offsetBlocks[idxHeader]; +// blockLen = readInt(tapeBuffer, tapePos, 2); +// // System.out.println(String.format("tapePos: %X. blockLen: %X", tapePos, blockLen)); +// tapePos += 2; + + // uint32_t tapePos = TapeListing[tapeCurBlock].StartPosition; + + uint16_t blockLen=(readByteFile(flashtape) | (readByteFile(flashtape) <<8)); + uint8_t tapeFlag = readByteFile(flashtape); + + // printf("BlockLen: %d. Flag: %d\n",blockLen,tapeFlag); + + // printf("%u\n",Z80::getRegA()); + // printf("%u\n",Z80::getRegAx()); + + // tapePos += 2; + +// // ¿Coincide el flag? (está en el registro A) +// if (cpu.getRegA() != (tapeBuffer[tapePos] & 0xff)) { +// cpu.xor(tapeBuffer[tapePos]); +// cpu.setCarryFlag(false); +// idxHeader++; +// return true; +// } + + if (Z80::getRegAx() != (tapeFlag & 0xff)) { + // printf("No coincide el flag\n"); + fclose(flashtape); + if (tapeCurBlock < (TapeListing.size() - 1)) { + Z80::setFlags(0x00); + Z80::setRegA(Z80::getRegAx() ^ tapeFlag); + tapeCurBlock++; + return true; + } else return false; + } + +// // La paridad incluye el byte de flag +// cpu.setRegA(tapeBuffer[tapePos]); + + // La paridad incluye el byte de flag + Z80::setRegA(tapeFlag); + +// int count = 0; +// int addr = cpu.getRegIX(); // Address start +// int nBytes = cpu.getRegDE(); // Lenght +// while (count < nBytes && count < blockLen - 1) { +// memory.writeByte(addr, tapeBuffer[tapePos + count + 1]); +// cpu.xor(tapeBuffer[tapePos + count + 1]); +// addr = (addr + 1) & 0xffff; +// count++; +// } + + int count = 0; + uint8_t data; + int addr = Z80::getRegIX(); // Address start + int nBytes = Z80::getRegDE(); // Lenght + // printf("Addr: %d. nBytes: %d\n",addr,nBytes); + while ((count < nBytes) && (count < blockLen - 1)) { + data = readByteFile(flashtape); + MemESP::writebyte(addr,data); + Z80::Xor(data); + addr = (addr + 1) & 0xffff; + count++; + } + + // printf("Count: %d. nBytes: %d\n",count,nBytes); + +// // Se cargarán los bytes pedidos en DE +// if (count == nBytes) { +// cpu.xor(tapeBuffer[tapePos + count + 1]); // Byte de paridad +// cpu.cp(0x01); +// } + + // Se cargarán los bytes pedidos en DE + if (count == nBytes) { + Z80::Xor(readByteFile(flashtape)); // Byte de paridad + Z80::Cp(0x01); + } + + // Hay menos bytes en la cinta de los indicados en DE + // En ese caso habrá dado un error de timeout en LD-SAMPLE (0x05ED) + // que se señaliza con CARRY==reset & ZERO==set + if (count < nBytes) { + Z80::setFlags(0x50); // when B==0xFF, then INC B, B=0x00, F=0x50 + } + + Z80::setRegIX(addr); + Z80::setRegDE(nBytes - count); + if (tapeCurBlock < (TapeListing.size() - 1)) tapeCurBlock++; + + fclose(flashtape); + + return true; + +} + +// bool Tape::FlashLoad2() { + +// // // The return value, representing the index of the TapeBlock which was flash loaded. +// // int lastBlockIndex = -1; + +// // // If we encounter a block with no data to load (for example a text block), just skip ahead. +// // if (tapeManager.NextBlock != null && tapeManager.NextBlock.BlockContent == null) +// // { +// // return lastBlockIndex; +// // } + +// // // The LD BYTES ROM routine is intercepted at an early stage just before the edge detection is started. +// // // Check that the tape position is at the end of a block and that there is a following block to flash load. +// // if (z80.PC == 0x056A && tapeManager.NextBlock != null && tapeManager.CurrentTapePosition > tapeManager.NextBlock.StartPosition - 10) +// // { + +// // // The target address for the data is stored in IX. +// // int dataTargetParameter = 256 * z80.I1 + z80.X; +// // // The block length (number of bytes) is stored in DE. +// // int dataLengthParameter = 256 * z80.D + z80.E; +// // // The flag byte is stored in A'. +// // int flagByte = z80.APrime; + +// int dataTargetParameter = Z80::getRegIX(); +// int dataLengthParameter = Z80::getRegDE(); +// int flagByte = Z80::getRegA(); + +// printf("dataTargetParameter: %04X\n",dataTargetParameter); +// printf("dataLengthParameter: %04X\n",dataLengthParameter); +// printf("flagByte: %02X\n",flagByte); + + +// // // Check for various errors: +// // // Is there a mismatch between the block type and the flag byte in the A' register? +// // if (tapeManager.NextBlock.BlockTypeNum != flagByte && dataLengthParameter > 0) +// // { +// // // Don't load the block, but reset all flags. +// // z80.CarryFlag = 0; +// // z80.SignFlag = 0; +// // z80.ZeroFlag = 0; +// // z80.HalfCarryFlag = 0; +// // z80.Parity_OverflowFlag = 0; +// // z80.SubtractFlag = 0; +// // z80.F3Flag = 0; +// // z80.F5Flag = 0; + +// // // The A register is updated by XOR:ing the flag byte with the block byte read from the file. +// // z80.A = flagByte ^ tapeManager.NextBlock.BlockTypeNum; +// // } + +// if (Tape::TapeListing[tapeCurBlock].BlockTypeNum != flagByte && dataLengthParameter > 0) { +// Z80::setFlags(0x00); +// Z80::setRegA(flagByte ^ Tape::TapeListing[tapeCurBlock].BlockTypeNum); +// } + +// // else +// // // Is the expected number of bytes larger than the actual length of the block? +// // if (dataLengthParameter > tapeManager.NextBlock.BlockContent.Length) +// // { +// // // If the DE register indicates a too long data length, the loader will fail after +// // // loading the block and it expects one more byte. +// // memory.WriteDataBlock(tapeManager.NextBlock.BlockContent, dataTargetParameter); + +// // // When a new edge is not found, set flags carry = 0 and zero = 1. +// // z80.CarryFlag = 0; +// // z80.ZeroFlag = 1; + +// // // The other flags are set by the last INC B (from 0xFF) at 0x05ED. +// // z80.HalfCarryFlag = 1; +// // z80.SignFlag = 0; +// // z80.Parity_OverflowFlag = 0; +// // z80.SubtractFlag = 0; +// // z80.F3Flag = 0; +// // z80.F5Flag = 0; + +// // // Check that we're not dealing with a data fragment (in which case IX and DE are intact). +// // if (tapeManager.NextBlock.BlockContent.Length >= 2) +// // { +// // z80.I1 = (dataTargetParameter + tapeManager.NextBlock.BlockContent.Length + 1) / 256; +// // z80.X = (dataTargetParameter + tapeManager.NextBlock.BlockContent.Length + 1) - 256 * z80.I1; +// // z80.D = (dataLengthParameter - (tapeManager.NextBlock.BlockContent.Length + 1)) / 256; +// // z80.E = (dataLengthParameter - (tapeManager.NextBlock.BlockContent.Length + 1)) - 256 * z80.D; +// // } + +// // z80.A = 0; +// // } + +// else if (dataLengthParameter > Tape::TapeListing[tapeCurBlock].BlockLength) { + +// } + +// // else + +// // Is the expected number of bytes smaller than the length of the block? +// // if (dataLengthParameter < tapeManager.NextBlock.BlockContent.Length) +// // { +// // memory.WriteDataBlock(tapeManager.NextBlock.BlockContent, dataTargetParameter); + +// // // When calculating the checksum for the loaded data, there are two different cases, +// // // either the block length parameter equals zero, in which case there is no parity +// // // calculated and the checksum contains the flag byte. +// // // Otherwise, the checksum is calculated in the usual way but only for the number +// // // of bytes specified in the data length parameter + 1. +// // int calculatedCheckSum; +// // if (dataLengthParameter == 0) +// // { +// // calculatedCheckSum = flagByte; +// // } +// // else +// // { +// // calculatedCheckSum = flagByte; + +// // // The checksum is calculated by XOR:ing each byte of data with the flag byte. +// // for (int i = 0; i < dataLengthParameter + 1; i++) +// // { +// // calculatedCheckSum ^= tapeManager.NextBlock.BlockContent[i]; +// // } +// // } + +// // // Update the flags and the A register. +// // UpdateFlags(calculatedCheckSum); + +// // // Update the IX and DE registers. +// // z80.I1 = (dataTargetParameter + dataLengthParameter) / 256; +// // z80.X = (dataTargetParameter + dataLengthParameter) - 256 * z80.I1; +// // z80.D = 0; +// // z80.E = 0; +// // } +// // else + +// // // Is the expected number of bytes equal to zero? +// // if (dataLengthParameter == 0) +// // { +// // // There is no parity check, so the checksum contains the block type value. +// // int calculatedCheckSum = 0xFF; + +// // // Update the flags and the A register. +// // UpdateFlags(calculatedCheckSum); +// // } +// else +// // // Flash load the block and update IX, DE and AF. +// { +// // int lastBytePos = memory.WriteDataBlock(tapeManager.NextBlock.BlockContent, dataTargetParameter); + +// tape = fopen(Tape::tapeFileName.c_str(), "rb"); +// if (tape == NULL) +// { +// OSD::osdCenteredMsg(OSD_TAPE_LOAD_ERR, LEVEL_ERROR); +// return false; +// } + +// // Move to selected block position +// fseek(tape,TapeListing[Tape::tapeCurBlock].StartPosition + 3,SEEK_SET); + +// int count = 0; +// uint8_t data; +// printf("Addr: %d. nBytes: %d\n",dataTargetParameter,dataLengthParameter); +// while (count < dataLengthParameter) { +// data = readByteFile(tape); +// MemESP::writebyte(dataTargetParameter,data); +// Z80::Xor(data); +// dataTargetParameter = (dataTargetParameter + 1) & 0xffff; +// count++; +// } + +// Z80::Xor(readByteFile(tape)); // Byte de paridad +// Z80::Cp(0x01); + + +// Z80::setRegIX(dataTargetParameter); +// Z80::setRegDE(0); +// tapeCurBlock++; + +// fclose(tape); +// return true; + +// // // After loading the entire block, including the last checksum byte, the current checksum will be 0. +// // // (the checksum being byte 0 XOR byte 1 XOR ... byte n). + +// // // Update the flags and the A register. +// // UpdateFlags(calculatedCheckSum); + + +// // // Set IX to the same value as if the block had been loaded by the ROM routine. +// // z80.I1 = lastBytePos / 256; +// // z80.X = lastBytePos - 256 * z80.I1; + +// // // Set DE to 0. +// // z80.D = 0; +// // z80.E = 0; +// // } + +// // // Keep track of the index of the last loaded tape block. This information +// // // can be used to rewind the tape to the start position of the next block +// // // after an auto pause. +// // lastBlockIndex = tapeManager.NextBlock.Index; + +// // // Skip forward to the end of the block which was just flash loaded into RAM. +// // tapeManager.GoToEndOfBlock(tapeManager.NextBlock.Index); + +// // // Skip to the end of the LD BYTES ROM routine (actually a RET, so it doesn't really matter which RET instruction we point to here). +// // z80.PC = 0x05E2; + +// } + +// // return lastBlockIndex; + +// // // Update the flags after loading a block of data. +// // void UpdateFlags(int checkSum) +// // { +// // // The flags are set by the CP 0x01 operation at 0x05E0, where A = the current checksum. +// // int flagTest = checkSum - 1; +// // z80.CarryFlag = BitOps.GetBit(flagTest, 8); +// // z80.SignFlag = Flags.SignFlag(flagTest); +// // z80.ZeroFlag = Flags.ZeroFlag(flagTest); +// // z80.HalfCarryFlag = Flags.HalfCarryFlagSub8(checkSum, 1, z80.CarryFlag); +// // z80.Parity_OverflowFlag = Flags.OverflowFlagSub8(checkSum, 1, flagTest); +// // z80.SubtractFlag = 1; +// // z80.F3Flag = 0; +// // z80.F5Flag = 0; + +// // z80.A = checkSum; +// // } +// // } +// // } +// // } + +// } + +// // public boolean flashLoad(Memory memory) { + +// // if (idxHeader >= nOffsetBlocks) { +// // // cpu.setCarryFlag(false); +// // return false; +// // } + +// // tapePos = offsetBlocks[idxHeader]; +// // blockLen = readInt(tapeBuffer, tapePos, 2); +// // // System.out.println(String.format("tapePos: %X. blockLen: %X", tapePos, blockLen)); +// // tapePos += 2; + +// // // ¿Coincide el flag? (está en el registro A) +// // if (cpu.getRegA() != (tapeBuffer[tapePos] & 0xff)) { +// // cpu.xor(tapeBuffer[tapePos]); +// // cpu.setCarryFlag(false); +// // idxHeader++; +// // return true; +// // } + +// // // La paridad incluye el byte de flag +// // cpu.setRegA(tapeBuffer[tapePos]); + +// // int count = 0; +// // int addr = cpu.getRegIX(); // Address start +// // int nBytes = cpu.getRegDE(); // Lenght +// // while (count < nBytes && count < blockLen - 1) { +// // memory.writeByte(addr, tapeBuffer[tapePos + count + 1]); +// // cpu.xor(tapeBuffer[tapePos + count + 1]); +// // addr = (addr + 1) & 0xffff; +// // count++; +// // } + +// // // Se cargarán los bytes pedidos en DE +// // if (count == nBytes) { +// // cpu.xor(tapeBuffer[tapePos + count + 1]); // Byte de paridad +// // cpu.cp(0x01); +// // } + +// // // Hay menos bytes en la cinta de los indicados en DE +// // // En ese caso habrá dado un error de timeout en LD-SAMPLE (0x05ED) +// // // que se señaliza con CARRY==reset & ZERO==set +// // if (count < nBytes) { +// // cpu.setFlags(0x50); // when B==0xFF, then INC B, B=0x00, F=0x50 +// // } + +// // cpu.setRegIX(addr); +// // cpu.setRegDE(nBytes - count); +// // idxHeader++; +// // fireTapeBlockChanged(idxHeader); + +// // // System.out.println(String.format("Salida -> IX: %04X DE: %04X AF: %04X", +// // // cpu.getRegIX(), cpu.getRegDE(), cpu.getRegAF())); +// // return true; +// // } + +// // private void fireTapeBlockChanged(final int block) { +// // blockListeners.forEach(listener -> { +// // listener.blockChanged(block); +// // }); +// // } + +// // saveTrap = settings.getTapeSettings().isEnableSaveTraps(); +// // z80.setBreakpoint(0x04D0, saveTrap); + +// // loadTrap = settings.getTapeSettings().isEnableLoadTraps(); +// // z80.setBreakpoint(0x0556, loadTrap); + +// // flashload = settings.getTapeSettings().isFlashLoad(); + + +// // case 0x04D0: +// // // SA_BYTES routine in Spectrum ROM at 0x04D0 +// // // SA_BYTES starts at 0x04C2, but the +3 ROM don't enter +// // // to SA_BYTES by his start address. +// // if (saveTrap && memory.isSpectrumRom() && tape.isTapeReady()) { +// // if (tape.saveTapeBlock(memory)) { +// // return 0xC9; // RET opcode +// // } +// // } +// // break; +// // case 0x0556: +// // // LD_BYTES routine in Spectrum ROM at address 0x0556 +// // if (loadTrap && memory.isSpectrumRom() && tape.isTapeReady()) { +// // if (flashload && tape.flashLoad(memory)) { +// // invalidateScreen(true); // thanks Andrew Owen +// // return 0xC9; // RET opcode +// // } else { +// // tape.play(false); +// // } +// // } +// // break; +// // } diff --git a/src/Z80_JLS.cpp b/src/Z80_JLS.cpp index 9b6f3c7c..686704d1 100644 --- a/src/Z80_JLS.cpp +++ b/src/Z80_JLS.cpp @@ -559,6 +559,10 @@ void Z80::xor_(uint8_t oper8) { flagQ = true; } +void Z80::Xor(uint8_t oper8) { + xor_(oper8); +} + // Operación OR lógica void Z80::or_(uint8_t oper8) { regA |= oper8; @@ -592,6 +596,10 @@ void Z80::cp(uint8_t oper8) { flagQ = true; } +void Z80::Cp(uint8_t oper8) { + cp(oper8); +} + // DAA void Z80::daa(void) { uint8_t suma = 0; From d2c4865606b99161d76f9d109200a6deca8fe56c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Wed, 19 Jul 2023 19:43:12 +0200 Subject: [PATCH 16/29] Tape block resets to cero on load completion --- src/Tape.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Tape.cpp b/src/Tape.cpp index 01067a0c..152d4059 100644 --- a/src/Tape.cpp +++ b/src/Tape.cpp @@ -380,7 +380,7 @@ void IRAM_ATTR Tape::TAP_Read() if (tapeCurByte) tapeHdrPulses=TAPE_HDR_SHORT; else tapeHdrPulses=TAPE_HDR_LONG; } } else { - tapeCurBlock--; + tapeCurBlock=0; TAP_Stop(); } } @@ -496,7 +496,10 @@ bool Tape::FlashLoad() { Z80::setRegA(Z80::getRegAx() ^ tapeFlag); tapeCurBlock++; return true; - } else return false; + } else { + tapeCurBlock = 0; + return false; + } } // // La paridad incluye el byte de flag @@ -551,7 +554,7 @@ bool Tape::FlashLoad() { Z80::setRegIX(addr); Z80::setRegDE(nBytes - count); - if (tapeCurBlock < (TapeListing.size() - 1)) tapeCurBlock++; + if (tapeCurBlock < (TapeListing.size() - 1)) tapeCurBlock++; else tapeCurBlock = 0; fclose(flashtape); From e5eea064dc4545493792d359e4dfdce38a8e017c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Thu, 20 Jul 2023 16:04:02 +0200 Subject: [PATCH 17/29] F11 Key as hardreset, more tap fast loading stuff --- src/CPU.cpp | 9 +-- src/ESPectrum.cpp | 5 +- src/OSDMain.cpp | 55 +++++++++++++++++-- src/Tape.cpp | 136 +++++++++++++++++++++++++++------------------- 4 files changed, 138 insertions(+), 67 deletions(-) diff --git a/src/CPU.cpp b/src/CPU.cpp index b48afcc4..38fc4c82 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -160,20 +160,20 @@ void IRAM_ATTR CPU::loop_trap() { while (tstates < IntEnd) { - Z80::execute(); CPU::checkTraps(); + Z80::execute(); Z80::checkINT(); } uint32_t stFrame = statesInFrame - IntEnd; while (tstates < stFrame) { - Z80::execute(); CPU::checkTraps(); + Z80::execute(); } while (tstates < statesInFrame) { - Z80::execute(); CPU::checkTraps(); + Z80::execute(); Z80::checkINT(); } @@ -256,7 +256,8 @@ void IRAM_ATTR CPU::checkTraps() { // } // } - if (Tape::tapeFileName != "none" && Tape::tapeStatus != TAPE_LOADING) { + if ((Tape::tapeFileName != "none") && (Tape::tapeStatus != TAPE_LOADING)) { + // printf("Loading tape %s\n",Tape::tapeFileName.c_str()); if (Tape::FlashLoad()) Z80::setRegPC(0x5e2); } diff --git a/src/ESPectrum.cpp b/src/ESPectrum.cpp index 65ae300c..f1c0d537 100644 --- a/src/ESPectrum.cpp +++ b/src/ESPectrum.cpp @@ -1026,10 +1026,13 @@ void IRAM_ATTR ESPectrum::processKeyboard() { OSD::do_OSD(fabgl::VK_F10); } else if (!bitRead(ZXKeyb::ZXcols[2],0)) { - CaptureToBmp(); + OSD::do_OSD(fabgl::VK_F11); } else if (!bitRead(ZXKeyb::ZXcols[2],1)) { OSD::do_OSD(fabgl::VK_F12); + } else + if (!bitRead(ZXKeyb::ZXcols[1],1)) { + CaptureToBmp(); } else zxDelay = 0; diff --git a/src/OSDMain.cpp b/src/OSDMain.cpp index 236a7152..021ca9c1 100644 --- a/src/OSDMain.cpp +++ b/src/OSDMain.cpp @@ -46,6 +46,7 @@ visit https://zxespectrum.speccy.org/contacto #include "Tape.h" #include "ZXKeyb.h" #include "pwm_audio.h" +#include "Z80_JLS/z80.h" #ifndef ESP32_SDL2_WRAPPER #include "esp_system.h" @@ -258,11 +259,27 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { menu_curopt = 1; string mFile = menuFile(FileUtils::MountPoint + DISK_TAP_DIR, MENU_TAP_TITLE[Config::lang],".tap.TAP"); if (mFile != "") { + + // TO DO: make this dependant on Flashload parameter + if (Z80Ops::is48) { + changeSnapshot(FileUtils::MountPoint + "/load48.z80"); + } else { + changeSnapshot(FileUtils::MountPoint + "/load128.z80"); + } + + // Put something random on FRAMES SYS VAR as recommended by Mark Woodmass + // https://skoolkid.github.io/rom/asm/5C78.html + MemESP::writebyte(0x5C78,rand() % 256); + MemESP::writebyte(0x5C79,rand() % 256); + Tape::TAP_Stop(); + // Read and analyze tape file Tape::Open(FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile); // Tape::tapeFileName=FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile; + } + } else if (KeytoESP == fabgl::VK_F6) { // Start / Stop .tap reproduction @@ -354,7 +371,16 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { // else if (KeytoESP == fabgl::VK_F10) { // ESPectrum::ESPoffset += 5; // } - else if (KeytoESP == fabgl::VK_F12) { + else if (KeytoESP == fabgl::VK_F11) { // Hard reset + // Hard + if (Config::ram_file != NO_RAM_FILE) { + Config::ram_file = NO_RAM_FILE; + Config::save("ram"); + } + Config::last_ram_file = NO_RAM_FILE; + ESPectrum::reset(); + } + else if (KeytoESP == fabgl::VK_F12) { // ESP32 reset // // Switch boot partition // string splabel; @@ -467,10 +493,27 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { // Select TAP File string mFile = menuFile(FileUtils::MountPoint + DISK_TAP_DIR, MENU_TAP_TITLE[Config::lang],".tap.TAP"); if (mFile != "") { + + // TO DO: make this dependant on Flashload parameter + if (Z80Ops::is48) { + changeSnapshot(FileUtils::MountPoint + "/load48.z80"); + } else { + changeSnapshot(FileUtils::MountPoint + "/load128.z80"); + } + + // Put something random on FRAMES SYS VAR as recommended by Mark Woodmass + // https://skoolkid.github.io/rom/asm/5C78.html + MemESP::writebyte(0x5C78,rand() % 256); + MemESP::writebyte(0x5C79,rand() % 256); + Tape::TAP_Stop(); + // Read and analyze tape file Tape::Open(FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile); + // Tape::tapeFileName=FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile; + return; + } } else if (tap_num == 2) { @@ -522,8 +565,10 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { } else if (opt2 == 2) { // Hard - Config::ram_file = NO_RAM_FILE; - Config::save("ram"); + if (Config::ram_file != NO_RAM_FILE) { + Config::ram_file = NO_RAM_FILE; + Config::save("ram"); + } Config::last_ram_file = NO_RAM_FILE; ESPectrum::reset(); return; @@ -868,7 +913,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { zxDelay = REPDEL; } } else - if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q (Capture screen) + if (!bitRead(ZXKeyb::ZXcols[1], 1)) { // S (Capture screen) if (zxDelay == 0) { ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, true, false); ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, false, false); @@ -933,7 +978,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { zxDelay = REPDEL; } } else - if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q (Capture screen) + if (!bitRead(ZXKeyb::ZXcols[1], 1)) { // S (Capture screen) if (zxDelay == 0) { ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, true, false); ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, false, false); diff --git a/src/Tape.cpp b/src/Tape.cpp index 152d4059..3eef0102 100644 --- a/src/Tape.cpp +++ b/src/Tape.cpp @@ -441,35 +441,17 @@ void Tape::Save() { bool Tape::FlashLoad() { - // if (tapeCurBlock >= (TapeListing.size() - 1)) { - // Z80::setCarryFlag(false); - // return false; - // } FILE *flashtape; flashtape = fopen(Tape::tapeFileName.c_str(), "rb"); - if (flashtape == NULL) - { - OSD::osdCenteredMsg(OSD_TAPE_LOAD_ERR, LEVEL_ERROR); + if (flashtape == NULL) { Z80::setCarryFlag(false); - return false; + return true; } - // fseek(tape,0,SEEK_END); - // tapeFileSize = ftell(tape); - // rewind (tape); // Move to selected block position fseek(flashtape,TapeListing[Tape::tapeCurBlock].StartPosition,SEEK_SET); - // tapePlayOffset = TapeListing[Tape::tapeCurBlock].StartPosition + 2; - -// tapePos = offsetBlocks[idxHeader]; -// blockLen = readInt(tapeBuffer, tapePos, 2); -// // System.out.println(String.format("tapePos: %X. blockLen: %X", tapePos, blockLen)); -// tapePos += 2; - - // uint32_t tapePos = TapeListing[tapeCurBlock].StartPosition; - uint16_t blockLen=(readByteFile(flashtape) | (readByteFile(flashtape) <<8)); uint8_t tapeFlag = readByteFile(flashtape); @@ -478,22 +460,12 @@ bool Tape::FlashLoad() { // printf("%u\n",Z80::getRegA()); // printf("%u\n",Z80::getRegAx()); - // tapePos += 2; - -// // ¿Coincide el flag? (está en el registro A) -// if (cpu.getRegA() != (tapeBuffer[tapePos] & 0xff)) { -// cpu.xor(tapeBuffer[tapePos]); -// cpu.setCarryFlag(false); -// idxHeader++; -// return true; -// } - if (Z80::getRegAx() != (tapeFlag & 0xff)) { // printf("No coincide el flag\n"); fclose(flashtape); + Z80::setFlags(0x00); + Z80::setRegA(Z80::getRegAx() ^ tapeFlag); if (tapeCurBlock < (TapeListing.size() - 1)) { - Z80::setFlags(0x00); - Z80::setRegA(Z80::getRegAx() ^ tapeFlag); tapeCurBlock++; return true; } else { @@ -502,22 +474,9 @@ bool Tape::FlashLoad() { } } -// // La paridad incluye el byte de flag -// cpu.setRegA(tapeBuffer[tapePos]); - // La paridad incluye el byte de flag Z80::setRegA(tapeFlag); -// int count = 0; -// int addr = cpu.getRegIX(); // Address start -// int nBytes = cpu.getRegDE(); // Lenght -// while (count < nBytes && count < blockLen - 1) { -// memory.writeByte(addr, tapeBuffer[tapePos + count + 1]); -// cpu.xor(tapeBuffer[tapePos + count + 1]); -// addr = (addr + 1) & 0xffff; -// count++; -// } - int count = 0; uint8_t data; int addr = Z80::getRegIX(); // Address start @@ -533,27 +492,20 @@ bool Tape::FlashLoad() { // printf("Count: %d. nBytes: %d\n",count,nBytes); -// // Se cargarán los bytes pedidos en DE -// if (count == nBytes) { -// cpu.xor(tapeBuffer[tapePos + count + 1]); // Byte de paridad -// cpu.cp(0x01); -// } - // Se cargarán los bytes pedidos en DE if (count == nBytes) { Z80::Xor(readByteFile(flashtape)); // Byte de paridad Z80::Cp(0x01); - } - - // Hay menos bytes en la cinta de los indicados en DE - // En ese caso habrá dado un error de timeout en LD-SAMPLE (0x05ED) - // que se señaliza con CARRY==reset & ZERO==set - if (count < nBytes) { + } else if (count < nBytes) { + // Hay menos bytes en la cinta de los indicados en DE + // En ese caso habrá dado un error de timeout en LD-SAMPLE (0x05ED) + // que se señaliza con CARRY==reset & ZERO==set Z80::setFlags(0x50); // when B==0xFF, then INC B, B=0x00, F=0x50 } Z80::setRegIX(addr); Z80::setRegDE(nBytes - count); + if (tapeCurBlock < (TapeListing.size() - 1)) tapeCurBlock++; else tapeCurBlock = 0; fclose(flashtape); @@ -884,3 +836,73 @@ bool Tape::FlashLoad() { // // } // // break; // // } + + +// void Spectrum::trapLdStart() { + +// // ZF = 1 means treat the flag byte as a normal byte. This is +// // indicated by setting the number of flag bytes to zero. +// uint16_t flagByte = (z80.af_.b.l & FLAG_Z) ? 1 : 0; + +// // If either there are no flag bytes or the expected flag matches the +// // block's flag, we signal flag ok. Expected flag is in A'. +// bool flagOk = tape.foundTapBlock(z80.af_.b.h) || flagByte; + +// // CF = 1 means LOAD, CF = 0 means VERIFY. +// bool verify = !(z80.af_.b.l & FLAG_C); + +// if (flagOk) { +// // Get parameters from CPU registers +// uint16_t address = z80.ix.w; +// uint16_t bytes = z80.de.w; + +// uint16_t block = tape.getBlockLength() + flagByte - 1; // Include parity +// uint16_t offset = 3 - flagByte; +// uint8_t parity = flagByte ? 0 : tape.getBlockByte(2); + +// if (verify) { +// while (bytes && block) { +// uint8_t byte = tape.getBlockByte(offset++); +// uint8_t mem = readMemory(address++); +// block--; +// bytes--; +// parity ^= byte; +// if (byte != mem) break; +// } +// } else { +// while (bytes && block) { +// uint8_t byte = tape.getBlockByte(offset++); +// writeMemory(address++, byte); +// block--; +// bytes--; +// parity ^= byte; +// } +// } + +// if (block) { +// parity ^= tape.getBlockByte(offset); +// } + +// if (!bytes && block && !parity) { +// z80.af.b.l |= FLAG_C; +// } else { +// z80.af.b.l &= ~FLAG_C; +// if (!block) z80.af.b.l |= FLAG_Z; +// } + +// z80.hl.b.h = parity; +// z80.ix.w = address; +// z80.de.w = bytes; +// } + +// // Advance tape +// tape.nextTapBlock(); + +// // Force RET +// z80.decode(0xC9); +// z80.startInstruction(); + +// if (tape.tapPointer == 0) { +// tape.rewind(); +// } +// } From 76a96c3e65b3e66bf315245030058a81bbe04c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Fri, 21 Jul 2023 02:29:55 +0200 Subject: [PATCH 18/29] Tape traps done and selectable, Main task queue size increased --- include/CPU.h | 18 +--- include/Config.h | 1 + include/Z80_JLS/z80.h | 3 +- include/messages.h | 31 +++++-- include/roms/romSinclair128K.h | 9 ++ include/roms/romSinclair48K.h | 9 ++ sdkconfig.ESPectrum | 4 +- sdkconfig.ESPectrum.old | 68 +-------------- src/CPU.cpp | 147 +-------------------------------- src/Config.cpp | 13 +++ src/ESPectrum.cpp | 2 +- src/OSDMain.cpp | 65 +++++++++------ src/OSDMenu.cpp | 2 + src/Tape.cpp | 3 +- src/Z80_JLS.cpp | 86 ++++++++++++++++++- 15 files changed, 196 insertions(+), 265 deletions(-) diff --git a/include/CPU.h b/include/CPU.h index 58542601..38255761 100644 --- a/include/CPU.h +++ b/include/CPU.h @@ -38,12 +38,6 @@ visit https://zxespectrum.speccy.org/contacto #include #include "ESPectrum.h" -#include "ESP32Lib/ESP32Lib.h" - -// #define INT_START48 0 -// #define INT_END48 32 -// #define INT_START128 0 -// #define INT_END128 36 #define INT_START48 0 #define INT_END48 32 @@ -56,16 +50,8 @@ class CPU // call this for initializing CPU static void setup(); - // call this for executing a frame's worth of instructions - static void IRAM_ATTR loop_fast(); - - // call this for executing a frame's worth of instructions - static void IRAM_ATTR loop_trap(); - - // call this for executing a frame's worth of instructions - static void IRAM_ATTR (*loop)(); - - static void IRAM_ATTR checkTraps(); + // // call this for executing a frame's worth of instructions + static void IRAM_ATTR loop(); // call this for resetting the CPU static void reset(); diff --git a/include/Config.h b/include/Config.h index ba75a9d0..e9f51ab3 100644 --- a/include/Config.h +++ b/include/Config.h @@ -62,6 +62,7 @@ class Config static uint8_t lang; static bool AY48; static bool Issue2; + static bool flashload; static uint8_t joystick; static uint8_t videomode; static uint8_t AluTiming; diff --git a/include/Z80_JLS/z80.h b/include/Z80_JLS/z80.h index f0550593..05490690 100644 --- a/include/Z80_JLS/z80.h +++ b/include/Z80_JLS/z80.h @@ -748,7 +748,8 @@ class Z80 { static void decodeOpcodebc(void); static void decodeOpcodebd(void); static void decodeOpcodebe(void); - static void decodeOpcodebf(void); + + static void IRAM_ATTR decodeOpcodebf(void); // Used for LOAD TRAP static void decodeOpcodec0(void); static void decodeOpcodec1(void); diff --git a/include/messages.h b/include/messages.h index 2e4a1d34..6385ddc7 100644 --- a/include/messages.h +++ b/include/messages.h @@ -208,12 +208,27 @@ static const char *MENU_PERSIST_LOAD[2] = { MENU_PERSIST_LOAD_EN, MENU_PERSIST_L // "Refrescar directorios\n" // static const char *MENU_STORAGE[2] = { MENU_STORAGE_EN, MENU_STORAGE_ES }; +// #define MENU_STORAGE_EN "Storage\n"\ +// "Refresh directories\n" +// #define MENU_STORAGE_ES "Almacenamiento\n"\ +// "Refrescar directorios\n" +// static const char *MENU_STORAGE[2] = { MENU_STORAGE_EN, MENU_STORAGE_ES }; + #define MENU_STORAGE_EN "Storage\n"\ + "Flash tape load\t>\n"\ "Refresh directories\n" #define MENU_STORAGE_ES "Almacenamiento\n"\ + "Carga rapida cinta\t>\n"\ "Refrescar directorios\n" -static const char *MENU_STORAGE[2] = { MENU_STORAGE_EN, MENU_STORAGE_ES }; +// static const char *MENU_STORAGE[2] = { MENU_STORAGE_EN, MENU_STORAGE_ES }; +#define MENU_FLASHLOAD_EN "Flash load\n"\ + "Yes\t[Y]\n"\ + "No\t[N]\n" +#define MENU_FLASHLOAD_ES "Carga rapida\n"\ + "Si\t[Y]\n"\ + "No\t[N]\n" +// static const char *MENU_FLASHLOAD[2] = { MENU_FLASHLOAD_EN, MENU_FLASHLOAD_ES }; #define MENU_OTHER_EN "Other\n"\ "AY on 48K\t>\n"\ @@ -327,8 +342,8 @@ static const char *MENU_JOY[2] = { MENU_JOY_EN, MENU_JOY_ES }; " PS2 driver by Fabrizio di Vittorio\n"\ "\n"\ " Greetings to Ackerman, zx81, azesmbog,\n"\ - " Rampa, D. Carrion, A. Villena and\n"\ - " to Retrowiki and his people\n"\ + " ZjoyKiLer, D. Carrion, A. Villena,\n"\ + " Rampa and to Retrowiki and his people\n"\ " for the support and inspiration.\n" #define OSD_ABOUT_ES \ " (C)2023 Victor Iborra \"Eremus\"\n"\ @@ -346,10 +361,11 @@ static const char *MENU_JOY[2] = { MENU_JOY_EN, MENU_JOY_ES }; " Driver PS2 por Fabrizio di Vittorio\n"\ "\n"\ " Saludos a Ackerman, zx81, azesmbog,\n"\ - " Rampa, D. Carrion, A. Villena y\n"\ - " a Retrowiki y su gente por su\n"\ + " ZjoyKiLer, D. Carrion, A. Villena,\n"\ + " Rampa y a Retrowiki y su gente por su\n"\ " ayuda e inspiracion.\n" -static const char *OSD_ABOUT[2] = { OSD_ABOUT_EN, OSD_ABOUT_ES }; + +// static const char *OSD_ABOUT[2] = { OSD_ABOUT_EN, OSD_ABOUT_ES }; #define OSD_HELP_EN \ " [F1] Menu\n"\ @@ -387,7 +403,8 @@ static const char *OSD_ABOUT[2] = { OSD_ABOUT_EN, OSD_ABOUT_ES }; " [F12] Resetear ESP32\n"\ " [Pause] Pausa\n"\ " [ImpPant] Captura BMP (Carpeta SD /c)\n" -static const char *OSD_HELP[2] = { OSD_HELP_EN, OSD_HELP_ES }; + +// static const char *OSD_HELP[2] = { OSD_HELP_EN, OSD_HELP_ES }; static const char *OSD_TAPE_OF[2] = { "of", "de" }; diff --git a/include/roms/romSinclair128K.h b/include/roms/romSinclair128K.h index 78d8ddbe..9830f66b 100644 --- a/include/roms/romSinclair128K.h +++ b/include/roms/romSinclair128K.h @@ -1109,7 +1109,10 @@ const unsigned char gb_rom_1_sinclair_128k[]={ 0x3E,0x89,0x43,0xFF,0x6A,0x73,0x89,0x4F,0xA7,0x00,0x54,0x89,0x5C,0x00,0x00,0x00, 0x89,0x69,0x14,0xF6,0x24,0x89,0x76,0xF1,0x10,0x05,0xCD,0xFB,0x24,0x3A,0x3B,0x5C, 0x87,0xFA,0x8A,0x1C,0xE1,0xD0,0xE5,0xCD,0xF1,0x2B,0x62,0x6B,0x0D,0xF8,0x09,0xCB, + 0xFE,0xC9,0x21,0x3F,0x05,0xE5,0x21,0x80,0x1F,0xCB,0x7F,0x28,0x03,0x21,0x98,0x0C, +// 0xFE,0xC9,0x21,0x3F,0x05,0x64,0x21,0x80,0x1F,0xCB,0x7F,0x28,0x03,0x21,0x98,0x0C, // Instruction 0xE5 replaced with 0x64 (LD H,H) to mark the save trap at SA_BYTES + 0x08,0x13,0xDD,0x2B,0xF3,0x3E,0x02,0x47,0x10,0xFE,0xD3,0xFE,0xEE,0x0F,0x06,0xA4, 0x2D,0x20,0xF5,0x05,0x25,0xF2,0xD8,0x04,0x06,0x2F,0x10,0xFE,0xD3,0xFE,0x3E,0x0D, 0x06,0x37,0x10,0xFE,0xD3,0xFE,0x01,0x0E,0x3B,0x08,0x6F,0xC3,0x07,0x05,0x7A,0xB3, @@ -1119,7 +1122,10 @@ const unsigned char gb_rom_1_sinclair_128k[]={ 0x7F,0xDB,0xFE,0x1F,0xD0,0x7A,0x3C,0xC2,0xFE,0x04,0x06,0x3B,0x10,0xFE,0xC9,0xF5, 0x3A,0x48,0x5C,0xE6,0x38,0x0F,0x0F,0x0F,0xD3,0xFE,0x3E,0x7F,0xDB,0xFE,0x1F,0xFB, 0x38,0x02,0xCF,0x0C,0xF1,0xC9,0x14,0x08,0x15,0xF3,0x3E,0x0F,0xD3,0xFE,0x21,0x3F, + 0x05,0xE5,0xDB,0xFE,0x1F,0xE6,0x20,0xF6,0x02,0x4F,0xBF,0xC0,0xCD,0xE7,0x05,0x30, +// 0x05,0xE5,0xDB,0xFE,0x1F,0xE6,0x20,0xF6,0x02,0x64,0xBF,0xC0,0xCD,0xE7,0x05,0x30, // Instruction 0x4F replaced with 0x64 (LD H,H) to mark the tape load trap + 0xFA,0x21,0x15,0x04,0x10,0xFE,0x2B,0x7C,0xB5,0x20,0xF9,0xCD,0xE3,0x05,0x30,0xEB, 0x06,0x9C,0xCD,0xE3,0x05,0x30,0xE4,0x3E,0xC6,0xB8,0x30,0xE0,0x24,0x20,0xF1,0x06, 0xC9,0xCD,0xE7,0x05,0x30,0xD5,0x78,0xFE,0xD4,0x30,0xF4,0xCD,0xE7,0x05,0xD0,0x79, @@ -1184,7 +1190,10 @@ const unsigned char gb_rom_1_sinclair_128k[]={ 0xCD,0xB8,0x19,0x22,0x5F,0x5C,0x2A,0x53,0x5C,0xE3,0xC5,0x08,0x38,0x07,0x2B,0xCD, 0x55,0x16,0x23,0x18,0x03,0xCD,0x55,0x16,0x23,0xC1,0xD1,0xED,0x53,0x53,0x5C,0xED, 0x5B,0x5F,0x5C,0xC5,0xD5,0xEB,0xED,0xB0,0xE1,0xC1,0xD5,0xCD,0xE8,0x19,0xD1,0xC9, + 0xE5,0x3E,0xFD,0xCD,0x01,0x16,0xAF,0x11,0xA1,0x09,0xCD,0x0A,0x0C,0xFD,0xCB,0x02, +// 0x64,0x3E,0xFD,0xCD,0x01,0x16,0xAF,0x11,0xA1,0x09,0xCD,0x0A,0x0C,0xFD,0xCB,0x02, // Instruction 0xE5 replaced with 0x64 (LD H,H) to mark the tape save SA_CONTRL trap + 0xEE,0xCD,0xD4,0x15,0xDD,0xE5,0x11,0x11,0x00,0xAF,0xCD,0xC2,0x04,0xDD,0xE1,0x06, 0x32,0x76,0x10,0xFD,0xDD,0x5E,0x0B,0xDD,0x56,0x0C,0x3E,0xFF,0xDD,0xE1,0xC3,0xC2, 0x04,0x80,0x53,0x74,0x61,0x72,0x74,0x20,0x74,0x61,0x70,0x65,0x2C,0x20,0x74,0x68, diff --git a/include/roms/romSinclair48K.h b/include/roms/romSinclair48K.h index 7191f3e0..fe39ed35 100644 --- a/include/roms/romSinclair48K.h +++ b/include/roms/romSinclair48K.h @@ -78,7 +78,10 @@ const unsigned char gb_rom_0_sinclair_48k[]={ 0x3E,0x89,0x43,0xFF,0x6A,0x73,0x89,0x4F,0xA7,0x00,0x54,0x89,0x5C,0x00,0x00,0x00, 0x89,0x69,0x14,0xF6,0x24,0x89,0x76,0xF1,0x10,0x05,0xCD,0xFB,0x24,0x3A,0x3B,0x5C, 0x87,0xFA,0x8A,0x1C,0xE1,0xD0,0xE5,0xCD,0xF1,0x2B,0x62,0x6B,0x0D,0xF8,0x09,0xCB, + 0xFE,0xC9,0x21,0x3F,0x05,0xE5,0x21,0x80,0x1F,0xCB,0x7F,0x28,0x03,0x21,0x98,0x0C, +// 0xFE,0xC9,0x21,0x3F,0x05,0x64,0x21,0x80,0x1F,0xCB,0x7F,0x28,0x03,0x21,0x98,0x0C, // Instruction 0xE5 replaced with 0x64 (LD H,H) to mark the save trap at SA_BYTES + 0x08,0x13,0xDD,0x2B,0xF3,0x3E,0x02,0x47,0x10,0xFE,0xD3,0xFE,0xEE,0x0F,0x06,0xA4, 0x2D,0x20,0xF5,0x05,0x25,0xF2,0xD8,0x04,0x06,0x2F,0x10,0xFE,0xD3,0xFE,0x3E,0x0D, 0x06,0x37,0x10,0xFE,0xD3,0xFE,0x01,0x0E,0x3B,0x08,0x6F,0xC3,0x07,0x05,0x7A,0xB3, @@ -88,7 +91,10 @@ const unsigned char gb_rom_0_sinclair_48k[]={ 0x7F,0xDB,0xFE,0x1F,0xD0,0x7A,0x3C,0xC2,0xFE,0x04,0x06,0x3B,0x10,0xFE,0xC9,0xF5, 0x3A,0x48,0x5C,0xE6,0x38,0x0F,0x0F,0x0F,0xD3,0xFE,0x3E,0x7F,0xDB,0xFE,0x1F,0xFB, 0x38,0x02,0xCF,0x0C,0xF1,0xC9,0x14,0x08,0x15,0xF3,0x3E,0x0F,0xD3,0xFE,0x21,0x3F, + 0x05,0xE5,0xDB,0xFE,0x1F,0xE6,0x20,0xF6,0x02,0x4F,0xBF,0xC0,0xCD,0xE7,0x05,0x30, +// 0x05,0xE5,0xDB,0xFE,0x1F,0xE6,0x20,0xF6,0x02,0x64,0xBF,0xC0,0xCD,0xE7,0x05,0x30, // Instruction 0x4F replaced with 0x64 (LD H,H) to mark the tape load trap + 0xFA,0x21,0x15,0x04,0x10,0xFE,0x2B,0x7C,0xB5,0x20,0xF9,0xCD,0xE3,0x05,0x30,0xEB, 0x06,0x9C,0xCD,0xE3,0x05,0x30,0xE4,0x3E,0xC6,0xB8,0x30,0xE0,0x24,0x20,0xF1,0x06, 0xC9,0xCD,0xE7,0x05,0x30,0xD5,0x78,0xFE,0xD4,0x30,0xF4,0xCD,0xE7,0x05,0xD0,0x79, @@ -153,7 +159,10 @@ const unsigned char gb_rom_0_sinclair_48k[]={ 0xCD,0xB8,0x19,0x22,0x5F,0x5C,0x2A,0x53,0x5C,0xE3,0xC5,0x08,0x38,0x07,0x2B,0xCD, 0x55,0x16,0x23,0x18,0x03,0xCD,0x55,0x16,0x23,0xC1,0xD1,0xED,0x53,0x53,0x5C,0xED, 0x5B,0x5F,0x5C,0xC5,0xD5,0xEB,0xED,0xB0,0xE1,0xC1,0xD5,0xCD,0xE8,0x19,0xD1,0xC9, + 0xE5,0x3E,0xFD,0xCD,0x01,0x16,0xAF,0x11,0xA1,0x09,0xCD,0x0A,0x0C,0xFD,0xCB,0x02, +// 0x64,0x3E,0xFD,0xCD,0x01,0x16,0xAF,0x11,0xA1,0x09,0xCD,0x0A,0x0C,0xFD,0xCB,0x02, // Instruction 0xE5 replaced with 0x64 (LD H,H) to mark the tape save SA_CONTRL trap + 0xEE,0xCD,0xD4,0x15,0xDD,0xE5,0x11,0x11,0x00,0xAF,0xCD,0xC2,0x04,0xDD,0xE1,0x06, 0x32,0x76,0x10,0xFD,0xDD,0x5E,0x0B,0xDD,0x56,0x0C,0x3E,0xFF,0xDD,0xE1,0xC3,0xC2, 0x04,0x80,0x53,0x74,0x61,0x72,0x74,0x20,0x74,0x61,0x70,0x65,0x2C,0x20,0x74,0x68, diff --git a/sdkconfig.ESPectrum b/sdkconfig.ESPectrum index 08d95131..0f562e26 100644 --- a/sdkconfig.ESPectrum +++ b/sdkconfig.ESPectrum @@ -336,7 +336,7 @@ CONFIG_ADC_CAL_LUT_ENABLE=y # CONFIG_ESP_ERR_TO_NAME_LOOKUP is not set CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304 -CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192 CONFIG_ESP_IPC_TASK_STACK_SIZE=1024 CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048 @@ -1176,7 +1176,7 @@ CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y # CONFIG_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 -CONFIG_MAIN_TASK_STACK_SIZE=3584 +CONFIG_MAIN_TASK_STACK_SIZE=8192 CONFIG_IPC_TASK_STACK_SIZE=1024 CONFIG_CONSOLE_UART_DEFAULT=y # CONFIG_CONSOLE_UART_CUSTOM is not set diff --git a/sdkconfig.ESPectrum.old b/sdkconfig.ESPectrum.old index ffcfd065..2fc58636 100644 --- a/sdkconfig.ESPectrum.old +++ b/sdkconfig.ESPectrum.old @@ -270,7 +270,6 @@ CONFIG_ESP_TLS_USING_MBEDTLS=y # # ESP32-specific # -CONFIG_ESP32_ECO3_CACHE_LOCK_FIX=y # CONFIG_ESP32_REV_MIN_0 is not set CONFIG_ESP32_REV_MIN_1=y # CONFIG_ESP32_REV_MIN_2 is not set @@ -281,66 +280,7 @@ CONFIG_ESP32_DPORT_WORKAROUND=y # CONFIG_ESP32_DEFAULT_CPU_FREQ_160 is not set CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240 -CONFIG_ESP32_SPIRAM_SUPPORT=y - -# -# SPI RAM config -# -CONFIG_SPIRAM_TYPE_AUTO=y -# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set -# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set -# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set -CONFIG_SPIRAM_SIZE=-1 -# CONFIG_SPIRAM_SPEED_40M is not set -CONFIG_SPIRAM_SPEED_80M=y -CONFIG_SPIRAM=y -CONFIG_SPIRAM_BOOT_INIT=y -# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set -# CONFIG_SPIRAM_USE_MEMMAP is not set -CONFIG_SPIRAM_USE_CAPS_ALLOC=y -# CONFIG_SPIRAM_USE_MALLOC is not set -CONFIG_SPIRAM_MEMTEST=y -# CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP is not set -# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set -CONFIG_SPIRAM_CACHE_WORKAROUND=y - -# -# SPIRAM cache workaround debugging -# -CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW=y -# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST is not set -# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS is not set -# end of SPIRAM cache workaround debugging - -CONFIG_SPIRAM_BANKSWITCH_ENABLE=y -CONFIG_SPIRAM_BANKSWITCH_RESERVE=8 -# CONFIG_SPIRAM_OCCUPY_HSPI_HOST is not set -CONFIG_SPIRAM_OCCUPY_VSPI_HOST=y -# CONFIG_SPIRAM_OCCUPY_NO_HOST is not set - -# -# PSRAM clock and cs IO for ESP32-DOWD -# -CONFIG_D0WD_PSRAM_CLK_IO=17 -CONFIG_D0WD_PSRAM_CS_IO=16 -# end of PSRAM clock and cs IO for ESP32-DOWD - -# -# PSRAM clock and cs IO for ESP32-D2WD -# -CONFIG_D2WD_PSRAM_CLK_IO=9 -CONFIG_D2WD_PSRAM_CS_IO=10 -# end of PSRAM clock and cs IO for ESP32-D2WD - -# -# PSRAM clock and cs IO for ESP32-PICO -# -CONFIG_PICO_PSRAM_CS_IO=10 -# end of PSRAM clock and cs IO for ESP32-PICO - -# CONFIG_SPIRAM_2T_MODE is not set -# end of SPI RAM config - +# CONFIG_ESP32_SPIRAM_SUPPORT is not set # CONFIG_ESP32_TRAX is not set CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0 # CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set @@ -489,7 +429,7 @@ CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER=y # CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT is not set CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT=y # CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set -# CONFIG_ESP_SYSTEM_PSRAM_LEAKAGE_WORKAROUND is not set +CONFIG_ESP_SYSTEM_PD_FLASH=y # CONFIG_ESP_SYSTEM_FLASH_LEAKAGE_WORKAROUND is not set # @@ -518,12 +458,10 @@ CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y # CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER is not set CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0 CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=16 -CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=32 # CONFIG_ESP32_WIFI_CSI_ENABLED is not set CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y CONFIG_ESP32_WIFI_TX_BA_WIN=6 # CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED is not set -# CONFIG_ESP32_WIFI_AMSDU_TX_ENABLED is not set CONFIG_ESP32_WIFI_NVS_ENABLED=y # CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0 is not set CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1=y @@ -595,7 +533,6 @@ CONFIG_FATFS_API_ENCODING_ANSI_OEM=y CONFIG_FATFS_FS_LOCK=0 CONFIG_FATFS_TIMEOUT_MS=10000 # CONFIG_FATFS_PER_FILE_CACHE is not set -CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y # CONFIG_FATFS_USE_FASTSEEK is not set # end of FAT Filesystem support @@ -834,7 +771,6 @@ CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y # mbedTLS # CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y -# CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC is not set # CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set # CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y diff --git a/src/CPU.cpp b/src/CPU.cpp index 38fc4c82..b3bebab9 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -33,16 +33,12 @@ visit https://zxespectrum.speccy.org/contacto */ -#include -#include - #include "CPU.h" #include "ESPectrum.h" #include "MemESP.h" #include "Ports.h" #include "hardconfig.h" #include "Config.h" -#include "Tape.h" #include "Video.h" #include "Z80_JLS/z80.h" @@ -50,8 +46,6 @@ visit https://zxespectrum.speccy.org/contacto static bool createCalled = false; -void (*CPU::loop)() = &CPU::loop_trap; - uint32_t CPU::statesPerFrame() { if (Config::getArch() == "48K") return 69888; @@ -131,7 +125,7 @@ void CPU::reset() { /////////////////////////////////////////////////////////////////////////////// -void IRAM_ATTR CPU::loop_fast() +void IRAM_ATTR CPU::loop() { while (tstates < IntEnd) { @@ -156,117 +150,6 @@ void IRAM_ATTR CPU::loop_fast() } -void IRAM_ATTR CPU::loop_trap() -{ - - while (tstates < IntEnd) { - CPU::checkTraps(); - Z80::execute(); - Z80::checkINT(); - } - - uint32_t stFrame = statesInFrame - IntEnd; - while (tstates < stFrame) { - CPU::checkTraps(); - Z80::execute(); - } - - while (tstates < statesInFrame) { - CPU::checkTraps(); - Z80::execute(); - Z80::checkINT(); - } - - - if (tstates & 0xFF000000) FlushOnHalt(); // If we're halted flush screen and update registers as needed - - global_tstates += statesInFrame; // increase global Tstates - tstates -= statesInFrame; - - framecnt++; - -} - -// trim from end (in place) -static inline void rtrim(std::string &s) { - s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { - return !std::isspace(ch); - }).base(), s.end()); -} - -void IRAM_ATTR CPU::checkTraps() { - - string name; - int result; - uint16_t header_data; - - switch(Z80::getRegPC()) { - - case 0x970 : - // if PC is 0x970, a call to SA_CONTRL has been made: - // remove .tap output file if exists - - // Get save name - - header_data = Z80::getRegIX(); - for (int i=0; i < 10; i++) - name += MemESP::ramCurrent[header_data++ >> 14][header_data & 0x3fff]; - rtrim(name); - Tape::tapeSaveName = "/sd/t/" + name + ".tap"; - - // TO DO: Check existence of file and ask for overwrite or append - - printf("Removing previuous tap file.\n"); - result = remove(Tape::tapeSaveName.c_str()); - - // check if file has been deleted successfully - // if (result != 0) { - // // print error message - // printf("File deletion failed\n"); - // } - // else { - // printf("File deleted succesfully\n"); - // } - - printf("%s\n",Tape::tapeSaveName.c_str()); - - break; - - case 0x4C2 : - // if PC is 0x04C2, a call to SA_BYTES has been made: - // Call Save function - - printf("Saving %s block.\n",Tape::tapeSaveName.c_str()); - Tape::Save(); - Z80::setRegPC(0x555); - - break; - - // case 0x556 : // Jspeccy - case 0x56A : // SoftSpectrum - - // LD_BYTES routine in Spectrum ROM at address 0x0556 - - // if (loadTrap && memory.isSpectrumRom() && tape.isTapeReady()) { - // if (flashload && tape.flashLoad(memory)) { - // invalidateScreen(true); // thanks Andrew Owen - // return 0xC9; // RET opcode - // } else { - // tape.play(false); - // } - // } - - if ((Tape::tapeFileName != "none") && (Tape::tapeStatus != TAPE_LOADING)) { - // printf("Loading tape %s\n",Tape::tapeFileName.c_str()); - if (Tape::FlashLoad()) Z80::setRegPC(0x5e2); - } - - break; - - } - -} - void CPU::FlushOnHalt() { tstates &= 0x00FFFFFF; @@ -279,40 +162,12 @@ void CPU::FlushOnHalt() { VIDEO::Draw(4,true); Z80::incRegR(1); } - - // if (Z80Ops::is48) { - - // while (tstates < statesInFrame ) { - // uint32_t currentTstates = CPU::tstates + 1; - // unsigned short int line = currentTstates / 224; - // if (line >= 64 && line < 256) tstates += wait_st[currentTstates % 224]; - // tstates += 4; - // Z80::incRegR(1); - // } - - // } else { - - // while (tstates < statesInFrame ) { - // uint32_t currentTstates = CPU::tstates + 3; - // unsigned short int line = currentTstates / 228; - // if (line >= 63 && line < 255) tstates += wait_st[currentTstates % 228]; - // tstates += 4; - // Z80::incRegR(1); - // } - - // } } else { uint32_t pre_tstates = tstates; VIDEO::Flush(); // Draw the rest of the frame tstates = pre_tstates; - - // uint32_t stFrame = statesInFrame - latetiming; - // while (tstates < stFrame ) { - // tstates += 4; - // Z80::incRegR(1); - // } pre_tstates += latetiming; uint32_t incr = (statesInFrame - pre_tstates) >> 2; diff --git a/src/Config.cpp b/src/Config.cpp index 5f37234c..43de4327 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -63,6 +63,7 @@ uint8_t Config::esp32rev = 0; uint8_t Config::lang = 0; bool Config::AY48 = false; bool Config::Issue2 = true; +bool Config::flashload = true; uint8_t Config::joystick = 0; // 0 -> Cursor, 1 -> Kempston uint8_t Config::AluTiming = 0; @@ -223,6 +224,15 @@ void Config::load() { free(str_data); } + err = nvs_get_str(handle, "flashload", NULL, &required_size); + if (err == ESP_OK) { + str_data = (char *)malloc(required_size); + nvs_get_str(handle, "flashload", str_data, &required_size); + printf("Flashload:%s\n",str_data); + flashload = strcmp(str_data, "false"); + free(str_data); + } + err = nvs_get_u8(handle, "joystick", &Config::joystick); if (err == ESP_OK) { printf("joystick:%u\n",Config::joystick); @@ -375,6 +385,9 @@ void Config::save(string value) { if((value=="Issue2") || (value=="all")) nvs_set_str(handle,"Issue2",Issue2 ? "true" : "false"); + if((value=="flashload") || (value=="all")) + nvs_set_str(handle,"flashload",flashload ? "true" : "false"); + if((value=="joystick") || (value=="all")) nvs_set_u8(handle,"joystick",Config::joystick); diff --git a/src/ESPectrum.cpp b/src/ESPectrum.cpp index f1c0d537..30693690 100644 --- a/src/ESPectrum.cpp +++ b/src/ESPectrum.cpp @@ -1304,7 +1304,7 @@ for(;;) { #else if (Tape::tapeStatus==TAPE_LOADING) { - snprintf(linea1, sizeof(linea1), "%02d/%02d %10s % 6d ", Tape::TapeListing[Tape::tapeCurBlock].Index, Tape::TapeListing.size() - 1, Tape::TapeListing[Tape::tapeCurBlock].FileName, Tape::TapeListing[Tape::tapeCurBlock].BlockLength); + snprintf(linea1, sizeof(linea1), "%02d/%02d %10s % 6d ", Tape::TapeListing[Tape::tapeCurBlock].Index + 1, Tape::TapeListing.size(), Tape::TapeListing[Tape::tapeCurBlock].FileName, Tape::TapeListing[Tape::tapeCurBlock].BlockLength); float percent = (float)((Tape::tapebufByteCount + Tape::tapePlayOffset) * 100) / (float)Tape::tapeFileSize; snprintf(linea2, sizeof(linea2), "%5.2f%% %06d %s %06d ", percent, Tape::tapebufByteCount + Tape::tapePlayOffset, OSD_TAPE_OF[Config::lang] , Tape::tapeFileSize); } else { diff --git a/src/OSDMain.cpp b/src/OSDMain.cpp index 021ca9c1..6c10184f 100644 --- a/src/OSDMain.cpp +++ b/src/OSDMain.cpp @@ -602,20 +602,45 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { while (1) { menu_level = 2; // Storage source - string stor_menu = MENU_STORAGE[Config::lang]; - // int curopt; - // if (FileUtils::MountPoint == MOUNT_POINT_SPIFFS) { - // stor_menu.replace(stor_menu.find("[I",0),2,"[*"); - // stor_menu.replace(stor_menu.find("[S",0),2,"[ "); - // curopt = 1; - // } else { - // stor_menu.replace(stor_menu.find("[I",0),2,"[ "); - // stor_menu.replace(stor_menu.find("[S",0),2,"[*"); - // curopt = 2; - // } + // string stor_menu = MENU_STORAGE[Config::lang]; + string stor_menu = Config::lang ? MENU_STORAGE_ES : MENU_STORAGE_EN; uint8_t opt2 = menuRun(stor_menu); if (opt2) { - // if (opt2 == 3) { + if (opt2 == 1) { + menu_level = 3; + menu_curopt = 1; + menu_saverect = true; + while (1) { + string flash_menu = Config::lang ? MENU_FLASHLOAD_ES : MENU_FLASHLOAD_EN; + bool prev_flashload = Config::flashload; + if (prev_flashload) { + flash_menu.replace(flash_menu.find("[Y",0),2,"[*"); + flash_menu.replace(flash_menu.find("[N",0),2,"[ "); + } else { + flash_menu.replace(flash_menu.find("[Y",0),2,"[ "); + flash_menu.replace(flash_menu.find("[N",0),2,"[*"); + } + uint8_t opt2 = menuRun(flash_menu); + if (opt2) { + if (opt2 == 1) + Config::flashload = true; + else + Config::flashload = false; + + if (Config::flashload != prev_flashload) { + Config::save("flashload"); + } + menu_curopt = opt2; + menu_saverect = false; + } else { + menu_curopt = 1; + menu_level = 2; + break; + } + } + } + else + if (opt2 == 2) { OSD::osdCenteredMsg("Refreshing snap dir", LEVEL_INFO); int chunks = FileUtils::DirToFile(FileUtils::MountPoint + DISK_SNA_DIR, ".sna.SNA.z80.Z80"); // Prepare sna filelist if (chunks) FileUtils::Mergefiles(FileUtils::MountPoint + DISK_SNA_DIR,chunks); // Merge files @@ -623,15 +648,9 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { chunks = FileUtils::DirToFile(FileUtils::MountPoint + DISK_TAP_DIR, ".tap.TAP"); // Prepare tap filelist if (chunks) FileUtils::Mergefiles(FileUtils::MountPoint + DISK_TAP_DIR,chunks); // Merge files return; - // } else if (opt2 != curopt) { - // if (opt2 == 1) - // FileUtils::MountPoint = MOUNT_POINT_SPIFFS; - // else - // FileUtils::MountPoint = MOUNT_POINT_SD; - // Config::save(); - // } - // menu_curopt = opt2; - // menu_saverect = false; + } + menu_curopt = opt2; + menu_saverect = false; } else { menu_curopt = 1; break; @@ -885,7 +904,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { drawOSD(true); osdAt(2, 0); VIDEO::vga.setTextColor(OSD::zxColor(7, 0), OSD::zxColor(1, 0)); - VIDEO::vga.print(OSD_HELP[Config::lang]); + VIDEO::vga.print(Config::lang ? OSD_HELP_ES : OSD_HELP_EN); // #ifdef ZXKEYB zxDelay = REPDEL; @@ -950,7 +969,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { drawOSD(false); osdAt(2, 0); VIDEO::vga.setTextColor(OSD::zxColor(7, 0), OSD::zxColor(1, 0)); - VIDEO::vga.print(OSD_ABOUT[Config::lang]); + VIDEO::vga.print(Config::lang ? OSD_ABOUT_ES : OSD_ABOUT_EN); // #ifdef ZXKEYB zxDelay = REPDEL; diff --git a/src/OSDMenu.cpp b/src/OSDMenu.cpp index 5c5e5066..f5ad20ec 100644 --- a/src/OSDMenu.cpp +++ b/src/OSDMenu.cpp @@ -854,6 +854,7 @@ string OSD::menuFile(string filedir, string title, string extensions) { click(); } else if (Menukey.vk == fabgl::VK_RETURN) { fclose(dirfile); + dirfile = NULL; filedir = rowGet(menu,focus); rtrim(filedir); click(); @@ -877,6 +878,7 @@ string OSD::menuFile(string filedir, string title, string extensions) { } fclose(dirfile); + dirfile = NULL; click(); return ""; } diff --git a/src/Tape.cpp b/src/Tape.cpp index 3eef0102..0bdef2f0 100644 --- a/src/Tape.cpp +++ b/src/Tape.cpp @@ -445,8 +445,7 @@ bool Tape::FlashLoad() { flashtape = fopen(Tape::tapeFileName.c_str(), "rb"); if (flashtape == NULL) { - Z80::setCarryFlag(false); - return true; + return false; } // Move to selected block position diff --git a/src/Z80_JLS.cpp b/src/Z80_JLS.cpp index 686704d1..4bff4094 100644 --- a/src/Z80_JLS.cpp +++ b/src/Z80_JLS.cpp @@ -15,11 +15,16 @@ //... v1.0.0 (13/02/2017) // quick & dirty conversion by dddddd (AKA deesix) +#include +#include + #include "Z80_JLS/z80.h" #include "Ports.h" #include "Video.h" #include "MemESP.h" #include "CPU.h" +#include "Tape.h" +#include "Config.h" #pragma GCC optimize ("O3") @@ -2213,10 +2218,22 @@ void Z80::decodeOpcodebe() } -void Z80::decodeOpcodebf() +void IRAM_ATTR Z80::decodeOpcodebf() { /* CP A */ + cp(regA); + if (REG_PC == 0x56b) { // LOAD trap + + // printf("Trap Load!\n"); + + if ((Config::flashload) && (Tape::tapeFileName != "none") && (Tape::tapeStatus != TAPE_LOADING)) { + // printf("Loading tape %s\n",Tape::tapeFileName.c_str()); + if (Tape::FlashLoad()) REG_PC = 0x5e2; + } + + } + } void Z80::decodeOpcodec0() @@ -4295,6 +4312,13 @@ void (*Z80::dcCB[256])() = { }; +// Trim from end (in place) (for SAVE trap, clean this up later) +static inline void rtrim(std::string &s) { + s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { + return !std::isspace(ch); + }).base(), s.end()); +} + //Subconjunto de instrucciones 0xDD / 0xFD /* * Hay que tener en cuenta el manejo de secuencias códigos DD/FD que no @@ -4375,6 +4399,66 @@ void Z80::decodeDDFD(RegisterPair& regIXY) { { /* DEC IX */ Z80Ops::addressOnBus(getPairIR().word, 2); regIXY.word--; + + if (REG_PC == 0x04d4) { // Save trap + + if (REG_HL == 0x1F80) { + + printf("Saving header!\n"); + + regIXY.word++; + + // remove .tap output file if exists + + // Get save name + string name; + uint16_t header_data = REG_IX; + for (int i=0; i < 10; i++) + name += MemESP::ramCurrent[header_data++ >> 14][header_data & 0x3fff]; + rtrim(name); + Tape::tapeSaveName = "/sd/t/" + name + ".tap"; + + printf("Removing previuous tap file %s.\n",Tape::tapeSaveName.c_str()); + /*int result = */remove(Tape::tapeSaveName.c_str()); + + // check if file has been deleted successfully + // if (result != 0) { + // // print error message + // printf("File deletion failed\n"); + // } + // else { + // printf("File deleted succesfully\n"); + // } + + printf("Saving %s header.\n",Tape::tapeSaveName.c_str()); + + REG_DE--; + regA = 0x00; + + Tape::Save(); + + REG_PC = 0x555; + + } else { + + printf("Saving data!\n"); + + // Call Save function + + printf("Saving %s block.\n",Tape::tapeSaveName.c_str()); + + REG_DE--; + regIXY.word++; + regA = 0xFF; + + Tape::Save(); + + REG_PC = 0x555; + + } + + } + break; } case 0x2C: From 3c858d4fa3a4ee5fd7825016c0dc80dc37763e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Fri, 21 Jul 2023 14:55:32 +0200 Subject: [PATCH 19/29] Tape loaders in code --- include/FileZ80.h | 2 + include/loaders.h | 422 ++++++++++++++++++++++++++++++++++++ src/FileZ80.cpp | 535 ++++++++++++++++++++++++++++++++++++++++++++++ src/OSDMain.cpp | 6 +- 4 files changed, 963 insertions(+), 2 deletions(-) create mode 100644 include/loaders.h diff --git a/include/FileZ80.h b/include/FileZ80.h index f6641919..bd86b1d8 100644 --- a/include/FileZ80.h +++ b/include/FileZ80.h @@ -46,6 +46,8 @@ class FileZ80 { public: static bool load(string z80_fn); + static void loader48(); + static void loader128(); private: static void loadCompressedMemData(FILE *f, uint16_t dataLen, uint16_t memStart, uint16_t memlen); static void loadCompressedMemPage(FILE *f, uint16_t dataLen, uint8_t* memPage, uint16_t memlen); diff --git a/include/loaders.h b/include/loaders.h new file mode 100644 index 00000000..db2cfefd --- /dev/null +++ b/include/loaders.h @@ -0,0 +1,422 @@ +/* + +ESPectrum, a Sinclair ZX Spectrum emulator for Espressif ESP32 SoC + +Copyright (c) 2023 Víctor Iborra [Eremus] and David Crespo [dcrespo3d] +https://github.com/EremusOne/ZX-ESPectrum-IDF + +Based on ZX-ESPectrum-Wiimote +Copyright (c) 2020, 2022 David Crespo [dcrespo3d] +https://github.com/dcrespo3d/ZX-ESPectrum-Wiimote + +Based on previous work by Ramón Martinez and Jorge Fuertes +https://github.com/rampa069/ZX-ESPectrum + +Original project by Pete Todd +https://github.com/retrogubbins/paseVGA + +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 3 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, see . + +To Contact the dev team you can write to zxespectrum@gmail.com or +visit https://zxespectrum.speccy.org/contacto + +*/ + +#ifndef Loaders_h +#define Loaders_h + +const unsigned char load48[1273] = { + 0x22, 0x24, 0x22, 0x00, 0x3F, 0x05, 0x00, 0x00, 0x4E, 0xFF, 0x3F, 0x27, + 0x0E, 0x11, 0x00, 0x21, 0x17, 0x9B, 0x36, 0xFF, 0xFF, 0x00, 0x01, 0x3A, + 0x5C, 0xE2, 0x5C, 0x00, 0xFF, 0x01, 0x36, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x44, 0x03, 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, 0x04, 0x01, 0x04, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0x40, + 0x00, 0xE5, 0x01, 0x05, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0x57, 0x00, 0xF3, 0x0D, 0xCE, 0x0B, + 0xE3, 0x50, 0xCE, 0x0B, 0xE4, 0x50, 0x1D, 0x17, 0xDC, 0x0A, 0xCE, 0x0B, + 0xE7, 0x50, 0x1A, 0x17, 0xDC, 0x0A, 0xD7, 0x18, 0x38, 0x00, 0x38, 0x00, + 0x0D, 0x19, 0xCF, 0x5C, 0xA9, 0x18, 0x06, 0x03, 0x07, 0x5C, 0xB1, 0x33, + 0xB1, 0x33, 0xDB, 0x02, 0x4D, 0x00, 0x11, 0x00, 0x22, 0x00, 0x24, 0x22, + 0x00, 0x00, 0x73, 0x07, 0xCB, 0x5C, 0x76, 0x1B, 0x03, 0x13, 0x00, 0x3E, + 0x00, 0x3C, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x00, 0x00, 0x7C, 0x42, 0x7C, + 0x42, 0x42, 0x7C, 0x00, 0x00, 0x3C, 0x42, 0x40, 0x40, 0x42, 0x3C, 0x00, + 0x00, 0x78, 0x44, 0x42, 0x42, 0x44, 0x78, 0x00, 0x00, 0x7E, 0x40, 0x7C, + 0x40, 0x40, 0x7E, 0x00, 0x00, 0x7E, 0x40, 0x7C, 0x40, 0x40, 0x40, 0x00, + 0x00, 0x3C, 0x42, 0x40, 0x4E, 0x42, 0x3C, 0x00, 0x00, 0x42, 0x42, 0x7E, + 0x42, 0x42, 0x42, 0x00, 0x00, 0x3E, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00, + 0x00, 0x02, 0x02, 0x02, 0x42, 0x42, 0x3C, 0x00, 0x00, 0x44, 0x48, 0x70, + 0x48, 0x44, 0x42, 0x00, 0x00, 0xED, 0xED, 0x05, 0x40, 0x7E, 0x00, 0x00, + 0x42, 0x66, 0x5A, 0x42, 0x42, 0x42, 0x00, 0x00, 0x42, 0x62, 0x52, 0x4A, + 0x46, 0x42, 0x00, 0x00, 0x3C, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00, 0x00, + 0x7C, 0x42, 0x42, 0x7C, 0x40, 0x40, 0x00, 0x00, 0x3C, 0x42, 0x42, 0x52, + 0x4A, 0x3C, 0x00, 0x00, 0x7C, 0x42, 0x42, 0x7C, 0x44, 0x42, 0x00, 0x00, + 0x3C, 0x40, 0x3C, 0x02, 0x42, 0x3C, 0x00, 0x00, 0xFE, 0xED, 0xED, 0x05, + 0x10, 0x00, 0x00, 0xED, 0xED, 0x05, 0x42, 0x3C, 0x00, 0xB1, 0x01, 0x08, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0x18, 0x00, 0xED, 0xED, 0xFF, 0x38, 0xED, 0xED, 0xFF, 0x38, + 0xED, 0xED, 0xFF, 0x38, 0x38, 0x38, 0x38, 0xED, 0xED, 0xFF, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x0D, 0x03, 0x23, 0x0D, 0x0D, 0x23, 0x05, 0xED, + 0xED, 0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x06, 0x00, 0x10, 0xED, 0xED, 0x1A, 0x00, 0x3C, 0x40, 0x00, 0xFF, + 0x8C, 0x01, 0x54, 0xFF, 0xED, 0xED, 0x05, 0x00, 0xFF, 0xFE, 0xFF, 0x01, + 0x38, 0x00, 0x00, 0xCB, 0x5C, 0x00, 0x00, 0xB6, 0x5C, 0xB6, 0x5C, 0xCB, + 0x5C, 0xD0, 0x5C, 0xCA, 0x5C, 0xCC, 0x5C, 0xCF, 0x5C, 0xCF, 0x5C, 0x00, + 0x00, 0xD1, 0x5C, 0xF3, 0x5C, 0xF3, 0x5C, 0x1B, 0x92, 0x5C, 0x10, 0x02, + 0xED, 0xED, 0x08, 0x00, 0x01, 0x1A, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x58, + 0xFF, 0x00, 0x00, 0x21, 0x00, 0x5B, 0x21, 0x17, 0x00, 0x40, 0xE0, 0x50, + 0x21, 0x18, 0x21, 0x17, 0x01, 0x38, 0x00, 0x38, 0xED, 0xED, 0x22, 0x00, + 0x57, 0xFF, 0xFF, 0xFF, 0xF4, 0x09, 0xA8, 0x10, 0x4B, 0xF4, 0x09, 0xC4, + 0x15, 0x53, 0x81, 0x0F, 0xC4, 0x15, 0x52, 0xF4, 0x09, 0xC4, 0x15, 0x50, + 0x80, 0x80, 0xEF, 0x22, 0x22, 0x0D, 0x80, 0x00, 0xFF, 0xED, 0xED, 0x09, + 0x20, 0x00, 0x00, 0x00, 0x80, 0xED, 0xED, 0x12, 0x00, 0x80, 0x0D, 0xCE, + 0x5C, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0x2D, + 0x00 +}; + +const unsigned char load128[3230] = { + 0x02, 0x00, 0x02, 0x00, 0x3F, 0x05, 0x00, 0x00, 0x46, 0xFF, 0x00, 0x2F, + 0x0E, 0x11, 0x00, 0x21, 0x18, 0x9B, 0x36, 0x38, 0x00, 0x00, 0x01, 0x3A, + 0x5C, 0xE2, 0x5C, 0x00, 0xFF, 0x01, 0x36, 0x00, 0x38, 0x00, 0x09, 0x10, + 0x00, 0x07, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x45, 0x03, 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, 0xD0, 0x01, 0x03, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0x64, 0x00, 0xEC, 0xED, 0xED, + 0x0C, 0x00, 0x45, 0x39, 0xA3, 0x39, 0xDB, 0x02, 0x7C, 0x38, 0xE2, 0x5C, + 0x4D, 0x00, 0x11, 0x00, 0x02, 0x00, 0x3F, 0x05, 0x00, 0x02, 0x55, 0x05, + 0x71, 0x07, 0xE2, 0x5C, 0xCB, 0x5C, 0x14, 0x5B, 0x21, 0x18, 0x1D, 0x5B, + 0x00, 0x3E, 0x14, 0x1B, 0x00, 0x3C, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x00, + 0x00, 0x7C, 0x42, 0x7C, 0x42, 0x42, 0x7C, 0x00, 0x00, 0x3C, 0x42, 0x40, + 0x40, 0x42, 0x3C, 0x00, 0x00, 0x78, 0x44, 0x42, 0x42, 0x44, 0x78, 0x00, + 0x00, 0x7E, 0x40, 0x7C, 0x40, 0x40, 0x7E, 0x00, 0x00, 0x7E, 0x40, 0x7C, + 0x40, 0x40, 0x40, 0x00, 0x00, 0x3C, 0x42, 0x40, 0x4E, 0x42, 0x3C, 0x00, + 0x00, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00, 0x00, 0x3E, 0x08, 0x08, + 0x08, 0x08, 0x3E, 0x00, 0x00, 0x02, 0x02, 0x02, 0x42, 0x42, 0x3C, 0x00, + 0x00, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x00, 0x00, 0xED, 0xED, 0x05, + 0x40, 0x7E, 0x00, 0x00, 0x42, 0x66, 0x5A, 0x42, 0x42, 0x42, 0x00, 0x00, + 0x42, 0x62, 0x52, 0x4A, 0x46, 0x42, 0x00, 0x00, 0x3C, 0x42, 0x42, 0x42, + 0x42, 0x3C, 0x00, 0x00, 0x7C, 0x42, 0x42, 0x7C, 0x40, 0x40, 0x00, 0x00, + 0x3C, 0x42, 0x42, 0x52, 0x4A, 0x3C, 0x00, 0x00, 0x7C, 0x42, 0x42, 0x7C, + 0x44, 0x42, 0x00, 0x00, 0x3C, 0x40, 0x3C, 0x02, 0x42, 0x3C, 0x00, 0x00, + 0xFE, 0xED, 0xED, 0x05, 0x10, 0x00, 0x00, 0xED, 0xED, 0x05, 0x42, 0x3C, + 0x00, 0x04, 0x01, 0x04, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0x40, 0x00, + 0x04, 0x01, 0x05, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0x40, 0x00, 0x04, + 0x01, 0x06, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0x40, 0x00, 0x04, 0x01, + 0x07, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0x40, 0x00, 0xC8, 0x03, 0x08, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xCA, 0x00, 0x01, 0xFE, 0x01, 0xFE, + 0x01, 0xED, 0xED, 0xE1, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x04, 0xED, 0xED, 0x11, 0x00, 0x03, 0xFC, 0x03, 0xFC, 0x03, 0xED, + 0xED, 0x21, 0x00, 0xFE, 0xED, 0xED, 0x07, 0x00, 0x10, 0xED, 0xED, 0x09, + 0x00, 0x7C, 0x7C, 0x7E, 0x3C, 0x44, 0x00, 0x10, 0x00, 0x10, 0xED, 0xED, + 0xA5, 0x00, 0x10, 0x38, 0x78, 0x38, 0x00, 0x40, 0x38, 0x38, 0x04, 0x38, + 0x1C, 0xED, 0xED, 0x0F, 0x00, 0x07, 0xF8, 0x07, 0xF8, 0x07, 0xED, 0xED, + 0x21, 0x00, 0x10, 0x38, 0x00, 0x1C, 0x38, 0x78, 0x1C, 0x38, 0x10, 0x00, + 0x00, 0x00, 0x78, 0x1C, 0x38, 0x38, 0x38, 0x00, 0x42, 0x42, 0x40, 0x42, + 0x48, 0x00, 0x38, 0x44, 0x00, 0x1C, 0x38, 0xED, 0xED, 0xA3, 0x00, 0x10, + 0x04, 0x44, 0x44, 0x00, 0x40, 0x44, 0x04, 0x3C, 0x44, 0x20, 0xED, 0xED, + 0x0F, 0x00, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xED, 0xED, 0x21, 0x00, 0x10, + 0x44, 0x00, 0x20, 0x04, 0x44, 0x20, 0x44, 0x10, 0x00, 0x00, 0x00, 0x44, + 0x20, 0x44, 0x40, 0x40, 0x00, 0x7C, 0x42, 0x7C, 0x42, 0x70, 0x00, 0x10, + 0x54, 0x30, 0x20, 0x44, 0xED, 0xED, 0xA3, 0x00, 0x10, 0x3C, 0x44, 0x78, + 0x00, 0x40, 0x44, 0x3C, 0x44, 0x78, 0x20, 0xED, 0xED, 0x0F, 0x00, 0x1F, + 0xE0, 0x1F, 0xE0, 0x1F, 0xED, 0xED, 0x21, 0x00, 0x10, 0x44, 0x00, 0x20, + 0x3C, 0x44, 0x20, 0x78, 0x10, 0x00, 0x3E, 0x00, 0x44, 0x20, 0x78, 0x38, + 0x38, 0x00, 0x42, 0x7C, 0x40, 0x7E, 0x48, 0x00, 0x10, 0x54, 0x10, 0x20, + 0x78, 0xED, 0xED, 0xA3, 0x00, 0x10, 0x44, 0x78, 0x40, 0x00, 0x40, 0x44, + 0x44, 0x44, 0x40, 0x20, 0xED, 0xED, 0x0F, 0x00, 0x3F, 0xC0, 0x3F, 0xC0, + 0x3F, 0xED, 0xED, 0x21, 0x00, 0x10, 0x44, 0x00, 0x20, 0x44, 0x44, 0x20, + 0x40, 0x10, 0x00, 0x00, 0x00, 0x78, 0x20, 0x40, 0x04, 0x04, 0x00, 0x42, + 0x44, 0x40, 0x42, 0x44, 0x00, 0x10, 0x54, 0x10, 0x20, 0x40, 0xED, 0xED, + 0xA3, 0x00, 0x10, 0x3C, 0x40, 0x3C, 0x00, 0x7E, 0x38, 0x3C, 0x3C, 0x3C, + 0x20, 0xED, 0xED, 0x0F, 0x00, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0xED, 0xED, + 0x21, 0x00, 0x10, 0x38, 0x00, 0x1C, 0x3C, 0x44, 0x1C, 0x3C, 0x0C, 0x00, + 0x00, 0x00, 0x40, 0x20, 0x3C, 0x78, 0x78, 0x00, 0x7C, 0x42, 0x7E, 0x42, + 0x42, 0x00, 0x0C, 0x28, 0x38, 0x1C, 0x3C, 0xED, 0xED, 0xA5, 0x00, 0x40, + 0xED, 0xED, 0x17, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xED, 0xED, 0x2D, + 0x00, 0x40, 0xED, 0xED, 0x13, 0x00, 0xED, 0xED, 0xFF, 0x38, 0xED, 0xED, + 0xFF, 0x38, 0xED, 0xED, 0xA2, 0x38, 0xED, 0xED, 0x0B, 0x47, 0xED, 0xED, + 0x0F, 0x40, 0x42, 0x72, 0x74, 0x6C, 0x68, 0x40, 0xED, 0xED, 0x40, 0x38, + 0xF5, 0xC5, 0x01, 0xFD, 0x7F, 0x3A, 0x5C, 0x5B, 0xEE, 0x10, 0xF3, 0x32, + 0x5C, 0x5B, 0xED, 0x79, 0xFB, 0xC1, 0xF1, 0xC9, 0xCD, 0x00, 0x5B, 0xE5, + 0x2A, 0x5A, 0x5B, 0xE3, 0xC9, 0xF3, 0x3A, 0x5C, 0x5B, 0xE6, 0xEF, 0x32, + 0x5C, 0x5B, 0x01, 0xFD, 0x7F, 0xED, 0x79, 0xFB, 0xC3, 0xC3, 0x00, 0x21, + 0xD8, 0x06, 0x18, 0x03, 0x21, 0xCA, 0x07, 0x08, 0x01, 0xFD, 0x7F, 0x3A, + 0x5C, 0x5B, 0xF5, 0xE6, 0xEF, 0xF3, 0x32, 0x5C, 0x5B, 0xED, 0x79, 0xC3, + 0xE6, 0x05, 0x08, 0xF1, 0x01, 0xFD, 0x7F, 0xF3, 0x32, 0x5C, 0x5B, 0xED, + 0x79, 0xFB, 0x08, 0xC9, 0x61, 0x07, 0x2E, 0x15, 0x10, 0xCF, 0x00, 0x0B, + 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x11, 0xED, 0xED, 0x1A, 0x00, 0xF3, + 0x5B, 0xEC, 0xEB, 0xEC, 0x2B, 0x01, 0x01, 0x38, 0x00, 0x21, 0x03, 0xED, + 0xED, 0x07, 0x00, 0x0A, 0x00, 0x0A, 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, + 0x3F, 0x7F, 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0xED, 0xED, + 0x24, 0x00, 0x45, 0x39, 0xA3, 0x39, 0xDB, 0x02, 0x7C, 0x38, 0x45, 0x39, + 0xA3, 0x39, 0xDB, 0x02, 0x7C, 0x38, 0x6C, 0xFD, 0x4D, 0x00, 0x11, 0x28, + 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x48, 0x00, 0x3C, 0x5C, + 0x00, 0x00, 0x27, 0x1F, 0xF7, 0x02, 0xE7, 0x3F, 0x2B, 0x27, 0xE7, 0x3F, + 0x7A, 0x26, 0x31, 0x0D, 0x67, 0x26, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x0D, + 0x02, 0x1F, 0x0D, 0x0D, 0x23, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x01, + 0x00, 0x06, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01, 0x00, 0x06, 0x00, 0x10, + 0xED, 0xED, 0x1A, 0x00, 0x3C, 0x40, 0x00, 0xFF, 0x9C, 0x20, 0x52, 0xFF, + 0xED, 0xED, 0x05, 0x00, 0xFF, 0xFE, 0xFF, 0x01, 0x38, 0x00, 0x00, 0xCB, + 0x5C, 0x00, 0x00, 0xB6, 0x5C, 0xBB, 0x5C, 0xCB, 0x5C, 0xD0, 0x5C, 0xCA, + 0x5C, 0xCC, 0x5C, 0xCC, 0x5C, 0xCF, 0x5C, 0x00, 0x00, 0xD1, 0x5C, 0xF3, + 0x5C, 0xF3, 0x5C, 0x7F, 0x92, 0x5C, 0x00, 0x02, 0xED, 0xED, 0x08, 0x00, + 0x01, 0x17, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x58, 0xFF, 0xED, 0xED, 0x05, + 0x00, 0x04, 0x17, 0x00, 0x40, 0xFD, 0x50, 0x21, 0x18, 0x04, 0x17, 0x01, + 0x38, 0x00, 0x38, 0xED, 0xED, 0x22, 0x00, 0x57, 0xFF, 0xFF, 0xFF, 0xF4, + 0x09, 0xA8, 0x10, 0x4B, 0xF4, 0x09, 0xC4, 0x15, 0x53, 0x81, 0x0F, 0xC4, + 0x15, 0x52, 0x34, 0x5B, 0x2F, 0x5B, 0x50, 0x80, 0x80, 0xEF, 0x22, 0x22, + 0x0D, 0x80, 0x00, 0xFF, 0xED, 0xED, 0x09, 0x20, 0x00, 0x00, 0x00, 0x80, + 0xED, 0xED, 0x12, 0x00, 0x80, 0x0D, 0xCE, 0x5C, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0x2D, 0x00, 0x04, 0x01, 0x09, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xFF, 0x00, 0xED, 0xED, 0x40, 0x00, 0x84, 0x01, 0x0A, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0x23, 0x00, 0xC0, 0xED, + 0xED, 0x15, 0x00, 0x80, 0xFF, 0x38, 0x00, 0x38, 0x00, 0x00, 0x00, 0x14, + 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xE2, 0x00, + 0x20, 0xED, 0xED, 0x05, 0x00, 0x05, 0x17, 0x00, 0x40, 0xFC, 0x50, 0x21, + 0x18, 0x05, 0x17, 0x01, 0x38, 0x00, 0x38, 0xED, 0xED, 0x71, 0x00, 0xED, + 0xED, 0x0E, 0x38, 0xED, 0xED, 0x70, 0x00, 0xED, 0xED, 0x0E, 0x38, 0xED, + 0xED, 0x70, 0x00, 0xED, 0xED, 0x0E, 0x38, 0xED, 0xED, 0x70, 0x00, 0xED, + 0xED, 0x0E, 0x38, 0xED, 0xED, 0x70, 0x00, 0xED, 0xED, 0x0E, 0x38, 0xED, + 0xED, 0x70, 0x00, 0xED, 0xED, 0x0E, 0x38, 0xED, 0xED, 0x70, 0x00, 0xED, + 0xED, 0x0E, 0x38, 0xED, 0xED, 0x70, 0x00, 0xED, 0xED, 0x0E, 0x38, 0xED, + 0xED, 0x70, 0x00, 0xED, 0xED, 0x0E, 0x38, 0xED, 0xED, 0x70, 0x00, 0xED, + 0xED, 0x0E, 0x38, 0xED, 0xED, 0x70, 0x00, 0xED, 0xED, 0x0E, 0x38, 0xED, + 0xED, 0x70, 0x00, 0xED, 0xED, 0x0E, 0x38, 0xED, 0xED, 0xFF, 0x00, 0xED, + 0xED, 0xF8, 0x00, 0x44, 0x27, 0x54, 0x27, 0x00, 0x00, 0x00, 0x04, 0x10, + 0x14, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, + 0x00, 0xED, 0xED, 0x7C, 0x00, 0x01, 0x05, 0x00, 0x00, 0x14, 0x00, 0x00, + 0x00, 0x0F, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, 0xFF, 0x00, 0xED, 0xED, + 0x8F, 0x00 +}; + +#endif // Loaders_h \ No newline at end of file diff --git a/src/FileZ80.cpp b/src/FileZ80.cpp index 76ccef8a..0d6125e3 100644 --- a/src/FileZ80.cpp +++ b/src/FileZ80.cpp @@ -47,6 +47,7 @@ visit https://zxespectrum.speccy.org/contacto #include "Tape.h" #include "pwm_audio.h" #include "AySound.h" +#include "loaders.h" /////////////////////////////////////////////////////////////////////////////// @@ -537,3 +538,537 @@ void FileZ80::loadCompressedMemPage(FILE *f, uint16_t dataLen, uint8_t* memPage, } } } + +void FileZ80::loader48() +{ + + printf("loader48 -----------------------------------\n"); + + unsigned char *z80_array = (unsigned char *) load48; + + // Stop keyboard input + ESPectrum::PS2Controller.keyboard()->suspendPort(); + + // Stop audio + pwm_audio_stop(); + + uint32_t file_size = 1273; + + // Reset Z80 and set bankLatch to default + MemESP::bankLatch = 0; + Z80::reset(); + + uint32_t dataOffset = 0; + + // initially assuming version 1; this assumption may change + uint8_t version = 1; + + // stack space for header, should be enough for + // version 1 (30 bytes) + // version 2 (55 bytes) (30 + 2 + 23) + // version 3 (87 bytes) (30 + 2 + 55) or (86 bytes) (30 + 2 + 54) + // uint8_t header[87]; + + // read first 30 bytes + for (uint8_t i = 0; i < 30; i++) { + // header[i] = readByteFile(file); + dataOffset ++; + } + + // additional vars + uint8_t b12, b29; + + // begin loading registers + Z80::setRegA ( z80_array[0]); + Z80::setFlags ( z80_array[1]); + Z80::setRegBC (mkword(z80_array[2], z80_array[3])); + Z80::setRegHL (mkword(z80_array[4], z80_array[5])); + Z80::setRegPC (mkword(z80_array[6], z80_array[7])); + Z80::setRegSP (mkword(z80_array[8], z80_array[9])); + Z80::setRegI ( z80_array[10]); + Z80::setRegR ( z80_array[11]); + b12 = z80_array[12]; + Z80::setRegDE (mkword(z80_array[13], z80_array[14])); + Z80::setRegBCx(mkword(z80_array[15], z80_array[16])); + Z80::setRegDEx(mkword(z80_array[17], z80_array[18])); + Z80::setRegHLx(mkword(z80_array[19], z80_array[20])); + Z80::setRegAFx(mkword(z80_array[22], z80_array[21])); // watch out for order!!! + Z80::setRegIY (mkword(z80_array[23], z80_array[24])); + Z80::setRegIX (mkword(z80_array[25], z80_array[26])); + Z80::setIFF1 ( z80_array[27] ? true : false); + Z80::setIFF2 ( z80_array[28] ? true : false); + b29 = z80_array[29]; + Z80::setIM((Z80::IntMode)(b29 & 0x03)); + + uint16_t RegPC = Z80::getRegPC(); + + VIDEO::borderColor = (b12 >> 1) & 0x07; + VIDEO::brd = VIDEO::border32[VIDEO::borderColor]; + + bool dataCompressed = (b12 & 0x20) ? true : false; + string fileArch = "48K"; + uint8_t memPagingReg = 0; + + // read 2 more bytes + for (uint8_t i = 30; i < 32; i++) { + // header[i] = readByteFile(file); + dataOffset ++; + } + + // additional header block length + uint16_t ahblen = mkword(z80_array[30], z80_array[31]); + if (ahblen == 23) + version = 2; + else if (ahblen == 54 || ahblen == 55) + version = 3; + else { + OSD::osdCenteredMsg("Z80 load: unknown version", LEVEL_ERROR); + // printf("Z80.load: unknown version, ahblen = %d\n", ahblen); + // Resume audio + pwm_audio_start(); + // Resume keyboard input + ESPectrum::PS2Controller.keyboard()->resumePort(); + ESPectrum::reset(); + return; + } + + // read additional header block + for (uint8_t i = 32; i < 32 + ahblen; i++) { + // header[i] = readByteFile(file); + dataOffset ++; + } + + // program counter + RegPC = mkword(z80_array[32], z80_array[33]); + Z80::setRegPC(RegPC); + + // hardware mode + uint8_t b34 = z80_array[34]; + + // defaulting to 128K + fileArch = "128K"; + + if (version == 2) { + if (b34 == 0) fileArch = "48K"; + if (b34 == 1) fileArch = "48K"; // + if1 + if (b34 == 2) fileArch = "SAMRAM"; + } + else if (version == 3) { + if (b34 == 0) fileArch = "48K"; + if (b34 == 1) fileArch = "48K"; // + if1 + if (b34 == 2) fileArch = "SAMRAM"; + if (b34 == 3) fileArch = "48K"; // + mgt + } + + #ifdef LOG_Z80_DETAILS + uint32_t memRawLength = file_size - dataOffset; + printf("Z80 format version: %d\n", version); + printf("machine type: %s\n", fileArch.c_str()); + printf("data offset: %d\n", dataOffset); + printf("file length: %d\n", file_size); + printf("b12: %d\n", b12); + printf("b34: %d\n", b34); + printf("pc: %d\n", RegPC); + printf("border: %d\n", VIDEO::borderColor); + #endif + + z80_array += dataOffset; + + MemESP::romLatch = 0; + MemESP::romInUse = 0; + MemESP::bankLatch = 0; + MemESP::pagingLock = 1; + MemESP::videoLatch = 0; + + uint16_t pageStart[12] = {0, 0, 0, 0, 0x8000, 0xC000, 0, 0, 0x4000, 0, 0}; + + uint32_t dataLen = file_size; + while (dataOffset < dataLen) { + uint8_t hdr0 = z80_array[0]; dataOffset ++; + uint8_t hdr1 = z80_array[1]; dataOffset ++; + uint8_t hdr2 = z80_array[2]; dataOffset ++; + z80_array += 3; + uint16_t compDataLen = mkword(hdr0, hdr1); + + #ifdef LOG_Z80_DETAILS + printf("compressed data length: %d\n", compDataLen); + printf("page number: %d\n", hdr2); + #endif + + uint16_t memoff = pageStart[hdr2]; + + #ifdef LOG_Z80_DETAILS + printf("page start: 0x%X\n", memoff); + #endif + + // loadCompressedMemData(file, compDataLen, memoff, 0x4000); + + // void FileZ80::loadCompressedMemData(FILE *f, uint16_t dataLen, uint16_t memoff, uint16_t memlen) + { + + uint16_t dataOff = 0; + uint8_t ed_cnt = 0; + uint8_t repcnt = 0; + uint8_t repval = 0; + uint16_t memidx = 0; + + while(dataOff < compDataLen && memidx < 0x4000) { + uint8_t databyte = z80_array[0]; z80_array ++; + if (ed_cnt == 0) { + if (databyte != 0xED) + MemESP::writebyte(memoff + memidx++, databyte); + else + ed_cnt++; + } + else if (ed_cnt == 1) { + if (databyte != 0xED) { + MemESP::writebyte(memoff + memidx++, 0xED); + MemESP::writebyte(memoff + memidx++, databyte); + ed_cnt = 0; + } + else + ed_cnt++; + } + else if (ed_cnt == 2) { + repcnt = databyte; + ed_cnt++; + } + else if (ed_cnt == 3) { + repval = databyte; + for (uint16_t i = 0; i < repcnt; i++) + MemESP::writebyte(memoff + memidx++, repval); + ed_cnt = 0; + } + } + + #ifdef LOG_Z80_DETAILS + printf("last byte: %d\n", (memoff+memidx-1)); + #endif + + } + + dataOffset += compDataLen; + + } + + // great success!!! + + // Ports + for (int i = 0; i < 128; i++) Ports::port[i] = 0xBF; + if (Config::joystick) Ports::port[0x1f] = 0; // Kempston + + CPU::tstates = 0; + CPU::global_tstates = 0; + ESPectrum::ESPoffset = 0; + + VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; + VIDEO::Draw = &VIDEO::Blank; + + MemESP::ramCurrent[0] = (unsigned char *)MemESP::rom[MemESP::romInUse]; + MemESP::ramCurrent[1] = (unsigned char *)MemESP::ram[5]; + MemESP::ramCurrent[2] = (unsigned char *)MemESP::ram[2]; + MemESP::ramCurrent[3] = (unsigned char *)MemESP::ram[MemESP::bankLatch]; + + MemESP::ramContended[0] = false; + MemESP::ramContended[1] = true; + MemESP::ramContended[2] = false; + MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; + + Tape::tapeFileName = "none"; + Tape::tapeStatus = TAPE_STOPPED; + Tape::SaveStatus = SAVE_STOPPED; + Tape::romLoading = false; + + // Empty audio buffers + for (int i=0;iresumePort(); + + printf("loader48 end -------------------------------\n"); + +} + +void FileZ80::loader128() +{ + + printf("loader128 -----------------------------------\n"); + + unsigned char *z80_array = (unsigned char *) load128; + + // Stop keyboard input + ESPectrum::PS2Controller.keyboard()->suspendPort(); + // Stop audio + pwm_audio_stop(); + + uint32_t file_size = 3230; + + // Reset Z80 and set bankLatch to default + MemESP::bankLatch = 0; + Z80::reset(); + + uint32_t dataOffset = 0; + + // initially assuming version 1; this assumption may change + uint8_t version = 1; + + // stack space for header, should be enough for + // version 1 (30 bytes) + // version 2 (55 bytes) (30 + 2 + 23) + // version 3 (87 bytes) (30 + 2 + 55) or (86 bytes) (30 + 2 + 54) + // uint8_t header[87]; + + // read first 30 bytes + for (uint8_t i = 0; i < 30; i++) { + // header[i] = readByteFile(file); + dataOffset ++; + } + + // additional vars + uint8_t b12, b29; + + // begin loading registers + Z80::setRegA ( z80_array[0]); + Z80::setFlags ( z80_array[1]); + Z80::setRegBC (mkword(z80_array[2], z80_array[3])); + Z80::setRegHL (mkword(z80_array[4], z80_array[5])); + Z80::setRegPC (mkword(z80_array[6], z80_array[7])); + Z80::setRegSP (mkword(z80_array[8], z80_array[9])); + Z80::setRegI ( z80_array[10]); + Z80::setRegR ( z80_array[11]); + b12 = z80_array[12]; + Z80::setRegDE (mkword(z80_array[13], z80_array[14])); + Z80::setRegBCx(mkword(z80_array[15], z80_array[16])); + Z80::setRegDEx(mkword(z80_array[17], z80_array[18])); + Z80::setRegHLx(mkword(z80_array[19], z80_array[20])); + Z80::setRegAFx(mkword(z80_array[22], z80_array[21])); // watch out for order!!! + Z80::setRegIY (mkword(z80_array[23], z80_array[24])); + Z80::setRegIX (mkword(z80_array[25], z80_array[26])); + Z80::setIFF1 ( z80_array[27] ? true : false); + Z80::setIFF2 ( z80_array[28] ? true : false); + b29 = z80_array[29]; + Z80::setIM((Z80::IntMode)(b29 & 0x03)); + + uint16_t RegPC = Z80::getRegPC(); + + VIDEO::borderColor = (b12 >> 1) & 0x07; + VIDEO::brd = VIDEO::border32[VIDEO::borderColor]; + + bool dataCompressed = (b12 & 0x20) ? true : false; + string fileArch = "48K"; + uint8_t memPagingReg = 0; + + // read 2 more bytes + for (uint8_t i = 30; i < 32; i++) { + // header[i] = readByteFile(file); + dataOffset ++; + } + + // additional header block length + uint16_t ahblen = mkword(z80_array[30], z80_array[31]); + if (ahblen == 23) + version = 2; + else if (ahblen == 54 || ahblen == 55) + version = 3; + else { + OSD::osdCenteredMsg("Z80 load: unknown version", LEVEL_ERROR); + // printf("Z80.load: unknown version, ahblen = %d\n", ahblen); + // Resume audio + pwm_audio_start(); + // Resume keyboard input + ESPectrum::PS2Controller.keyboard()->resumePort(); + ESPectrum::reset(); + return; + } + + // read additional header block + for (uint8_t i = 32; i < 32 + ahblen; i++) { + // header[i] = readByteFile(file); + dataOffset ++; + } + + // program counter + RegPC = mkword(z80_array[32], z80_array[33]); + Z80::setRegPC(RegPC); + + // hardware mode + uint8_t b34 = z80_array[34]; + + // defaulting to 128K + fileArch = "128K"; + + if (version == 2) { + if (b34 == 0) fileArch = "48K"; + if (b34 == 1) fileArch = "48K"; // + if1 + if (b34 == 2) fileArch = "SAMRAM"; + } + else if (version == 3) { + if (b34 == 0) fileArch = "48K"; + if (b34 == 1) fileArch = "48K"; // + if1 + if (b34 == 2) fileArch = "SAMRAM"; + if (b34 == 3) fileArch = "48K"; // + mgt + } + + #ifdef LOG_Z80_DETAILS + uint32_t memRawLength = file_size - dataOffset; + printf("Z80 format version: %d\n", version); + printf("machine type: %s\n", fileArch.c_str()); + printf("data offset: %d\n", dataOffset); + printf("file length: %d\n", file_size); + printf("b12: %d\n", b12); + printf("b34: %d\n", b34); + printf("pc: %d\n", RegPC); + printf("border: %d\n", VIDEO::borderColor); + #endif + + MemESP::romInUse = 1; + + // paging register + uint8_t b35 = z80_array[35]; + MemESP::pagingLock = bitRead(b35, 5); + MemESP::romLatch = bitRead(b35, 4); + MemESP::videoLatch = bitRead(b35, 3); + MemESP::bankLatch = b35 & 0x07; + + z80_array += dataOffset; + + uint8_t* pages[12] = { + MemESP::rom[0], MemESP::rom[2], MemESP::rom[1], + MemESP::ram0, MemESP::ram1, MemESP::ram2, MemESP::ram3, + MemESP::ram4, MemESP::ram5, MemESP::ram6, MemESP::ram7, + MemESP::rom[3] }; + + const char* pagenames[12] = { "rom0", "IDP", "rom1", + "ram0", "ram1", "ram2", "ram3", "ram4", "ram5", "ram6", "ram7", "MFR" }; + + uint32_t dataLen = file_size; + while (dataOffset < dataLen) { + uint8_t hdr0 = z80_array[0]; dataOffset ++; + uint8_t hdr1 = z80_array[1]; dataOffset ++; + uint8_t hdr2 = z80_array[2]; dataOffset ++; + z80_array += 3; + uint16_t compDataLen = mkword(hdr0, hdr1); + + #ifdef LOG_Z80_DETAILS + printf("compressed data length: %d\n", compDataLen); + printf("page: %s\n", pagenames[hdr2]); + #endif + + uint8_t* memPage = pages[hdr2]; + + // loadCompressedMemPage(file, compDataLen, memPage, 0x4000); + + // void FileZ80::loadCompressedMemPage(FILE *f, uint16_t dataLen, uint8_t* memPage, uint16_t memlen) + { + uint16_t dataOff = 0; + uint8_t ed_cnt = 0; + uint8_t repcnt = 0; + uint8_t repval = 0; + uint16_t memidx = 0; + + while(dataOff < compDataLen && memidx < 0x4000) { + uint8_t databyte = z80_array[0]; + z80_array ++; + if (ed_cnt == 0) { + if (databyte != 0xED) + memPage[memidx++] = databyte; + else + ed_cnt++; + } + else if (ed_cnt == 1) { + if (databyte != 0xED) { + memPage[memidx++] = 0xED; + memPage[memidx++] = databyte; + ed_cnt = 0; + } + else + ed_cnt++; + } + else if (ed_cnt == 2) { + repcnt = databyte; + ed_cnt++; + } + else if (ed_cnt == 3) { + repval = databyte; + for (uint16_t i = 0; i < repcnt; i++) + memPage[memidx++] = repval; + ed_cnt = 0; + } + } + } + + dataOffset += compDataLen; + + } + + // great success!!! + + // Ports + for (int i = 0; i < 128; i++) Ports::port[i] = 0xBF; + if (Config::joystick) Ports::port[0x1f] = 0; // Kempston + + CPU::tstates = 0; + CPU::global_tstates = 0; + ESPectrum::ESPoffset = 0; + + VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; + VIDEO::Draw = &VIDEO::Blank; + + MemESP::ramCurrent[0] = (unsigned char *)MemESP::rom[MemESP::romInUse]; + MemESP::ramCurrent[1] = (unsigned char *)MemESP::ram[5]; + MemESP::ramCurrent[2] = (unsigned char *)MemESP::ram[2]; + MemESP::ramCurrent[3] = (unsigned char *)MemESP::ram[MemESP::bankLatch]; + + MemESP::ramContended[0] = false; + MemESP::ramContended[1] = true; + MemESP::ramContended[2] = false; + MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; + + Tape::tapeFileName = "none"; + Tape::tapeStatus = TAPE_STOPPED; + Tape::SaveStatus = SAVE_STOPPED; + Tape::romLoading = false; + + // Empty audio buffers + for (int i=0;iresumePort(); + + printf("loader128 end -------------------------------\n"); + +} diff --git a/src/OSDMain.cpp b/src/OSDMain.cpp index 6c10184f..cde7a447 100644 --- a/src/OSDMain.cpp +++ b/src/OSDMain.cpp @@ -262,9 +262,11 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { // TO DO: make this dependant on Flashload parameter if (Z80Ops::is48) { - changeSnapshot(FileUtils::MountPoint + "/load48.z80"); + FileZ80::loader48(); + // changeSnapshot(FileUtils::MountPoint + "/load48.z80"); } else { - changeSnapshot(FileUtils::MountPoint + "/load128.z80"); + FileZ80::loader128(); + // changeSnapshot(FileUtils::MountPoint + "/load128.z80"); } // Put something random on FRAMES SYS VAR as recommended by Mark Woodmass From ba3508d88a44cca3eeb6669667240963e9a4454b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Mon, 24 Jul 2023 03:46:39 +0200 Subject: [PATCH 20/29] Peek16, Poke16 diff. page of bytes mismatch solved --- src/CPU.cpp | 60 ++++++++++++++++++++++++++++++++++++------------- src/FileZ80.cpp | 53 ++++--------------------------------------- 2 files changed, 48 insertions(+), 65 deletions(-) diff --git a/src/CPU.cpp b/src/CPU.cpp index b3bebab9..a1dbfee0 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -202,15 +202,27 @@ void IRAM_ATTR Z80Ops::poke8(uint16_t address, uint8_t value) { // Read word from RAM uint16_t IRAM_ATTR Z80Ops::peek16(uint16_t address) { - uint8_t page = address >> 14; + // Check if address is between two different pages + if ((address >> 14) == ((address + 1) >> 14)) { - if (MemESP::ramContended[page]) { - VIDEO::Draw(3, true); - VIDEO::Draw(3, true); - } else - VIDEO::Draw(6, false); + uint8_t page = address >> 14; + + if (MemESP::ramContended[page]) { + VIDEO::Draw(3, true); + VIDEO::Draw(3, true); + } else + VIDEO::Draw(6, false); + + return ((MemESP::ramCurrent[page][(address & 0x3fff) + 1] << 8) | MemESP::ramCurrent[page][address & 0x3fff]); - return ((MemESP::ramCurrent[page][(address & 0x3fff) + 1] << 8) | MemESP::ramCurrent[page][address & 0x3fff]); + } else { + + // Order matters, first read lsb, then read msb, don't "optimize" + uint8_t lsb = Z80Ops::peek8(address); + uint8_t msb = Z80Ops::peek8(address + 1); + return (msb << 8) | lsb; + + } } @@ -218,16 +230,32 @@ uint16_t IRAM_ATTR Z80Ops::peek16(uint16_t address) { void IRAM_ATTR Z80Ops::poke16(uint16_t address, RegisterPair word) { uint8_t page = address >> 14; - - if (MemESP::ramContended[page]) { - VIDEO::Draw(3, true); - VIDEO::Draw(3, true); - } else - VIDEO::Draw(6, false); - if (page != 0) { - MemESP::ramCurrent[page][address & 0x3fff] = word.byte8.lo; - MemESP::ramCurrent[page][(address & 0x3fff) + 1] = word.byte8.hi; + // Check if address is between two different pages + if (page == ((address + 1) >> 14)) { + + if (MemESP::ramContended[page]) { + VIDEO::Draw(3, true); + VIDEO::Draw(3, true); + } else + VIDEO::Draw(6, false); + + if (page != 0) { + MemESP::ramCurrent[page][address & 0x3fff] = word.byte8.lo; + MemESP::ramCurrent[page][(address & 0x3fff) + 1] = word.byte8.hi; + } + + } else { + + // Order matters, first write lsb, then write msb, don't "optimize" + + // Z80Ops::poke8(address, word.byte8.lo); + + VIDEO::Draw(3, MemESP::ramContended[page]); + if (page != 0) MemESP::ramCurrent[page][address & 0x3fff] = word.byte8.lo; + + Z80Ops::poke8(address + 1, word.byte8.hi); + } } diff --git a/src/FileZ80.cpp b/src/FileZ80.cpp index 0d6125e3..b198b4a8 100644 --- a/src/FileZ80.cpp +++ b/src/FileZ80.cpp @@ -552,7 +552,7 @@ void FileZ80::loader48() // Stop audio pwm_audio_stop(); - uint32_t file_size = 1273; + uint32_t file_size = sizeof(load48); // Reset Z80 and set bankLatch to default MemESP::bankLatch = 0; @@ -621,16 +621,6 @@ void FileZ80::loader48() version = 2; else if (ahblen == 54 || ahblen == 55) version = 3; - else { - OSD::osdCenteredMsg("Z80 load: unknown version", LEVEL_ERROR); - // printf("Z80.load: unknown version, ahblen = %d\n", ahblen); - // Resume audio - pwm_audio_start(); - // Resume keyboard input - ESPectrum::PS2Controller.keyboard()->resumePort(); - ESPectrum::reset(); - return; - } // read additional header block for (uint8_t i = 32; i < 32 + ahblen; i++) { @@ -818,7 +808,7 @@ void FileZ80::loader128() // Stop audio pwm_audio_stop(); - uint32_t file_size = 3230; + uint32_t file_size = sizeof(load128); // Reset Z80 and set bankLatch to default MemESP::bankLatch = 0; @@ -826,15 +816,6 @@ void FileZ80::loader128() uint32_t dataOffset = 0; - // initially assuming version 1; this assumption may change - uint8_t version = 1; - - // stack space for header, should be enough for - // version 1 (30 bytes) - // version 2 (55 bytes) (30 + 2 + 23) - // version 3 (87 bytes) (30 + 2 + 55) or (86 bytes) (30 + 2 + 54) - // uint8_t header[87]; - // read first 30 bytes for (uint8_t i = 0; i < 30; i++) { // header[i] = readByteFile(file); @@ -877,30 +858,16 @@ void FileZ80::loader128() // read 2 more bytes for (uint8_t i = 30; i < 32; i++) { - // header[i] = readByteFile(file); dataOffset ++; } // additional header block length uint16_t ahblen = mkword(z80_array[30], z80_array[31]); - if (ahblen == 23) - version = 2; - else if (ahblen == 54 || ahblen == 55) - version = 3; - else { - OSD::osdCenteredMsg("Z80 load: unknown version", LEVEL_ERROR); - // printf("Z80.load: unknown version, ahblen = %d\n", ahblen); - // Resume audio - pwm_audio_start(); - // Resume keyboard input - ESPectrum::PS2Controller.keyboard()->resumePort(); - ESPectrum::reset(); - return; - } + + uint8_t version = 3; // read additional header block for (uint8_t i = 32; i < 32 + ahblen; i++) { - // header[i] = readByteFile(file); dataOffset ++; } @@ -914,18 +881,6 @@ void FileZ80::loader128() // defaulting to 128K fileArch = "128K"; - if (version == 2) { - if (b34 == 0) fileArch = "48K"; - if (b34 == 1) fileArch = "48K"; // + if1 - if (b34 == 2) fileArch = "SAMRAM"; - } - else if (version == 3) { - if (b34 == 0) fileArch = "48K"; - if (b34 == 1) fileArch = "48K"; // + if1 - if (b34 == 2) fileArch = "SAMRAM"; - if (b34 == 3) fileArch = "48K"; // + mgt - } - #ifdef LOG_Z80_DETAILS uint32_t memRawLength = file_size - dataOffset; printf("Z80 format version: %d\n", version); From a49f898d2abfcbea6a6d994852e9a272b6e739ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Mon, 24 Jul 2023 12:21:55 +0200 Subject: [PATCH 21/29] Peek16 and Poke16 fix --- src/CPU.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/CPU.cpp b/src/CPU.cpp index a1dbfee0..fa24d2fc 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -215,7 +215,7 @@ uint16_t IRAM_ATTR Z80Ops::peek16(uint16_t address) { return ((MemESP::ramCurrent[page][(address & 0x3fff) + 1] << 8) | MemESP::ramCurrent[page][address & 0x3fff]); - } else { + } else { // Order matters, first read lsb, then read msb, don't "optimize" uint8_t lsb = Z80Ops::peek8(address); @@ -229,11 +229,11 @@ uint16_t IRAM_ATTR Z80Ops::peek16(uint16_t address) { // Write word to RAM void IRAM_ATTR Z80Ops::poke16(uint16_t address, RegisterPair word) { - uint8_t page = address >> 14; - // Check if address is between two different pages - if (page == ((address + 1) >> 14)) { - + if ((address >> 14) == ((address + 1) >> 14)) { + + uint8_t page = address >> 14; + if (MemESP::ramContended[page]) { VIDEO::Draw(3, true); VIDEO::Draw(3, true); @@ -248,12 +248,7 @@ void IRAM_ATTR Z80Ops::poke16(uint16_t address, RegisterPair word) { } else { // Order matters, first write lsb, then write msb, don't "optimize" - - // Z80Ops::poke8(address, word.byte8.lo); - - VIDEO::Draw(3, MemESP::ramContended[page]); - if (page != 0) MemESP::ramCurrent[page][address & 0x3fff] = word.byte8.lo; - + Z80Ops::poke8(address, word.byte8.lo); Z80Ops::poke8(address + 1, word.byte8.hi); } From 640efcd490067a89feba19eecec9256f3620e48a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Tue, 25 Jul 2023 15:47:33 +0200 Subject: [PATCH 22/29] Olimex board SD detection tryout --- include/FileUtils.h | 2 +- include/hardpins.h | 16 +++++++++++----- include/messages.h | 16 ++++++++-------- src/AySound.cpp | 2 +- src/CPU.cpp | 10 ++++------ src/FileUtils.cpp | 24 +++++++++++++++++------- 6 files changed, 42 insertions(+), 28 deletions(-) diff --git a/include/FileUtils.h b/include/FileUtils.h index 4316c586..2c8e35a1 100644 --- a/include/FileUtils.h +++ b/include/FileUtils.h @@ -54,7 +54,7 @@ class FileUtils { public: static void initFileSystem(); - static bool mountSDCard(); + static bool mountSDCard(int PIN_MISO, int PIN_MOSI, int PIN_CLK, int PIN_CS); static void unmountSDCard(); // static String getAllFilesFrom(const String path); // static void listAllFiles(); diff --git a/include/hardpins.h b/include/hardpins.h index 717d494f..7d9f6ba3 100644 --- a/include/hardpins.h +++ b/include/hardpins.h @@ -42,11 +42,17 @@ visit https://zxespectrum.speccy.org/contacto #define SPEAKER_PIN 25 -// Storage mode: pins for external SD card -#define PIN_NUM_MISO GPIO_NUM_2 -#define PIN_NUM_MOSI GPIO_NUM_12 -#define PIN_NUM_CLK GPIO_NUM_14 -#define PIN_NUM_CS GPIO_NUM_13 +// Storage mode: pins for external SD card (LILYGO TTGO VGA32 Board and ESPectrum Board) +#define PIN_NUM_MISO_LILYGO_ESPECTRUM GPIO_NUM_2 +#define PIN_NUM_MOSI_LILYGO_ESPECTRUM GPIO_NUM_12 +#define PIN_NUM_CLK_LILYGO_ESPECTRUM GPIO_NUM_14 +#define PIN_NUM_CS_LILYGO_ESPECTRUM GPIO_NUM_13 + +// Storage mode: pins for external SD card (Olimex ESP32-SBC-FABGL Board) +#define PIN_NUM_MISO_SBCFABGL GPIO_NUM_35 +#define PIN_NUM_MOSI_SBCFABGL GPIO_NUM_12 +#define PIN_NUM_CLK_SBCFABGL GPIO_NUM_14 +#define PIN_NUM_CS_SBCFABGL GPIO_NUM_13 // VGA Pins (6 bit) #define RED_PINS_6B 21, 22 diff --git a/include/messages.h b/include/messages.h index 6385ddc7..06e3becb 100644 --- a/include/messages.h +++ b/include/messages.h @@ -373,15 +373,15 @@ static const char *MENU_JOY[2] = { MENU_JOY_EN, MENU_JOY_ES }; " [F3] Load custom snapshot\n"\ " [F4] Save custom snapshot\n"\ " [F5] Select TAP file\n"\ - " [F6] Play/Pause tape\n"\ - " [F7] Stop tape\n"\ + " [F6] Play/Stop tape\n"\ + " [F7] Tape browser\n"\ " [F8] OSD Stats:\n"\ " CPU: microsec. per CPU cycle\n"\ " IDL: unused microsec.\n"\ " FPS: Frames per second\n"\ " FND: FPS without delay\n"\ - " [F9] Volume down\n"\ - " [F10] Volume up\n"\ + " [F9-F10] Volume down-up\n"\ + " [F11] Hard reset\n"\ " [F12] Reset ESP32\n"\ " [Pause] Pause\n"\ " [PrtScr] BMP screenshot (SD folder /c)\n" @@ -391,15 +391,15 @@ static const char *MENU_JOY[2] = { MENU_JOY_EN, MENU_JOY_ES }; " [F3] Cargar snapshot\n"\ " [F4] Guardar snapshot\n"\ " [F5] Elegir TAP\n"\ - " [F6] Play/Pausa\n"\ - " [F7] Stop\n"\ + " [F6] Play/Stop cinta\n"\ + " [F7] Explorador cinta\n"\ " [F8] OSD\n"\ " CPU: microsg. por ciclo CPU\n"\ " IDL: microsg. sin usar\n"\ " FPS: Frames por segundo\n"\ " FND: FPS sin delay\n"\ - " [F9] Subir volumen\n"\ - " [F10] Bajar volumen\n"\ + " [F9-F10] Bajar-Subir volumen\n"\ + " [F11] Reset completo\n"\ " [F12] Resetear ESP32\n"\ " [Pause] Pausa\n"\ " [ImpPant] Captura BMP (Carpeta SD /c)\n" diff --git a/src/AySound.cpp b/src/AySound.cpp index cc5ab847..edd3b36b 100644 --- a/src/AySound.cpp +++ b/src/AySound.cpp @@ -489,7 +489,7 @@ uint8_t AySound::getRegisterData() { if ((selectedRegister >= 14) && ((regs[7] >> (selectedRegister - 8)) & 1) == 0) { - printf("getAYRegister %d: %02X\n", selectedRegister, 0xFF); + // printf("getAYRegister %d: %02X\n", selectedRegister, 0xFF); return 0xFF; } diff --git a/src/CPU.cpp b/src/CPU.cpp index fa24d2fc..5426a141 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -202,10 +202,9 @@ void IRAM_ATTR Z80Ops::poke8(uint16_t address, uint8_t value) { // Read word from RAM uint16_t IRAM_ATTR Z80Ops::peek16(uint16_t address) { - // Check if address is between two different pages - if ((address >> 14) == ((address + 1) >> 14)) { + uint8_t page = address >> 14; - uint8_t page = address >> 14; + if (page == ((address + 1) >> 14)) { // Check if address is between two different pages if (MemESP::ramContended[page]) { VIDEO::Draw(3, true); @@ -229,10 +228,9 @@ uint16_t IRAM_ATTR Z80Ops::peek16(uint16_t address) { // Write word to RAM void IRAM_ATTR Z80Ops::poke16(uint16_t address, RegisterPair word) { - // Check if address is between two different pages - if ((address >> 14) == ((address + 1) >> 14)) { + uint8_t page = address >> 14; - uint8_t page = address >> 14; + if (page == ((address + 1) >> 14)) { // Check if address is between two different pages if (MemESP::ramContended[page]) { VIDEO::Draw(3, true); diff --git a/src/FileUtils.cpp b/src/FileUtils.cpp index 6539de41..7ee7db2b 100644 --- a/src/FileUtils.cpp +++ b/src/FileUtils.cpp @@ -47,6 +47,7 @@ visit https://zxespectrum.speccy.org/contacto #include "OSDMain.h" #include "roms.h" #include "Video.h" +#include "ZXKeyb.h" #include "esp_vfs.h" #include @@ -62,13 +63,15 @@ sdmmc_card_t *FileUtils::card; void FileUtils::initFileSystem() { - SDReady = mountSDCard(); + // Try to mount SD card on LILYGO TTGO VGA32 Board or ESPectrum Board + if (!SDReady) SDReady = mountSDCard(PIN_NUM_MISO_LILYGO_ESPECTRUM,PIN_NUM_MOSI_LILYGO_ESPECTRUM,PIN_NUM_CLK_LILYGO_ESPECTRUM,PIN_NUM_CS_LILYGO_ESPECTRUM); - vTaskDelay(20 / portTICK_PERIOD_MS); + // Try to mount SD card on Olimex ESP32-SBC-FABGL Board + if ((!ZXKeyb::Exists) && (!SDReady)) SDReady = mountSDCard(PIN_NUM_MISO_SBCFABGL,PIN_NUM_MOSI_SBCFABGL,PIN_NUM_CLK_SBCFABGL,PIN_NUM_CS_SBCFABGL); } -bool FileUtils::mountSDCard() { +bool FileUtils::mountSDCard(int PIN_MISO, int PIN_MOSI, int PIN_CLK, int PIN_CS) { // Init SD Card esp_err_t ret; @@ -82,9 +85,9 @@ bool FileUtils::mountSDCard() { sdmmc_host_t host = SDSPI_HOST_DEFAULT(); spi_bus_config_t bus_cfg = { - .mosi_io_num = PIN_NUM_MOSI, - .miso_io_num = PIN_NUM_MISO, - .sclk_io_num = PIN_NUM_CLK, + .mosi_io_num = PIN_MOSI, + .miso_io_num = PIN_MISO, + .sclk_io_num = PIN_CLK, .quadwp_io_num = -1, .quadhd_io_num = -1, .max_transfer_sz = 4000, @@ -93,9 +96,12 @@ bool FileUtils::mountSDCard() { ret = spi_bus_initialize(SPI2_HOST, &bus_cfg, SPI_DMA_CH1); if (ret != ESP_OK) { printf("SD Card init: Failed to initialize bus.\n"); + vTaskDelay(20 / portTICK_PERIOD_MS); return false; } + vTaskDelay(20 / portTICK_PERIOD_MS); + sdspi_device_config_t slot_config = { .host_id = SDSPI_DEFAULT_HOST, .gpio_cs = GPIO_NUM_13, @@ -103,7 +109,7 @@ bool FileUtils::mountSDCard() { .gpio_wp = SDSPI_SLOT_NO_WP, .gpio_int = GPIO_NUM_NC, \ }; - slot_config.gpio_cs = PIN_NUM_CS; + slot_config.gpio_cs = (gpio_num_t) PIN_CS; slot_config.host_id = SPI2_HOST; ret = esp_vfs_fat_sdspi_mount(MOUNT_POINT_SD, &host, &slot_config, &mount_config, &FileUtils::card); @@ -113,9 +119,13 @@ bool FileUtils::mountSDCard() { } else { printf("Failed to initialize the card.\n"); } + spi_bus_free(SPI2_HOST); + vTaskDelay(20 / portTICK_PERIOD_MS); return false; } + vTaskDelay(20 / portTICK_PERIOD_MS); + return true; } From 5c81348e5b90c7f8e3927c99f5c8924df4e024f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Crespo=20Tasc=C3=B3n?= Date: Tue, 1 Aug 2023 20:25:42 +0200 Subject: [PATCH 23/29] EBF (ESPectrum Bitmap Format) codec --- tools/EBF-convert/.gitignore | 2 + tools/EBF-convert/EBF-convert.py | 322 ++++++++++++++++++ tools/EBF-convert/RGB222.gpl | 66 ++++ tools/EBF-convert/espectrum-logo-cropped.ebf4 | Bin 0 -> 2562 bytes tools/EBF-convert/espectrum-logo-cropped.ebf8 | Bin 0 -> 5057 bytes tools/EBF-convert/espectrum-logo-cropped.png | Bin 0 -> 834 bytes 6 files changed, 390 insertions(+) create mode 100644 tools/EBF-convert/.gitignore create mode 100644 tools/EBF-convert/EBF-convert.py create mode 100644 tools/EBF-convert/RGB222.gpl create mode 100644 tools/EBF-convert/espectrum-logo-cropped.ebf4 create mode 100644 tools/EBF-convert/espectrum-logo-cropped.ebf8 create mode 100644 tools/EBF-convert/espectrum-logo-cropped.png diff --git a/tools/EBF-convert/.gitignore b/tools/EBF-convert/.gitignore new file mode 100644 index 00000000..da491a70 --- /dev/null +++ b/tools/EBF-convert/.gitignore @@ -0,0 +1,2 @@ +*.ebf4.png +*.ebf8.png diff --git a/tools/EBF-convert/EBF-convert.py b/tools/EBF-convert/EBF-convert.py new file mode 100644 index 00000000..d4f09189 --- /dev/null +++ b/tools/EBF-convert/EBF-convert.py @@ -0,0 +1,322 @@ +##############################################################################/ +## +## ZX-ESPectrum - ZX Spectrum emulator for ESP32 +## ESPectrum Bitmap Format (EBF) converter +## +## Copyright (c) 2023 David Crespo [dcrespo3d] +## https://github.com/dcrespo3d +## +## Permission is hereby granted, free of charge, to any person obtaining a copy +## of this software and associated documentation files (the "Software"), to +## deal in the Software without restriction, including without limitation the +## rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +## sell copies of the Software, and to permit persons to whom the Software is +## furnished to do so, subject to the following conditions: +## +## The above copyright notice and this permission notice shall be included in +## all copies or substantial portions of the Software. +## +## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +## FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +## DEALINGS IN THE SOFTWARE. + +import sys +from PIL import Image +## https://pillow.readthedocs.io/en/stable/ + +MAGIC_EBF8 = 'EBF8' +MAGIC_EBF4 = 'EBF4' + +# EBF Format description + +# EBF8 (Native ESPectrum pixelformat, HVBBGGRR) +# [4 bytes] magic: "EBF8" +# [2 bytes] image width W (little endian) +# [2 bytes] image height H (little endian) +# [N bytes] image data in native pixelformat: N = W * H + +# EBF4 (4bpp indices into palette) +# [4 bytes] magic: "EBF4" +# [2 bytes] image width W (little endian) +# [2 bytes] image height H (little endian) +# [16 bytes] palette with 16 entries in native ESPectrum pixelformat, HVBBGGRR +# [N bytes] image indices in 16bpp. N = floor(W/2) * H +# NOTE: when W is an odd value, an additional index 15 (the last one) will be padded into last byte of scanline + +# from video.h: some colors for 6 bit mode +# // BB GGRR +#define BRI_BLACK 0xC0 // 1100 0000 +#define BRI_BLUE 0xF0 // 1111 0000 +#define BRI_RED 0xC3 // 1100 0011 +#define BRI_GREEN 0xCC // 1100 1100 +#define BRI_WHITE 0xFF // 1111 1111 + +def rgb222_from_rgb888(rgb888tuple): + # a tuple is (r,g,b) with r,g,b between 0 and 255 + r, g, b = rgb888tuple + r = r >> 6 + g = g >> 6 + b = b >> 6 + # set high two bits and compose others as pattern says (MSB HVBBGGRR LSB) + rgb222 = 0xC0 | r | (g << 2) | (b << 4) + return rgb222 + +def rgb888_from_rgb222(rgb222int): + r2 = rgb222int & 0x03 + g2 = (rgb222int & 0x0C) >> 2 + b2 = (rgb222int & 0x30) >> 4 + r8 = r2 | (r2 << 2) | (r2 << 4) | (r2 << 6) + g8 = g2 | (g2 << 2) | (g2 << 4) | (g2 << 6) + b8 = b2 | (b2 << 2) | (b2 << 4) | (b2 << 6) + return (r8, g8, b8) + +def iarr_from_str(magic_str): + res = [] + for ch in magic_str: + res.append(ord(ch)) + return res + +def str_from_iarr(iarr): + s = '' + for val in iarr: + s += chr(val) + return s + +def iarr_from_u16(u16): + lo = u16 & 0x00FF + hi = (u16 & 0xFF00) >> 8 + return [lo, hi] # little endian + +def u16_from_iarr(iarr): + lo = iarr[0] + hi = iarr[1] + return lo + (hi << 8) + +def ebf8arr_from_pngfile(ifn): + # print('opening ' + ifn) + img = Image.open(ifn) + img = img.convert('RGB') + w, h = img.size + # print('image size:', img.size) + + ebf8arr = [] + ebf8arr += iarr_from_str(MAGIC_EBF8) + ebf8arr += iarr_from_u16(w) + ebf8arr += iarr_from_u16(h) + for y in range(h): + for x in range(w): + pixel888 = img.getpixel((x,y)) + pixel222 = rgb222_from_rgb888(pixel888) + # print(pixel888, hex(pixel222)) + ebf8arr.append(pixel222) + return ebf8arr + +def ebf8arr_to_pngfile(ebf8arr, ofn): + magic_str = str_from_iarr(ebf8arr[0:4]) + if magic_str != MAGIC_EBF8: + raise Exception('ebf8: expected magic EBF8, found ' + magic_str); + + w = u16_from_iarr(ebf8arr[4:6]) + h = u16_from_iarr(ebf8arr[6:8]) + pixdata = ebf8arr[8:] + img = Image.new('RGB', (w,h)) + idx = 0 + for y in range(h): + for x in range(w): + pixel222 = pixdata[idx] + idx += 1 + pixel888 = rgb888_from_rgb222(pixel222) + img.putpixel((x,y), pixel888) + img.save(ofn) + +def ebf4arr_from_ebf8arr(ebf8arr): + magic_str = str_from_iarr(ebf8arr[0:4]) + w = u16_from_iarr(ebf8arr[4:6]) + h = u16_from_iarr(ebf8arr[6:8]) + pixdata = ebf8arr[8:] + ebf4arr = [] + ebf4arr += iarr_from_str(MAGIC_EBF4) + ebf4arr += iarr_from_u16(w) + ebf4arr += iarr_from_u16(h) + + # table: for a given pixel value, get its palette index + idx4pix = {} + # table: for a given palette index, get its pixel value + pix4idx = {} + idxcount = 0 + + # for indexing into bitmap + bmpidx = 0 + + # create palette + # traverse scanlines, then pixels in scanline + for y in range(h): + for x in range(w): + # pixel bitamp value + pixel222 = pixdata[bmpidx] + bmpidx += 1 + # annotate into tables if not present + if not pixel222 in idx4pix: + idx4pix[pixel222] = idxcount + pix4idx[idxcount] = pixel222 + idxcount += 1 + + if idxcount > 16: + raise Exception('EBF4: unique colors must NOT exceed 16, found ' + str(idxcount)) + + # convert palette table into palette array, padding up to 16 entries + palette = [] + for palidx in range(16): + if palidx in pix4idx: + palette.append(pix4idx[palidx]) + else: + palette.append(0xF3) # unused palette entries default to purple for error detection + # print(palette) + + # add palette to data array + ebf4arr += palette + + # xpad: x coordinate for padding, -1 if not applyable + xpad = -1 + if w & 1: xpad = w - 1 + + # temporary array of palette index values + # which will be compacted to 2 4bpp values per byte, ex: 0F 03 07 04 -> F3 74 + tmpdata = [] + + # populate tmp data, each bye a looked up index into palette, for given pixel value + palidx = 0 + bmpidx = 0 + for y in range(h): + for x in range(w): + pixel222 = pixdata[bmpidx] + bmpidx += 1 + palidx = idx4pix[pixel222] + tmpdata.append(palidx) + if x == xpad: + tmpdata.append(15) # last index + # print(tmpdata) + + # array for compacted data + compdata = [] + + # compact two nibbles into one byte + compval = 0 + for i in range(len(tmpdata)): + if not i & 1: + compval = tmpdata[i] << 4 + else: + compval |= tmpdata[i] + compdata.append(compval) + # print(compdata) + + # add bitmap to data array + ebf4arr += compdata + + return ebf4arr + +def ebf4arr_to_pngfile(ebf4arr, ofn): + magic_str = str_from_iarr(ebf4arr[0:4]) + if magic_str != MAGIC_EBF4: + raise Exception('ebf4: expected magic EBF4, found ' + magic_str); + + w = u16_from_iarr(ebf4arr[4:6]) + h = u16_from_iarr(ebf4arr[6:8]) + palette = ebf4arr[8:24] + pixdata = ebf4arr[24:] + + # f*ck around and find out (uncommenting this) + # palette.reverse() + + # create lookup table for palette + pix4idx = {} + for i in range(16): + pix4idx[i] = palette[i] + + # uncompact data + uncompdata = [] + for compval in pixdata: + hinib = (compval & 0xF0) >> 4 + lonib = (compval & 0x0F) + uncompdata.append(hinib) + uncompdata.append(lonib) + # print(uncompdata) + + stride = w + if (w & 1): stride += 1 + + img = Image.new('RGB', (w,h)) + for y in range(h): + for x in range(w): + bmpidx = x + y * stride + palidx = uncompdata[bmpidx] + pixel222 = pix4idx[palidx] + pixel888 = rgb888_from_rgb222(pixel222) + img.putpixel((x,y), pixel888) + img.save(ofn) + +def pngfile_to_ebf8file(ifn, ofn): + print('converting ' + ifn + ' to ' + ofn + '...') + ebf8arr = ebf8arr_from_pngfile(ifn) + f = open(ofn, 'wb') + f.write(bytes(ebf8arr)) + f.close() + +def pngfile_to_ebf4file(ifn, ofn): + print('converting ' + ifn + ' to ' + ofn + '...') + ebf8arr = ebf8arr_from_pngfile(ifn) + ebf4arr = ebf4arr_from_ebf8arr(ebf8arr) + f = open(ofn, 'wb') + f.write(bytes(ebf4arr)) + f.close() + +def ebf8file_to_pngfile(ifn, ofn): + print('converting ' + ifn + ' to ' + ofn + '...') + f = open(ifn, 'rb') + ebf8arr = list(f.read()) + f.close() + ebf8arr_to_pngfile(ebf8arr, ofn) + +def ebf4file_to_pngfile(ifn, ofn): + print('converting ' + ifn + ' to ' + ofn + '...') + f = open(ifn, 'rb') + ebf4arr = list(f.read()) + f.close() + ebf4arr_to_pngfile(ebf4arr, ofn) + + +TEST_DECODE = True + +usage = '''EBF-convert, converts PNG to EBF (ESPectrum Bitmap Format) +usage: + python EBF-convert.py input-file.png +''' + +if __name__ == '__main__': + if (len(sys.argv) != 2): + print(usage) + exit(-1) + + ifn = sys.argv[1] + if not ifn.endswith('.png'): + print('expected lowercase png extension, please try again') + exit(-1) + + print('='*80) + print('Creating EBF8 and EBF4 versions of input file:') + + ofn8 = ifn.replace('.png', '.ebf8') + pngfile_to_ebf8file(ifn, ofn8); + + ofn4 = ifn.replace('.png', '.ebf4') + pngfile_to_ebf4file(ifn, ofn4) + + if TEST_DECODE: + print('='*80) + print('Conversion check: converting EBF8 and EBF4 back to PNG:') + ebf8file_to_pngfile(ofn8, ofn8+'.png') + ebf4file_to_pngfile(ofn4, ofn4+'.png') diff --git a/tools/EBF-convert/RGB222.gpl b/tools/EBF-convert/RGB222.gpl new file mode 100644 index 00000000..5c5f8bfe --- /dev/null +++ b/tools/EBF-convert/RGB222.gpl @@ -0,0 +1,66 @@ +GIMP Palette +# + 0 0 0 Untitled + 0 0 85 Untitled + 0 0 170 Untitled + 0 0 255 Untitled + 0 85 0 Untitled + 0 85 85 Untitled + 0 85 170 Untitled + 0 85 255 Untitled + 0 170 0 Untitled + 0 170 85 Untitled + 0 170 170 Untitled + 0 170 255 Untitled + 0 255 0 Untitled + 0 255 85 Untitled + 0 255 170 Untitled + 0 255 255 Untitled + 85 0 0 Untitled + 85 0 85 Untitled + 85 0 170 Untitled + 85 0 255 Untitled + 85 85 0 Untitled + 85 85 85 Untitled + 85 85 170 Untitled + 85 85 255 Untitled + 85 170 0 Untitled + 85 170 85 Untitled + 85 170 170 Untitled + 85 170 255 Untitled + 85 255 0 Untitled + 85 255 85 Untitled + 85 255 170 Untitled + 85 255 255 Untitled +170 0 0 Untitled +170 0 85 Untitled +170 0 170 Untitled +170 0 255 Untitled +170 85 0 Untitled +170 85 85 Untitled +170 85 170 Untitled +170 85 255 Untitled +170 170 0 Untitled +170 170 85 Untitled +170 170 170 Untitled +170 170 255 Untitled +170 255 0 Untitled +170 255 85 Untitled +170 255 170 Untitled +170 255 255 Untitled +255 0 0 Untitled +255 0 85 Untitled +255 0 170 Untitled +255 0 255 Untitled +255 85 0 Untitled +255 85 85 Untitled +255 85 170 Untitled +255 85 255 Untitled +255 170 0 Untitled +255 170 85 Untitled +255 170 170 Untitled +255 170 255 Untitled +255 255 0 Untitled +255 255 85 Untitled +255 255 170 Untitled +255 255 255 Untitled diff --git a/tools/EBF-convert/espectrum-logo-cropped.ebf4 b/tools/EBF-convert/espectrum-logo-cropped.ebf4 new file mode 100644 index 0000000000000000000000000000000000000000..05bb95f3fa0a0ae7f768a7d5a190614bb74c07ce GIT binary patch literal 2562 zcmcJRPma?t6vkg5n_0D%x`|j!rCuPa2WgfW2uM9ZIYPMrQn!`3Kq7UM6$fF%pDhwA zF2M?k1Hkt^|B2H{I~|yL3&*kJpFe+ocKhnZ>#L9QOg{bj^7Y5}Z@)hO{H-C`R7@;H zFLt}9dl)zFe5$L)L#2M z+>yzZpo%$%j+KipI)jxY+OaXZrg8cX-}>MYz1-)VCQ2XJp_TeE) z=-J>VXn7pfqd=cwb$8I?ueM7>EFx-$GDf_`+)DiINHXKJ_HcN@)8As=8ji2R4cwp+ z@6K^7L*ov5__wrB@wkB(!FS190QQ`Smtd%PI#*U4<_y0*KkB-2ALpUckInhBJdDX- D%3K5s literal 0 HcmV?d00001 diff --git a/tools/EBF-convert/espectrum-logo-cropped.ebf8 b/tools/EBF-convert/espectrum-logo-cropped.ebf8 new file mode 100644 index 0000000000000000000000000000000000000000..63a5af908042754e9a54633968130f7340ac44ab GIT binary patch literal 5057 zcmd6rO;Y4A428MJT!i&h!KK+Wu$?MaeTl5*1{uAlA4|3q%m7_@k-U~<`?IV#frsCZ z_fL1f?k<S+%oUy z=rzZJJ{Wq-dfIns|Gz<3Zy`BZqq%%+*P$e=_SEz@#<$ zYcZ)8SG-#GUA?Leymw+O8$*<#W25_eN$9z>SrgfiYQ4$8l<6&%SCCkfv0Xa4{yspD zU|+rTT0M^lCloS|M)!33^M)V)oIlOC&KhP6(Vcr*byC`o5^ z6-M{d2^ihCP@46RppR*fg{hF|fV_Z{1}#*{Lcf89Kl>nb_&84xR&%ey0Sz(gVxZ?fx^jf@yf1QM=a(jO-%|A{Tn4>-3e_WDx0CI zHS{)HQDm-J*F|EE(iYHtWb|7`Kd6^fFg|Q|&*;Tfu$2W@PprqPM}CEpGxMHK!pY$n-arXa zvTkwBS=Aakiy9X>9lKYO|J_v3nJ>+;OTXurQ=o(}barJAd19M$P<)_g7t#c^ih7>F zW|o4^>Et_a_94JrYS{y&7QLavt#O}0?~**A`-eb9*Ng!TjipyiX-AMW1o;4l3=>** z>Td*^nkBrA)V=oybQy>H;WOJkgWAE8OiHc6pAO{{i@_4;26a literal 0 HcmV?d00001 diff --git a/tools/EBF-convert/espectrum-logo-cropped.png b/tools/EBF-convert/espectrum-logo-cropped.png new file mode 100644 index 0000000000000000000000000000000000000000..3b8eabb00bddffcc4c51176f1da7f1dc0de375a9 GIT binary patch literal 834 zcmeAS@N?(olHy`uVBq!ia0vp^yMb7mgBeH)2k~tKQjEnx?oJHr&dIz4at;Legt!7} z28K`uhE)s<|3P$UC`0HfhS2{YfmNXlt5z|r`VW+0_#evfe-*=jAO%zfR0Nd!4^j&P zt3pHngERr@RjWc*{Rip>3WWY&75X2j2WS#d5@-;R57Y)!1yuAOWH5*Y1pk3H05t*W zRsa8ktO8pPv=wA0*l3`MAj`qpfU1FtfO0?~AWQ$uV=xHSDz zJ}``)c)B=-M6}+$VVif@fQL1KG1j``;kucV`2!rj?+;yjOYEfksr??Wra3RPx%p8% zblRLHQ-U<-+Iv3@)N*gEvz7n2?bgQrW#5`VT7K&>5MS_juJZoe^5$3Wm0vDi)PB9Q za#zOMs*CGa+AaSzBdd$4ny;z-HhXCs_oRmQ_>Jr(sr^eGKjptUawcW{u{FjUuHUoU zGWSN*`pv~Ny;r0xx|Ef7e(y8p#B|$HXyw6Xrhr`QPjG2X*m{H=a!XcjkNF+^apwx%@9>t>3K9 zJG!1d@bS{nu8G?>vn`%`tA5>9y&L7_w;W%JY0mCQs=l?MxLSAZ7RUEz%4L3Lh^1oo85_3+Dw|2I6yw15hGAxRBVXeo(w@X=rj`>MsS(nY-(EjCG`={(Oak)+9FP^{Q z`#SyYhP~O<7Wd^dpKr@~&HJrk?zgwLzjjt%{gShO;>Ta_-o9geJ}Fjz(gyR^vaNz^ zeLI(2-Fmt(`di6&>-da#vr`{tCitB&xEQy4=bdf4*I#ouzfe|wk3mxHl&zaBzfQYr zE3zYzKR>=Z%$fcjVVcp5)D6 Date: Sun, 6 Aug 2023 10:48:43 +0200 Subject: [PATCH 24/29] Road to rc2 --- include/ESPectrum.h | 2 + include/Tape.h | 21 +- include/Video.h | 2 +- include/hardconfig.h | 10 - include/messages.h | 642 +++++++++++++++++++++++++++-- include/roms.h | 67 ++-- include/roms/romZX81.edition3.h | 689 ++++++++++++++++++++++++++++++++ src/ESPectrum.cpp | 284 +++---------- src/FileSNA.cpp | 4 + src/FileUtils.cpp | 2 +- src/FileZ80.cpp | 4 + src/OSDMain.cpp | 257 ++++++++---- src/OSDMenu.cpp | 228 ++++++----- src/Tape.cpp | 428 +++++++++++++++----- src/Video.cpp | 9 +- 15 files changed, 2055 insertions(+), 594 deletions(-) create mode 100644 include/roms/romZX81.edition3.h diff --git a/include/ESPectrum.h b/include/ESPectrum.h index eeb1ec76..5d51a344 100644 --- a/include/ESPectrum.h +++ b/include/ESPectrum.h @@ -91,6 +91,8 @@ class ESPectrum static int sync_cnt; static uint8_t *audbuffertosend; + static int TapeNameScroller; + // static bool Audio_restart; static int64_t target; diff --git a/include/Tape.h b/include/Tape.h index d379f466..d891256c 100644 --- a/include/Tape.h +++ b/include/Tape.h @@ -85,14 +85,14 @@ class TapeBlock Info, Unassigned }; - uint8_t Index; // Index (position) of the tape block in the tape file. - BlockType Type; // Type of tape block (enum). - char FileName[11]; // File name in header block. - bool IsHeaderless; // Set to true for data blocks without a header. - uint8_t Checksum; // Header checksum byte. - uint8_t BlockTypeNum; // Block type, 0x00 = header; 0xFF = data block. - uint32_t StartPosition; // Where in the translated tape data is the start point of this block? - uint16_t BlockLength; + // uint8_t Index; // Index (position) of the tape block in the tape file. + // BlockType Type; // Type of tape block (enum). + // char FileName[11]; // File name in header block. + // bool IsHeaderless; // Set to true for data blocks without a header. + // uint8_t Checksum; // Header checksum byte. + // uint8_t BlockTypeNum; // Block type, 0x00 = header; 0xFF = data block. + uint32_t StartPosition; // Start point of this block? + // uint16_t BlockLength; }; class Tape @@ -107,7 +107,8 @@ class Tape static uint8_t tapeStatus; static uint8_t SaveStatus; static uint8_t romLoading; - static uint16_t tapeCurBlock; + static uint16_t tapeCurBlock; + static uint16_t tapeNumBlocks; static uint32_t tapebufByteCount; static uint32_t tapePlayOffset; static size_t tapeFileSize; @@ -120,8 +121,8 @@ class Tape static void TAP_Stop(); static void IRAM_ATTR TAP_Read(); static bool FlashLoad(); - // static bool FlashLoad2(); static void Save(); + static uint32_t CalcTapBlockPos(int block); }; diff --git a/include/Video.h b/include/Video.h index 3e7daa5f..d40735c5 100644 --- a/include/Video.h +++ b/include/Video.h @@ -91,7 +91,7 @@ class VIDEO static void IRAM_ATTR TopBorder(unsigned int statestoadd, bool contended); static void IRAM_ATTR MainScreen_Blank(unsigned int statestoadd, bool contended); static void MainScreen(unsigned int statestoadd, bool contended); - static void IRAM_ATTR MainScreen_OSD(unsigned int statestoadd, bool contended); + static void MainScreen_OSD(unsigned int statestoadd, bool contended); static void IRAM_ATTR BottomBorder_Blank(unsigned int statestoadd, bool contended); static void IRAM_ATTR BottomBorder(unsigned int statestoadd, bool contended); static void IRAM_ATTR BottomBorder_OSD(unsigned int statestoadd, bool contended); diff --git a/include/hardconfig.h b/include/hardconfig.h index 341a3aa3..774ae331 100644 --- a/include/hardconfig.h +++ b/include/hardconfig.h @@ -60,16 +60,6 @@ visit https://zxespectrum.speccy.org/contacto // #define LOG_DEBUG_TIMING -/////////////////////////////////////////////////////////////////////////////// -// TO DO: Tape traps -// -// define TAPE_TRAPS for emulator trapping LOAD and SAVE rom code. In some -// titles it could help with right loading or auto-stoping tape in right places. -// (If a .tap doesn't load with tape load active try disabling it) -/////////////////////////////////////////////////////////////////////////////// - -// #define TAPE_TRAPS // STILL NOT WORKING! - /////////////////////////////////////////////////////////////////////////////// // Snapshot loading behaviour // diff --git a/include/messages.h b/include/messages.h index 06e3becb..a72719f2 100644 --- a/include/messages.h +++ b/include/messages.h @@ -69,6 +69,7 @@ static const char *OSD_PAUSE[2] = { OSD_PAUSE_EN,OSD_PAUSE_ES }; #define OSD_PSNA_LOADED " Persist Snapshot Loaded " #define OSD_PSNA_LOAD_ERR "ERROR Loading Persist Snapshot" #define OSD_PSNA_SAVED " Persist Snapshot Saved " +#define OSD_TAPE_FLASHLOAD "Flash loading TAP file" #define OSD_TAPE_LOAD_ERR "ERROR Loading TAP file" #define OSD_TAPE_SAVE_ERR "ERROR Saving TAP file" @@ -326,47 +327,185 @@ static const char *MENU_JOY[2] = { MENU_JOY_EN, MENU_JOY_ES }; // "Ingles GB\t[UK]\n" // static const char *MENU_KBD_LAYOUT[2] = { MENU_KBD_LAYOUT_EN, MENU_KBD_LAYOUT_ES }; -#define OSD_ABOUT_EN \ - " (C)2023 Victor Iborra \"Eremus\"\n"\ - " David Crespo \"dcrespo3d\"\n"\ - "\n"\ - " Based on ZX-ESPectrum-Wiimote\n"\ - " (C)2020-2023 David Crespo\n"\ - "\n"\ - " Inspired by previous projects\n"\ - " from Pete Todd and Rampa & Queru\n"\ - "\n"\ - " Z80 emulation by JL Sanchez\n"\ - " VGA driver by BitLuni\n"\ - " AY-3-8912 library by A. Sashnov\n"\ - " PS2 driver by Fabrizio di Vittorio\n"\ - "\n"\ - " Greetings to Ackerman, zx81, azesmbog,\n"\ - " ZjoyKiLer, D. Carrion, A. Villena,\n"\ - " Rampa and to Retrowiki and his people\n"\ - " for the support and inspiration.\n" -#define OSD_ABOUT_ES \ - " (C)2023 Victor Iborra \"Eremus\"\n"\ - " David Crespo \"dcrespo3d\"\n"\ - "\n"\ - " Basado en ZX-ESPectrum-Wiimote\n"\ - " (C)2020-2023 David Crespo\n"\ - "\n"\ - " Inspirado en proyectos anteriores\n"\ - " de Pete Todd y Rampa & Queru\n"\ - "\n"\ - " Emulacion Z80 por JL Sanchez\n"\ - " Driver VGA por BitLuni\n"\ - " Libreria AY-3-8912 por A. Sashnov\n"\ - " Driver PS2 por Fabrizio di Vittorio\n"\ - "\n"\ - " Saludos a Ackerman, zx81, azesmbog,\n"\ - " ZjoyKiLer, D. Carrion, A. Villena,\n"\ - " Rampa y a Retrowiki y su gente por su\n"\ - " ayuda e inspiracion.\n" +// #define OSD_ABOUT1_EN \ +// " (C)2023 Victor Iborra \"Eremus\"\n"\ +// " David Crespo \"dcrespo3d\"\n"\ +// "\n"\ +// " Based on ZX-ESPectrum-Wiimote\n"\ +// " (C)2020-2023 David Crespo\n"\ +// "\n"\ +// " Inspired by previous projects\n"\ +// " from Pete Todd and Rampa & Queru\n"\ +// "\n"\ +// " Z80 emulation by JL Sanchez\n"\ +// " VGA driver by BitLuni\n"\ +// " AY-3-8912 library by A. Sashnov\n"\ +// " PS2 driver by Fabrizio di Vittorio\n" + +// #define OSD_ABOUT2_EN \ +// " Greetings to Ackerman, zx81, azesmbog,\n"\ +// " ZjoyKiLer, D. Carrion, A. Villena,\n"\ +// " Rampa and to Retrowiki and his people\n"\ +// " for the support and inspiration.\n" + +// #define OSD_ABOUT1_ES \ +// " (C)2023 Victor Iborra \"Eremus\"\n"\ +// " David Crespo \"dcrespo3d\"\n"\ +// "\n"\ +// " Basado en ZX-ESPectrum-Wiimote\n"\ +// " (C)2020-2023 David Crespo\n"\ +// "\n"\ +// " Inspirado en proyectos anteriores\n"\ +// " de Pete Todd y Rampa & Queru\n"\ +// "\n"\ +// " Emulacion Z80 por JL Sanchez\n"\ +// " Driver VGA por BitLuni\n"\ +// " Libreria AY-3-8912 por A. Sashnov\n"\ +// " Driver PS2 por Fabrizio di Vittorio\n" + +// #define OSD_ABOUT2_ES \ +// " Saludos a Ackerman, zx81, azesmbog,\n"\ +// " ZjoyKiLer, D. Carrion, A. Villena,\n"\ +// " Rampa y a Retrowiki y su gente por su\n"\ +// " ayuda e inspiracion.\n" // static const char *OSD_ABOUT[2] = { OSD_ABOUT_EN, OSD_ABOUT_ES }; + #define DEDICATORIA "\nF1Dedicado especialmente a:\r"\ + "\nB1 _ _ _\r"\ + "\nB1 | | | (_) \nA1d88b d88b\r"\ + "\nB1 | |_ _| |_ __ _ \nA188888888888\r"\ + "\nB1 _ | | | | | | |/ _` | \nA1`Y8888888Y'\r"\ + "\nB1| |__| | |_| | | | (_| | \nA1`Y888Y'\r"\ + "\nB1 \\____/ \\___/|_|_|\\__,_| \nA1`Y'\r"\ + "\nF1 _ _ \nE1 __ __ _ \r"\ + "\nF1| | | | \nE1| \\/ | | |\r"\ + "\nF1| |_| | \nE1| \\ / | __ _ _ __| |_ __ _\r"\ + "\nF1 \\__, | \nE1| |\\/| |/ _` | '__| __/ _` |\r"\ + "\nF1 __/ | \nE1| | | | (_| | | | || (_| |\r"\ + "\nF1 |___/ \nE1|_| |_|\\__,_|_| \\__\\__,_|\r" + + static const char *AboutMsg[2][5] = { + { + "\nF1(C)2023 Victor Iborra \"Eremus\"\r"\ + " David Crespo \"dcrespo3d\"\r"\ + "\r"\ + "\nA1Based on ZX-ESPectrum-Wiimote\r"\ + "(C)2020-2023 David Crespo\r"\ + "\r"\ + "\nB1Inspired by previous projects\r"\ + "from Pete Todd and Rampa & Queru\r"\ + "\r"\ + "\nC1Z80 emulation by JL Sanchez\r"\ + "\nD1VGA driver by BitLuni\r"\ + "\nE1AY-3-8912 library by A. Sashnov\r"\ + "\nF1PS2 driver by Fabrizio di Vittorio\r" + , + "\nF1Collaborators:\r"\ + "\r"\ + "\nA1ackerman \nF1Code & ideas\r"\ + "\nB1Armand \nF1Testing & difusion\r"\ + "\nC1azesmbog \nF1Testing & ideas\r"\ + "\nD1David Carrion \nF1H/W code, ZX kbd\r"\ + "\nE1Ramon Martinez \nF1AY emul. improvements\r"\ + "\nA1Ron \nF1Testing & difusion\r"\ + "\nB1J. L. Sanchez \nF1Z80 core improvements\r"\ + "\nC1Antonio Villena \nF1Hardware support\r"\ + "\nD1ZjoyKiLer \nF1Testing & ideas\r"\ + "\r" + "\r" + , + "\nF1Big thanks to our Patreons:\r"\ + "\r"\ + "\nA1The Mega Trees:\r"\ + "\r"\ + "\nB1Victor Llamazares, \nC1Antonio Villena\r"\ + "\r"\ + "\nD1The Manic Miners:\r"\ + "\r"\ + "\nE1Fernando Bonilla, \nA1Magnetrix, \nB1M.Ignacio\r"\ + "Monge, \nC1Jose Maria Rodriguez, \nD1Julia\r"\ + "Salvador, \nE1Marta Sicilia, \nA1Radoslaw\r"\ + "Wojciechowski\r"\ + "\r" + , + "\nF1Thanks also to:\r"\ + "\r"\ + "\nA1Retrowiki.es \nF1and its great community\r"\ + "\nB1Ron \nF1for his cool RetroCrypta\r"\ + "\nC1Viejoven FX\nF1, \nD1J.Ortiz \"El Spectrumero\"\r" + "\nE1J.C. Gonzalez Amestoy \nF1for RVM\r"\ + "\nA1Tsvetan Usunov from Olimex Ltd.\r"\ + "\nB1All creators in ZX Spectrum server at\r"\ + "Discord\r"\ + "\r"\ + "\nF1and, of course, to:\r"\ + "\r"\ + "\nD1Sir Clive Sinclair \nF1& \nA1M\nE1a\nC1t\nD1t\nB1h\nA1e\nE1w \nC1S\nD1m\nB1i\nA1t\nE1h\r"\ + , + DEDICATORIA + }, + { + "\nF1(C)2023 Victor Iborra \"Eremus\"\r"\ + " David Crespo \"dcrespo3d\"\r"\ + "\r"\ + "\nA1Basado en ZX-ESPectrum-Wiimote\r"\ + "(C)2020-2023 David Crespo\r"\ + "\r"\ + "\nB1Inspirado en proyectos anteriores\r"\ + "de Pete Todd y Rampa & Queru\r"\ + "\r"\ + "\nC1Emulacion Z80 por JL Sanchez\r"\ + "\nD1Driver VGA por BitLuni\r"\ + "\nE1Libreria AY-3-8912 por A. Sashnov\r"\ + "\nF1Driver PS2 por Fabrizio di Vittorio\r" + , + "\nF1Colaboradores:\r"\ + "\r"\ + "\nA1ackerman \nF1Codigo e ideas\r"\ + "\nB1Armand \nF1Testing y difusion\r"\ + "\nC1azesmbog \nF1Testing e ideas\r"\ + "\nD1David Carrion \nF1Codigo h/w, teclado ZX\r"\ + "\nE1Ramon Martinez \nF1Mejoras emulacion AY\r"\ + "\nA1Ron \nF1Testing y difusion\r"\ + "\nB1J. L. Sanchez \nF1Mejoras core Z80\r"\ + "\nC1Antonio Villena \nF1Soporte hardware\r"\ + "\nD1ZjoyKiLer \nF1Testing e ideas\r"\ + "\r" + "\r" + , + "\nF1Muchas gracias a nuestros Patreons:\r"\ + "\r"\ + "\nA1The Mega Trees:\r"\ + "\r"\ + "\nB1Victor Llamazares, \nC1Antonio Villena\r"\ + "\r"\ + "\nD1The Manic Miners:\r"\ + "\r"\ + "\nE1Fernando Bonilla, \nA1Magnetrix, \nB1M.Ignacio\r"\ + "Monge, \nC1Jose Maria Rodriguez, \nD1Julia\r"\ + "Salvador, \nE1Marta Sicilia, \nA1Radoslaw\r"\ + "Wojciechowski\r"\ + "\r" + , + "\nF1Gracias tambien a:\r"\ + "\r"\ + "\nA1Retrowiki.es \nF1y su magnifica comunidad\r"\ + "\nB1Ron \nF1por su genial RetroCrypta\r"\ + "\nC1Viejoven FX\nF1, \nD1J.Ortiz \"El Spectrumero\"\r" + "\nE1J.C. Gonzalez Amestoy \nF1por RVM\r"\ + "\nA1Tsvetan Usunov de Olimex Ltd.\r"\ + "\nB1Todos los creadores en el servidor\r"\ + "ZX Spectrum en Discord\r"\ + "\r"\ + "\nF1y, por supuesto, a:\r"\ + "\r"\ + "\nD1Sir Clive Sinclair \nF1& \nA1M\nE1a\nC1t\nD1t\nB1h\nA1e\nE1w \nC1S\nD1m\nB1i\nA1t\nE1h\r"\ + , + DEDICATORIA + } + }; + #define OSD_HELP_EN \ " [F1] Menu\n"\ " [F2] Load (SNA,Z80)\n"\ @@ -406,6 +545,431 @@ static const char *MENU_JOY[2] = { MENU_JOY_EN, MENU_JOY_ES }; // static const char *OSD_HELP[2] = { OSD_HELP_EN, OSD_HELP_ES }; -static const char *OSD_TAPE_OF[2] = { "of", "de" }; +// static const char *OSD_TAPE_OF[2] = { "of", "de" }; + +const uint8_t ESPectrum_logo[] = { + 0x45, 0x42, 0x46, 0x38, 0xBB, 0x00, 0x1B, 0x00, 0xC0, 0xC0, 0xC0, 0xFF, + 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, + 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC2, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC2, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC2, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC2, 0xC0, 0xC0, 0xC0, 0xC2, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC2, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, + 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, + 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, + 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC2, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, + 0xC2, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC2, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, + 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, + 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, + 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, + 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xC3, 0xC3, 0xC3, + 0xC3, 0xCF, 0xCF, 0xCF, 0xCF, 0xCC, 0xCC, 0xCC, 0xCC, 0xF0, 0xF0, 0xF0, + 0xF0, 0xD5, 0xD5, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC2, + 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC2, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, + 0xD5, 0xD5, 0xD5, 0xD5, 0xC3, 0xC3, 0xC3, 0xC3, 0xCF, 0xCF, 0xCF, 0xCF, + 0xCC, 0xCC, 0xCC, 0xCC, 0xF0, 0xF0, 0xF0, 0xF0, 0xD5, 0xD5, 0xD5, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC1, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC1, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC1, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xC3, 0xC3, + 0xC3, 0xC3, 0xCF, 0xCF, 0xCF, 0xCF, 0xCC, 0xCC, 0xCC, 0xCC, 0xF0, 0xF0, + 0xF0, 0xF0, 0xD5, 0xD5, 0xD5, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, 0xD5, 0xD5, + 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xC3, 0xC3, 0xC3, 0xC3, 0xCF, 0xCF, 0xCF, + 0xCF, 0xCC, 0xCC, 0xCC, 0xCC, 0xF0, 0xF0, 0xF0, 0xF0, 0xD5, 0xD5, 0xD5, + 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, 0xEA, 0xEA, 0xEA, 0xD5, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, + 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, 0xEA, 0xEA, 0xEA, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, 0xEA, + 0xEA, 0xEA, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, 0xEA, 0xEA, 0xEA, + 0xD5, 0xC0, 0xC0, 0xC0, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, + 0xC3, 0xC3, 0xC3, 0xC3, 0xCF, 0xCF, 0xCF, 0xCF, 0xCC, 0xCC, 0xCC, 0xCC, + 0xF0, 0xF0, 0xF0, 0xF0, 0xD5, 0xD5, 0xD5, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xEA, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xEA, 0xD5, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, 0xEA, + 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xD5, 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xD5, + 0xC0, 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xD5, 0xC0, 0xD5, + 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xC3, 0xC3, 0xC3, 0xC3, 0xCF, 0xCF, + 0xCF, 0xCF, 0xCC, 0xCC, 0xCC, 0xCC, 0xF0, 0xF0, 0xF0, 0xF0, 0xD5, 0xD5, + 0xD5, 0xD5, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC1, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC1, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, + 0xC0, 0xC0, 0xC0, 0xD5, 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xEA, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, 0xC0, + 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, + 0xD5, 0xC3, 0xC3, 0xC3, 0xC3, 0xCF, 0xCF, 0xCF, 0xCF, 0xCC, 0xCC, 0xCC, + 0xCC, 0xF0, 0xF0, 0xF0, 0xF0, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC2, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC2, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, + 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xEA, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xC3, 0xC3, 0xC3, 0xC3, + 0xCF, 0xCF, 0xCF, 0xCF, 0xCC, 0xCC, 0xCC, 0xCC, 0xF0, 0xF0, 0xF0, 0xF0, + 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC1, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC0, 0xC0, 0xC0, 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xD5, 0xD5, + 0xD5, 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xEA, + 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xD5, 0xD5, 0xD5, 0xEA, 0xFF, 0xFF, 0xFF, + 0xFF, 0xEA, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xEA, + 0xEA, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xEA, 0xD5, 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xEA, 0xD5, 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xD5, 0xD5, 0xD5, 0xD5, + 0xD5, 0xD5, 0xC3, 0xC3, 0xC3, 0xC3, 0xCF, 0xCF, 0xCF, 0xCF, 0xCC, 0xCC, + 0xCC, 0xCC, 0xF0, 0xF0, 0xF0, 0xF0, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC2, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC2, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xD5, 0xFF, + 0xFF, 0xFF, 0xFF, 0xEA, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xEA, 0xFF, 0xFF, + 0xFF, 0xFF, 0xEA, 0xC0, 0xC0, 0xD5, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, + 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xEA, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, + 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, + 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, 0xC0, 0xC0, 0xC0, + 0xD5, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, 0xC0, 0xC0, 0xC0, 0xD5, 0xFF, + 0xFF, 0xFF, 0xFF, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xC3, 0xC3, 0xC3, + 0xC3, 0xCF, 0xCF, 0xCF, 0xCF, 0xCC, 0xCC, 0xCC, 0xCC, 0xF0, 0xF0, 0xF0, + 0xF0, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC1, 0xC0, 0xC0, 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xEA, 0xFF, 0xFF, 0xFF, 0xEA, 0xC0, 0xC0, + 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, + 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, + 0xFF, 0xFF, 0xEA, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xEA, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, 0xD5, + 0xD5, 0xD5, 0xD5, 0xC3, 0xC3, 0xC3, 0xC3, 0xCF, 0xCF, 0xCF, 0xCF, 0xCC, + 0xCC, 0xCC, 0xCC, 0xF0, 0xF0, 0xF0, 0xF0, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, + 0xD5, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC2, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC2, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xEA, 0xEA, 0xEA, 0xEA, 0xC0, + 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xC3, 0xC3, + 0xC3, 0xC3, 0xCF, 0xCF, 0xCF, 0xCF, 0xCC, 0xCC, 0xCC, 0xCC, 0xF0, 0xF0, + 0xF0, 0xF0, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC1, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC1, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, + 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC1, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, + 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, + 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xC3, 0xC3, 0xC3, 0xC3, 0xCF, 0xCF, 0xCF, + 0xCF, 0xCC, 0xCC, 0xCC, 0xCC, 0xF0, 0xF0, 0xF0, 0xF0, 0xD5, 0xD5, 0xD5, + 0xD5, 0xD5, 0xD5, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC1, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, + 0xFF, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, 0xD5, 0xD5, 0xD5, 0xC3, + 0xC3, 0xC3, 0xC3, 0xCF, 0xCF, 0xCF, 0xCF, 0xCC, 0xCC, 0xCC, 0xCC, 0xF0, + 0xF0, 0xF0, 0xF0, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, + 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, + 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, + 0xFF, 0xFF, 0xD5, 0xD5, 0xD5, 0xD5, 0xC3, 0xC3, 0xC3, 0xC3, 0xCF, 0xCF, + 0xCF, 0xCF, 0xCC, 0xCC, 0xCC, 0xCC, 0xF0, 0xF0, 0xF0, 0xF0, 0xD5, 0xD5, + 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xEA, + 0xEA, 0xEA, 0xEA, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, + 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, 0xD5, 0xD5, + 0xD5, 0xC3, 0xC3, 0xC3, 0xC3, 0xCF, 0xCF, 0xCF, 0xCF, 0xCC, 0xCC, 0xCC, + 0xCC, 0xF0, 0xF0, 0xF0, 0xF0, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, + 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xEA, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xEA, 0xEA, 0xEA, 0xEA, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, + 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, 0xFF, 0xFF, + 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, 0xD5, 0xD5, 0xC3, 0xC3, 0xC3, 0xC3, 0xCF, + 0xCF, 0xCF, 0xCF, 0xCC, 0xCC, 0xCC, 0xCC, 0xF0, 0xF0, 0xF0, 0xF0, 0xD5, + 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC1, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC1, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xEA, 0xFF, 0xFF, 0xFF, 0xEA, 0xC0, + 0xC0, 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, + 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, + 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, + 0xD5, 0xD5, 0xC3, 0xC3, 0xC3, 0xC3, 0xCF, 0xCF, 0xCF, 0xCF, 0xCC, 0xCC, + 0xCC, 0xCC, 0xF0, 0xF0, 0xF0, 0xF0, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, + 0xD5, 0xD5, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC2, 0xC0, + 0xC0, 0xC2, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xD5, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xD5, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xC0, 0xC0, 0xD5, 0xFF, 0xFF, 0xFF, + 0xFF, 0xEA, 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, + 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, + 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, + 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xEA, 0xD5, 0xD5, 0xD5, 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC0, 0xC0, 0xC0, 0xC0, 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xD5, 0xD5, + 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xEA, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xD5, 0xC0, 0xC0, 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, + 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, + 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, + 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC2, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC2, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xEA, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, + 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, + 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC0, 0xC0, 0xC0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xD5, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, + 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, + 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, + 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC2, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC2, 0xC0, 0xC0, 0xC2, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC2, 0xC0, 0xC0, 0xC0, 0xC0, 0xC2, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, 0xEA, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xD5, 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEA, + 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, 0xEA, 0xFF, + 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xEA, 0xD5, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, + 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xD5, 0xD5, 0xD5, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0 +}; #endif // ESPECTRUM_MESSAGES_h diff --git a/include/roms.h b/include/roms.h index cbd34353..463a0c7f 100644 --- a/include/roms.h +++ b/include/roms.h @@ -36,7 +36,7 @@ visit https://zxespectrum.speccy.org/contacto #ifndef ROMS_H #define ROMS_H - #include +// #include //#include "roms/romDiag48K.h" #include "roms/romSinclair48K.h" //#include "roms/romSE48K.h" @@ -47,41 +47,42 @@ visit https://zxespectrum.speccy.org/contacto // #include "roms/romPlus3E128K.h" #include "roms/romSinclair128K.h" //#include "roms/romPlus2128K.h" +// #include "roms/romZX81.edition3.h" + +// #define max_list_rom_48 1 - #define max_list_rom_48 1 - - #define max_list_rom_128 1 +// #define max_list_rom_128 1 - //roms 48K - //Titulos - static const char * gb_list_roms_48k_title[max_list_rom_48]={ - "SINCLAIR", - /* "DIAG", - "SE", - "TESTRAM128"*/ - }; +// //roms 48K +// //Titulos +// static const char * gb_list_roms_48k_title[max_list_rom_48]={ +// "SINCLAIR", +// /* "DIAG", +// "SE", +// "TESTRAM128"*/ +// }; - //Datos 48K 1 ROM en slot 0 - static const unsigned char * gb_list_roms_48k_data[max_list_rom_48]={ - gb_rom_0_sinclair_48k, - /*gb_rom_0_diag_48k, - gb_rom_0_SE_48k, - gb_rom_0_ramtester_48k*/ - }; - - //Datos 128K - static const char * gb_list_roms_128k_title[max_list_rom_128]={ - "SINCLAIR"/*, - "PLUS2", - "PLUS3", - "PLUS3E"*/ - }; - - - //Datos 128K 4 roms en 4 slots - static const unsigned char * gb_list_roms_128k_data[max_list_rom_128][4]={ - gb_rom_0_sinclair_128k,gb_rom_1_sinclair_128k,gb_rom_0_sinclair_128k,gb_rom_1_sinclair_128k - }; +// //Datos 48K 1 ROM en slot 0 +// static const unsigned char * gb_list_roms_48k_data[max_list_rom_48]={ +// gb_rom_0_sinclair_48k, +// /*gb_rom_0_diag_48k, +// gb_rom_0_SE_48k, +// gb_rom_0_ramtester_48k*/ +// }; + +// //Datos 128K +// static const char * gb_list_roms_128k_title[max_list_rom_128]={ +// "SINCLAIR"/*, +// "PLUS2", +// "PLUS3", +// "PLUS3E"*/ +// }; + + +// //Datos 128K 4 roms en 4 slots +// static const unsigned char * gb_list_roms_128k_data[max_list_rom_128][4]={ +// gb_rom_0_sinclair_128k,gb_rom_1_sinclair_128k,gb_rom_0_sinclair_128k,gb_rom_1_sinclair_128k +// }; // //Datos 128K 4 roms en 4 slots // static const unsigned char * gb_list_roms_128k_data[max_list_rom_128][4]={ diff --git a/include/roms/romZX81.edition3.h b/include/roms/romZX81.edition3.h new file mode 100644 index 00000000..14050bf4 --- /dev/null +++ b/include/roms/romZX81.edition3.h @@ -0,0 +1,689 @@ +#ifndef ROM_ZX81_EDITION3_H + #define ROM_ZX81_EDITION3_H +//ROM 0 48K SINCLAIR +const unsigned char gb_rom_0_zx81_edition3[]={ + 0xD3, 0xFD, 0x01, 0xFF, 0x7F, 0xC3, 0xCB, 0x03, 0x2A, 0x16, 0x40, 0x22, + 0x18, 0x40, 0x18, 0x46, 0xA7, 0xC2, 0xF1, 0x07, 0xC3, 0xF5, 0x07, 0xFF, + 0x2A, 0x16, 0x40, 0x7E, 0xA7, 0xC0, 0x00, 0x00, 0xCD, 0x49, 0x00, 0x18, + 0xF7, 0xFF, 0xFF, 0xFF, 0xC3, 0x9D, 0x19, 0xF1, 0xD9, 0xE3, 0xD9, 0xC9, + 0xC5, 0x2A, 0x14, 0x40, 0xE5, 0xC3, 0x88, 0x14, 0x0D, 0xC2, 0x45, 0x00, + 0xE1, 0x05, 0xC8, 0xCB, 0xD9, 0xED, 0x4F, 0xFB, 0xE9, 0xD1, 0xC8, 0x18, + 0xF8, 0x2A, 0x16, 0x40, 0x23, 0x22, 0x16, 0x40, 0x7E, 0xFE, 0x7F, 0xC0, + 0x18, 0xF6, 0xE1, 0x6E, 0xFD, 0x75, 0x00, 0xED, 0x7B, 0x02, 0x40, 0xCD, + 0x07, 0x02, 0xC3, 0xBC, 0x14, 0xFF, 0x08, 0x3C, 0xFA, 0x6D, 0x00, 0x28, + 0x02, 0x08, 0xC9, 0x08, 0xF5, 0xC5, 0xD5, 0xE5, 0x2A, 0x0C, 0x40, 0xCB, + 0xFC, 0x76, 0xD3, 0xFD, 0xDD, 0xE9, 0x3F, 0x3D, 0x28, 0x3B, 0x26, 0x38, + 0x29, 0x2B, 0x2C, 0x36, 0x3C, 0x2A, 0x37, 0x39, 0x1D, 0x1E, 0x1F, 0x20, + 0x21, 0x1C, 0x25, 0x24, 0x23, 0x22, 0x35, 0x34, 0x2E, 0x3A, 0x3E, 0x76, + 0x31, 0x30, 0x2F, 0x2D, 0x00, 0x1B, 0x32, 0x33, 0x27, 0x0E, 0x19, 0x0F, + 0x18, 0xE3, 0xE1, 0xE4, 0xE5, 0xE2, 0xC0, 0xD9, 0xE0, 0xDB, 0xDD, 0x75, + 0xDA, 0xDE, 0xDF, 0x72, 0x77, 0x74, 0x73, 0x70, 0x71, 0x0B, 0x11, 0x10, + 0x0D, 0xDC, 0x79, 0x14, 0x15, 0x16, 0xD8, 0x0C, 0x1A, 0x12, 0x13, 0x17, + 0xCD, 0xCE, 0xC1, 0x78, 0xCA, 0xCB, 0xCC, 0xD1, 0xD2, 0xC7, 0xC8, 0xC9, + 0xCF, 0x40, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0xC2, 0xD3, 0xC4, 0xD6, 0xD5, 0x78, 0xD4, 0xC6, 0xC5, 0xD0, 0x78, 0x78, + 0x42, 0xD7, 0x41, 0x08, 0x0A, 0x09, 0x8A, 0x89, 0x81, 0x82, 0x07, 0x84, + 0x06, 0x01, 0x02, 0x87, 0x04, 0x05, 0x77, 0x78, 0x85, 0x03, 0x83, 0x8B, + 0x91, 0x90, 0x8D, 0x86, 0x78, 0x92, 0x95, 0x96, 0x88, 0x8F, 0x0B, 0x8B, + 0x26, 0xB9, 0x39, 0x26, 0xA7, 0x8F, 0x28, 0x34, 0x29, 0xAA, 0x3B, 0x26, + 0xB1, 0x31, 0x2A, 0xB3, 0x38, 0x2E, 0xB3, 0x28, 0x34, 0xB8, 0x39, 0x26, + 0xB3, 0x26, 0x38, 0xB3, 0x26, 0x28, 0xB8, 0x26, 0x39, 0xB3, 0x31, 0xB3, + 0x2A, 0x3D, 0xB5, 0x2E, 0x33, 0xB9, 0x38, 0x36, 0xB7, 0x38, 0x2C, 0xB3, + 0x26, 0x27, 0xB8, 0x35, 0x2A, 0x2A, 0xB0, 0x3A, 0x38, 0xB7, 0x38, 0x39, + 0x37, 0x8D, 0x28, 0x2D, 0x37, 0x8D, 0x33, 0x34, 0xB9, 0x17, 0x97, 0x34, + 0xB7, 0x26, 0x33, 0xA9, 0x13, 0x94, 0x12, 0x94, 0x13, 0x92, 0x39, 0x2D, + 0x2A, 0xB3, 0x39, 0xB4, 0x38, 0x39, 0x2A, 0xB5, 0x31, 0x35, 0x37, 0x2E, + 0x33, 0xB9, 0x31, 0x31, 0x2E, 0x38, 0xB9, 0x38, 0x39, 0x34, 0xB5, 0x38, + 0x31, 0x34, 0xBC, 0x2B, 0x26, 0x38, 0xB9, 0x33, 0x2A, 0xBC, 0x38, 0x28, + 0x37, 0x34, 0x31, 0xB1, 0x28, 0x34, 0x33, 0xB9, 0x29, 0x2E, 0xB2, 0x37, + 0x2A, 0xB2, 0x2B, 0x34, 0xB7, 0x2C, 0x34, 0x39, 0xB4, 0x2C, 0x34, 0x38, + 0x3A, 0xA7, 0x2E, 0x33, 0x35, 0x3A, 0xB9, 0x31, 0x34, 0x26, 0xA9, 0x31, + 0x2E, 0x38, 0xB9, 0x31, 0x2A, 0xB9, 0x35, 0x26, 0x3A, 0x38, 0xAA, 0x33, + 0x2A, 0x3D, 0xB9, 0x35, 0x34, 0x30, 0xAA, 0x35, 0x37, 0x2E, 0x33, 0xB9, + 0x35, 0x31, 0x34, 0xB9, 0x37, 0x3A, 0xB3, 0x38, 0x26, 0x3B, 0xAA, 0x37, + 0x26, 0x33, 0xA9, 0x2E, 0xAB, 0x28, 0x31, 0xB8, 0x3A, 0x33, 0x35, 0x31, + 0x34, 0xB9, 0x28, 0x31, 0x2A, 0x26, 0xB7, 0x37, 0x2A, 0x39, 0x3A, 0x37, + 0xB3, 0x28, 0x34, 0x35, 0xBE, 0x37, 0x33, 0xA9, 0x2E, 0x33, 0x30, 0x2A, + 0x3E, 0x8D, 0x35, 0xAE, 0x23, 0xEB, 0x2A, 0x14, 0x40, 0x37, 0xED, 0x52, + 0xEB, 0xD0, 0xE1, 0x21, 0x3B, 0x40, 0x7E, 0x17, 0xAE, 0x17, 0xD0, 0x3E, + 0x7F, 0x08, 0x06, 0x11, 0xD3, 0xFE, 0x10, 0xFE, 0xD3, 0xFD, 0x08, 0x17, + 0x30, 0x08, 0xCB, 0xFE, 0xF5, 0xC5, 0xD5, 0xE5, 0x18, 0x03, 0xCB, 0xB6, + 0xC9, 0x2A, 0x34, 0x40, 0x2B, 0x3E, 0x7F, 0xA4, 0xB5, 0x7C, 0x20, 0x03, + 0x17, 0x18, 0x02, 0x46, 0x37, 0x67, 0x22, 0x34, 0x40, 0xD0, 0xCD, 0xBB, + 0x02, 0xED, 0x4B, 0x25, 0x40, 0x22, 0x25, 0x40, 0x78, 0xC6, 0x02, 0xED, + 0x42, 0x3A, 0x27, 0x40, 0xB4, 0xB5, 0x58, 0x06, 0x0B, 0x21, 0x3B, 0x40, + 0xCB, 0x86, 0x20, 0x08, 0xCB, 0x7E, 0xCB, 0xC6, 0xC8, 0x05, 0x00, 0x37, + 0x21, 0x27, 0x40, 0x3F, 0xCB, 0x10, 0x10, 0xFE, 0x46, 0x7B, 0xFE, 0xFE, + 0x9F, 0x06, 0x1F, 0xB6, 0xA0, 0x1F, 0x77, 0xD3, 0xFF, 0x2A, 0x0C, 0x40, + 0xCB, 0xFC, 0xCD, 0x92, 0x02, 0xED, 0x5F, 0x01, 0x01, 0x19, 0x3E, 0xF5, + 0xCD, 0xB5, 0x02, 0x2B, 0xCD, 0x92, 0x02, 0xC3, 0x29, 0x02, 0xDD, 0xE1, + 0xFD, 0x4E, 0x28, 0xFD, 0xCB, 0x3B, 0x7E, 0x28, 0x0C, 0x79, 0xED, 0x44, + 0x3C, 0x08, 0xD3, 0xFE, 0xE1, 0xD1, 0xC1, 0xF1, 0xC9, 0x3E, 0xFC, 0x06, + 0x01, 0xCD, 0xB5, 0x02, 0x2B, 0xE3, 0xE3, 0xDD, 0xE9, 0xED, 0x4F, 0x3E, + 0xDD, 0xFB, 0xE9, 0x21, 0xFF, 0xFF, 0x01, 0xFE, 0xFE, 0xED, 0x78, 0xF6, + 0x01, 0xF6, 0xE0, 0x57, 0x2F, 0xFE, 0x01, 0x9F, 0xB0, 0xA5, 0x6F, 0x7C, + 0xA2, 0x67, 0xCB, 0x00, 0xED, 0x78, 0x38, 0xED, 0x1F, 0xCB, 0x14, 0x17, + 0x17, 0x17, 0x9F, 0xE6, 0x18, 0xC6, 0x1F, 0x32, 0x28, 0x40, 0xC9, 0xFD, + 0xCB, 0x3B, 0x7E, 0xC8, 0x76, 0xD3, 0xFD, 0xFD, 0xCB, 0x3B, 0xBE, 0xC9, + 0xCF, 0x0E, 0xCD, 0xA8, 0x03, 0x38, 0xF9, 0xEB, 0x11, 0xCB, 0x12, 0xCD, + 0x46, 0x0F, 0x30, 0x2E, 0x10, 0xFE, 0x1B, 0x7A, 0xB3, 0x20, 0xF4, 0xCD, + 0x1E, 0x03, 0xCB, 0x7E, 0x23, 0x28, 0xF8, 0x21, 0x09, 0x40, 0xCD, 0x1E, + 0x03, 0xCD, 0xFC, 0x01, 0x18, 0xF8, 0x5E, 0x37, 0xCB, 0x13, 0xC8, 0x9F, + 0xE6, 0x05, 0xC6, 0x04, 0x4F, 0xD3, 0xFF, 0x06, 0x23, 0x10, 0xFE, 0xCD, + 0x46, 0x0F, 0x30, 0x72, 0x06, 0x1E, 0x10, 0xFE, 0x0D, 0x20, 0xEE, 0xA7, + 0x10, 0xFD, 0x18, 0xE0, 0xCD, 0xA8, 0x03, 0xCB, 0x12, 0xCB, 0x0A, 0xCD, + 0x4C, 0x03, 0x18, 0xFB, 0x0E, 0x01, 0x06, 0x00, 0x3E, 0x7F, 0xDB, 0xFE, + 0xD3, 0xFF, 0x1F, 0x30, 0x49, 0x17, 0x17, 0x38, 0x28, 0x10, 0xF1, 0xF1, + 0xBA, 0xD2, 0xE5, 0x03, 0x62, 0x6B, 0xCD, 0x4C, 0x03, 0xCB, 0x7A, 0x79, + 0x20, 0x03, 0xBE, 0x20, 0xD6, 0x23, 0x17, 0x30, 0xF1, 0xFD, 0x34, 0x15, + 0x21, 0x09, 0x40, 0x50, 0xCD, 0x4C, 0x03, 0x71, 0xCD, 0xFC, 0x01, 0x18, + 0xF6, 0xD5, 0x1E, 0x94, 0x06, 0x1A, 0x1D, 0xDB, 0xFE, 0x17, 0xCB, 0x7B, + 0x7B, 0x38, 0xF5, 0x10, 0xF5, 0xD1, 0x20, 0x04, 0xFE, 0x56, 0x30, 0xB2, + 0x3F, 0xCB, 0x11, 0x30, 0xAD, 0xC9, 0x7A, 0xA7, 0x28, 0xBB, 0xCF, 0x0C, + 0xCD, 0x55, 0x0F, 0x3A, 0x01, 0x40, 0x87, 0xFA, 0x9A, 0x0D, 0xE1, 0xD0, + 0xE5, 0xCD, 0xE7, 0x02, 0xCD, 0xF8, 0x13, 0x62, 0x6B, 0x0D, 0xF8, 0x09, + 0xCB, 0xFE, 0xC9, 0xCD, 0xE7, 0x02, 0xED, 0x4B, 0x04, 0x40, 0x0B, 0x60, + 0x69, 0x3E, 0x3F, 0x36, 0x02, 0x2B, 0xBC, 0x20, 0xFA, 0xA7, 0xED, 0x42, + 0x09, 0x23, 0x30, 0x06, 0x35, 0x28, 0x03, 0x35, 0x28, 0xF3, 0x22, 0x04, + 0x40, 0x2A, 0x04, 0x40, 0x2B, 0x36, 0x3E, 0x2B, 0xF9, 0x2B, 0x2B, 0x22, + 0x02, 0x40, 0x3E, 0x1E, 0xED, 0x47, 0xED, 0x56, 0xFD, 0x21, 0x00, 0x40, + 0xFD, 0x36, 0x3B, 0x40, 0x21, 0x7D, 0x40, 0x22, 0x0C, 0x40, 0x06, 0x19, + 0x36, 0x76, 0x23, 0x10, 0xFB, 0x22, 0x10, 0x40, 0xCD, 0x9A, 0x14, 0xCD, + 0xAD, 0x14, 0xCD, 0x07, 0x02, 0xCD, 0x2A, 0x0A, 0x2A, 0x0A, 0x40, 0xED, + 0x5B, 0x23, 0x40, 0xA7, 0xED, 0x52, 0xEB, 0x30, 0x04, 0x19, 0x22, 0x23, + 0x40, 0xCD, 0xD8, 0x09, 0x28, 0x01, 0xEB, 0xCD, 0x3E, 0x07, 0xFD, 0x35, + 0x1E, 0x20, 0x37, 0x2A, 0x0A, 0x40, 0xCD, 0xD8, 0x09, 0x2A, 0x16, 0x40, + 0x37, 0xED, 0x52, 0x21, 0x23, 0x40, 0x30, 0x0B, 0xEB, 0x7E, 0x23, 0xED, + 0xA0, 0x12, 0x18, 0xC5, 0x21, 0x0A, 0x40, 0x5E, 0x23, 0x56, 0xE5, 0xEB, + 0x23, 0xCD, 0xD8, 0x09, 0xCD, 0xBB, 0x05, 0xE1, 0xFD, 0xCB, 0x2D, 0x6E, + 0x20, 0x08, 0x72, 0x2B, 0x73, 0x18, 0xAA, 0xCD, 0xAD, 0x14, 0x2A, 0x14, + 0x40, 0x7E, 0xFE, 0x7E, 0x20, 0x08, 0x01, 0x06, 0x00, 0xCD, 0x60, 0x0A, + 0x18, 0xF3, 0xFE, 0x76, 0x23, 0x20, 0xEE, 0xCD, 0x37, 0x05, 0xCD, 0x1F, + 0x0A, 0x2A, 0x14, 0x40, 0xFD, 0x36, 0x00, 0xFF, 0xCD, 0x66, 0x07, 0xFD, + 0xCB, 0x00, 0x7E, 0x20, 0x24, 0x3A, 0x22, 0x40, 0xFE, 0x18, 0x30, 0x1D, + 0x3C, 0x32, 0x22, 0x40, 0x47, 0x0E, 0x01, 0xCD, 0x18, 0x09, 0x54, 0x5D, + 0x7E, 0x2B, 0xBE, 0x20, 0xFC, 0x23, 0xEB, 0x3A, 0x05, 0x40, 0xFE, 0x4D, + 0xDC, 0x5D, 0x0A, 0x18, 0xC9, 0x21, 0x00, 0x00, 0x22, 0x18, 0x40, 0x21, + 0x3B, 0x40, 0xCB, 0x7E, 0xCC, 0x29, 0x02, 0xCB, 0x46, 0x28, 0xFC, 0xED, + 0x4B, 0x25, 0x40, 0xCD, 0x4B, 0x0F, 0xCD, 0xBD, 0x07, 0x30, 0x93, 0x3A, + 0x06, 0x40, 0x3D, 0xFA, 0x08, 0x05, 0x20, 0x0F, 0x32, 0x06, 0x40, 0x1D, + 0x7B, 0xD6, 0x27, 0x38, 0x01, 0x5F, 0x21, 0xCC, 0x00, 0x18, 0x0E, 0x7E, + 0xFE, 0x76, 0x28, 0x2F, 0xFE, 0x40, 0xCB, 0xFF, 0x38, 0x19, 0x21, 0xC7, + 0x00, 0x19, 0x18, 0x0D, 0x7E, 0xFD, 0xCB, 0x01, 0x56, 0x20, 0x07, 0xC6, + 0xC0, 0xFE, 0xE6, 0x30, 0x01, 0x7E, 0xFE, 0xF0, 0xEA, 0x2D, 0x05, 0x5F, + 0xCD, 0x37, 0x05, 0x7B, 0xCD, 0x26, 0x05, 0xC3, 0x72, 0x04, 0xCD, 0x9B, + 0x09, 0x12, 0xC9, 0x3E, 0x78, 0x5F, 0x21, 0x82, 0x04, 0x19, 0x19, 0x4E, + 0x23, 0x46, 0xC5, 0x2A, 0x14, 0x40, 0xFD, 0xCB, 0x2D, 0x6E, 0x20, 0x16, + 0xFD, 0xCB, 0x01, 0x96, 0x7E, 0xFE, 0x7F, 0xC8, 0x23, 0xCD, 0xB4, 0x07, + 0x28, 0xF6, 0xFE, 0x26, 0x38, 0xF2, 0xFE, 0xDE, 0x28, 0xEA, 0xFD, 0xCB, + 0x01, 0xD6, 0x18, 0xE8, 0x01, 0x01, 0x00, 0xC3, 0x60, 0x0A, 0x9F, 0x05, + 0x54, 0x04, 0x76, 0x05, 0x7F, 0x05, 0xAF, 0x05, 0xC4, 0x05, 0x0C, 0x06, + 0x8B, 0x05, 0xAF, 0x05, 0xAF, 0x05, 0xCD, 0x93, 0x05, 0x7E, 0x36, 0x7F, + 0x23, 0x18, 0x09, 0x23, 0x7E, 0xFE, 0x76, 0x28, 0x18, 0x36, 0x7F, 0x2B, + 0x77, 0x18, 0x98, 0xCD, 0x93, 0x05, 0xCD, 0x5C, 0x05, 0x18, 0xF6, 0x2B, + 0xED, 0x5B, 0x14, 0x40, 0x1A, 0xFE, 0x7F, 0xC0, 0xD1, 0x18, 0xEA, 0x2A, + 0x0A, 0x40, 0xCD, 0xD8, 0x09, 0xEB, 0xCD, 0xBB, 0x05, 0x21, 0x0B, 0x40, + 0xC3, 0x64, 0x04, 0x7B, 0xE6, 0x07, 0x32, 0x06, 0x40, 0x18, 0xE6, 0xEB, + 0x11, 0xC2, 0x04, 0x7E, 0xE6, 0xC0, 0x20, 0xF7, 0x56, 0x23, 0x5E, 0xC9, + 0xCD, 0x1F, 0x0A, 0x21, 0x6F, 0x04, 0xE5, 0xFD, 0xCB, 0x2D, 0x6E, 0xC0, + 0x2A, 0x14, 0x40, 0x22, 0x0E, 0x40, 0x21, 0x21, 0x18, 0x22, 0x39, 0x40, + 0x2A, 0x0A, 0x40, 0xCD, 0xD8, 0x09, 0xCD, 0xBB, 0x05, 0x7A, 0xB3, 0xC8, + 0x2B, 0xCD, 0xA5, 0x0A, 0x23, 0x4E, 0x23, 0x46, 0x23, 0xED, 0x5B, 0x0E, + 0x40, 0x3E, 0x7F, 0x12, 0x13, 0xE5, 0x21, 0x1D, 0x00, 0x19, 0x09, 0xED, + 0x72, 0xE1, 0xD0, 0xED, 0xB0, 0xEB, 0xD1, 0xCD, 0xA6, 0x14, 0x18, 0x91, + 0xCD, 0x1F, 0x0A, 0x21, 0x72, 0x04, 0xFD, 0xCB, 0x2D, 0x6E, 0x20, 0x11, + 0x2A, 0x14, 0x40, 0x7E, 0xFE, 0xFF, 0x28, 0x06, 0xCD, 0xE2, 0x08, 0xCD, + 0x2A, 0x0A, 0x21, 0x19, 0x04, 0xE5, 0xCD, 0xBA, 0x0C, 0xE1, 0xCD, 0x37, + 0x05, 0xCD, 0x5C, 0x05, 0xCD, 0x73, 0x0A, 0x20, 0x15, 0x78, 0xB1, 0xC2, + 0xE0, 0x06, 0x0B, 0x0B, 0xED, 0x43, 0x07, 0x40, 0xFD, 0x36, 0x22, 0x02, + 0xED, 0x5B, 0x0C, 0x40, 0x18, 0x13, 0xFE, 0x76, 0x28, 0x12, 0xED, 0x4B, + 0x30, 0x40, 0xCD, 0x18, 0x09, 0xED, 0x5B, 0x29, 0x40, 0xFD, 0x36, 0x22, + 0x02, 0xDF, 0xFE, 0x76, 0xCA, 0x13, 0x04, 0xFD, 0x36, 0x01, 0x80, 0xEB, + 0x22, 0x29, 0x40, 0xEB, 0xCD, 0x4D, 0x00, 0xCD, 0xC1, 0x0C, 0xFD, 0xCB, + 0x01, 0x8E, 0x3E, 0xC0, 0xFD, 0x77, 0x19, 0xCD, 0xA3, 0x14, 0xFD, 0xCB, + 0x2D, 0xAE, 0xFD, 0xCB, 0x00, 0x7E, 0x28, 0x22, 0x2A, 0x29, 0x40, 0xA6, + 0x20, 0x1C, 0x56, 0x23, 0x5E, 0xED, 0x53, 0x07, 0x40, 0x23, 0x5E, 0x23, + 0x56, 0x23, 0xEB, 0x19, 0xCD, 0x46, 0x0F, 0x38, 0xC7, 0x21, 0x00, 0x40, + 0xCB, 0x7E, 0x28, 0x02, 0x36, 0x0C, 0xFD, 0xCB, 0x38, 0x7E, 0xCC, 0x71, + 0x08, 0x01, 0x21, 0x01, 0xCD, 0x18, 0x09, 0x3A, 0x00, 0x40, 0xED, 0x4B, + 0x07, 0x40, 0x3C, 0x28, 0x0C, 0xFE, 0x09, 0x20, 0x01, 0x03, 0xED, 0x43, + 0x2B, 0x40, 0x20, 0x01, 0x0B, 0xCD, 0xEB, 0x07, 0x3E, 0x18, 0xD7, 0xCD, + 0x98, 0x0A, 0xCD, 0xAD, 0x14, 0xC3, 0xC1, 0x04, 0xED, 0x43, 0x0A, 0x40, + 0x2A, 0x16, 0x40, 0xEB, 0x21, 0x13, 0x04, 0xE5, 0x2A, 0x1A, 0x40, 0xED, + 0x52, 0xE5, 0xC5, 0xCD, 0xE7, 0x02, 0xCD, 0x2A, 0x0A, 0xE1, 0xCD, 0xD8, + 0x09, 0x20, 0x06, 0xCD, 0xF2, 0x09, 0xCD, 0x60, 0x0A, 0xC1, 0x79, 0x3D, + 0xB0, 0xC8, 0xC5, 0x03, 0x03, 0x03, 0x03, 0x2B, 0xCD, 0x9E, 0x09, 0xCD, + 0x07, 0x02, 0xC1, 0xC5, 0x13, 0x2A, 0x1A, 0x40, 0x2B, 0xED, 0xB8, 0x2A, + 0x0A, 0x40, 0xEB, 0xC1, 0x70, 0x2B, 0x71, 0x2B, 0x73, 0x2B, 0x72, 0xC9, + 0xFD, 0xCB, 0x01, 0xCE, 0xCD, 0xA7, 0x0E, 0x78, 0xE6, 0x3F, 0x67, 0x69, + 0x22, 0x0A, 0x40, 0xCD, 0xD8, 0x09, 0x1E, 0x00, 0xCD, 0x45, 0x07, 0x18, + 0xFB, 0xED, 0x4B, 0x0A, 0x40, 0xCD, 0xEA, 0x09, 0x16, 0x92, 0x28, 0x05, + 0x11, 0x00, 0x00, 0xCB, 0x13, 0xFD, 0x73, 0x1E, 0x7E, 0xFE, 0x40, 0xC1, + 0xD0, 0xC5, 0xCD, 0xA5, 0x0A, 0x23, 0x7A, 0xD7, 0x23, 0x23, 0x22, 0x16, + 0x40, 0xFD, 0xCB, 0x01, 0xC6, 0xED, 0x4B, 0x18, 0x40, 0x2A, 0x16, 0x40, + 0xA7, 0xED, 0x42, 0x20, 0x03, 0x3E, 0xB8, 0xD7, 0x2A, 0x16, 0x40, 0x7E, + 0x23, 0xCD, 0xB4, 0x07, 0x22, 0x16, 0x40, 0x28, 0xE4, 0xFE, 0x7F, 0x28, + 0x10, 0xFE, 0x76, 0x28, 0x5D, 0xCB, 0x77, 0x28, 0x05, 0xCD, 0x4B, 0x09, + 0x18, 0xD3, 0xD7, 0x18, 0xD0, 0x3A, 0x06, 0x40, 0x06, 0xAB, 0xA7, 0x20, + 0x05, 0x3A, 0x01, 0x40, 0x06, 0xB0, 0x1F, 0x1F, 0xE6, 0x01, 0x80, 0xCD, + 0xF5, 0x07, 0x18, 0xB9, 0xFE, 0x7E, 0xC0, 0x23, 0x23, 0x23, 0x23, 0x23, + 0xC9, 0x16, 0x00, 0xCB, 0x28, 0x9F, 0xF6, 0x26, 0x2E, 0x05, 0x95, 0x85, + 0x37, 0xCB, 0x19, 0x38, 0xFA, 0x0C, 0xC0, 0x48, 0x2D, 0x2E, 0x01, 0x20, + 0xF2, 0x21, 0x7D, 0x00, 0x5F, 0x19, 0x37, 0xC9, 0x7B, 0xA7, 0xF8, 0x18, + 0x10, 0xAF, 0x09, 0x3C, 0x38, 0xFC, 0xED, 0x42, 0x3D, 0x28, 0xF1, 0x1E, + 0x1C, 0x83, 0xA7, 0x28, 0x04, 0xFD, 0xCB, 0x01, 0x86, 0xD9, 0xE5, 0xFD, + 0xCB, 0x01, 0x4E, 0x20, 0x05, 0xCD, 0x08, 0x08, 0x18, 0x03, 0xCD, 0x51, + 0x08, 0xE1, 0xD9, 0xC9, 0x57, 0xED, 0x4B, 0x39, 0x40, 0x79, 0xFE, 0x21, + 0x28, 0x1A, 0x3E, 0x76, 0xBA, 0x28, 0x30, 0x2A, 0x0E, 0x40, 0xBE, 0x7A, + 0x20, 0x20, 0x0D, 0x20, 0x19, 0x23, 0x22, 0x0E, 0x40, 0x0E, 0x21, 0x05, + 0xED, 0x43, 0x39, 0x40, 0x78, 0xFD, 0xBE, 0x22, 0x28, 0x03, 0xA7, 0x20, + 0xDD, 0x2E, 0x04, 0xC3, 0x58, 0x00, 0xCD, 0x9B, 0x09, 0xEB, 0x77, 0x23, + 0x22, 0x0E, 0x40, 0xFD, 0x35, 0x39, 0xC9, 0x0E, 0x21, 0x05, 0xFD, 0xCB, + 0x01, 0xC6, 0xC3, 0x18, 0x09, 0xFE, 0x76, 0x28, 0x1C, 0x4F, 0x3A, 0x38, + 0x40, 0xE6, 0x7F, 0xFE, 0x5C, 0x6F, 0x26, 0x40, 0xCC, 0x71, 0x08, 0x71, + 0x2C, 0xFD, 0x75, 0x38, 0xC9, 0x16, 0x16, 0x2A, 0x0C, 0x40, 0x23, 0x18, + 0x05, 0x16, 0x01, 0x21, 0x3C, 0x40, 0xCD, 0xE7, 0x02, 0xC5, 0xE5, 0xAF, + 0x5F, 0xD3, 0xFB, 0xE1, 0xCD, 0x46, 0x0F, 0x38, 0x05, 0x1F, 0xD3, 0xFB, + 0xCF, 0x0C, 0xDB, 0xFB, 0x87, 0xFA, 0xDE, 0x08, 0x30, 0xEE, 0xE5, 0xD5, + 0x7A, 0xFE, 0x02, 0x9F, 0xA3, 0x07, 0xA3, 0x57, 0x4E, 0x79, 0x23, 0xFE, + 0x76, 0x28, 0x24, 0xE5, 0xCB, 0x27, 0x87, 0x87, 0x26, 0x0F, 0xCB, 0x14, + 0x83, 0x6F, 0xCB, 0x11, 0x9F, 0xAE, 0x4F, 0x06, 0x08, 0x7A, 0xCB, 0x01, + 0x1F, 0x67, 0xDB, 0xFB, 0x1F, 0x30, 0xFB, 0x7C, 0xD3, 0xFB, 0x10, 0xF1, + 0xE1, 0x18, 0xD5, 0xDB, 0xFB, 0x1F, 0x30, 0xFB, 0x7A, 0x0F, 0xD3, 0xFB, + 0xD1, 0x1C, 0xCB, 0x5B, 0x28, 0xA7, 0xC1, 0x15, 0x20, 0xA0, 0x3E, 0x04, + 0xD3, 0xFB, 0xCD, 0x07, 0x02, 0xC1, 0x21, 0x5C, 0x40, 0x36, 0x76, 0x06, + 0x20, 0x2B, 0x36, 0x00, 0x10, 0xFB, 0x7D, 0xCB, 0xFF, 0x32, 0x38, 0x40, + 0xC9, 0x3E, 0x17, 0x90, 0x38, 0x0B, 0xFD, 0xBE, 0x22, 0xDA, 0x35, 0x08, + 0x3C, 0x47, 0x3E, 0x1F, 0x91, 0xDA, 0xAD, 0x0E, 0xC6, 0x02, 0x4F, 0xFD, + 0xCB, 0x01, 0x4E, 0x28, 0x07, 0x3E, 0x5D, 0x91, 0x32, 0x38, 0x40, 0xC9, + 0xED, 0x43, 0x39, 0x40, 0x2A, 0x10, 0x40, 0x51, 0x3E, 0x22, 0x91, 0x4F, + 0x3E, 0x76, 0x04, 0x2B, 0xBE, 0x20, 0xFC, 0x10, 0xFA, 0x23, 0xED, 0xB1, + 0x2B, 0x22, 0x0E, 0x40, 0x37, 0xE0, 0x15, 0xC8, 0xC5, 0xCD, 0x9E, 0x09, + 0xC1, 0x41, 0x62, 0x6B, 0x36, 0x00, 0x2B, 0x10, 0xFB, 0xEB, 0x23, 0x22, + 0x0E, 0x40, 0xC9, 0xF5, 0xCD, 0x75, 0x09, 0x30, 0x08, 0xFD, 0xCB, 0x01, + 0x46, 0x20, 0x02, 0xAF, 0xD7, 0x0A, 0xE6, 0x3F, 0xD7, 0x0A, 0x03, 0x87, + 0x30, 0xF7, 0xC1, 0xCB, 0x78, 0xC8, 0xFE, 0x1A, 0x28, 0x03, 0xFE, 0x38, + 0xD8, 0xAF, 0xFD, 0xCB, 0x01, 0xC6, 0xC3, 0xF5, 0x07, 0xE5, 0x21, 0x11, + 0x01, 0xCB, 0x7F, 0x28, 0x02, 0xE6, 0x3F, 0xFE, 0x43, 0x30, 0x10, 0x47, + 0x04, 0xCB, 0x7E, 0x23, 0x28, 0xFB, 0x10, 0xF9, 0xCB, 0x77, 0x20, 0x02, + 0xFE, 0x18, 0x3F, 0x44, 0x4D, 0xE1, 0xD0, 0x0A, 0xC6, 0xE4, 0xC9, 0x01, + 0x01, 0x00, 0xE5, 0xCD, 0xC5, 0x0E, 0xE1, 0xCD, 0xAD, 0x09, 0x2A, 0x1C, + 0x40, 0xEB, 0xED, 0xB8, 0xC9, 0xF5, 0xE5, 0x21, 0x0C, 0x40, 0x3E, 0x09, + 0x5E, 0x23, 0x56, 0xE3, 0xA7, 0xED, 0x52, 0x19, 0xE3, 0x30, 0x09, 0xD5, + 0xEB, 0x09, 0xEB, 0x72, 0x2B, 0x73, 0x23, 0xD1, 0x23, 0x3D, 0x20, 0xE8, + 0xEB, 0xD1, 0xF1, 0xA7, 0xED, 0x52, 0x44, 0x4D, 0x03, 0x19, 0xEB, 0xC9, + 0xE5, 0x21, 0x7D, 0x40, 0x54, 0x5D, 0xC1, 0xCD, 0xEA, 0x09, 0xD0, 0xC5, + 0xCD, 0xF2, 0x09, 0xEB, 0x18, 0xF4, 0x7E, 0xB8, 0xC0, 0x23, 0x7E, 0x2B, + 0xB9, 0xC9, 0xE5, 0x7E, 0xFE, 0x40, 0x38, 0x17, 0xCB, 0x6F, 0x28, 0x14, + 0x87, 0xFA, 0x01, 0x0A, 0x3F, 0x01, 0x05, 0x00, 0x30, 0x02, 0x0E, 0x11, + 0x17, 0x23, 0x7E, 0x30, 0xFB, 0x18, 0x06, 0x23, 0x23, 0x4E, 0x23, 0x46, + 0x23, 0x09, 0xD1, 0xA7, 0xED, 0x52, 0x44, 0x4D, 0x19, 0xEB, 0xC9, 0xFD, + 0x46, 0x22, 0xC5, 0xCD, 0x2C, 0x0A, 0xC1, 0x05, 0x18, 0x02, 0x06, 0x18, + 0xFD, 0xCB, 0x01, 0x8E, 0x0E, 0x21, 0xC5, 0xCD, 0x18, 0x09, 0xC1, 0x3A, + 0x05, 0x40, 0xFE, 0x4D, 0x38, 0x14, 0xFD, 0xCB, 0x3A, 0xFE, 0xAF, 0xCD, + 0xF5, 0x07, 0x2A, 0x39, 0x40, 0x7D, 0xB4, 0xE6, 0x7E, 0x20, 0xF3, 0xC3, + 0x18, 0x09, 0x54, 0x5D, 0x2B, 0x48, 0x06, 0x00, 0xED, 0xB0, 0x2A, 0x10, + 0x40, 0xCD, 0x17, 0x0A, 0xC5, 0x78, 0x2F, 0x47, 0x79, 0x2F, 0x4F, 0x03, + 0xCD, 0xAD, 0x09, 0xEB, 0xE1, 0x19, 0xD5, 0xED, 0xB0, 0xE1, 0xC9, 0x2A, + 0x14, 0x40, 0xCD, 0x4D, 0x00, 0xDF, 0xFD, 0xCB, 0x2D, 0x6E, 0xC0, 0x21, + 0x5D, 0x40, 0x22, 0x1C, 0x40, 0xCD, 0x48, 0x15, 0xCD, 0x8A, 0x15, 0x38, + 0x04, 0x21, 0xF0, 0xD8, 0x09, 0xDA, 0x9A, 0x0D, 0xBF, 0xC3, 0xBC, 0x14, + 0xD5, 0xE5, 0xAF, 0xCB, 0x78, 0x20, 0x20, 0x60, 0x69, 0x1E, 0xFF, 0x18, + 0x08, 0xD5, 0x56, 0x23, 0x5E, 0xE5, 0xEB, 0x1E, 0x00, 0x01, 0x18, 0xFC, + 0xCD, 0xE1, 0x07, 0x01, 0x9C, 0xFF, 0xCD, 0xE1, 0x07, 0x0E, 0xF6, 0xCD, + 0xE1, 0x07, 0x7D, 0xCD, 0xEB, 0x07, 0xE1, 0xD1, 0xC9, 0xCD, 0xA6, 0x0D, + 0xE1, 0xC8, 0xE9, 0xFD, 0xCB, 0x01, 0xCE, 0x7E, 0xFE, 0x76, 0xCA, 0x84, + 0x0B, 0xD6, 0x1A, 0xCE, 0x00, 0x28, 0x69, 0xFE, 0xA7, 0x20, 0x1B, 0xE7, + 0xCD, 0x92, 0x0D, 0xFE, 0x1A, 0xC2, 0x9A, 0x0D, 0xE7, 0xCD, 0x92, 0x0D, + 0xCD, 0x4E, 0x0B, 0xEF, 0x01, 0x34, 0xCD, 0xF5, 0x0B, 0xCD, 0xF5, 0x08, + 0x18, 0x3D, 0xFE, 0xA8, 0x20, 0x33, 0xE7, 0xCD, 0x92, 0x0D, 0xCD, 0x4E, + 0x0B, 0xCD, 0x02, 0x0C, 0xC2, 0xAD, 0x0E, 0xE6, 0x1F, 0x4F, 0xFD, 0xCB, + 0x01, 0x4E, 0x28, 0x0A, 0xFD, 0x96, 0x38, 0xCB, 0xFF, 0xC6, 0x3C, 0xD4, + 0x71, 0x08, 0xFD, 0x86, 0x39, 0xFE, 0x21, 0x3A, 0x3A, 0x40, 0xDE, 0x01, + 0xCD, 0xFA, 0x08, 0xFD, 0xCB, 0x01, 0xC6, 0x18, 0x06, 0xCD, 0x55, 0x0F, + 0xCD, 0x55, 0x0B, 0xDF, 0xD6, 0x1A, 0xCE, 0x00, 0x28, 0x06, 0xCD, 0x1D, + 0x0D, 0xC3, 0x84, 0x0B, 0xD4, 0x8B, 0x0B, 0xE7, 0xFE, 0x76, 0xC8, 0xC3, + 0xD5, 0x0A, 0xCD, 0xA6, 0x0D, 0xC0, 0xE1, 0x18, 0xE2, 0xCD, 0xC5, 0x0A, + 0xFD, 0xCB, 0x01, 0x76, 0xCC, 0xF8, 0x13, 0x28, 0x0A, 0xC3, 0xDB, 0x15, + 0x3E, 0x0B, 0xD7, 0xED, 0x5B, 0x18, 0x40, 0x78, 0xB1, 0x0B, 0xC8, 0x1A, + 0x13, 0xED, 0x53, 0x18, 0x40, 0xCB, 0x77, 0x28, 0xED, 0xFE, 0xC0, 0x28, + 0xE7, 0xC5, 0xCD, 0x4B, 0x09, 0xC1, 0x18, 0xE3, 0xCD, 0xC5, 0x0A, 0x3E, + 0x76, 0xD7, 0xC9, 0xCD, 0xC5, 0x0A, 0xFD, 0xCB, 0x01, 0xC6, 0xAF, 0xD7, + 0xED, 0x4B, 0x39, 0x40, 0x79, 0xFD, 0xCB, 0x01, 0x4E, 0x28, 0x05, 0x3E, + 0x5D, 0xFD, 0x96, 0x38, 0x0E, 0x11, 0xB9, 0x30, 0x02, 0x0E, 0x01, 0xCD, + 0x0B, 0x09, 0xC9, 0xCD, 0xF5, 0x0B, 0xED, 0x43, 0x36, 0x40, 0x3E, 0x2B, + 0x90, 0xDA, 0xAD, 0x0E, 0x47, 0x3E, 0x01, 0xCB, 0x28, 0x30, 0x02, 0x3E, + 0x04, 0xCB, 0x29, 0x30, 0x01, 0x07, 0xF5, 0xCD, 0xF5, 0x08, 0x7E, 0x07, + 0xFE, 0x10, 0x30, 0x06, 0x0F, 0x30, 0x02, 0xEE, 0x8F, 0x47, 0x11, 0x9E, + 0x0C, 0x3A, 0x30, 0x40, 0x93, 0xFA, 0xE9, 0x0B, 0xF1, 0x2F, 0xA0, 0x18, + 0x02, 0xF1, 0xB0, 0xFE, 0x08, 0x38, 0x02, 0xEE, 0x8F, 0xD9, 0xD7, 0xD9, + 0xC9, 0xCD, 0x02, 0x0C, 0x47, 0xC5, 0xCD, 0x02, 0x0C, 0x59, 0xC1, 0x51, + 0x4F, 0xC9, 0xCD, 0xCD, 0x15, 0xDA, 0xAD, 0x0E, 0x0E, 0x01, 0xC8, 0x0E, + 0xFF, 0xC9, 0xFD, 0x46, 0x22, 0x0E, 0x21, 0xCD, 0x18, 0x09, 0xCD, 0x9B, + 0x09, 0x7E, 0x12, 0xFD, 0x34, 0x3A, 0x2A, 0x0C, 0x40, 0x23, 0x54, 0x5D, + 0xED, 0xB1, 0xC3, 0x5D, 0x0A, 0x8B, 0x8D, 0x2D, 0x7F, 0x81, 0x49, 0x75, + 0x5F, 0x40, 0x42, 0x2B, 0x17, 0x1F, 0x37, 0x52, 0x45, 0x0F, 0x6D, 0x2B, + 0x44, 0x2D, 0x5A, 0x3B, 0x4C, 0x45, 0x0D, 0x52, 0x5A, 0x4D, 0x15, 0x6A, + 0x01, 0x14, 0x02, 0x06, 0x00, 0x81, 0x0E, 0x06, 0xDE, 0x05, 0xAB, 0x0D, + 0x06, 0x00, 0xB5, 0x0E, 0x00, 0xDC, 0x0C, 0x00, 0xD8, 0x0E, 0x04, 0x14, + 0x06, 0xDF, 0x06, 0x05, 0xB9, 0x0D, 0x04, 0x00, 0x2E, 0x0E, 0x05, 0xCF, + 0x0A, 0x01, 0x00, 0xE9, 0x0E, 0x05, 0x09, 0x14, 0x05, 0x6A, 0x0D, 0x00, + 0xC3, 0x03, 0x03, 0xAF, 0x0E, 0x03, 0x30, 0x07, 0x06, 0x1A, 0x06, 0x00, + 0x92, 0x0E, 0x03, 0x6C, 0x0E, 0x05, 0x40, 0x03, 0x05, 0xF6, 0x02, 0x00, + 0x7C, 0x0E, 0x00, 0x9A, 0x14, 0x00, 0x2A, 0x0A, 0x06, 0x1A, 0x06, 0x00, + 0xAF, 0x0B, 0x06, 0x1A, 0x06, 0x00, 0xAF, 0x0B, 0x00, 0x0E, 0x0C, 0x06, + 0x00, 0x32, 0x0F, 0x00, 0x2B, 0x0F, 0x00, 0x23, 0x0F, 0x00, 0x69, 0x08, + 0x05, 0xCB, 0x0A, 0x03, 0x2C, 0x07, 0xFD, 0x36, 0x01, 0x01, 0xCD, 0x73, + 0x0A, 0xCD, 0xBC, 0x14, 0x21, 0x00, 0x40, 0x36, 0xFF, 0x21, 0x2D, 0x40, + 0xCB, 0x6E, 0x28, 0x0E, 0xFE, 0xE3, 0x7E, 0xC2, 0x6F, 0x0D, 0xCD, 0xA6, + 0x0D, 0xC8, 0xCF, 0x0C, 0xCF, 0x08, 0xDF, 0x06, 0x00, 0xFE, 0x76, 0xC8, + 0x4F, 0xE7, 0x79, 0xD6, 0xE1, 0x38, 0x3B, 0x4F, 0x21, 0x29, 0x0C, 0x09, + 0x4E, 0x09, 0x18, 0x03, 0x2A, 0x30, 0x40, 0x7E, 0x23, 0x22, 0x30, 0x40, + 0x01, 0xF4, 0x0C, 0xC5, 0x4F, 0xFE, 0x0B, 0x30, 0x0B, 0x21, 0x16, 0x0D, + 0x06, 0x00, 0x09, 0x4E, 0x09, 0xE5, 0xDF, 0xC9, 0xDF, 0xB9, 0x20, 0x12, + 0xE7, 0xC9, 0x17, 0x25, 0x53, 0x0F, 0x6B, 0x13, 0x76, 0xCD, 0xA6, 0x0D, + 0xC0, 0xC1, 0x7E, 0xFE, 0x76, 0xC8, 0x18, 0x72, 0xFE, 0x76, 0xCD, 0x9C, + 0x0D, 0xBF, 0xC1, 0xCC, 0x1D, 0x0D, 0xEB, 0x2A, 0x30, 0x40, 0x4E, 0x23, + 0x46, 0xEB, 0xC5, 0xC9, 0xCD, 0x1C, 0x11, 0xFD, 0x36, 0x2D, 0x00, 0x30, + 0x08, 0xFD, 0xCB, 0x2D, 0xCE, 0x20, 0x18, 0xCF, 0x01, 0xCC, 0xA7, 0x11, + 0xFD, 0xCB, 0x01, 0x76, 0x20, 0x0D, 0xAF, 0xCD, 0xA6, 0x0D, 0xC4, 0xF8, + 0x13, 0x21, 0x2D, 0x40, 0xB6, 0x77, 0xEB, 0xED, 0x43, 0x2E, 0x40, 0x22, + 0x12, 0x40, 0xC9, 0xC1, 0x3A, 0x01, 0x40, 0xF5, 0xCD, 0x55, 0x0F, 0xF1, + 0x01, 0x21, 0x13, 0xFD, 0x56, 0x01, 0xAA, 0xE6, 0x40, 0x20, 0x1B, 0xCB, + 0x7A, 0x20, 0xB7, 0x18, 0x9D, 0xCD, 0x1C, 0x11, 0xF5, 0x79, 0xF6, 0x9F, + 0x3C, 0x20, 0x0B, 0xF1, 0x18, 0xAD, 0xCD, 0x55, 0x0F, 0xFD, 0xCB, 0x01, + 0x76, 0xC0, 0xCF, 0x0B, 0x20, 0xF4, 0xCD, 0xA6, 0x0D, 0xC8, 0xEF, 0xA0, + 0x34, 0xC9, 0xFD, 0xCB, 0x01, 0x7E, 0xC9, 0xCD, 0xA6, 0x0D, 0x28, 0x06, + 0xEF, 0x02, 0x34, 0x1A, 0xA7, 0xC8, 0xC3, 0xDE, 0x0C, 0xFE, 0xE0, 0x20, + 0x09, 0xE7, 0xCD, 0x92, 0x0D, 0xCD, 0x1D, 0x0D, 0x18, 0x06, 0xCD, 0x1D, + 0x0D, 0xEF, 0xA1, 0x34, 0xEF, 0xC0, 0x02, 0x01, 0xE0, 0x01, 0x34, 0xCD, + 0x21, 0x13, 0x22, 0x1F, 0x40, 0x2B, 0x7E, 0xCB, 0xFE, 0x01, 0x06, 0x00, + 0x09, 0x07, 0x38, 0x06, 0xCB, 0x21, 0xCD, 0x9E, 0x09, 0x23, 0xE5, 0xEF, + 0x02, 0x02, 0x34, 0xE1, 0xEB, 0x0E, 0x0A, 0xED, 0xB0, 0x2A, 0x07, 0x40, + 0xEB, 0x13, 0x73, 0x23, 0x72, 0xCD, 0x5A, 0x0E, 0xD0, 0xFD, 0xCB, 0x08, + 0x7E, 0xC0, 0xFD, 0x46, 0x2E, 0xCB, 0xB0, 0x2A, 0x29, 0x40, 0x7E, 0xE6, + 0xC0, 0x20, 0x17, 0xC5, 0xCD, 0xF2, 0x09, 0xC1, 0x23, 0x23, 0x23, 0xCD, + 0x4C, 0x00, 0xDF, 0xFE, 0xF3, 0xEB, 0x20, 0xEA, 0xEB, 0xE7, 0xEB, 0xB8, + 0x20, 0xE4, 0x22, 0x29, 0x40, 0xC9, 0xFD, 0xCB, 0x2D, 0x4E, 0xC2, 0x4B, + 0x0D, 0x2A, 0x12, 0x40, 0xCB, 0x7E, 0x28, 0x1C, 0x23, 0x22, 0x1F, 0x40, + 0xEF, 0xE0, 0xE2, 0x0F, 0xC0, 0x02, 0x34, 0xCD, 0x5A, 0x0E, 0xD8, 0x2A, + 0x1F, 0x40, 0x11, 0x0F, 0x00, 0x19, 0x5E, 0x23, 0x56, 0xEB, 0x18, 0x2E, + 0xCF, 0x00, 0xEF, 0xE1, 0xE0, 0xE2, 0x32, 0x00, 0x02, 0x01, 0x03, 0x33, + 0x00, 0x04, 0x34, 0xA7, 0xC9, 0x34, 0x37, 0xC9, 0xCD, 0xA7, 0x0E, 0x78, + 0xB1, 0x20, 0x04, 0xED, 0x4B, 0x34, 0x40, 0xED, 0x43, 0x32, 0x40, 0xC9, + 0x2A, 0x2B, 0x40, 0x18, 0x05, 0xCD, 0xA7, 0x0E, 0x60, 0x69, 0x7C, 0xFE, + 0xF0, 0x30, 0x22, 0xCD, 0xD8, 0x09, 0x22, 0x29, 0x40, 0xC9, 0xCD, 0xCD, + 0x15, 0x38, 0x16, 0x28, 0x02, 0xED, 0x44, 0xF5, 0xCD, 0xA7, 0x0E, 0xF1, + 0xFD, 0xCB, 0x00, 0x7E, 0xC8, 0x02, 0xC9, 0xCD, 0x8A, 0x15, 0x38, 0x01, + 0xC8, 0xCF, 0x0A, 0xCD, 0x81, 0x0E, 0xC3, 0x9A, 0x14, 0x2A, 0x07, 0x40, + 0x23, 0xE3, 0xE5, 0xED, 0x73, 0x02, 0x40, 0xCD, 0x81, 0x0E, 0x01, 0x06, + 0x00, 0x2A, 0x1C, 0x40, 0x09, 0x38, 0x08, 0xEB, 0x21, 0x24, 0x00, 0x19, + 0xED, 0x72, 0xD8, 0x2E, 0x03, 0xC3, 0x58, 0x00, 0xE1, 0xE3, 0x7C, 0xFE, + 0x3E, 0x28, 0x06, 0xED, 0x73, 0x02, 0x40, 0x18, 0xA1, 0xE3, 0xE5, 0xCF, + 0x06, 0xFD, 0xCB, 0x08, 0x7E, 0x20, 0x32, 0xCD, 0xA3, 0x14, 0x21, 0x2D, + 0x40, 0xCB, 0xEE, 0xCB, 0xB6, 0x3A, 0x01, 0x40, 0xE6, 0x40, 0x01, 0x02, + 0x00, 0x20, 0x02, 0x0E, 0x04, 0xB6, 0x77, 0xF7, 0x36, 0x76, 0x79, 0x0F, + 0x0F, 0x38, 0x05, 0x3E, 0x0B, 0x12, 0x2B, 0x77, 0x2B, 0x36, 0x7F, 0x2A, + 0x39, 0x40, 0x22, 0x30, 0x40, 0xE1, 0xC3, 0x72, 0x04, 0xCF, 0x07, 0xCD, + 0xE7, 0x02, 0xFD, 0xCB, 0x3B, 0xB6, 0xC9, 0xFD, 0xCB, 0x3B, 0xF6, 0xC3, + 0x07, 0x02, 0xCD, 0xA7, 0x0E, 0xCD, 0xE7, 0x02, 0x60, 0x69, 0xCD, 0x2D, + 0x02, 0xFD, 0x36, 0x35, 0xFF, 0xCD, 0x07, 0x02, 0x18, 0x05, 0x3E, 0x7F, + 0xDB, 0xFE, 0x1F, 0xFD, 0xCB, 0x3B, 0x86, 0x3E, 0xFF, 0x32, 0x27, 0x40, + 0xC9, 0xDF, 0x06, 0x00, 0xC5, 0xFE, 0x40, 0x20, 0x2F, 0xCD, 0xA6, 0x0D, + 0x28, 0x28, 0xED, 0x4B, 0x32, 0x40, 0xCD, 0x20, 0x15, 0xEF, 0xA1, 0x0F, + 0x30, 0x37, 0x16, 0x04, 0x30, 0x80, 0x41, 0x00, 0x00, 0x80, 0x2E, 0x02, + 0xA1, 0x03, 0x2D, 0x34, 0xCD, 0x8A, 0x15, 0xED, 0x43, 0x32, 0x40, 0x7E, + 0xA7, 0x28, 0x03, 0xD6, 0x10, 0x77, 0x18, 0x0D, 0xFE, 0x42, 0x20, 0x0D, + 0xCD, 0xA6, 0x0D, 0x28, 0x04, 0xEF, 0xA3, 0x34, 0x34, 0xE7, 0xC3, 0x83, + 0x10, 0xFE, 0x41, 0x20, 0x11, 0xCD, 0xBB, 0x02, 0x44, 0x4D, 0x51, 0x14, + 0xC4, 0xBD, 0x07, 0x7A, 0x8A, 0x42, 0x4F, 0xEB, 0x18, 0x3B, 0xCD, 0xD2, + 0x14, 0x38, 0x6E, 0xFE, 0x1B, 0xCA, 0x47, 0x10, 0x01, 0xD8, 0x09, 0xFE, + 0x16, 0x28, 0x5D, 0xFE, 0x10, 0x20, 0x0F, 0xCD, 0x49, 0x00, 0xCD, 0x55, + 0x0F, 0xFE, 0x11, 0x20, 0x2E, 0xCD, 0x49, 0x00, 0x18, 0x22, 0xFE, 0x0B, + 0x20, 0x28, 0xCD, 0x49, 0x00, 0xE5, 0x18, 0x03, 0xCD, 0x49, 0x00, 0xFE, + 0x0B, 0x20, 0x14, 0xD1, 0xA7, 0xED, 0x52, 0x44, 0x4D, 0x21, 0x01, 0x40, + 0xCB, 0xB6, 0xCB, 0x7E, 0xC4, 0xC3, 0x12, 0xE7, 0xC3, 0x88, 0x10, 0xFE, + 0x76, 0x20, 0xE1, 0xC3, 0x9A, 0x0D, 0xD6, 0xC4, 0x38, 0xF9, 0x01, 0xEC, + 0x04, 0xFE, 0x13, 0x28, 0x13, 0x30, 0xF0, 0x06, 0x10, 0xC6, 0xD9, 0x4F, + 0xFE, 0xDC, 0x30, 0x02, 0xCB, 0xB1, 0xFE, 0xEA, 0x38, 0x02, 0xCB, 0xB9, + 0xC5, 0xE7, 0xC3, 0x59, 0x0F, 0xFE, 0x26, 0x38, 0x1E, 0xCD, 0x1C, 0x11, + 0xDA, 0x4B, 0x0D, 0xCC, 0xA7, 0x11, 0x3A, 0x01, 0x40, 0xFE, 0xC0, 0x38, + 0x4E, 0x23, 0xED, 0x5B, 0x1C, 0x40, 0xCD, 0xF6, 0x19, 0xEB, 0x22, 0x1C, + 0x40, 0x18, 0x40, 0xCD, 0xA6, 0x0D, 0x20, 0x23, 0xCD, 0xD9, 0x14, 0xDF, + 0x01, 0x06, 0x00, 0xCD, 0x9E, 0x09, 0x23, 0x36, 0x7E, 0x23, 0xEB, 0x2A, + 0x1C, 0x40, 0x0E, 0x05, 0xA7, 0xED, 0x42, 0x22, 0x1C, 0x40, 0xED, 0xB0, + 0xEB, 0x2B, 0xCD, 0x4C, 0x00, 0x18, 0x14, 0xE7, 0xFE, 0x7E, 0x20, 0xFB, + 0x23, 0xED, 0x5B, 0x1C, 0x40, 0xCD, 0xF6, 0x19, 0xED, 0x53, 0x1C, 0x40, + 0x22, 0x16, 0x40, 0xFD, 0xCB, 0x01, 0xF6, 0xDF, 0xFE, 0x10, 0x20, 0x0C, + 0xFD, 0xCB, 0x01, 0x76, 0x20, 0x2A, 0xCD, 0x63, 0x12, 0xE7, 0x18, 0xF0, + 0x01, 0xC3, 0x00, 0xFE, 0x12, 0x38, 0x1D, 0xD6, 0x16, 0x30, 0x04, 0xC6, + 0x0D, 0x18, 0x0E, 0xFE, 0x03, 0x38, 0x0A, 0xD6, 0xC2, 0x38, 0x0D, 0xFE, + 0x06, 0x30, 0x09, 0xC6, 0x03, 0x81, 0x4F, 0x21, 0x4C, 0x10, 0x09, 0x46, + 0xD1, 0x7A, 0xB8, 0x38, 0x2C, 0xA7, 0xCA, 0x18, 0x00, 0xC5, 0xD5, 0xCD, + 0xA6, 0x0D, 0x28, 0x09, 0x7B, 0xE6, 0x3F, 0x47, 0xEF, 0x37, 0x34, 0x18, + 0x09, 0x7B, 0xFD, 0xAE, 0x01, 0xE6, 0x40, 0xC2, 0x9A, 0x0D, 0xD1, 0x21, + 0x01, 0x40, 0xCB, 0xF6, 0xCB, 0x7B, 0x20, 0x02, 0xCB, 0xB6, 0xC1, 0x18, + 0xCF, 0xD5, 0x79, 0xFD, 0xCB, 0x01, 0x76, 0x20, 0x15, 0xE6, 0x3F, 0xC6, + 0x08, 0x4F, 0xFE, 0x10, 0x20, 0x04, 0xCB, 0xF1, 0x18, 0x08, 0x38, 0xD7, + 0xFE, 0x17, 0x28, 0x02, 0xCB, 0xF9, 0xC5, 0xE7, 0xC3, 0x59, 0x0F, 0x06, + 0x08, 0x08, 0x0A, 0x02, 0x03, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, + 0xFD, 0xCB, 0x01, 0xF6, 0xDF, 0xCD, 0xCE, 0x14, 0xD2, 0x9A, 0x0D, 0xE5, + 0x4F, 0xE7, 0xE5, 0xCB, 0xA9, 0xFE, 0x10, 0x28, 0x17, 0xCB, 0xF1, 0xFE, + 0x0D, 0x28, 0x0C, 0xCB, 0xE9, 0xCD, 0xD2, 0x14, 0x30, 0x0A, 0xCB, 0xB1, + 0xE7, 0x18, 0xF6, 0xE7, 0xFD, 0xCB, 0x01, 0xB6, 0x41, 0xCD, 0xA6, 0x0D, + 0x20, 0x08, 0x79, 0xE6, 0xE0, 0xCB, 0xFF, 0x4F, 0x18, 0x34, 0x2A, 0x10, + 0x40, 0x7E, 0xE6, 0x7F, 0x28, 0x2A, 0xB9, 0x20, 0x1F, 0x17, 0x87, 0xF2, + 0x95, 0x11, 0x38, 0x2D, 0xD1, 0xD5, 0xE5, 0x23, 0x1A, 0x13, 0xA7, 0x28, + 0xFB, 0xBE, 0x28, 0xF7, 0xF6, 0x80, 0xBE, 0x20, 0x06, 0x1A, 0xCD, 0xD2, + 0x14, 0x30, 0x15, 0xE1, 0xC5, 0xCD, 0xF2, 0x09, 0xEB, 0xC1, 0x18, 0xD1, + 0xCB, 0xF8, 0xD1, 0xDF, 0xFE, 0x10, 0x28, 0x09, 0xCB, 0xE8, 0x18, 0x0D, + 0xD1, 0xD1, 0xD1, 0xE5, 0xDF, 0xCD, 0xD2, 0x14, 0x30, 0x03, 0xE7, 0x18, + 0xF8, 0xE1, 0xCB, 0x10, 0xCB, 0x70, 0xC9, 0xAF, 0x47, 0xCB, 0x79, 0x20, + 0x4B, 0xCB, 0x7E, 0x20, 0x0E, 0x3C, 0x23, 0x4E, 0x23, 0x46, 0x23, 0xEB, + 0xCD, 0xC3, 0x12, 0xDF, 0xC3, 0x5A, 0x12, 0x23, 0x23, 0x23, 0x46, 0xCB, + 0x71, 0x28, 0x0A, 0x05, 0x28, 0xE8, 0xEB, 0xDF, 0xFE, 0x10, 0x20, 0x61, + 0xEB, 0xEB, 0x18, 0x24, 0xE5, 0xDF, 0xE1, 0xFE, 0x1A, 0x28, 0x20, 0xCB, + 0x79, 0x28, 0x52, 0xCB, 0x71, 0x20, 0x06, 0xFE, 0x11, 0x20, 0x3C, 0xE7, + 0xC9, 0xFE, 0x11, 0x28, 0x6C, 0xFE, 0xDF, 0x20, 0x32, 0xDF, 0x2B, 0x22, + 0x16, 0x40, 0x18, 0x5E, 0x21, 0x00, 0x00, 0xE5, 0xE7, 0xE1, 0x79, 0xFE, + 0xC0, 0x20, 0x09, 0xDF, 0xFE, 0x11, 0x28, 0x51, 0xFE, 0xDF, 0x28, 0xE5, + 0xC5, 0xE5, 0xCD, 0xFF, 0x12, 0xE3, 0xEB, 0xCD, 0xDD, 0x12, 0x38, 0x19, + 0x0B, 0xCD, 0x05, 0x13, 0x09, 0xD1, 0xC1, 0x10, 0xB3, 0xCB, 0x79, 0x20, + 0x66, 0xE5, 0xCB, 0x71, 0x20, 0x13, 0x42, 0x4B, 0xDF, 0xFE, 0x11, 0x28, + 0x02, 0xCF, 0x02, 0xE7, 0xE1, 0x11, 0x05, 0x00, 0xCD, 0x05, 0x13, 0x09, + 0xC9, 0xCD, 0xFF, 0x12, 0xE3, 0xCD, 0x05, 0x13, 0xC1, 0x09, 0x23, 0x42, + 0x4B, 0xEB, 0xCD, 0xC2, 0x12, 0xDF, 0xFE, 0x11, 0x28, 0x07, 0xFE, 0x1A, + 0x20, 0xDB, 0xCD, 0x63, 0x12, 0xE7, 0xFE, 0x10, 0x28, 0xF8, 0xFD, 0xCB, + 0x01, 0xB6, 0xC9, 0xCD, 0xA6, 0x0D, 0xC4, 0xF8, 0x13, 0xE7, 0xFE, 0x11, + 0x28, 0x50, 0xD5, 0xAF, 0xF5, 0xC5, 0x11, 0x01, 0x00, 0xDF, 0xE1, 0xFE, + 0xDF, 0x28, 0x17, 0xF1, 0xCD, 0xDE, 0x12, 0xF5, 0x50, 0x59, 0xE5, 0xDF, + 0xE1, 0xFE, 0xDF, 0x28, 0x09, 0xFE, 0x11, 0xC2, 0x9A, 0x0D, 0x62, 0x6B, + 0x18, 0x13, 0xE5, 0xE7, 0xE1, 0xFE, 0x11, 0x28, 0x0C, 0xF1, 0xCD, 0xDE, + 0x12, 0xF5, 0xDF, 0x60, 0x69, 0xFE, 0x11, 0x20, 0xE6, 0xF1, 0xE3, 0x19, + 0x2B, 0xE3, 0xA7, 0xED, 0x52, 0x01, 0x00, 0x00, 0x38, 0x07, 0x23, 0xA7, + 0xFA, 0x31, 0x12, 0x44, 0x4D, 0xD1, 0xFD, 0xCB, 0x01, 0xB6, 0xCD, 0xA6, + 0x0D, 0xC8, 0xAF, 0xC5, 0xCD, 0xEB, 0x19, 0xC1, 0x2A, 0x1C, 0x40, 0x77, + 0x23, 0x73, 0x23, 0x72, 0x23, 0x71, 0x23, 0x70, 0x23, 0x22, 0x1C, 0x40, + 0xFD, 0xCB, 0x01, 0xB6, 0xC9, 0xAF, 0xD5, 0xE5, 0xF5, 0xCD, 0x92, 0x0D, + 0xF1, 0xCD, 0xA6, 0x0D, 0x28, 0x12, 0xF5, 0xCD, 0xA7, 0x0E, 0xD1, 0x78, + 0xB1, 0x37, 0x28, 0x05, 0xE1, 0xE5, 0xA7, 0xED, 0x42, 0x7A, 0xDE, 0x00, + 0xE1, 0xD1, 0xC9, 0xEB, 0x23, 0x5E, 0x23, 0x56, 0xC9, 0xCD, 0xA6, 0x0D, + 0xC8, 0xC5, 0x06, 0x10, 0x7C, 0x4D, 0x21, 0x00, 0x00, 0x29, 0x38, 0x06, + 0xCB, 0x11, 0x17, 0x30, 0x04, 0x19, 0xDA, 0xD3, 0x0E, 0x10, 0xF2, 0xC1, + 0xC9, 0x2A, 0x12, 0x40, 0xFD, 0xCB, 0x2D, 0x4E, 0x28, 0x44, 0x01, 0x05, + 0x00, 0x03, 0x23, 0x7E, 0xA7, 0x28, 0xFB, 0xCD, 0xD2, 0x14, 0x38, 0xF5, + 0xFE, 0x0D, 0xCA, 0xC8, 0x13, 0xF7, 0xD5, 0x2A, 0x12, 0x40, 0x1B, 0x79, + 0xD6, 0x06, 0x47, 0x3E, 0x40, 0x28, 0x0E, 0x23, 0x7E, 0xA7, 0x28, 0xFB, + 0x13, 0x12, 0x10, 0xF7, 0xF6, 0x80, 0x12, 0x3E, 0x80, 0x2A, 0x12, 0x40, + 0xAE, 0xE1, 0xCD, 0xE7, 0x13, 0xE5, 0xEF, 0x02, 0x34, 0xE1, 0x01, 0x05, + 0x00, 0xA7, 0xED, 0x42, 0x18, 0x40, 0xFD, 0xCB, 0x01, 0x76, 0x28, 0x06, + 0x11, 0x06, 0x00, 0x19, 0x18, 0xE7, 0x2A, 0x12, 0x40, 0xED, 0x4B, 0x2E, + 0x40, 0xFD, 0xCB, 0x2D, 0x46, 0x20, 0x30, 0x78, 0xB1, 0xC8, 0xE5, 0xF7, + 0xD5, 0xC5, 0x54, 0x5D, 0x23, 0x36, 0x00, 0xED, 0xB8, 0xE5, 0xCD, 0xF8, + 0x13, 0xE1, 0xE3, 0xA7, 0xED, 0x42, 0x09, 0x30, 0x02, 0x44, 0x4D, 0xE3, + 0xEB, 0x78, 0xB1, 0x28, 0x02, 0xED, 0xB0, 0xC1, 0xD1, 0xE1, 0xEB, 0x78, + 0xB1, 0xC8, 0xD5, 0xED, 0xB0, 0xE1, 0xC9, 0x2B, 0x2B, 0x2B, 0x7E, 0xE5, + 0xC5, 0xCD, 0xCE, 0x13, 0xC1, 0xE1, 0x03, 0x03, 0x03, 0xC3, 0x60, 0x0A, + 0x3E, 0x60, 0x2A, 0x12, 0x40, 0xAE, 0xF5, 0xCD, 0xF8, 0x13, 0xEB, 0x09, + 0xE5, 0x03, 0x03, 0x03, 0xF7, 0xEB, 0xE1, 0x0B, 0x0B, 0xC5, 0xED, 0xB8, + 0xEB, 0xC1, 0x0B, 0x70, 0x2B, 0x71, 0xF1, 0xF5, 0xCD, 0xC7, 0x14, 0xF1, + 0x2B, 0x77, 0x2A, 0x1A, 0x40, 0x22, 0x14, 0x40, 0x2B, 0x36, 0x80, 0xC9, + 0x2A, 0x1C, 0x40, 0x2B, 0x46, 0x2B, 0x4E, 0x2B, 0x56, 0x2B, 0x5E, 0x2B, + 0x7E, 0x22, 0x1C, 0x40, 0xC9, 0xCD, 0x1C, 0x11, 0xC2, 0x9A, 0x0D, 0xCD, + 0xA6, 0x0D, 0x20, 0x08, 0xCB, 0xB1, 0xCD, 0xA7, 0x11, 0xCD, 0x1D, 0x0D, + 0x38, 0x08, 0xC5, 0xCD, 0xF2, 0x09, 0xCD, 0x60, 0x0A, 0xC1, 0xCB, 0xF9, + 0x06, 0x00, 0xC5, 0x21, 0x01, 0x00, 0xCB, 0x71, 0x20, 0x02, 0x2E, 0x05, + 0xEB, 0xE7, 0x26, 0x40, 0xCD, 0xDD, 0x12, 0xDA, 0x31, 0x12, 0xE1, 0xC5, + 0x24, 0xE5, 0x60, 0x69, 0xCD, 0x05, 0x13, 0xEB, 0xDF, 0xFE, 0x1A, 0x28, + 0xE8, 0xFE, 0x11, 0x20, 0xBB, 0xE7, 0xC1, 0x79, 0x68, 0x26, 0x00, 0x23, + 0x23, 0x29, 0x19, 0xDA, 0xD3, 0x0E, 0xD5, 0xC5, 0xE5, 0x44, 0x4D, 0x2A, + 0x14, 0x40, 0x2B, 0xCD, 0x9E, 0x09, 0x23, 0x77, 0xC1, 0x0B, 0x0B, 0x0B, + 0x23, 0x71, 0x23, 0x70, 0xF1, 0x23, 0x77, 0x62, 0x6B, 0x1B, 0x36, 0x00, + 0xC1, 0xED, 0xB8, 0xC1, 0x70, 0x2B, 0x71, 0x2B, 0x3D, 0x20, 0xF8, 0xC9, + 0x2A, 0x1A, 0x40, 0x2B, 0xCD, 0x9E, 0x09, 0x23, 0x23, 0xC1, 0xED, 0x43, + 0x14, 0x40, 0xC1, 0xEB, 0x23, 0xC9, 0x2A, 0x10, 0x40, 0x36, 0x80, 0x23, + 0x22, 0x14, 0x40, 0x2A, 0x14, 0x40, 0x22, 0x1A, 0x40, 0x22, 0x1C, 0x40, + 0xC9, 0x2A, 0x14, 0x40, 0x36, 0x7F, 0x23, 0x36, 0x76, 0x23, 0xFD, 0x36, + 0x22, 0x02, 0x18, 0xEA, 0x21, 0x5D, 0x40, 0x22, 0x1F, 0x40, 0x2A, 0x1A, + 0x40, 0x18, 0xE2, 0xED, 0x5B, 0x14, 0x40, 0xC3, 0x5D, 0x0A, 0xFE, 0x26, + 0x18, 0x02, 0xFE, 0x1C, 0x3F, 0xD0, 0xFE, 0x40, 0xC9, 0xCD, 0x48, 0x15, + 0xFE, 0x1B, 0x20, 0x15, 0xEF, 0xA1, 0xC0, 0x02, 0x34, 0xE7, 0xCD, 0x14, + 0x15, 0x38, 0x0A, 0xEF, 0xE0, 0xA4, 0x05, 0xC0, 0x04, 0x0F, 0x34, 0x18, + 0xF0, 0xFE, 0x2A, 0xC0, 0xFD, 0x36, 0x5D, 0xFF, 0xE7, 0xFE, 0x15, 0x28, + 0x07, 0xFE, 0x16, 0x20, 0x04, 0xFD, 0x34, 0x5D, 0xE7, 0xCD, 0x48, 0x15, + 0xEF, 0xE0, 0x00, 0x02, 0x18, 0x38, 0x34, 0xC9, 0xFE, 0x1C, 0xD8, 0xFE, + 0x26, 0x3F, 0xD8, 0xD6, 0x1C, 0x4F, 0x06, 0x00, 0xFD, 0x21, 0x00, 0x40, + 0xC5, 0xEF, 0xA0, 0x34, 0xC1, 0x36, 0x91, 0x78, 0xA7, 0x20, 0x07, 0x77, + 0xB1, 0xC8, 0x41, 0x4E, 0x36, 0x89, 0x35, 0xCB, 0x21, 0xCB, 0x10, 0x30, + 0xF9, 0xCB, 0x38, 0xCB, 0x19, 0x23, 0x70, 0x23, 0x71, 0x2B, 0x2B, 0xC9, + 0xF5, 0xEF, 0xA0, 0x34, 0xF1, 0xCD, 0x14, 0x15, 0xD8, 0xEF, 0x01, 0xA4, + 0x04, 0x0F, 0x34, 0xE7, 0x18, 0xF3, 0xEF, 0x2D, 0x32, 0xC0, 0x02, 0x27, + 0xA1, 0x03, 0x2D, 0x32, 0x00, 0x22, 0x2D, 0x30, 0x33, 0x40, 0x03, 0x2D, + 0x32, 0x00, 0x0C, 0x01, 0x02, 0x01, 0x30, 0x80, 0x48, 0x18, 0x96, 0x80, + 0x2F, 0x04, 0x02, 0x01, 0xA4, 0xE0, 0x00, 0x04, 0x04, 0x2F, 0x02, 0x05, + 0x01, 0x2F, 0xDA, 0x02, 0x34, 0xC9, 0xCD, 0xF8, 0x13, 0xA7, 0x20, 0x05, + 0x47, 0x4F, 0xF5, 0x18, 0x31, 0x43, 0x59, 0x4A, 0xD6, 0x91, 0x3F, 0xCB, + 0x78, 0xF5, 0xCB, 0xF8, 0x38, 0x24, 0x3C, 0xED, 0x44, 0xFE, 0x08, 0x38, + 0x06, 0x59, 0x48, 0x06, 0x00, 0xD6, 0x08, 0xA7, 0x57, 0x7B, 0x07, 0x28, + 0x07, 0xCB, 0x38, 0xCB, 0x19, 0x15, 0x20, 0xF9, 0x30, 0x08, 0x03, 0x78, + 0xB1, 0x20, 0x03, 0xF1, 0x37, 0xF5, 0xC5, 0xEF, 0x34, 0xC1, 0xF1, 0x79, + 0xC9, 0xCD, 0x8A, 0x15, 0xD8, 0xF5, 0x05, 0x04, 0x28, 0x03, 0xF1, 0x37, + 0xC9, 0xF1, 0xC9, 0xEF, 0x2D, 0x32, 0x00, 0x0B, 0x2D, 0x33, 0x00, 0x0D, + 0x02, 0x34, 0x3E, 0x1C, 0xD7, 0xC9, 0x27, 0x34, 0x3E, 0x16, 0xD7, 0xEF, + 0x34, 0x7E, 0xCD, 0x1D, 0x15, 0xEF, 0x30, 0x78, 0x00, 0x80, 0x03, 0x30, + 0xEF, 0x1A, 0x20, 0x9A, 0x85, 0x04, 0x24, 0xC1, 0x30, 0x34, 0x00, 0x03, + 0x18, 0x38, 0xA2, 0x0F, 0x24, 0x34, 0x21, 0x6B, 0x40, 0x36, 0x90, 0x06, + 0x0A, 0x23, 0xE5, 0xC5, 0xEF, 0xA4, 0x2E, 0x01, 0x34, 0xCD, 0xCD, 0x15, + 0xF6, 0x90, 0xC1, 0xE1, 0x77, 0x10, 0xEE, 0x23, 0x01, 0x08, 0x00, 0xE5, + 0x2B, 0x7E, 0xFE, 0x90, 0x28, 0xFA, 0xED, 0x42, 0xE5, 0x7E, 0xC6, 0x6B, + 0xF5, 0xF1, 0x23, 0x7E, 0xCE, 0x00, 0x27, 0xF5, 0xE6, 0x0F, 0x77, 0xCB, + 0xFE, 0x28, 0xF2, 0xF1, 0xE1, 0x06, 0x06, 0x36, 0x80, 0x2B, 0x10, 0xFB, + 0xEF, 0x02, 0xE1, 0x34, 0xCD, 0xCD, 0x15, 0x28, 0x02, 0xED, 0x44, 0x5F, + 0x1C, 0x1C, 0xE1, 0x2B, 0x1D, 0x7E, 0xE6, 0x0F, 0x28, 0xF9, 0x7B, 0xD6, + 0x05, 0xFE, 0x08, 0xF2, 0x82, 0x16, 0xFE, 0xF6, 0xFA, 0x82, 0x16, 0xC6, + 0x06, 0x28, 0x48, 0xFA, 0xB2, 0x16, 0x47, 0xCD, 0xD0, 0x16, 0x10, 0xFB, + 0x18, 0x40, 0x43, 0xCD, 0xD0, 0x16, 0xCD, 0xC2, 0x16, 0x3E, 0x2A, 0xD7, + 0x78, 0xA7, 0xF2, 0x98, 0x16, 0xED, 0x44, 0x47, 0x3E, 0x16, 0x18, 0x02, + 0x3E, 0x15, 0xD7, 0x78, 0x06, 0xFF, 0x04, 0xD6, 0x0A, 0x30, 0xFB, 0xC6, + 0x0A, 0x4F, 0x78, 0xA7, 0x28, 0x03, 0xCD, 0xEB, 0x07, 0x79, 0xCD, 0xEB, + 0x07, 0xC9, 0xED, 0x44, 0x47, 0x3E, 0x1B, 0xD7, 0x3E, 0x1C, 0xD7, 0x10, + 0xFD, 0x18, 0x09, 0x3E, 0x1C, 0xD7, 0x35, 0x34, 0xE8, 0x3E, 0x1B, 0xD7, + 0x35, 0x34, 0xE8, 0xCD, 0xD0, 0x16, 0x18, 0xF8, 0x7E, 0xE6, 0x0F, 0xCD, + 0xEB, 0x07, 0x2B, 0xC9, 0x7E, 0x36, 0x00, 0xA7, 0xC8, 0x23, 0xCB, 0x7E, + 0xCB, 0xFE, 0x2B, 0xC8, 0xC5, 0x01, 0x05, 0x00, 0x09, 0x41, 0x4F, 0x37, + 0x2B, 0x7E, 0x2F, 0xCE, 0x00, 0x77, 0x10, 0xF8, 0x79, 0xC1, 0xC9, 0xE5, + 0xF5, 0x4E, 0x23, 0x46, 0x77, 0x23, 0x79, 0x4E, 0xC5, 0x23, 0x4E, 0x23, + 0x46, 0xEB, 0x57, 0x5E, 0xD5, 0x23, 0x56, 0x23, 0x5E, 0xD5, 0xD9, 0xD1, + 0xE1, 0xC1, 0xD9, 0x23, 0x56, 0x23, 0x5E, 0xF1, 0xE1, 0xC9, 0xA7, 0xC8, + 0xFE, 0x21, 0x30, 0x16, 0xC5, 0x47, 0xD9, 0xCB, 0x2D, 0xCB, 0x1A, 0xCB, + 0x1B, 0xD9, 0xCB, 0x1A, 0xCB, 0x1B, 0x10, 0xF2, 0xC1, 0xD0, 0xCD, 0x41, + 0x17, 0xC0, 0xD9, 0xAF, 0x2E, 0x00, 0x57, 0x5D, 0xD9, 0x11, 0x00, 0x00, + 0xC9, 0x1C, 0xC0, 0x14, 0xC0, 0xD9, 0x1C, 0x20, 0x01, 0x14, 0xD9, 0xC9, + 0x1A, 0xA7, 0xC8, 0x13, 0x1A, 0xEE, 0x80, 0x12, 0x1B, 0xD9, 0xE5, 0xD9, + 0xD5, 0xE5, 0xCD, 0xD8, 0x16, 0x47, 0xEB, 0xCD, 0xD8, 0x16, 0x4F, 0xB8, + 0x30, 0x03, 0x78, 0x41, 0xEB, 0xF5, 0x90, 0xCD, 0xF7, 0x16, 0xCD, 0x1A, + 0x17, 0xF1, 0xE1, 0x77, 0xE5, 0x68, 0x61, 0x19, 0xD9, 0xEB, 0xED, 0x4A, + 0xEB, 0x7C, 0x8D, 0x6F, 0x1F, 0xAD, 0xD9, 0xEB, 0xE1, 0x1F, 0x30, 0x08, + 0x3E, 0x01, 0xCD, 0x1A, 0x17, 0x34, 0x28, 0x23, 0xD9, 0x7D, 0xE6, 0x80, + 0xD9, 0x23, 0x77, 0x2B, 0x28, 0x1F, 0x7B, 0xED, 0x44, 0x3F, 0x5F, 0x7A, + 0x2F, 0xCE, 0x00, 0x57, 0xD9, 0x7B, 0x2F, 0xCE, 0x00, 0x5F, 0x7A, 0x2F, + 0xCE, 0x00, 0x30, 0x07, 0x1F, 0xD9, 0x34, 0xCA, 0x80, 0x18, 0xD9, 0x57, + 0xD9, 0xAF, 0x18, 0x6C, 0x37, 0x35, 0x34, 0xC8, 0x23, 0xAE, 0xCB, 0xFE, + 0x2B, 0xC9, 0xAF, 0xCD, 0xBC, 0x17, 0xD8, 0xD9, 0xE5, 0xD9, 0xD5, 0xEB, + 0xCD, 0xBC, 0x17, 0xEB, 0x38, 0x5A, 0xE5, 0xCD, 0xF7, 0x16, 0x78, 0xA7, + 0xED, 0x62, 0xD9, 0xE5, 0xED, 0x62, 0xD9, 0x06, 0x21, 0x18, 0x11, 0x30, + 0x05, 0x19, 0xD9, 0xED, 0x5A, 0xD9, 0xD9, 0xCB, 0x1C, 0xCB, 0x1D, 0xD9, + 0xCB, 0x1C, 0xCB, 0x1D, 0xD9, 0xCB, 0x18, 0xCB, 0x19, 0xD9, 0xCB, 0x19, + 0x1F, 0x10, 0xE4, 0xEB, 0xD9, 0xEB, 0xD9, 0xC1, 0xE1, 0x78, 0x81, 0x20, + 0x01, 0xA7, 0x3D, 0x3F, 0x17, 0x3F, 0x1F, 0xF2, 0x19, 0x18, 0x30, 0x68, + 0xA7, 0x3C, 0x20, 0x08, 0x38, 0x06, 0xD9, 0xCB, 0x7A, 0xD9, 0x20, 0x5C, + 0x77, 0xD9, 0x78, 0xD9, 0x30, 0x15, 0x7E, 0xA7, 0x3E, 0x80, 0x28, 0x01, + 0xAF, 0xD9, 0xA2, 0xCD, 0x38, 0x17, 0x07, 0x77, 0x38, 0x2E, 0x23, 0x77, + 0x2B, 0x18, 0x29, 0x06, 0x20, 0xD9, 0xCB, 0x7A, 0xD9, 0x20, 0x12, 0x07, + 0xCB, 0x13, 0xCB, 0x12, 0xD9, 0xCB, 0x13, 0xCB, 0x12, 0xD9, 0x35, 0x28, + 0xD7, 0x10, 0xEA, 0x18, 0xD7, 0x17, 0x30, 0x0C, 0xCD, 0x41, 0x17, 0x20, + 0x07, 0xD9, 0x16, 0x80, 0xD9, 0x34, 0x28, 0x18, 0xE5, 0x23, 0xD9, 0xD5, + 0xD9, 0xC1, 0x78, 0x17, 0xCB, 0x16, 0x1F, 0x77, 0x23, 0x71, 0x23, 0x72, + 0x23, 0x73, 0xE1, 0xD1, 0xD9, 0xE1, 0xD9, 0xC9, 0xCF, 0x05, 0xEB, 0xAF, + 0xCD, 0xBC, 0x17, 0x38, 0xF7, 0xEB, 0xCD, 0xBC, 0x17, 0xD8, 0xD9, 0xE5, + 0xD9, 0xD5, 0xE5, 0xCD, 0xF7, 0x16, 0xD9, 0xE5, 0x60, 0x69, 0xD9, 0x61, + 0x68, 0xAF, 0x06, 0xDF, 0x18, 0x10, 0x17, 0xCB, 0x11, 0xD9, 0xCB, 0x11, + 0xCB, 0x10, 0xD9, 0x29, 0xD9, 0xED, 0x6A, 0xD9, 0x38, 0x10, 0xED, 0x52, + 0xD9, 0xED, 0x52, 0xD9, 0x30, 0x0F, 0x19, 0xD9, 0xED, 0x5A, 0xD9, 0xA7, + 0x18, 0x08, 0xA7, 0xED, 0x52, 0xD9, 0xED, 0x52, 0xD9, 0x37, 0x04, 0xFA, + 0xA2, 0x18, 0xF5, 0x28, 0xE1, 0x5F, 0x51, 0xD9, 0x59, 0x50, 0xF1, 0xCB, + 0x18, 0xF1, 0xCB, 0x18, 0xD9, 0xC1, 0xE1, 0x78, 0x91, 0xC3, 0x10, 0x18, + 0x7E, 0xFE, 0x81, 0x30, 0x06, 0x36, 0x00, 0x3E, 0x20, 0x18, 0x05, 0xD6, + 0xA0, 0xF0, 0xED, 0x44, 0xD5, 0xEB, 0x2B, 0x47, 0xCB, 0x38, 0xCB, 0x38, + 0xCB, 0x38, 0x28, 0x05, 0x36, 0x00, 0x2B, 0x10, 0xFB, 0xE6, 0x07, 0x28, + 0x09, 0x47, 0x3E, 0xFF, 0xCB, 0x27, 0x10, 0xFC, 0xA6, 0x77, 0xEB, 0xD1, + 0xC9, 0x00, 0xB0, 0x00, 0x31, 0x00, 0x30, 0x00, 0xF1, 0x49, 0x0F, 0xDA, + 0xA2, 0x34, 0x20, 0x2F, 0x1C, 0x72, 0x1A, 0xE3, 0x19, 0x4C, 0x17, 0xC6, + 0x17, 0x82, 0x18, 0xE2, 0x1D, 0xED, 0x1A, 0xF3, 0x1A, 0x03, 0x1B, 0x03, + 0x1B, 0x03, 0x1B, 0x03, 0x1B, 0x03, 0x1B, 0x03, 0x1B, 0x55, 0x17, 0xF8, + 0x1A, 0x03, 0x1B, 0x03, 0x1B, 0x03, 0x1B, 0x03, 0x1B, 0x03, 0x1B, 0x03, + 0x1B, 0x62, 0x1B, 0xA0, 0x1A, 0x06, 0x1C, 0xA4, 0x1B, 0x11, 0x1C, 0x49, + 0x1D, 0x3E, 0x1D, 0x6E, 0x1D, 0xC4, 0x1D, 0xD4, 0x1D, 0x76, 0x1D, 0xA9, + 0x1C, 0x5B, 0x1C, 0x46, 0x1C, 0xDB, 0x1D, 0xAF, 0x1A, 0xAA, 0x1A, 0xBE, + 0x1A, 0xC5, 0x1A, 0xD5, 0x1B, 0x8F, 0x1B, 0xD5, 0x1A, 0xF6, 0x19, 0x37, + 0x1C, 0x23, 0x1C, 0xFC, 0x19, 0x17, 0x1C, 0xDB, 0x1A, 0xCE, 0x1A, 0x2B, + 0x00, 0x18, 0x1D, 0xE4, 0x18, 0xE4, 0x19, 0x5A, 0x15, 0x7F, 0x1A, 0x51, + 0x1A, 0x63, 0x1A, 0x45, 0x1A, 0xCD, 0x85, 0x1B, 0x78, 0x32, 0x1E, 0x40, + 0xD9, 0xE3, 0xD9, 0xED, 0x53, 0x1C, 0x40, 0xD9, 0x7E, 0x23, 0xE5, 0xA7, + 0xF2, 0xC2, 0x19, 0x57, 0xE6, 0x60, 0x0F, 0x0F, 0x0F, 0x0F, 0xC6, 0x72, + 0x6F, 0x7A, 0xE6, 0x1F, 0x18, 0x0E, 0xFE, 0x18, 0x30, 0x08, 0xD9, 0x01, + 0xFB, 0xFF, 0x54, 0x5D, 0x09, 0xD9, 0x07, 0x6F, 0x11, 0x23, 0x19, 0x26, + 0x00, 0x19, 0x5E, 0x23, 0x56, 0x21, 0xA7, 0x19, 0xE3, 0xD5, 0xD9, 0xED, + 0x4B, 0x1D, 0x40, 0xC9, 0xF1, 0x3A, 0x1E, 0x40, 0xD9, 0x18, 0xC3, 0xD5, + 0xE5, 0x01, 0x05, 0x00, 0xCD, 0xC5, 0x0E, 0xE1, 0xD1, 0xC9, 0xCD, 0xEB, + 0x19, 0xED, 0xB0, 0xC9, 0x62, 0x6B, 0xCD, 0xEB, 0x19, 0xD9, 0xE5, 0xD9, + 0xE3, 0xC5, 0x7E, 0xE6, 0xC0, 0x07, 0x07, 0x4F, 0x0C, 0x7E, 0xE6, 0x3F, + 0x20, 0x02, 0x23, 0x7E, 0xC6, 0x50, 0x12, 0x3E, 0x05, 0x91, 0x23, 0x13, + 0x06, 0x00, 0xED, 0xB0, 0xC1, 0xE3, 0xD9, 0xE1, 0xD9, 0x47, 0xAF, 0x05, + 0xC8, 0x12, 0x13, 0x18, 0xFA, 0xA7, 0xC8, 0xF5, 0xD5, 0x11, 0x00, 0x00, + 0xCD, 0xFE, 0x19, 0xD1, 0xF1, 0x3D, 0x18, 0xF2, 0x4F, 0x07, 0x07, 0x81, + 0x4F, 0x06, 0x00, 0x09, 0xC9, 0xD5, 0x2A, 0x1F, 0x40, 0xCD, 0x3C, 0x1A, + 0xCD, 0xF6, 0x19, 0xE1, 0xC9, 0x62, 0x6B, 0xD9, 0xE5, 0x21, 0x15, 0x19, + 0xD9, 0xCD, 0x2D, 0x1A, 0xCD, 0xFE, 0x19, 0xD9, 0xE1, 0xD9, 0xC9, 0xE5, + 0xEB, 0x2A, 0x1F, 0x40, 0xCD, 0x3C, 0x1A, 0xEB, 0xCD, 0xF6, 0x19, 0xEB, + 0xE1, 0xC9, 0x06, 0x05, 0x1A, 0x4E, 0xEB, 0x12, 0x71, 0x23, 0x13, 0x10, + 0xF7, 0xEB, 0xC9, 0x47, 0xCD, 0xA0, 0x19, 0x2D, 0x0F, 0xC0, 0x02, 0xA0, + 0xC2, 0x2D, 0xE0, 0x04, 0xE2, 0xC1, 0x03, 0x34, 0xCD, 0xFC, 0x19, 0xCD, + 0xA4, 0x19, 0x0F, 0x01, 0xC2, 0x02, 0x31, 0xEE, 0xE1, 0x03, 0x34, 0xC9, + 0x7E, 0xA7, 0xC8, 0x23, 0x7E, 0xEE, 0x80, 0x77, 0x2B, 0xC9, 0x23, 0xCB, + 0xBE, 0x2B, 0xC9, 0x23, 0x7E, 0x2B, 0x35, 0x34, 0x37, 0xC4, 0xE0, 0x1A, + 0x23, 0x07, 0xCB, 0x1E, 0x2B, 0xC9, 0xCD, 0xA7, 0x0E, 0x0A, 0xC3, 0x1D, + 0x15, 0xCD, 0xA7, 0x0E, 0x21, 0x20, 0x15, 0xE5, 0xC5, 0xC9, 0x7E, 0xA7, + 0xC8, 0x3E, 0xFF, 0x18, 0x07, 0x7E, 0xED, 0x44, 0x3F, 0x18, 0x05, 0xAF, + 0x23, 0xAE, 0x2B, 0x07, 0xE5, 0x06, 0x05, 0x36, 0x00, 0x23, 0x10, 0xFB, + 0xE1, 0xD0, 0x36, 0x81, 0xC9, 0x1A, 0xA7, 0xC8, 0x37, 0x18, 0xED, 0x1A, + 0xA7, 0xC0, 0x18, 0xE8, 0x1A, 0xA7, 0xC0, 0xD5, 0x1B, 0xAF, 0x12, 0x1B, + 0x12, 0xD1, 0xC9, 0x78, 0xD6, 0x08, 0xCB, 0x57, 0x20, 0x01, 0x3D, 0x0F, + 0x30, 0x08, 0xF5, 0xE5, 0xCD, 0x72, 0x1A, 0xD1, 0xEB, 0xF1, 0xCB, 0x57, + 0x20, 0x07, 0x0F, 0xF5, 0xCD, 0x4C, 0x17, 0x18, 0x33, 0x0F, 0xF5, 0xCD, + 0xF8, 0x13, 0xD5, 0xC5, 0xCD, 0xF8, 0x13, 0xE1, 0x7C, 0xB5, 0xE3, 0x78, + 0x20, 0x0B, 0xB1, 0xC1, 0x28, 0x04, 0xF1, 0x3F, 0x18, 0x16, 0xF1, 0x18, + 0x13, 0xB1, 0x28, 0x0D, 0x1A, 0x96, 0x38, 0x09, 0x20, 0xED, 0x0B, 0x13, + 0x23, 0xE3, 0x2B, 0x18, 0xDF, 0xC1, 0xF1, 0xA7, 0xF5, 0xEF, 0xA0, 0x34, + 0xF1, 0xF5, 0xDC, 0xD5, 0x1A, 0xCD, 0xCE, 0x1A, 0xF1, 0x0F, 0xD4, 0xD5, + 0x1A, 0xC9, 0xCD, 0xF8, 0x13, 0xD5, 0xC5, 0xCD, 0xF8, 0x13, 0xE1, 0xE5, + 0xD5, 0xC5, 0x09, 0x44, 0x4D, 0xF7, 0xCD, 0xC3, 0x12, 0xC1, 0xE1, 0x78, + 0xB1, 0x28, 0x02, 0xED, 0xB0, 0xC1, 0xE1, 0x78, 0xB1, 0x28, 0x02, 0xED, + 0xB0, 0x2A, 0x1C, 0x40, 0x11, 0xFB, 0xFF, 0xE5, 0x19, 0xD1, 0xC9, 0xCD, + 0xCD, 0x15, 0x38, 0x0E, 0x20, 0x0C, 0xF5, 0x01, 0x01, 0x00, 0xF7, 0xF1, + 0x12, 0xCD, 0xC3, 0x12, 0xEB, 0xC9, 0xCF, 0x0A, 0x2A, 0x16, 0x40, 0xE5, + 0xCD, 0xF8, 0x13, 0xD5, 0x03, 0xF7, 0xE1, 0xED, 0x53, 0x16, 0x40, 0xD5, + 0xED, 0xB0, 0xEB, 0x2B, 0x36, 0x76, 0xFD, 0xCB, 0x01, 0xBE, 0xCD, 0x92, + 0x0D, 0xCD, 0x22, 0x0D, 0xE1, 0x22, 0x16, 0x40, 0xFD, 0xCB, 0x01, 0xFE, + 0xCD, 0x55, 0x0F, 0xE1, 0x22, 0x16, 0x40, 0x18, 0xB0, 0x01, 0x01, 0x00, + 0xF7, 0x36, 0x76, 0x2A, 0x39, 0x40, 0xE5, 0x2E, 0xFF, 0x22, 0x39, 0x40, + 0x2A, 0x0E, 0x40, 0xE5, 0xED, 0x53, 0x0E, 0x40, 0xD5, 0xCD, 0xDB, 0x15, + 0xD1, 0x2A, 0x0E, 0x40, 0xA7, 0xED, 0x52, 0x44, 0x4D, 0xE1, 0x22, 0x0E, + 0x40, 0xE1, 0x22, 0x39, 0x40, 0xCD, 0xC3, 0x12, 0xEB, 0xC9, 0xCD, 0xF8, + 0x13, 0x78, 0xB1, 0x28, 0x01, 0x1A, 0xC3, 0x1D, 0x15, 0xCD, 0xF8, 0x13, + 0xC3, 0x20, 0x15, 0xD9, 0xE5, 0x21, 0x1E, 0x40, 0x35, 0xE1, 0x20, 0x04, + 0x23, 0xD9, 0xC9, 0xD9, 0x5E, 0xAF, 0xCB, 0x7B, 0x28, 0x01, 0x2F, 0x57, + 0x19, 0xD9, 0xC9, 0x1A, 0xA7, 0x20, 0xF0, 0xD9, 0x23, 0xD9, 0xC9, 0xEF, + 0xC0, 0x02, 0x2D, 0xE0, 0x05, 0x24, 0xE0, 0x01, 0xC0, 0x04, 0x03, 0xE0, + 0x34, 0xC9, 0xEF, 0x2D, 0x32, 0x00, 0x04, 0x36, 0x34, 0xC9, 0x2D, 0x36, + 0xC0, 0x03, 0xE0, 0x01, 0x2C, 0x00, 0x03, 0xA1, 0x03, 0x34, 0xC9, 0xEF, + 0x30, 0xF1, 0x38, 0xAA, 0x3B, 0x29, 0x04, 0x2D, 0x24, 0xC3, 0x03, 0x2D, + 0x0F, 0xA1, 0x03, 0x88, 0x13, 0x36, 0x58, 0x65, 0x66, 0x9D, 0x78, 0x65, + 0x40, 0xA2, 0x60, 0x32, 0xC9, 0xE7, 0x21, 0xF7, 0xAF, 0x24, 0xEB, 0x2F, + 0xB0, 0xB0, 0x14, 0xEE, 0x7E, 0xBB, 0x94, 0x58, 0xF1, 0x3A, 0x7E, 0xF8, + 0xCF, 0xE3, 0x34, 0xCD, 0xCD, 0x15, 0x20, 0x07, 0x38, 0x03, 0x86, 0x30, + 0x09, 0xCF, 0x05, 0x38, 0x07, 0x96, 0x30, 0x04, 0xED, 0x44, 0x77, 0xC9, + 0xEF, 0x02, 0xA0, 0x34, 0xC9, 0xEF, 0x2D, 0x33, 0x00, 0x04, 0x34, 0xCF, + 0x09, 0xA0, 0x02, 0x34, 0x7E, 0x36, 0x80, 0xCD, 0x1D, 0x15, 0xEF, 0x30, + 0x38, 0x00, 0x03, 0x01, 0x2D, 0x30, 0xF0, 0x4C, 0xCC, 0xCC, 0xCD, 0x03, + 0x33, 0x00, 0x08, 0x01, 0xA1, 0x03, 0x01, 0x34, 0x34, 0xEF, 0x01, 0x30, + 0xF0, 0x31, 0x72, 0x17, 0xF8, 0x04, 0x01, 0xA2, 0x03, 0xA2, 0x03, 0x2D, + 0x30, 0x32, 0x20, 0x04, 0xA2, 0x03, 0x8C, 0x11, 0xAC, 0x14, 0x09, 0x56, + 0xDA, 0xA5, 0x59, 0x30, 0xC5, 0x5C, 0x90, 0xAA, 0x9E, 0x70, 0x6F, 0x61, + 0xA1, 0xCB, 0xDA, 0x96, 0xA4, 0x31, 0x9F, 0xB4, 0xE7, 0xA0, 0xFE, 0x5C, + 0xFC, 0xEA, 0x1B, 0x43, 0xCA, 0x36, 0xED, 0xA7, 0x9C, 0x7E, 0x5E, 0xF0, + 0x6E, 0x23, 0x80, 0x93, 0x04, 0x0F, 0x34, 0xC9, 0xEF, 0x30, 0xEE, 0x22, + 0xF9, 0x83, 0x6E, 0x04, 0x2D, 0xA2, 0x0F, 0x24, 0x03, 0x2D, 0x0F, 0x2D, + 0x0F, 0x2D, 0x27, 0xA1, 0x03, 0x2D, 0x33, 0xC0, 0x00, 0x04, 0x02, 0x34, + 0xC9, 0xA1, 0x03, 0x01, 0x32, 0x00, 0x02, 0x18, 0x34, 0xC9, 0xEF, 0x35, + 0x27, 0xA1, 0x03, 0xE0, 0x00, 0x06, 0x18, 0x2F, 0x03, 0xEF, 0x35, 0x2D, + 0x2D, 0x04, 0x2D, 0x0F, 0xA1, 0x03, 0x86, 0x14, 0xE6, 0x5C, 0x1F, 0x0B, + 0xA3, 0x8F, 0x38, 0xEE, 0xE9, 0x15, 0x63, 0xBB, 0x23, 0xEE, 0x92, 0x0D, + 0xCD, 0xED, 0xF1, 0x23, 0x5D, 0x1B, 0xEA, 0x04, 0x34, 0xC9, 0xEF, 0x2D, + 0x1C, 0x01, 0x1D, 0x05, 0x34, 0xC9, 0x7E, 0xFE, 0x81, 0x38, 0x0E, 0xEF, + 0xA1, 0x18, 0x01, 0x05, 0x2D, 0x32, 0xA3, 0x01, 0x00, 0x06, 0x18, 0x2F, + 0x03, 0xEF, 0xA0, 0x01, 0x2D, 0x2D, 0x04, 0x2D, 0x0F, 0xA1, 0x03, 0x8C, + 0x10, 0xB2, 0x13, 0x0E, 0x55, 0xE4, 0x8D, 0x58, 0x39, 0xBC, 0x5B, 0x98, + 0xFD, 0x9E, 0x00, 0x36, 0x75, 0xA0, 0xDB, 0xE8, 0xB4, 0x63, 0x42, 0xC4, + 0xE6, 0xB5, 0x09, 0x36, 0xBE, 0xE9, 0x36, 0x73, 0x1B, 0x5D, 0xEC, 0xD8, + 0xDE, 0x63, 0xBE, 0xF0, 0x61, 0xA1, 0xB3, 0x0C, 0x04, 0x0F, 0x34, 0xC9, + 0xEF, 0x2D, 0x2D, 0x04, 0xA1, 0x03, 0x18, 0x25, 0xA1, 0x0F, 0x05, 0x21, + 0x2D, 0x0F, 0x34, 0xC9, 0xEF, 0x1F, 0xA3, 0x03, 0x18, 0x34, 0xC9, 0xEF, + 0x2D, 0x2C, 0x00, 0x1E, 0xA2, 0x34, 0xEF, 0x01, 0x2D, 0x2C, 0x00, 0x07, + 0x22, 0x04, 0x34, 0xC3, 0x5B, 0x1C, 0x02, 0x2D, 0x2C, 0x00, 0x09, 0xA0, + 0x01, 0x33, 0x00, 0x06, 0xA1, 0x01, 0x05, 0x02, 0xA1, 0x34, 0xC9, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, + 0x00, 0x00, 0x00, 0x00, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1C, 0x22, 0x78, 0x20, 0x20, 0x7E, 0x00, 0x00, 0x08, 0x3E, 0x28, + 0x3E, 0x0A, 0x3E, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x3C, 0x42, 0x04, 0x08, 0x00, 0x08, 0x00, 0x00, 0x04, 0x08, 0x08, + 0x08, 0x08, 0x04, 0x00, 0x00, 0x20, 0x10, 0x10, 0x10, 0x10, 0x20, 0x00, + 0x00, 0x00, 0x10, 0x08, 0x04, 0x08, 0x10, 0x00, 0x00, 0x00, 0x04, 0x08, + 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, 0x00, + 0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x3C, 0x46, 0x4A, + 0x52, 0x62, 0x3C, 0x00, 0x00, 0x18, 0x28, 0x08, 0x08, 0x08, 0x3E, 0x00, + 0x00, 0x3C, 0x42, 0x02, 0x3C, 0x40, 0x7E, 0x00, 0x00, 0x3C, 0x42, 0x0C, + 0x02, 0x42, 0x3C, 0x00, 0x00, 0x08, 0x18, 0x28, 0x48, 0x7E, 0x08, 0x00, + 0x00, 0x7E, 0x40, 0x7C, 0x02, 0x42, 0x3C, 0x00, 0x00, 0x3C, 0x40, 0x7C, + 0x42, 0x42, 0x3C, 0x00, 0x00, 0x7E, 0x02, 0x04, 0x08, 0x10, 0x10, 0x00, + 0x00, 0x3C, 0x42, 0x3C, 0x42, 0x42, 0x3C, 0x00, 0x00, 0x3C, 0x42, 0x42, + 0x3E, 0x02, 0x3C, 0x00, 0x00, 0x3C, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x00, + 0x00, 0x7C, 0x42, 0x7C, 0x42, 0x42, 0x7C, 0x00, 0x00, 0x3C, 0x42, 0x40, + 0x40, 0x42, 0x3C, 0x00, 0x00, 0x78, 0x44, 0x42, 0x42, 0x44, 0x78, 0x00, + 0x00, 0x7E, 0x40, 0x7C, 0x40, 0x40, 0x7E, 0x00, 0x00, 0x7E, 0x40, 0x7C, + 0x40, 0x40, 0x40, 0x00, 0x00, 0x3C, 0x42, 0x40, 0x4E, 0x42, 0x3C, 0x00, + 0x00, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00, 0x00, 0x3E, 0x08, 0x08, + 0x08, 0x08, 0x3E, 0x00, 0x00, 0x02, 0x02, 0x02, 0x42, 0x42, 0x3C, 0x00, + 0x00, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x00, 0x00, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x7E, 0x00, 0x00, 0x42, 0x66, 0x5A, 0x42, 0x42, 0x42, 0x00, + 0x00, 0x42, 0x62, 0x52, 0x4A, 0x46, 0x42, 0x00, 0x00, 0x3C, 0x42, 0x42, + 0x42, 0x42, 0x3C, 0x00, 0x00, 0x7C, 0x42, 0x42, 0x7C, 0x40, 0x40, 0x00, + 0x00, 0x3C, 0x42, 0x42, 0x52, 0x4A, 0x3C, 0x00, 0x00, 0x7C, 0x42, 0x42, + 0x7C, 0x44, 0x42, 0x00, 0x00, 0x3C, 0x40, 0x3C, 0x02, 0x42, 0x3C, 0x00, + 0x00, 0xFE, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x3C, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00, + 0x00, 0x42, 0x42, 0x42, 0x42, 0x5A, 0x24, 0x00, 0x00, 0x42, 0x24, 0x18, + 0x18, 0x24, 0x42, 0x00, 0x00, 0x82, 0x44, 0x28, 0x10, 0x10, 0x10, 0x00, + 0x00, 0x7E, 0x04, 0x08, 0x10, 0x20, 0x7E, 0x00 +}; +#endif diff --git a/src/ESPectrum.cpp b/src/ESPectrum.cpp index 30693690..83820bc6 100644 --- a/src/ESPectrum.cpp +++ b/src/ESPectrum.cpp @@ -92,6 +92,7 @@ int ESPectrum::samplesPerFrame = ESP_AUDIO_SAMPLES_48; int ESPectrum::overSamplesPerFrame = ESP_AUDIO_OVERSAMPLES_48; bool ESPectrum::AY_emu = false; int ESPectrum::Audio_freq = ESP_AUDIO_FREQ_48; +int ESPectrum::TapeNameScroller = 0; // bool ESPectrum::Audio_restart = false; QueueHandle_t audioTaskQueue; @@ -215,8 +216,6 @@ std::string ESPectrum::bootKeyboard() { fabgl::VirtualKeyItem NextKey; bool r = false; - // #ifdef ZXKEYB - if (ZXKeyb::Exists) { // Process physical keyboard @@ -250,217 +249,24 @@ std::string ESPectrum::bootKeyboard() { } - // #endif + string kbdstr=""; while (Kbd->virtualKeyAvailable()) { r = Kbd->getNextVirtualKey(&NextKey); if (r) { - // Check keyboard status - if (PS2Controller.keyboard()->isVKDown(fabgl::VK_1)) return "1"; - if (PS2Controller.keyboard()->isVKDown(fabgl::VK_2)) return "2"; - if (PS2Controller.keyboard()->isVKDown(fabgl::VK_3)) return "3"; - if (PS2Controller.keyboard()->isVKDown(fabgl::VK_Q) || PS2Controller.keyboard()->isVKDown(fabgl::VK_q)) return "Q"; - if (PS2Controller.keyboard()->isVKDown(fabgl::VK_W) || PS2Controller.keyboard()->isVKDown(fabgl::VK_w)) return "W"; + // // Check keyboard status + if (PS2Controller.keyboard()->isVKDown(fabgl::VK_1)) kbdstr += "1"; + if (PS2Controller.keyboard()->isVKDown(fabgl::VK_2)) kbdstr += "2"; + if (PS2Controller.keyboard()->isVKDown(fabgl::VK_3)) kbdstr += "3"; + if (PS2Controller.keyboard()->isVKDown(fabgl::VK_Q) || PS2Controller.keyboard()->isVKDown(fabgl::VK_q)) kbdstr += "Q"; + if (PS2Controller.keyboard()->isVKDown(fabgl::VK_W) || PS2Controller.keyboard()->isVKDown(fabgl::VK_w)) kbdstr += "W"; } } - return ""; + return kbdstr; } -// void ESPectrum::bootKeyboard() { - -// std::string b = "00"; - -// #ifdef ZXKEYB -// if (ZXKeyb::Exists) { // START - ZXKeyb Exists - -// // Process physical keyboard -// ZXKeyb::process(); -// // Detect and process physical kbd menu key combinations - -// if (!bitRead(ZXKeyb::ZXcols[3], 0)) { // 1 -// if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q -// b = "1Q"; -// } else -// if (!bitRead(ZXKeyb::ZXcols[2], 1)) { // W -// b = "1W"; -// } -// } else -// if (!bitRead(ZXKeyb::ZXcols[3], 1)) { // 2 -// if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q -// b = "2Q"; -// } else -// if (!bitRead(ZXKeyb::ZXcols[2], 1)) { // W -// b = "2W"; -// } -// } else -// if (!bitRead(ZXKeyb::ZXcols[3], 2)) { // 3 -// if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q -// b = "3Q"; -// } else -// if (!bitRead(ZXKeyb::ZXcols[2], 1)) { // W -// b = "3W"; -// } -// } - -// } // END - ZXKeyb Exists -// #endif - -// //PS2Controller.keyboard()->reset(); - -// if ((PS2Controller.keyboard()->isVKDown(fabgl::VK_q) && PS2Controller.keyboard()->isVKDown(fabgl::VK_1)) || (b == "1Q")) { -// b = "1Q"; -// Config::aspect_16_9=false; -// Config::videomode=0; -// } else -// if ((PS2Controller.keyboard()->isVKDown(fabgl::VK_w) && PS2Controller.keyboard()->isVKDown(fabgl::VK_1)) || (b == "1W")) { -// b = "1W"; -// Config::aspect_16_9=true; -// Config::videomode=0; -// } else -// if ((PS2Controller.keyboard()->isVKDown(fabgl::VK_q) && PS2Controller.keyboard()->isVKDown(fabgl::VK_2)) || (b == "2Q")) { -// b = "2Q"; -// Config::aspect_16_9=false; -// Config::videomode=1; -// } else -// if ((PS2Controller.keyboard()->isVKDown(fabgl::VK_w) && PS2Controller.keyboard()->isVKDown(fabgl::VK_2)) || (b == "2W")) { -// b = "2W"; -// Config::aspect_16_9=true; -// Config::videomode=1; -// } else -// if ((PS2Controller.keyboard()->isVKDown(fabgl::VK_q) && PS2Controller.keyboard()->isVKDown(fabgl::VK_3)) || (b == "3Q")) { -// b = "3Q"; -// Config::aspect_16_9=false; -// Config::videomode=2; -// } else -// if ((PS2Controller.keyboard()->isVKDown(fabgl::VK_w) && PS2Controller.keyboard()->isVKDown(fabgl::VK_3)) || (b == "3W")) { -// b = "3W"; -// Config::aspect_16_9=true; -// Config::videomode=2; -// } - -// if (b != "00") { -// Config::ram_file="none"; -// Config::save(); -// printf("%s\n", b.c_str()); -// } - -// //return b; - - - -// /* -// std:string b = "00"; -// std::string s; -// for (int i=0; i<2000; i++) { -// s = bootKeyboard(); -// if (s!="") { - -// if (s.length()==2) -// b = s; -// else { -// b[0] = b[1]; -// b[1] = s[0]; -// } - -// bool chgRes = true; - -// if (b=="1Q" || b=="Q1") { -// Config::aspect_16_9=false; -// Config::videomode=0; -// } else -// if (b=="1W" || b=="W1") { -// Config::aspect_16_9=true; -// Config::videomode=0; -// } else -// if (b=="2Q" || b=="Q2") { -// Config::aspect_16_9=false; -// Config::videomode=1; -// } else -// if (b=="2W" || b=="W2") { -// Config::aspect_16_9=true; -// Config::videomode=1; -// } else -// if (b=="3Q" || b=="Q3") { -// Config::aspect_16_9=false; -// Config::videomode=2; -// } else -// if (b=="3W" || b=="W3") { -// Config::aspect_16_9=true; -// Config::videomode=2; -// } else chgRes = false; - -// if (chgRes) { -// Config::ram_file="none"; -// Config::save(); -// printf("%s\n", b.c_str()); -// break; -// } - -// } - -// delayMicroseconds(250); - -// } -// */ - - -// /* -// auto Kbd = PS2Controller.keyboard(); -// fabgl::VirtualKeyItem NextKey; -// bool r = false; - -// #ifdef ZXKEYB - -// // Process physical keyboard -// ZXKeyb::process(); -// // Detect and process physical kbd menu key combinations - -// if (!bitRead(ZXKeyb::ZXcols[3], 0)) { // 1 -// if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q -// return "1Q"; -// } else -// if (!bitRead(ZXKeyb::ZXcols[2], 1)) { // W -// return "1W"; -// } -// } else -// if (!bitRead(ZXKeyb::ZXcols[3], 1)) { // 2 -// if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q -// return "2Q"; -// } else -// if (!bitRead(ZXKeyb::ZXcols[2], 1)) { // W -// return "2W"; -// } -// } else -// if (!bitRead(ZXKeyb::ZXcols[3], 2)) { // 3 -// if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q -// return "3Q"; -// } else -// if (!bitRead(ZXKeyb::ZXcols[2], 1)) { // W -// return "3W"; -// } -// } - -// #endif - -// while (Kbd->virtualKeyAvailable()) { -// r = Kbd->getNextVirtualKey(&NextKey); -// if (r) { -// // Check keyboard status -// if (PS2Controller.keyboard()->isVKDown(fabgl::VK_1)) return "1"; -// if (PS2Controller.keyboard()->isVKDown(fabgl::VK_2)) return "2"; -// if (PS2Controller.keyboard()->isVKDown(fabgl::VK_3)) return "3"; -// if (PS2Controller.keyboard()->isVKDown(fabgl::VK_Q) || PS2Controller.keyboard()->isVKDown(fabgl::VK_q)) return "Q"; -// if (PS2Controller.keyboard()->isVKDown(fabgl::VK_W) || PS2Controller.keyboard()->isVKDown(fabgl::VK_w)) return "W"; -// } -// } - -// return ""; -// */ - -// } - //======================================================================================= // SETUP //======================================================================================= @@ -484,9 +290,7 @@ void ESPectrum::setup() // PHYSICAL KEYBOARD (SINCLAIR 8 + 5 MEMBRANE KEYBOARD) //======================================================================================= - // #ifdef ZXKEYB ZXKeyb::setup(); - // #endif //======================================================================================= // FILESYSTEM @@ -762,6 +566,10 @@ void ESPectrum::reset() VIDEO::Reset(); Tape::tapeFileName = "none"; + if (Tape::tape != NULL) { + fclose(Tape::tape); + Tape::tape = NULL; + } Tape::tapeStatus = TAPE_STOPPED; Tape::SaveStatus = SAVE_STOPPED; Tape::romLoading = false; @@ -813,22 +621,31 @@ void ESPectrum::reset() void ESPectrum::loadRom(string arch, string romset) { if (arch == "48K") { - for (int i=0;i < max_list_rom_48; i++) { - if (romset.find(gb_list_roms_48k_title[i]) != string::npos) { - MemESP::rom[0] = (uint8_t *) gb_list_roms_48k_data[i]; - break; - } - } + + MemESP::rom[0] = (uint8_t *) gb_rom_0_sinclair_48k; + + // for (int i=0;i < max_list_rom_48; i++) { + // if (romset.find(gb_list_roms_48k_title[i]) != string::npos) { + // MemESP::rom[0] = (uint8_t *) gb_list_roms_48k_data[i]; + // break; + // } + // } + } else { - for (int i=0;i < max_list_rom_128; i++) { - if (romset.find(gb_list_roms_128k_title[i]) != string::npos) { - MemESP::rom[0] = (uint8_t *) gb_list_roms_128k_data[i][0]; - MemESP::rom[1] = (uint8_t *) gb_list_roms_128k_data[i][1]; - MemESP::rom[2] = (uint8_t *) gb_list_roms_128k_data[i][2]; - MemESP::rom[3] = (uint8_t *) gb_list_roms_128k_data[i][3]; - break; - } - } + + MemESP::rom[0] = (uint8_t *) gb_rom_0_sinclair_128k; + MemESP::rom[1] = (uint8_t *) gb_rom_1_sinclair_128k; + + // for (int i=0;i < max_list_rom_128; i++) { + // if (romset.find(gb_list_roms_128k_title[i]) != string::npos) { + // MemESP::rom[0] = (uint8_t *) gb_list_roms_128k_data[i][0]; + // MemESP::rom[1] = (uint8_t *) gb_list_roms_128k_data[i][1]; + // MemESP::rom[2] = (uint8_t *) gb_list_roms_128k_data[i][2]; + // MemESP::rom[3] = (uint8_t *) gb_list_roms_128k_data[i][3]; + // break; + // } + // } + } } @@ -860,9 +677,7 @@ bool IRAM_ATTR ESPectrum::readKbd(fabgl::VirtualKeyItem *Nextkey) { uint8_t ESPectrum::PS2cols[8] = { 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf }; -// #ifdef ZXKEYB static int zxDelay = 0; -// #endif void IRAM_ATTR ESPectrum::processKeyboard() { @@ -977,8 +792,6 @@ void IRAM_ATTR ESPectrum::processKeyboard() { } - // #ifdef ZXKEYB - if (ZXKeyb::Exists) { // START - ZXKeyb Exists if (zxDelay > 0) @@ -988,9 +801,7 @@ void IRAM_ATTR ESPectrum::processKeyboard() { ZXKeyb::process(); // Detect and process physical kbd menu key combinations - // CS+SS+N -> FN Keys - // F11 -> CS+SS+Q, F12 -> CS+SS+W - // TO DO: Add delay after special key so keys as vol up vol down or toggles like F8 doesn't get re-pressed too fast. + // CS+SS+N -> FN Keys, F11 -> CS+SS+Q, F12 -> CS+SS+W, CS+SS+S -> Capture screen if ((!bitRead(ZXKeyb::ZXcols[0],0)) && (!bitRead(ZXKeyb::ZXcols[7],1))) { zxDelay = 15; @@ -1058,14 +869,6 @@ void IRAM_ATTR ESPectrum::processKeyboard() { } } - // #else - - // if (r) { - // for (uint8_t rowidx = 0; rowidx < 8; rowidx++) { - // Ports::port[rowidx] = PS2cols[rowidx]; - // } - // } - // #endif } @@ -1304,12 +1107,19 @@ for(;;) { #else if (Tape::tapeStatus==TAPE_LOADING) { - snprintf(linea1, sizeof(linea1), "%02d/%02d %10s % 6d ", Tape::TapeListing[Tape::tapeCurBlock].Index + 1, Tape::TapeListing.size(), Tape::TapeListing[Tape::tapeCurBlock].FileName, Tape::TapeListing[Tape::tapeCurBlock].BlockLength); + + snprintf(linea1, sizeof(linea1), " %12s %04d/%04d ", Tape::tapeFileName.substr(TapeNameScroller + 6,12).c_str(), Tape::tapeCurBlock + 1, Tape::tapeNumBlocks); + float percent = (float)((Tape::tapebufByteCount + Tape::tapePlayOffset) * 100) / (float)Tape::tapeFileSize; - snprintf(linea2, sizeof(linea2), "%5.2f%% %06d %s %06d ", percent, Tape::tapebufByteCount + Tape::tapePlayOffset, OSD_TAPE_OF[Config::lang] , Tape::tapeFileSize); + snprintf(linea2, sizeof(linea2), " %05.2f%% %07d%s%07d ", percent, Tape::tapebufByteCount + Tape::tapePlayOffset, "/" , Tape::tapeFileSize); + + if (++TapeNameScroller > (Tape::tapeFileName.length() - 18)) TapeNameScroller = 0; + } else { + snprintf(linea1, sizeof(linea1), "CPU: %05d / IDL: %05d ", (int)(elapsed), (int)(idle)); snprintf(linea2, sizeof(linea2), "FPS:%6.2f / FND:%6.2f ", CPU::framecnt / (totalseconds / 1000000), CPU::framecnt / (totalsecondsnodelay / 1000000)); + } #endif diff --git a/src/FileSNA.cpp b/src/FileSNA.cpp index 662e7d26..e1b0b9a5 100644 --- a/src/FileSNA.cpp +++ b/src/FileSNA.cpp @@ -336,6 +336,10 @@ bool FileSNA::load(string sna_fn) MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; Tape::tapeFileName = "none"; + if (Tape::tape != NULL) { + fclose(Tape::tape); + Tape::tape = NULL; + } Tape::tapeStatus = TAPE_STOPPED; Tape::SaveStatus = SAVE_STOPPED; Tape::romLoading = false; diff --git a/src/FileUtils.cpp b/src/FileUtils.cpp index 7ee7db2b..2552aec2 100644 --- a/src/FileUtils.cpp +++ b/src/FileUtils.cpp @@ -78,7 +78,7 @@ bool FileUtils::mountSDCard(int PIN_MISO, int PIN_MOSI, int PIN_CLK, int PIN_CS) esp_vfs_fat_sdmmc_mount_config_t mount_config = { .format_if_mount_failed = false, - .max_files = 3, + .max_files = 4, .allocation_unit_size = 16 * 1024 }; diff --git a/src/FileZ80.cpp b/src/FileZ80.cpp index b198b4a8..1a73243d 100644 --- a/src/FileZ80.cpp +++ b/src/FileZ80.cpp @@ -430,6 +430,10 @@ bool FileZ80::load(string z80_fn) MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; Tape::tapeFileName = "none"; + if (Tape::tape != NULL) { + fclose(Tape::tape); + Tape::tape = NULL; + } Tape::tapeStatus = TAPE_STOPPED; Tape::SaveStatus = SAVE_STOPPED; Tape::romLoading = false; diff --git a/src/OSDMain.cpp b/src/OSDMain.cpp index cde7a447..3e59cfeb 100644 --- a/src/OSDMain.cpp +++ b/src/OSDMain.cpp @@ -174,14 +174,14 @@ static bool persistSave(uint8_t slotnumber) OSD::osdCenteredMsg(OSD_PSNA_SAVE_ERR, LEVEL_WARN); return false; } - OSD::osdCenteredMsg(OSD_PSNA_SAVED, LEVEL_INFO); + // OSD::osdCenteredMsg(OSD_PSNA_SAVED, LEVEL_INFO); return true; } static bool persistLoad(uint8_t slotnumber) { - OSD::osdCenteredMsg(OSD_PSNA_LOADING, LEVEL_INFO); + OSD::osdCenteredMsg(OSD_PSNA_LOADING, LEVEL_INFO, 0); char persistfname[sizeof(DISK_PSNA_FILE) + 6]; sprintf(persistfname,DISK_PSNA_FILE "%u.sna",slotnumber); @@ -198,7 +198,7 @@ static bool persistLoad(uint8_t slotnumber) Config::save("ram"); #endif Config::last_ram_file = Config::ram_file; - OSD::osdCenteredMsg(OSD_PSNA_LOADED, LEVEL_INFO); + // OSD::osdCenteredMsg(OSD_PSNA_LOADED, LEVEL_INFO); } } @@ -206,10 +206,8 @@ static bool persistLoad(uint8_t slotnumber) } -// #ifdef ZXKEYB #define REPDEL 140 // As in real ZX Spectrum (700 ms.) static int zxDelay = 0; -// #endif // OSD Main Loop void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { @@ -233,6 +231,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { menu_curopt = 1; string mFile = menuFile(FileUtils::MountPoint + DISK_SNA_DIR, MENU_SNA_TITLE[Config::lang],".sna.SNA.z80.Z80"); if (mFile != "") { + mFile.erase(0, 1); changeSnapshot(FileUtils::MountPoint + DISK_SNA_DIR + "/" + mFile); } } @@ -260,24 +259,43 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { string mFile = menuFile(FileUtils::MountPoint + DISK_TAP_DIR, MENU_TAP_TITLE[Config::lang],".tap.TAP"); if (mFile != "") { - // TO DO: make this dependant on Flashload parameter - if (Z80Ops::is48) { - FileZ80::loader48(); - // changeSnapshot(FileUtils::MountPoint + "/load48.z80"); - } else { - FileZ80::loader128(); - // changeSnapshot(FileUtils::MountPoint + "/load128.z80"); - } + string keySel = mFile.substr(0,1); + mFile.erase(0, 1); + + if ((keySel == "R") && (Config::flashload)) { + + OSD::osdCenteredMsg(OSD_TAPE_FLASHLOAD, LEVEL_INFO, 0); + + if (Z80Ops::is48) { + FileZ80::loader48(); + // changeSnapshot(FileUtils::MountPoint + "/load48.z80"); + } else { + FileZ80::loader128(); + // changeSnapshot(FileUtils::MountPoint + "/load128.z80"); + } + + // Put something random on FRAMES SYS VAR as recommended by Mark Woodmass + // https://skoolkid.github.io/rom/asm/5C78.html + MemESP::writebyte(0x5C78,rand() % 256); + MemESP::writebyte(0x5C79,rand() % 256); + + if (Config::ram_file != NO_RAM_FILE) { + Config::ram_file = NO_RAM_FILE; + #ifdef SNAPSHOT_LOAD_LAST + Config::save("ram"); + #endif + } + Config::last_ram_file = NO_RAM_FILE; - // Put something random on FRAMES SYS VAR as recommended by Mark Woodmass - // https://skoolkid.github.io/rom/asm/5C78.html - MemESP::writebyte(0x5C78,rand() % 256); - MemESP::writebyte(0x5C79,rand() % 256); + } Tape::TAP_Stop(); // Read and analyze tape file Tape::Open(FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile); + + ESPectrum::TapeNameScroller = 0; + // Tape::tapeFileName=FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile; } @@ -300,7 +318,6 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { if (tBlock >= 0) { Tape::tapeCurBlock = tBlock; Tape::TAP_Stop(); - Tape::TAP_Play(); } } @@ -319,27 +336,28 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { else VIDEO::DrawOSD43 = VIDEO::BottomBorder_OSD; VIDEO::OSD = true; + ESPectrum::TapeNameScroller = 0; } click(); } else if (KeytoESP == fabgl::VK_F9) { // Volume down - #ifdef TESTING_CODE + // #ifdef TESTING_CODE - ESPectrum::target--; + // ESPectrum::target--; - // // Check if destination file exists - // struct stat st; - // if (stat("/sd/s/1942.z80", &st) == 0) { - // //printf("Exists!\n"); - // } + // // // Check if destination file exists + // // struct stat st; + // // if (stat("/sd/s/1942.z80", &st) == 0) { + // // //printf("Exists!\n"); + // // } - // FILE *f = fopen("/sd/s/1942.z80", "r"); - // if (f == NULL) { - // printf("Null file!\n"); - // } else fclose(f); + // // FILE *f = fopen("/sd/s/1942.z80", "r"); + // // if (f == NULL) { + // // printf("Null file!\n"); + // // } else fclose(f); - #else + // #else if (ESPectrum::aud_volume>-16) { click(); @@ -347,16 +365,16 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { pwm_audio_set_volume(ESPectrum::aud_volume); } - #endif + // #endif } else if (KeytoESP == fabgl::VK_F10) { // Volume up - #ifdef TESTING_CODE + // #ifdef TESTING_CODE - ESPectrum::target++; + // ESPectrum::target++; - #else + // #else if (ESPectrum::aud_volume<0) { click(); @@ -364,7 +382,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { pwm_audio_set_volume(ESPectrum::aud_volume); } - #endif + // #endif } // else if (KeytoESP == fabgl::VK_F9) { @@ -377,7 +395,9 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { // Hard if (Config::ram_file != NO_RAM_FILE) { Config::ram_file = NO_RAM_FILE; + #ifdef SNAPSHOT_LOAD_LAST Config::save("ram"); + #endif } Config::last_ram_file = NO_RAM_FILE; ESPectrum::reset(); @@ -442,6 +462,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { menu_curopt = 1; string mFile = menuFile(FileUtils::MountPoint + DISK_SNA_DIR, MENU_SNA_TITLE[Config::lang],".sna.SNA.z80.Z80"); if (mFile != "") { + mFile.erase(0, 1); changeSnapshot(FileUtils::MountPoint + DISK_SNA_DIR + "/" + mFile); return; } @@ -495,24 +516,43 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { // Select TAP File string mFile = menuFile(FileUtils::MountPoint + DISK_TAP_DIR, MENU_TAP_TITLE[Config::lang],".tap.TAP"); if (mFile != "") { - - // TO DO: make this dependant on Flashload parameter - if (Z80Ops::is48) { - changeSnapshot(FileUtils::MountPoint + "/load48.z80"); - } else { - changeSnapshot(FileUtils::MountPoint + "/load128.z80"); - } - // Put something random on FRAMES SYS VAR as recommended by Mark Woodmass - // https://skoolkid.github.io/rom/asm/5C78.html - MemESP::writebyte(0x5C78,rand() % 256); - MemESP::writebyte(0x5C79,rand() % 256); + string keySel = mFile.substr(0,1); + mFile.erase(0, 1); + + if ((keySel == "R") && (Config::flashload)) { + + OSD::osdCenteredMsg(OSD_TAPE_FLASHLOAD, LEVEL_INFO, 0); + + if (Z80Ops::is48) { + FileZ80::loader48(); + // changeSnapshot(FileUtils::MountPoint + "/load48.z80"); + } else { + FileZ80::loader128(); + // changeSnapshot(FileUtils::MountPoint + "/load128.z80"); + } + + // Put something random on FRAMES SYS VAR as recommended by Mark Woodmass + // https://skoolkid.github.io/rom/asm/5C78.html + MemESP::writebyte(0x5C78,rand() % 256); + MemESP::writebyte(0x5C79,rand() % 256); + + if (Config::ram_file != NO_RAM_FILE) { + Config::ram_file = NO_RAM_FILE; + #ifdef SNAPSHOT_LOAD_LAST + Config::save("ram"); + #endif + } + Config::last_ram_file = NO_RAM_FILE; + + } Tape::TAP_Stop(); // Read and analyze tape file Tape::Open(FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile); - // Tape::tapeFileName=FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile; + + ESPectrum::TapeNameScroller = 0; return; @@ -524,6 +564,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { return; } else if (tap_num == 3) { + // Tape Browser if (Tape::tapeFileName=="none") { OSD::osdCenteredMsg(OSD_TAPE_SELECT_ERR[Config::lang], LEVEL_WARN); @@ -537,10 +578,10 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { if (tBlock >= 0) { Tape::tapeCurBlock = tBlock; Tape::TAP_Stop(); - Tape::TAP_Play(); } return; } + } } else { menu_curopt = 2; @@ -569,7 +610,9 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { // Hard if (Config::ram_file != NO_RAM_FILE) { Config::ram_file = NO_RAM_FILE; + #ifdef SNAPSHOT_LOAD_LAST Config::save("ram"); + #endif } Config::last_ram_file = NO_RAM_FILE; ESPectrum::reset(); @@ -643,10 +686,10 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { } else if (opt2 == 2) { - OSD::osdCenteredMsg("Refreshing snap dir", LEVEL_INFO); + OSD::osdCenteredMsg("Refreshing snap dir", LEVEL_INFO, 0); int chunks = FileUtils::DirToFile(FileUtils::MountPoint + DISK_SNA_DIR, ".sna.SNA.z80.Z80"); // Prepare sna filelist if (chunks) FileUtils::Mergefiles(FileUtils::MountPoint + DISK_SNA_DIR,chunks); // Merge files - OSD::osdCenteredMsg("Refreshing tape dir", LEVEL_INFO); + OSD::osdCenteredMsg("Refreshing tape dir", LEVEL_INFO, 0); chunks = FileUtils::DirToFile(FileUtils::MountPoint + DISK_TAP_DIR, ".tap.TAP"); // Prepare tap filelist if (chunks) FileUtils::Mergefiles(FileUtils::MountPoint + DISK_TAP_DIR,chunks); // Merge files return; @@ -908,14 +951,10 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { VIDEO::vga.setTextColor(OSD::zxColor(7, 0), OSD::zxColor(1, 0)); VIDEO::vga.print(Config::lang ? OSD_HELP_ES : OSD_HELP_EN); - // #ifdef ZXKEYB zxDelay = REPDEL; - // #endif while (1) { - // #ifdef ZXKEYB - if (ZXKeyb::Exists) { ZXKeyb::process(); @@ -955,9 +994,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { vTaskDelay(5 / portTICK_PERIOD_MS); - // #ifdef ZXKEYB if (zxDelay > 0) zxDelay--; - // #endif } @@ -967,20 +1004,92 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { } else if (opt == 6) { + // About drawOSD(false); - osdAt(2, 0); - VIDEO::vga.setTextColor(OSD::zxColor(7, 0), OSD::zxColor(1, 0)); - VIDEO::vga.print(Config::lang ? OSD_ABOUT_ES : OSD_ABOUT_EN); - // #ifdef ZXKEYB - zxDelay = REPDEL; - // #endif + VIDEO::vga.fillRect(Config::aspect_16_9 ? 60 : 40,Config::aspect_16_9 ? 12 : 32,240,50,OSD::zxColor(0, 0)); + + // Decode Logo in EBF8 format + uint8_t *logo = (uint8_t *)ESPectrum_logo; + int pos_x = Config::aspect_16_9 ? 86 : 66; + int pos_y = Config::aspect_16_9 ? 23 : 43; + int logo_w = (logo[5] << 8) + logo[4]; // Get Width + int logo_h = (logo[7] << 8) + logo[6]; // Get Height + logo+=8; // Skip header + for (int i=0; i < logo_h; i++) + for(int n=0; n= 'A') ? (fore - 'A' + 10) : (fore - '0'); + int backint = (back >= 'A') ? (back - 'A' + 10) : (back - '0'); + VIDEO::vga.setTextColor(zxColor(foreint & 0x7, foreint >> 3), zxColor(backint & 0x7, backint >> 3)); + msgChar++; + continue; + } else { + VIDEO::vga.drawChar(pos_x + (osdCol * 6), pos_y + (osdRow * 8), nextChar); + } + msgChar++; + } else { + VIDEO::vga.fillRect(pos_x + (osdCol * 6), pos_y + (osdRow * 8), 6,8, zxColor(1, 0) ); + } + osdCol++; + if (osdCol == 38) { + if (osdRow == 12) { + osdCol--; + msgDelay = 192; + } else { + VIDEO::vga.fillRect(pos_x + (osdCol * 6), pos_y + (osdRow * 8), 6,8, zxColor(1, 0) ); + osdCol = 0; + msgChar++; + osdRow++; + } + } + } else { + msgDelay--; + if (msgDelay==0) { + VIDEO::vga.fillRect(Config::aspect_16_9 ? 60 : 40,Config::aspect_16_9 ? 64 : 84,240,114,OSD::zxColor(1, 0)); + osdCol = 0; + osdRow = 0; + msgChar = 0; + msgIndex++; + if (msgIndex==5) msgIndex = 0; + } + } + + if (--cursorBlink == 0) { + uint16_t cursorSwap = cursorCol; + cursorCol = cursorCol2; + cursorCol2 = cursorSwap; + cursorBlink = 16; + } + VIDEO::vga.fillRect(pos_x + ((osdCol + 1) * 6), pos_y + (osdRow * 8), 6,8, cursorCol ); + if (ZXKeyb::Exists) { ZXKeyb::process(); @@ -989,28 +1098,26 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { if (zxDelay == 0) { ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, true, false); ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, false, false); - zxDelay = REPDEL; + zxDelay = REPABOUT; } } else if ((!bitRead(ZXKeyb::ZXcols[7], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 1))) { // BREAK if (zxDelay == 0) { ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, true, false); ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, false, false); - zxDelay = REPDEL; + zxDelay = REPABOUT; } } else if (!bitRead(ZXKeyb::ZXcols[1], 1)) { // S (Capture screen) if (zxDelay == 0) { ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, true, false); ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, false, false); - zxDelay = REPDEL; + zxDelay = REPABOUT; } } } - // #endif - if (ESPectrum::PS2Controller.keyboard()->virtualKeyAvailable()) { if (ESPectrum::readKbd(&Nextkey)) { if(!Nextkey.down) continue; @@ -1018,12 +1125,16 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { } } - vTaskDelay(5 / portTICK_PERIOD_MS); - - // #ifdef ZXKEYB + if(Config::videomode) { + // Wait for vertical sync + for (;;) { + if (ESPectrum::vsync) break; + } + } else { + vTaskDelay(20 / portTICK_PERIOD_MS); + } + if (zxDelay > 0) zxDelay--; - // #endif - } diff --git a/src/OSDMenu.cpp b/src/OSDMenu.cpp index f5ad20ec..c6c4118f 100644 --- a/src/OSDMenu.cpp +++ b/src/OSDMenu.cpp @@ -303,12 +303,10 @@ string OSD::getRomsetMenu(string arch) { return menu; } -// #ifdef ZXKEYB #define REPDEL 140 // As in real ZX Spectrum (700 ms.) #define REPPER 20 // As in real ZX Spectrum (100 ms.) static int zxDelay = 0; static int lastzxKey = 0; -// #endif // Run a new menu unsigned short OSD::menuRun(string new_menu) { @@ -317,15 +315,11 @@ unsigned short OSD::menuRun(string new_menu) { newMenu(new_menu); - // #ifdef ZXKEYB zxDelay = REPDEL; lastzxKey = 0; - // #endif while (1) { - // #ifdef ZXKEYB - if (ZXKeyb::Exists) { ZXKeyb::process(); @@ -414,8 +408,6 @@ unsigned short OSD::menuRun(string new_menu) { } - // #endif - // Process external keyboard if (ESPectrum::PS2Controller.keyboard()->virtualKeyAvailable()) { if (ESPectrum::readKbd(&Menukey)) { @@ -517,9 +509,7 @@ unsigned short OSD::menuRun(string new_menu) { } vTaskDelay(5 / portTICK_PERIOD_MS); - // #ifdef ZXKEYB if (zxDelay > 0) zxDelay--; - // #endif } @@ -624,10 +614,10 @@ string OSD::menuFile(string filedir, string title, string extensions) { rc = stat((filedir + "/.d").c_str(), &stat_buf); if (rc < 0) { // deallocAluBytes(); - OSD::osdCenteredMsg("Please wait: sorting directory", LEVEL_INFO); + OSD::osdCenteredMsg("Please wait: sorting directory", LEVEL_INFO, 0); int chunks = FileUtils::DirToFile(filedir, extensions); // Prepare sna filelist if (chunks) FileUtils::Mergefiles(filedir,chunks); // Merge files - OSD::osdCenteredMsg(" Done: directory index ready ", LEVEL_INFO); + // OSD::osdCenteredMsg(" Done: directory index ready ", LEVEL_INFO); // precalcAluBytes(); rc = stat((filedir + "/.d").c_str(), &stat_buf); } @@ -674,15 +664,11 @@ string OSD::menuFile(string filedir, string title, string extensions) { menuDraw(); - // #ifdef ZXKEYB zxDelay = REPDEL; lastzxKey = 0; - // #endif while (1) { - // #ifdef ZXKEYB - if (ZXKeyb::Exists) { ZXKeyb::process(); @@ -709,7 +695,7 @@ string OSD::menuFile(string filedir, string title, string extensions) { lastzxKey = 2; } } else - if ((!bitRead(ZXKeyb::ZXcols[6], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 0))) { // ENTER + if (!bitRead(ZXKeyb::ZXcols[6], 0)) { // ENTER if (zxDelay == 0) { ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, true, false); ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, false, false); @@ -720,48 +706,59 @@ string OSD::menuFile(string filedir, string title, string extensions) { lastzxKey = 3; } } else + if (!bitRead(ZXKeyb::ZXcols[4], 0)) { // 0 + if (zxDelay == 0) { + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_SPACE, true, false); + ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_SPACE, false, false); + if (lastzxKey == 4) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 4; + } + } else if ((!bitRead(ZXKeyb::ZXcols[7], 0)) || (!bitRead(ZXKeyb::ZXcols[4], 1))) { // BREAK if (zxDelay == 0) { ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, true, false); ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_ESCAPE, false, false); - if (lastzxKey == 4) + if (lastzxKey == 5) zxDelay = REPPER; else zxDelay = REPDEL; - lastzxKey = 4; + lastzxKey = 5; } } else if (!bitRead(ZXKeyb::ZXcols[3], 4)) { // LEFT if (zxDelay == 0) { ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEUP, true, false); ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEUP, false, false); - if (lastzxKey == 5) + if (lastzxKey == 6) zxDelay = REPPER; else zxDelay = REPDEL; - lastzxKey = 5; + lastzxKey = 6; } } else if (!bitRead(ZXKeyb::ZXcols[4], 2)) { // RIGHT if (zxDelay == 0) { ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEDOWN, true, false); ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PAGEDOWN, false, false); - if (lastzxKey == 6) + if (lastzxKey == 7) zxDelay = REPPER; else zxDelay = REPDEL; - lastzxKey = 6; + lastzxKey = 7; } } else if (!bitRead(ZXKeyb::ZXcols[2], 0)) { // Q (Capture screen) if (zxDelay == 0) { ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, true, false); ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_PRINTSCREEN, false, false); - if (lastzxKey == 7) + if (lastzxKey == 8) zxDelay = REPPER; else zxDelay = REPDEL; - lastzxKey = 7; + lastzxKey = 8; } } else { @@ -771,8 +768,6 @@ string OSD::menuFile(string filedir, string title, string extensions) { } - // #endif - // Process external keyboard if (ESPectrum::PS2Controller.keyboard()->virtualKeyAvailable()) { if (ESPectrum::readKbd(&Menukey)) { @@ -858,7 +853,14 @@ string OSD::menuFile(string filedir, string title, string extensions) { filedir = rowGet(menu,focus); rtrim(filedir); click(); - return filedir; + return "R" + filedir; + } else if (Menukey.vk == fabgl::VK_SPACE) { + fclose(dirfile); + dirfile = NULL; + filedir = rowGet(menu,focus); + rtrim(filedir); + click(); + return "S" + filedir; } else if (Menukey.vk == fabgl::VK_ESCAPE) { if (menu_level!=0) { @@ -887,10 +889,7 @@ string OSD::menuFile(string filedir, string title, string extensions) { vTaskDelay(5 / portTICK_PERIOD_MS); - // #ifdef ZXKEYB if (zxDelay > 0) zxDelay--; - // #endif - } } @@ -965,45 +964,97 @@ void OSD::filemenuRedraw(string title) { } } +string tapeBlockReadData(int Blocknum) { + + int tapeContentIndex=0; + int tapeBlkLen=0; + string blktype; + char buf[48]; + char fname[10]; + + tapeContentIndex = Tape::CalcTapBlockPos(Blocknum); + + // Analyze .tap file + tapeBlkLen=(readByteFile(Tape::tape) | (readByteFile(Tape::tape) << 8)); + + // Read the flag byte from the block. + // If the last block is a fragmented data block, there is no flag byte, so set the flag to 255 + // to indicate a data block. + uint8_t flagByte; + if (tapeContentIndex + 2 < Tape::tapeFileSize) { + flagByte = readByteFile(Tape::tape); + } else { + flagByte = 255; + } + + // Process the block depending on if it is a header or a data block. + // Block type 0 should be a header block, but it happens that headerless blocks also + // have block type 0, so we need to check the block length as well. + if (flagByte == 0 && tapeBlkLen == 19) { // This is a header. + + // Get the block type. + uint8_t blocktype = readByteFile(Tape::tape); + + switch (blocktype) { + case 0: + blktype = "Program "; + break; + case 1: + blktype = "Number array "; + break; + case 2: + blktype = "Char array "; + break; + case 3: + blktype = "Code "; + break; + case 4: + blktype = "Data block "; + break; + case 5: + blktype = "Info "; + break; + case 6: + blktype = "Unassigned "; + break; + default: + blktype = "Unassigned "; + break; + } + + // Get the filename. + if (blocktype > 5) { + fname[0] = '\0'; + } else { + for (int i = 0; i < 10; i++) { + fname[i] = readByteFile(Tape::tape); + } + fname[10]='\0'; + } + + } else { + + blktype = "Data block "; + fname[0]='\0'; + + } + + snprintf(buf, sizeof(buf), "%04d %s %10s % 6d\n", Blocknum + 1, blktype.c_str(), fname, tapeBlkLen); + + return buf; + +} + // Redraw inside rows void OSD::tapemenuRedraw(string title) { + if ((focus != last_focus) || (begin_row != last_begin_row)) { // Read bunch of rows menu = title + "\n"; - char buf[256]; for (int i = begin_row - 1; i < virtual_rows + begin_row - 2; i++) { - if (i > Tape::TapeListing.size()) break; - - string blktype; - switch (Tape::TapeListing[i].Type) { - case 0: - blktype = "Program "; - break; - case 1: - blktype = "Number array "; - break; - case 2: - blktype = "Char array "; - break; - case 3: - blktype = "Code "; - break; - case 4: - blktype = "Data block "; - break; - case 5: - blktype = "Info "; - break; - case 6: - blktype = "Unassigned "; - break; - } - - snprintf(buf, sizeof(buf), "%02d %s %10s % 6d\n", Tape::TapeListing[i].Index, blktype.c_str(), Tape::TapeListing[i].FileName, Tape::TapeListing[i].BlockLength); - - menu += buf; - + if (i > Tape::tapeNumBlocks) break; + menu += tapeBlockReadData(i); } for (uint8_t row = 1; row < virtual_rows; row++) { @@ -1018,6 +1069,7 @@ void OSD::tapemenuRedraw(string title) { last_focus = focus; last_begin_row = begin_row; + } } @@ -1026,9 +1078,11 @@ int OSD::menuTape(string title) { fabgl::VirtualKeyItem Menukey; + uint32_t tapeBckPos = ftell(Tape::tape); + // Tape::TapeListing.erase(Tape::TapeListing.begin(),Tape::TapeListing.begin() + 2); - real_rows = Tape::TapeListing.size() + 1; + real_rows = Tape::tapeNumBlocks + 1; virtual_rows = (real_rows > 19 ? 19 : real_rows); begin_row = last_begin_row = last_focus = focus = 1; @@ -1045,42 +1099,9 @@ int OSD::menuTape(string title) { // Get first bunch of rows menu = title + "\n"; - char buf[256]; for (int i = (begin_row - 1); i < (begin_row - 1) + (virtual_rows - 1); i++) { - - if (i > Tape::TapeListing.size()) break; - - string blktype; - switch (Tape::TapeListing[i].Type) { - case 0: - blktype = "Program "; - break; - case 1: - blktype = "Number array "; - break; - case 2: - blktype = "Char array "; - break; - case 3: - blktype = "Code "; - break; - case 4: - blktype = "Data block "; - break; - case 5: - blktype = "Info "; - break; - case 6: - blktype = "Unassigned "; - break; - } - - snprintf(buf, sizeof(buf), "%02d %s %10s % 6d\n", Tape::TapeListing[i].Index, blktype.c_str(), Tape::TapeListing[i].FileName, Tape::TapeListing[i].BlockLength); - - // printf("%02d %s %10s % 6d\n", Tape::TapeListing[i].Index, blktype.c_str(), Tape::TapeListing[i].FileName, Tape::TapeListing[i].BlockLength); - - menu += buf; - + if (i > Tape::tapeNumBlocks) break; + menu += tapeBlockReadData(i); } printf(menu.c_str()); @@ -1095,7 +1116,7 @@ int OSD::menuTape(string title) { } // Columns - cols = 37; // 34 for block info + 2 pre and post space + 1 for scrollbar + cols = 39; // 36 for block info + 2 pre and post space + 1 for scrollbar // Size w = (cols * OSD_FONT_W) + 2; @@ -1281,9 +1302,15 @@ int OSD::menuTape(string title) { click(); } else if (Menukey.vk == fabgl::VK_RETURN) { click(); + Tape::CalcTapBlockPos(begin_row + focus - 2); + printf("Ret value: %d\n", begin_row + focus - 2); return (begin_row + focus - 2); } else if (Menukey.vk == fabgl::VK_ESCAPE) { + // if (Tape::tapeStatus==TAPE_LOADING) { + fseek(Tape::tape, tapeBckPos, SEEK_SET); + // } + if (menu_level!=0) { // Restore backbuffer data int j = SaveRectpos - (((w >> 2) + 1) * h); @@ -1297,6 +1324,7 @@ int OSD::menuTape(string title) { } menu_saverect = false; } + click(); return -1; } diff --git a/src/Tape.cpp b/src/Tape.cpp index 0bdef2f0..053528cf 100644 --- a/src/Tape.cpp +++ b/src/Tape.cpp @@ -49,6 +49,8 @@ using namespace std; #include "messages.h" #include "Z80_JLS/z80.h" +#define TAPE_LISTING_DIV 16 + FILE *Tape::tape; string Tape::tapeFileName = "none"; string Tape::tapeSaveName = "none"; @@ -58,6 +60,7 @@ uint8_t Tape::romLoading = false; uint8_t Tape::tapeEarBit; std::vector Tape::TapeListing; uint16_t Tape::tapeCurBlock; +uint16_t Tape::tapeNumBlocks; uint32_t Tape::tapebufByteCount; uint32_t Tape::tapePlayOffset; size_t Tape::tapeFileSize; @@ -81,18 +84,21 @@ void Tape::Init() void Tape::Open(string name) { - FILE *file; + if (tape != NULL) { + fclose(tape); + tape = NULL; + } - file = fopen(name.c_str(), "rb"); - if (file == NULL) { + tape = fopen(name.c_str(), "rb"); + if (tape == NULL) { OSD::osdCenteredMsg(OSD_TAPE_LOAD_ERR, LEVEL_ERROR); return; } - fseek(file,0,SEEK_END); - long tSize = ftell(file); - rewind(file); - if (tSize == 0) return; + fseek(tape,0,SEEK_END); + tapeFileSize = ftell(tape); + rewind(tape); + if (tapeFileSize == 0) return; tapeFileName = name; @@ -106,7 +112,7 @@ void Tape::Open(string name) { do { // Analyze .tap file - tapeBlkLen=(readByteFile(file) | (readByteFile(file) << 8)); + tapeBlkLen=(readByteFile(tape) | (readByteFile(tape) << 8)); // printf("Analyzing block %d\n",tapeListIndex); // printf(" Block Len: %d\n",tapeBlockLen - 2); @@ -115,8 +121,8 @@ void Tape::Open(string name) { // If the last block is a fragmented data block, there is no flag byte, so set the flag to 255 // to indicate a data block. uint8_t flagByte; - if (tapeContentIndex + 2 < tSize) { - flagByte = readByteFile(file); + if (tapeContentIndex + 2 < tapeFileSize) { + flagByte = readByteFile(tape); } else { flagByte = 255; } @@ -128,7 +134,7 @@ void Tape::Open(string name) { // Get the block type. TapeBlock::BlockType dataBlockType; - uint8_t blocktype = readByteFile(file); + uint8_t blocktype = readByteFile(tape); switch (blocktype) { case 0: @@ -150,24 +156,26 @@ void Tape::Open(string name) { // Get the filename. for (int i = 0; i < 10; i++) { - block.FileName[i] = readByteFile(file); + // block.FileName[i] = readByteFile(file); + uint8_t tst = readByteFile(tape); } - block.FileName[10]='\0'; + // block.FileName[10]='\0'; - fseek(file,6,SEEK_CUR); + fseek(tape,6,SEEK_CUR); // Get the checksum. - uint8_t checksum = readByteFile(file); + uint8_t checksum = readByteFile(tape); - block.Type = dataBlockType; - block.Index = tapeListIndex; - block.IsHeaderless = false; - block.Checksum = checksum; - block.BlockLength = 19; - block.BlockTypeNum = 0; - block.StartPosition = tapeContentIndex; - - TapeListing.push_back(block); + // block.Type = dataBlockType; + // block.Index = tapeListIndex; + // block.IsHeaderless = false; + // block.Checksum = checksum; + // block.BlockLength = 19; + // block.BlockTypeNum = 0; + if ((tapeListIndex & (TAPE_LISTING_DIV - 1)) == 0) { + block.StartPosition = tapeContentIndex; + TapeListing.push_back(block); + } } else { @@ -187,29 +195,30 @@ void Tape::Open(string name) { contentOffset = 2; } - // If the preceeding block is a data block, this is a headerless block. - bool isHeaderless; - if (tapeListIndex > 0 && TapeListing[tapeListIndex - 1].Type == TapeBlock::BlockType::Data_block) { - isHeaderless = true; - } else { - isHeaderless = false; - } + // // If the preceeding block is a data block, this is a headerless block. + // bool isHeaderless; + // if (tapeListIndex > 0 && TapeListing[tapeListIndex - 1].Type == TapeBlock::BlockType::Data_block) { + // isHeaderless = true; + // } else { + // isHeaderless = false; + // } - fseek(file,contentLength,SEEK_CUR); + fseek(tape,contentLength,SEEK_CUR); // Get the checksum. - uint8_t checksum = readByteFile(file); - - block.FileName[0]='\0'; - block.Type = TapeBlock::BlockType::Data_block; - block.Index = tapeListIndex; - block.IsHeaderless = isHeaderless; - block.Checksum = checksum; - block.BlockLength = tapeBlkLen; - block.BlockTypeNum = flagByte; - block.StartPosition = tapeContentIndex; - - TapeListing.push_back(block); + uint8_t checksum = readByteFile(tape); + + // block.FileName[0]='\0'; + // block.Type = TapeBlock::BlockType::Data_block; + // block.Index = tapeListIndex; + // block.IsHeaderless = isHeaderless; + // block.Checksum = checksum; + // block.BlockLength = tapeBlkLen; + // block.BlockTypeNum = flagByte; + if ((tapeListIndex & (TAPE_LISTING_DIV - 1)) == 0) { + block.StartPosition = tapeContentIndex; + TapeListing.push_back(block); + } } @@ -217,9 +226,12 @@ void Tape::Open(string name) { tapeContentIndex += tapeBlkLen + 2; - } while(tapeContentIndex < tSize); + } while(tapeContentIndex < tapeFileSize); + + // } while((tapeListIndex < 1000) && (tapeContentIndex < tapeFileSize)); tapeCurBlock = 0; + tapeNumBlocks = tapeListIndex; // printf("------------------------------------\n"); // for (int i = 0; i < tapeListIndex; i++) { @@ -258,10 +270,147 @@ void Tape::Open(string name) { // } - fclose(file); + rewind(tape); + +} + +uint32_t Tape::CalcTapBlockPos(int block) { + + int TapeBlockRest = block & (TAPE_LISTING_DIV -1); + int CurrentPos = TapeListing[block / TAPE_LISTING_DIV].StartPosition; + // printf("TapeBlockRest: %d\n",TapeBlockRest); + // printf("Tapecurblock: %d\n",Tape::tapeCurBlock); + + fseek(tape,CurrentPos,SEEK_SET); + + while (TapeBlockRest-- != 0) { + uint16_t tapeBlkLen=(readByteFile(tape) | (readByteFile(tape) << 8)); + // printf("Tapeblklen: %d\n",tapeBlkLen); + fseek(tape,tapeBlkLen,SEEK_CUR); + CurrentPos += tapeBlkLen + 2; + } + + return CurrentPos; } +// void Tape::readBlockData(int BlockIndex) { + + +// // Analyze .tap file +// tapeBlockLen=(readByteFile(tape) | (readByteFile(tape) << 8)); + +// // printf("Analyzing block %d\n",tapeListIndex); +// // printf(" Block Len: %d\n",tapeBlockLen - 2); + +// // Read the flag byte from the block. +// // If the last block is a fragmented data block, there is no flag byte, so set the flag to 255 +// // to indicate a data block. +// uint8_t flagByte; +// if (tapeContentIndex + 2 < tapeFileSize) { +// flagByte = readByteFile(file); +// } else { +// flagByte = 255; +// } + +// // Process the block depending on if it is a header or a data block. +// // Block type 0 should be a header block, but it happens that headerless blocks also +// // have block type 0, so we need to check the block length as well. +// if (flagByte == 0 && tapeBlkLen == 19) { // This is a header. + +// // Get the block type. +// TapeBlock::BlockType dataBlockType; +// uint8_t blocktype = readByteFile(file); +// switch (blocktype) +// { +// case 0: +// dataBlockType = TapeBlock::BlockType::Program_header; +// break; +// case 1: +// dataBlockType = TapeBlock::BlockType::Number_array_header; +// break; +// case 2: +// dataBlockType = TapeBlock::BlockType::Character_array_header; +// break; +// case 3: +// dataBlockType = TapeBlock::BlockType::Code_header; +// break; +// default: +// dataBlockType = TapeBlock::BlockType::Unassigned; +// break; +// } + +// // Get the filename. +// for (int i = 0; i < 10; i++) { +// // block.FileName[i] = readByteFile(file); +// uint8_t tst = readByteFile(file); +// } +// // block.FileName[10]='\0'; + +// fseek(file,6,SEEK_CUR); + +// // Get the checksum. +// uint8_t checksum = readByteFile(file); + +// // block.Type = dataBlockType; +// // block.Index = tapeListIndex; +// // block.IsHeaderless = false; +// // block.Checksum = checksum; +// // block.BlockLength = 19; +// // block.BlockTypeNum = 0; +// if ((tapeListIndex & 0x07) == 0) { +// block.StartPosition = tapeContentIndex; +// TapeListing.push_back(block); +// } + +// } else { + +// // Get the block content length. +// int contentLength; +// int contentOffset; +// if (tapeBlkLen >= 2) { +// // Normally the content length equals the block length minus two +// // (the flag byte and the checksum are not included in the content). +// contentLength = tapeBlkLen - 2; +// // The content is found at an offset of 3 (two byte block size + one flag byte). +// contentOffset = 3; +// } else { +// // Fragmented data doesn't have a flag byte or a checksum. +// contentLength = tapeBlkLen; +// // The content is found at an offset of 2 (two byte block size). +// contentOffset = 2; +// } + +// // // If the preceeding block is a data block, this is a headerless block. +// // bool isHeaderless; +// // if (tapeListIndex > 0 && TapeListing[tapeListIndex - 1].Type == TapeBlock::BlockType::Data_block) { +// // isHeaderless = true; +// // } else { +// // isHeaderless = false; +// // } + +// fseek(file,contentLength,SEEK_CUR); + +// // Get the checksum. +// uint8_t checksum = readByteFile(file); + +// // block.FileName[0]='\0'; +// // block.Type = TapeBlock::BlockType::Data_block; +// // block.Index = tapeListIndex; +// // block.IsHeaderless = isHeaderless; +// // block.Checksum = checksum; +// // block.BlockLength = tapeBlkLen; +// // block.BlockTypeNum = flagByte; +// if ((tapeListIndex & 0x07) == 0) { +// block.StartPosition = tapeContentIndex; +// TapeListing.push_back(block); +// } + +// } + +// } + + void Tape::TAP_Play() { @@ -270,19 +419,21 @@ void Tape::TAP_Play() switch (Tape::tapeStatus) { case TAPE_STOPPED: - tape = fopen(Tape::tapeFileName.c_str(), "rb"); + // tape = fopen(Tape::tapeFileName.c_str(), "rb"); if (tape == NULL) { OSD::osdCenteredMsg(OSD_TAPE_LOAD_ERR, LEVEL_ERROR); return; } - fseek(tape,0,SEEK_END); - tapeFileSize = ftell(tape); - rewind (tape); + + // fseek(tape,0,SEEK_END); + // tapeFileSize = ftell(tape); + // rewind (tape); // Move to selected block position - fseek(tape,TapeListing[Tape::tapeCurBlock].StartPosition,SEEK_SET); - tapePlayOffset = TapeListing[Tape::tapeCurBlock].StartPosition; + // fseek(tape,TapeListing[Tape::tapeCurBlock].StartPosition,SEEK_SET); + // tapePlayOffset = TapeListing[Tape::tapeCurBlock].StartPosition; + tapePlayOffset = CalcTapBlockPos(tapeCurBlock); tapePhase=TAPE_PHASE_SYNC; tapePulseCount=0; @@ -311,8 +462,8 @@ void Tape::TAP_Play() void Tape::TAP_Stop() { tapeStatus=TAPE_STOPPED; - fclose(tape); - tape = NULL; + // fclose(tape); + // tape = NULL; } void IRAM_ATTR Tape::TAP_Read() @@ -441,34 +592,26 @@ void Tape::Save() { bool Tape::FlashLoad() { - FILE *flashtape; - - flashtape = fopen(Tape::tapeFileName.c_str(), "rb"); - if (flashtape == NULL) { - return false; + if (tape == NULL) { + tape = fopen(Tape::tapeFileName.c_str(), "rb"); + if (tape == NULL) { + return false; + } } - // Move to selected block position - fseek(flashtape,TapeListing[Tape::tapeCurBlock].StartPosition,SEEK_SET); - - uint16_t blockLen=(readByteFile(flashtape) | (readByteFile(flashtape) <<8)); - uint8_t tapeFlag = readByteFile(flashtape); - - // printf("BlockLen: %d. Flag: %d\n",blockLen,tapeFlag); + uint16_t blockLen=(readByteFile(tape) | (readByteFile(tape) <<8)); + uint8_t tapeFlag = readByteFile(tape); - // printf("%u\n",Z80::getRegA()); - // printf("%u\n",Z80::getRegAx()); - - if (Z80::getRegAx() != (tapeFlag & 0xff)) { - // printf("No coincide el flag\n"); - fclose(flashtape); + if (Z80::getRegAx() != tapeFlag) { Z80::setFlags(0x00); Z80::setRegA(Z80::getRegAx() ^ tapeFlag); - if (tapeCurBlock < (TapeListing.size() - 1)) { + if (tapeCurBlock < (tapeNumBlocks - 1)) { tapeCurBlock++; + CalcTapBlockPos(tapeCurBlock); return true; } else { tapeCurBlock = 0; + rewind(tape); return false; } } @@ -476,40 +619,147 @@ bool Tape::FlashLoad() { // La paridad incluye el byte de flag Z80::setRegA(tapeFlag); - int count = 0; - uint8_t data; int addr = Z80::getRegIX(); // Address start int nBytes = Z80::getRegDE(); // Lenght - // printf("Addr: %d. nBytes: %d\n",addr,nBytes); + + int addr2 = addr & 0x3fff; + uint8_t page = addr >> 14; + + if ((addr2 + nBytes) <= 0x4000) { + + if (page != 0 ) + fread(&MemESP::ramCurrent[page][addr2], nBytes, 1, tape); + else { + fseek(tape,nBytes, SEEK_CUR); + } + + } else { + + int chunk1 = 0x4000 - addr2; + int chunkrest = nBytes; + do { + if ((page > 0) && (page < 4)) { + fread(&MemESP::ramCurrent[page][addr2], chunk1, 1, tape); + } else { + fseek(tape,chunk1, SEEK_CUR); + } + addr2 = 0; + chunkrest = chunkrest - chunk1; + if (chunkrest > 0x4000) chunk1 = 0x4000; else chunk1 = chunkrest; + page++; + } while (chunkrest > 0); + + } + + int count = 0; while ((count < nBytes) && (count < blockLen - 1)) { - data = readByteFile(flashtape); - MemESP::writebyte(addr,data); - Z80::Xor(data); + Z80::Xor(MemESP::readbyte(addr)); addr = (addr + 1) & 0xffff; count++; } - // printf("Count: %d. nBytes: %d\n",count,nBytes); + if (nBytes != (blockLen - 2)) { + + if (tapeCurBlock < (tapeNumBlocks - 1)) { + tapeCurBlock++; + } else { + tapeCurBlock = 0; + rewind(tape); + } - // Se cargarán los bytes pedidos en DE - if (count == nBytes) { - Z80::Xor(readByteFile(flashtape)); // Byte de paridad - Z80::Cp(0x01); - } else if (count < nBytes) { // Hay menos bytes en la cinta de los indicados en DE // En ese caso habrá dado un error de timeout en LD-SAMPLE (0x05ED) // que se señaliza con CARRY==reset & ZERO==set Z80::setFlags(0x50); // when B==0xFF, then INC B, B=0x00, F=0x50 + CalcTapBlockPos(tapeCurBlock); + + } else { + + Z80::Xor(readByteFile(tape)); // Byte de paridad + Z80::Cp(0x01); + + if (tapeCurBlock < (tapeNumBlocks - 1)) { + tapeCurBlock++; + } else { + tapeCurBlock = 0; + rewind(tape); + } + } Z80::setRegIX(addr); - Z80::setRegDE(nBytes - count); + Z80::setRegDE(nBytes - (blockLen - 2)); - if (tapeCurBlock < (TapeListing.size() - 1)) tapeCurBlock++; else tapeCurBlock = 0; + return true; - fclose(flashtape); + // uint16_t count = 0; + // uint8_t data; + // uint16_t addr = Z80::getRegIX(); // Address start + // uint16_t nBytes = Z80::getRegDE(); // Lenght + + // uint16_t addr2 = addr & 0x3fff; + // uint8_t page = addr >> 14; + + // if ((addr2 + nBytes) < 0x4000) { - return true; + // if (page != 0 ) + // fread(&MemESP::ramCurrent[page][addr2], nBytes, 1, tape); + // else { + // fseek(tape,nBytes, SEEK_CUR); + // } + + // } else { + + // uint16_t chunk1 = 0x4000 - addr2; + // if (page) { + // fread(&MemESP::ramCurrent[page][addr2], chunk1, 1, tape); + // } else + // fseek(tape,chunk1, SEEK_CUR); + + // if (page < 3) + // fread(&MemESP::ramCurrent[page + 1][0], nBytes - chunk1, 1, tape); + // else + // fseek(tape,nBytes - chunk1, SEEK_CUR); + + // } + + // addr += nBytes; + + // fseek(tape,1, SEEK_CUR); // Saltar el byte de paridad + + // // printf("Blocklen: %d. nBytes: %d\n",blockLen,nBytes); + + + // if (tapeCurBlock < (tapeNumBlocks - 1)) { + // tapeCurBlock++; + // } else { + // tapeCurBlock = 0; + // rewind(tape); + // } + + // if (nBytes != (blockLen - 2)) { + // // Hay menos bytes en la cinta de los indicados en DE + // // En ese caso habrá dado un error de timeout en LD-SAMPLE (0x05ED) + // // que se señaliza con CARRY==reset & ZERO==set + // // printf("Hay menos bytes en la cinta de los indicados en DE\n"); + // Z80::setFlags(0x50); // when B==0xFF, then INC B, B=0x00, F=0x50 + // CalcTapBlockPos(tapeCurBlock); + // } else { + // Z80::Xor(Z80::getRegA()); // A = 0 <- Everything OK + // Z80::Cp(0x01); + // } + + // Z80::setRegIX(addr); + // Z80::setRegDE(nBytes - (blockLen - 2)); + + // // if (tapeCurBlock < (tapeNumBlocks - 1)) { + // // tapeCurBlock++; + // // } else { + // // tapeCurBlock = 0; + // // rewind(tape); + // // } + + // return true; } diff --git a/src/Video.cpp b/src/Video.cpp index 69ae3d25..02d1bbda 100644 --- a/src/Video.cpp +++ b/src/Video.cpp @@ -510,11 +510,13 @@ void IRAM_ATTR VIDEO::MainScreenLB(unsigned int statestoadd, bool contended) { // ------------------------------- // Non ptime-128 compliant version + // ------------------------------- Draw(0,false); // ------------------------------- // // --------------------------- // // ptime-128 compliant version + // // --------------------------- // dispUpdCycle = 6 + CPU::latetiming; // Draw(0,false); // video_rest = 0; @@ -609,7 +611,7 @@ void VIDEO::MainScreen(unsigned int statestoadd, bool contended) { // } -void IRAM_ATTR VIDEO::MainScreen_OSD(unsigned int statestoadd, bool contended) { +void VIDEO::MainScreen_OSD(unsigned int statestoadd, bool contended) { uint8_t att, bmp; @@ -619,7 +621,9 @@ void IRAM_ATTR VIDEO::MainScreen_OSD(unsigned int statestoadd, bool contended) { CPU::tstates += statestoadd; statestoadd += video_rest; + video_rest = statestoadd & 0x03; // Mod 4 + for (int i=0; i < (statestoadd >> 2); i++) { if ((linedraw_cnt>175) && (linedraw_cnt<192) && (coldraw_cnt>20) && (coldraw_cnt<39)) { @@ -639,11 +643,14 @@ void IRAM_ATTR VIDEO::MainScreen_OSD(unsigned int statestoadd, bool contended) { *lineptr32++ = AluBytes[bmp & 0xF][att]; } else { + *lineptr32++ = brd; *lineptr32++ = brd; + } if (++coldraw_cnt == 40) { + tstateDraw += tStatesPerLine; Draw = ++linedraw_cnt == 196 ? &BottomBorder_Blank : &MainScreen_Blank; return; } From 17479783216ae9c2039e6d8100077832155e1786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Thu, 10 Aug 2023 03:31:14 +0200 Subject: [PATCH 25/29] CPU and Halt fix, Tape OSD fix --- include/Z80_JLS/z80.h | 1 + src/CPU.cpp | 13 +++++------ src/ESPectrum.cpp | 4 ++-- src/Z80_JLS.cpp | 52 +++++++++++++++++++++++++++++++++++++++---- 4 files changed, 56 insertions(+), 14 deletions(-) diff --git a/include/Z80_JLS/z80.h b/include/Z80_JLS/z80.h index 05490690..4f761c2a 100644 --- a/include/Z80_JLS/z80.h +++ b/include/Z80_JLS/z80.h @@ -391,6 +391,7 @@ class Z80 { // Execute one instruction static void IRAM_ATTR execute(); + static void IRAM_ATTR exec_nocheck(); // Check INT static void IRAM_ATTR checkINT(void); diff --git a/src/CPU.cpp b/src/CPU.cpp index 5426a141..0e68a33d 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -128,18 +128,15 @@ void CPU::reset() { void IRAM_ATTR CPU::loop() { - while (tstates < IntEnd) { + while (tstates < IntEnd) Z80::execute(); - Z80::checkINT(); - } - + uint32_t stFrame = statesInFrame - IntEnd; - while (tstates < stFrame) Z80::execute(); + while (tstates < stFrame) + Z80::exec_nocheck(); - while (tstates < statesInFrame) { + while (tstates < statesInFrame) Z80::execute(); - Z80::checkINT(); - } if (tstates & 0xFF000000) FlushOnHalt(); // If we're halted flush screen and update registers as needed diff --git a/src/ESPectrum.cpp b/src/ESPectrum.cpp index 83820bc6..9006d558 100644 --- a/src/ESPectrum.cpp +++ b/src/ESPectrum.cpp @@ -1108,12 +1108,12 @@ for(;;) { if (Tape::tapeStatus==TAPE_LOADING) { - snprintf(linea1, sizeof(linea1), " %12s %04d/%04d ", Tape::tapeFileName.substr(TapeNameScroller + 6,12).c_str(), Tape::tapeCurBlock + 1, Tape::tapeNumBlocks); + snprintf(linea1, sizeof(linea1), " %-12s %04d/%04d ", Tape::tapeFileName.substr(6 + TapeNameScroller, 12).c_str(), Tape::tapeCurBlock + 1, Tape::tapeNumBlocks); float percent = (float)((Tape::tapebufByteCount + Tape::tapePlayOffset) * 100) / (float)Tape::tapeFileSize; snprintf(linea2, sizeof(linea2), " %05.2f%% %07d%s%07d ", percent, Tape::tapebufByteCount + Tape::tapePlayOffset, "/" , Tape::tapeFileSize); - if (++TapeNameScroller > (Tape::tapeFileName.length() - 18)) TapeNameScroller = 0; + if ((++TapeNameScroller + 18) > Tape::tapeFileName.length()) TapeNameScroller = 0; } else { diff --git a/src/Z80_JLS.cpp b/src/Z80_JLS.cpp index 4bff4094..f3902438 100644 --- a/src/Z80_JLS.cpp +++ b/src/Z80_JLS.cpp @@ -1003,7 +1003,7 @@ void IRAM_ATTR Z80::execute() { regR++; - // if (!halted) { + if (!halted) { REG_PC++; @@ -1035,8 +1035,8 @@ void IRAM_ATTR Z80::execute() { lastFlagQ = flagQ; - // } - + } + // Primero se comprueba NMI // Si se activa NMI no se comprueba INT porque la siguiente // instrucción debe ser la de 0x0066. @@ -1048,8 +1048,52 @@ void IRAM_ATTR Z80::execute() { // } // Ahora se comprueba si está activada la señal INT - // checkINT(); + checkINT(); + +} +void IRAM_ATTR Z80::exec_nocheck() { + + uint8_t pg = REG_PC >> 14; + VIDEO::Draw(4,MemESP::ramContended[pg]); + opCode = MemESP::ramCurrent[pg][REG_PC & 0x3fff]; + + regR++; + + if (!halted) { + + REG_PC++; + + // El prefijo 0xCB no cuenta para esta guerra. + // En CBxx todas las xx producen un código válido + // de instrucción, incluyendo CBCB. + switch (prefixOpcode) { + case 0x00: + flagQ = pendingEI = false; + dcOpcode[opCode](); + break; + case 0xDD: + prefixOpcode = 0; + decodeDDFD(regIX); + break; + case 0xED: + prefixOpcode = 0; + decodeED(); + break; + case 0xFD: + prefixOpcode = 0; + decodeDDFD(regIY); + break; + default: + return; + } + + if (prefixOpcode != 0) return; + + lastFlagQ = flagQ; + + } + } void Z80::decodeOpcode00() From 3c3cbd580a11117f1a9d7e4f7e446d2a95c79fd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Fri, 11 Aug 2023 01:29:20 +0200 Subject: [PATCH 26/29] Road to rc2: flashload fix and credits update --- include/messages.h | 41 ++-- src/OSDMain.cpp | 9 +- src/Tape.cpp | 507 +++------------------------------------------ 3 files changed, 50 insertions(+), 507 deletions(-) diff --git a/include/messages.h b/include/messages.h index a72719f2..a57cd8a6 100644 --- a/include/messages.h +++ b/include/messages.h @@ -41,7 +41,7 @@ visit https://zxespectrum.speccy.org/contacto #define MSG_LOADING_Z80 "Loading Z80 file" #define MSG_SAVE_CONFIG "Saving config file" #define MSG_VGA_INIT "Initializing VGA" -#define EMU_VERSION " v1.0rc2pr " +#define EMU_VERSION "v1.0rc2pr3.2" // Error #define ERROR_TITLE " !!! ERROR - CLIVE MEDITATION !!! " @@ -385,6 +385,19 @@ static const char *MENU_JOY[2] = { MENU_JOY_EN, MENU_JOY_ES }; "\nF1 __/ | \nE1| | | | (_| | | | || (_| |\r"\ "\nF1 |___/ \nE1|_| |_|\\__,_|_| \\__\\__,_|\r" + #define PATREONS "\r"\ + "\nA1The Mega Trees:\r"\ + "\nB1Victor Llamazares, \nC1Antonio Villena\r"\ + "\r"\ + "\nA1The Jet Set Willys:\r"\ + "\nD1Inacio Santos\r"\ + "\r"\ + "\nA1The Manic Miners:\r"\ + "\nE1Fernando Bonilla, \nB1M.Ignacio Monge\r"\ + "\nC1Jose Maria Rodriguez, \nD1Julia Salvador\r"\ + "\nB1Marta Sicilia, \nE1Radoslaw Wojciechowski\r"\ + "\r" + static const char *AboutMsg[2][5] = { { "\nF1(C)2023 Victor Iborra \"Eremus\"\r"\ @@ -416,18 +429,7 @@ static const char *MENU_JOY[2] = { MENU_JOY_EN, MENU_JOY_ES }; "\r" , "\nF1Big thanks to our Patreons:\r"\ - "\r"\ - "\nA1The Mega Trees:\r"\ - "\r"\ - "\nB1Victor Llamazares, \nC1Antonio Villena\r"\ - "\r"\ - "\nD1The Manic Miners:\r"\ - "\r"\ - "\nE1Fernando Bonilla, \nA1Magnetrix, \nB1M.Ignacio\r"\ - "Monge, \nC1Jose Maria Rodriguez, \nD1Julia\r"\ - "Salvador, \nE1Marta Sicilia, \nA1Radoslaw\r"\ - "Wojciechowski\r"\ - "\r" + PATREONS , "\nF1Thanks also to:\r"\ "\r"\ @@ -475,18 +477,7 @@ static const char *MENU_JOY[2] = { MENU_JOY_EN, MENU_JOY_ES }; "\r" , "\nF1Muchas gracias a nuestros Patreons:\r"\ - "\r"\ - "\nA1The Mega Trees:\r"\ - "\r"\ - "\nB1Victor Llamazares, \nC1Antonio Villena\r"\ - "\r"\ - "\nD1The Manic Miners:\r"\ - "\r"\ - "\nE1Fernando Bonilla, \nA1Magnetrix, \nB1M.Ignacio\r"\ - "Monge, \nC1Jose Maria Rodriguez, \nD1Julia\r"\ - "Salvador, \nE1Marta Sicilia, \nA1Radoslaw\r"\ - "Wojciechowski\r"\ - "\r" + PATREONS , "\nF1Gracias tambien a:\r"\ "\r"\ diff --git a/src/OSDMain.cpp b/src/OSDMain.cpp index 3e59cfeb..ee6d13b3 100644 --- a/src/OSDMain.cpp +++ b/src/OSDMain.cpp @@ -1125,14 +1125,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { } } - if(Config::videomode) { - // Wait for vertical sync - for (;;) { - if (ESPectrum::vsync) break; - } - } else { - vTaskDelay(20 / portTICK_PERIOD_MS); - } + vTaskDelay(20 / portTICK_PERIOD_MS); if (zxDelay > 0) zxDelay--; diff --git a/src/Tape.cpp b/src/Tape.cpp index 053528cf..4f12b7c6 100644 --- a/src/Tape.cpp +++ b/src/Tape.cpp @@ -296,7 +296,6 @@ uint32_t Tape::CalcTapBlockPos(int block) { // void Tape::readBlockData(int BlockIndex) { - // // Analyze .tap file // tapeBlockLen=(readByteFile(tape) | (readByteFile(tape) << 8)); @@ -603,6 +602,7 @@ bool Tape::FlashLoad() { uint8_t tapeFlag = readByteFile(tape); if (Z80::getRegAx() != tapeFlag) { + // printf("No coincide el flag\n"); Z80::setFlags(0x00); Z80::setRegA(Z80::getRegAx() ^ tapeFlag); if (tapeCurBlock < (tapeNumBlocks - 1)) { @@ -619,43 +619,64 @@ bool Tape::FlashLoad() { // La paridad incluye el byte de flag Z80::setRegA(tapeFlag); + int count = 0; int addr = Z80::getRegIX(); // Address start int nBytes = Z80::getRegDE(); // Lenght - int addr2 = addr & 0x3fff; uint8_t page = addr >> 14; - + if ((addr2 + nBytes) <= 0x4000) { + // printf("Case 1\n"); + if (page != 0 ) fread(&MemESP::ramCurrent[page][addr2], nBytes, 1, tape); else { fseek(tape,nBytes, SEEK_CUR); } + while ((count < nBytes) && (count < blockLen - 1)) { + Z80::Xor(MemESP::readbyte(addr)); + addr = (addr + 1) & 0xffff; + count++; + } + } else { + // printf("Case 2\n"); + int chunk1 = 0x4000 - addr2; - int chunkrest = nBytes; + int chunkrest = nBytes > (blockLen - 1) ? (blockLen - 1) : nBytes; + do { + if ((page > 0) && (page < 4)) { + fread(&MemESP::ramCurrent[page][addr2], chunk1, 1, tape); + + for (int i=0; i < chunk1; i++) { + Z80::Xor(MemESP::readbyte(addr)); + addr = (addr + 1) & 0xffff; + count++; + } + } else { - fseek(tape,chunk1, SEEK_CUR); + + for (int i=0; i < chunk1; i++) { + Z80::Xor(readByteFile(tape)); + addr = (addr + 1) & 0xffff; + count++; + } + } + addr2 = 0; chunkrest = chunkrest - chunk1; if (chunkrest > 0x4000) chunk1 = 0x4000; else chunk1 = chunkrest; page++; - } while (chunkrest > 0); - } + } while (chunkrest > 0); - int count = 0; - while ((count < nBytes) && (count < blockLen - 1)) { - Z80::Xor(MemESP::readbyte(addr)); - addr = (addr + 1) & 0xffff; - count++; } if (nBytes != (blockLen - 2)) { @@ -692,466 +713,4 @@ bool Tape::FlashLoad() { return true; - // uint16_t count = 0; - // uint8_t data; - // uint16_t addr = Z80::getRegIX(); // Address start - // uint16_t nBytes = Z80::getRegDE(); // Lenght - - // uint16_t addr2 = addr & 0x3fff; - // uint8_t page = addr >> 14; - - // if ((addr2 + nBytes) < 0x4000) { - - // if (page != 0 ) - // fread(&MemESP::ramCurrent[page][addr2], nBytes, 1, tape); - // else { - // fseek(tape,nBytes, SEEK_CUR); - // } - - // } else { - - // uint16_t chunk1 = 0x4000 - addr2; - // if (page) { - // fread(&MemESP::ramCurrent[page][addr2], chunk1, 1, tape); - // } else - // fseek(tape,chunk1, SEEK_CUR); - - // if (page < 3) - // fread(&MemESP::ramCurrent[page + 1][0], nBytes - chunk1, 1, tape); - // else - // fseek(tape,nBytes - chunk1, SEEK_CUR); - - // } - - // addr += nBytes; - - // fseek(tape,1, SEEK_CUR); // Saltar el byte de paridad - - // // printf("Blocklen: %d. nBytes: %d\n",blockLen,nBytes); - - - // if (tapeCurBlock < (tapeNumBlocks - 1)) { - // tapeCurBlock++; - // } else { - // tapeCurBlock = 0; - // rewind(tape); - // } - - // if (nBytes != (blockLen - 2)) { - // // Hay menos bytes en la cinta de los indicados en DE - // // En ese caso habrá dado un error de timeout en LD-SAMPLE (0x05ED) - // // que se señaliza con CARRY==reset & ZERO==set - // // printf("Hay menos bytes en la cinta de los indicados en DE\n"); - // Z80::setFlags(0x50); // when B==0xFF, then INC B, B=0x00, F=0x50 - // CalcTapBlockPos(tapeCurBlock); - // } else { - // Z80::Xor(Z80::getRegA()); // A = 0 <- Everything OK - // Z80::Cp(0x01); - // } - - // Z80::setRegIX(addr); - // Z80::setRegDE(nBytes - (blockLen - 2)); - - // // if (tapeCurBlock < (tapeNumBlocks - 1)) { - // // tapeCurBlock++; - // // } else { - // // tapeCurBlock = 0; - // // rewind(tape); - // // } - - // return true; - } - -// bool Tape::FlashLoad2() { - -// // // The return value, representing the index of the TapeBlock which was flash loaded. -// // int lastBlockIndex = -1; - -// // // If we encounter a block with no data to load (for example a text block), just skip ahead. -// // if (tapeManager.NextBlock != null && tapeManager.NextBlock.BlockContent == null) -// // { -// // return lastBlockIndex; -// // } - -// // // The LD BYTES ROM routine is intercepted at an early stage just before the edge detection is started. -// // // Check that the tape position is at the end of a block and that there is a following block to flash load. -// // if (z80.PC == 0x056A && tapeManager.NextBlock != null && tapeManager.CurrentTapePosition > tapeManager.NextBlock.StartPosition - 10) -// // { - -// // // The target address for the data is stored in IX. -// // int dataTargetParameter = 256 * z80.I1 + z80.X; -// // // The block length (number of bytes) is stored in DE. -// // int dataLengthParameter = 256 * z80.D + z80.E; -// // // The flag byte is stored in A'. -// // int flagByte = z80.APrime; - -// int dataTargetParameter = Z80::getRegIX(); -// int dataLengthParameter = Z80::getRegDE(); -// int flagByte = Z80::getRegA(); - -// printf("dataTargetParameter: %04X\n",dataTargetParameter); -// printf("dataLengthParameter: %04X\n",dataLengthParameter); -// printf("flagByte: %02X\n",flagByte); - - -// // // Check for various errors: -// // // Is there a mismatch between the block type and the flag byte in the A' register? -// // if (tapeManager.NextBlock.BlockTypeNum != flagByte && dataLengthParameter > 0) -// // { -// // // Don't load the block, but reset all flags. -// // z80.CarryFlag = 0; -// // z80.SignFlag = 0; -// // z80.ZeroFlag = 0; -// // z80.HalfCarryFlag = 0; -// // z80.Parity_OverflowFlag = 0; -// // z80.SubtractFlag = 0; -// // z80.F3Flag = 0; -// // z80.F5Flag = 0; - -// // // The A register is updated by XOR:ing the flag byte with the block byte read from the file. -// // z80.A = flagByte ^ tapeManager.NextBlock.BlockTypeNum; -// // } - -// if (Tape::TapeListing[tapeCurBlock].BlockTypeNum != flagByte && dataLengthParameter > 0) { -// Z80::setFlags(0x00); -// Z80::setRegA(flagByte ^ Tape::TapeListing[tapeCurBlock].BlockTypeNum); -// } - -// // else -// // // Is the expected number of bytes larger than the actual length of the block? -// // if (dataLengthParameter > tapeManager.NextBlock.BlockContent.Length) -// // { -// // // If the DE register indicates a too long data length, the loader will fail after -// // // loading the block and it expects one more byte. -// // memory.WriteDataBlock(tapeManager.NextBlock.BlockContent, dataTargetParameter); - -// // // When a new edge is not found, set flags carry = 0 and zero = 1. -// // z80.CarryFlag = 0; -// // z80.ZeroFlag = 1; - -// // // The other flags are set by the last INC B (from 0xFF) at 0x05ED. -// // z80.HalfCarryFlag = 1; -// // z80.SignFlag = 0; -// // z80.Parity_OverflowFlag = 0; -// // z80.SubtractFlag = 0; -// // z80.F3Flag = 0; -// // z80.F5Flag = 0; - -// // // Check that we're not dealing with a data fragment (in which case IX and DE are intact). -// // if (tapeManager.NextBlock.BlockContent.Length >= 2) -// // { -// // z80.I1 = (dataTargetParameter + tapeManager.NextBlock.BlockContent.Length + 1) / 256; -// // z80.X = (dataTargetParameter + tapeManager.NextBlock.BlockContent.Length + 1) - 256 * z80.I1; -// // z80.D = (dataLengthParameter - (tapeManager.NextBlock.BlockContent.Length + 1)) / 256; -// // z80.E = (dataLengthParameter - (tapeManager.NextBlock.BlockContent.Length + 1)) - 256 * z80.D; -// // } - -// // z80.A = 0; -// // } - -// else if (dataLengthParameter > Tape::TapeListing[tapeCurBlock].BlockLength) { - -// } - -// // else - -// // Is the expected number of bytes smaller than the length of the block? -// // if (dataLengthParameter < tapeManager.NextBlock.BlockContent.Length) -// // { -// // memory.WriteDataBlock(tapeManager.NextBlock.BlockContent, dataTargetParameter); - -// // // When calculating the checksum for the loaded data, there are two different cases, -// // // either the block length parameter equals zero, in which case there is no parity -// // // calculated and the checksum contains the flag byte. -// // // Otherwise, the checksum is calculated in the usual way but only for the number -// // // of bytes specified in the data length parameter + 1. -// // int calculatedCheckSum; -// // if (dataLengthParameter == 0) -// // { -// // calculatedCheckSum = flagByte; -// // } -// // else -// // { -// // calculatedCheckSum = flagByte; - -// // // The checksum is calculated by XOR:ing each byte of data with the flag byte. -// // for (int i = 0; i < dataLengthParameter + 1; i++) -// // { -// // calculatedCheckSum ^= tapeManager.NextBlock.BlockContent[i]; -// // } -// // } - -// // // Update the flags and the A register. -// // UpdateFlags(calculatedCheckSum); - -// // // Update the IX and DE registers. -// // z80.I1 = (dataTargetParameter + dataLengthParameter) / 256; -// // z80.X = (dataTargetParameter + dataLengthParameter) - 256 * z80.I1; -// // z80.D = 0; -// // z80.E = 0; -// // } -// // else - -// // // Is the expected number of bytes equal to zero? -// // if (dataLengthParameter == 0) -// // { -// // // There is no parity check, so the checksum contains the block type value. -// // int calculatedCheckSum = 0xFF; - -// // // Update the flags and the A register. -// // UpdateFlags(calculatedCheckSum); -// // } -// else -// // // Flash load the block and update IX, DE and AF. -// { -// // int lastBytePos = memory.WriteDataBlock(tapeManager.NextBlock.BlockContent, dataTargetParameter); - -// tape = fopen(Tape::tapeFileName.c_str(), "rb"); -// if (tape == NULL) -// { -// OSD::osdCenteredMsg(OSD_TAPE_LOAD_ERR, LEVEL_ERROR); -// return false; -// } - -// // Move to selected block position -// fseek(tape,TapeListing[Tape::tapeCurBlock].StartPosition + 3,SEEK_SET); - -// int count = 0; -// uint8_t data; -// printf("Addr: %d. nBytes: %d\n",dataTargetParameter,dataLengthParameter); -// while (count < dataLengthParameter) { -// data = readByteFile(tape); -// MemESP::writebyte(dataTargetParameter,data); -// Z80::Xor(data); -// dataTargetParameter = (dataTargetParameter + 1) & 0xffff; -// count++; -// } - -// Z80::Xor(readByteFile(tape)); // Byte de paridad -// Z80::Cp(0x01); - - -// Z80::setRegIX(dataTargetParameter); -// Z80::setRegDE(0); -// tapeCurBlock++; - -// fclose(tape); -// return true; - -// // // After loading the entire block, including the last checksum byte, the current checksum will be 0. -// // // (the checksum being byte 0 XOR byte 1 XOR ... byte n). - -// // // Update the flags and the A register. -// // UpdateFlags(calculatedCheckSum); - - -// // // Set IX to the same value as if the block had been loaded by the ROM routine. -// // z80.I1 = lastBytePos / 256; -// // z80.X = lastBytePos - 256 * z80.I1; - -// // // Set DE to 0. -// // z80.D = 0; -// // z80.E = 0; -// // } - -// // // Keep track of the index of the last loaded tape block. This information -// // // can be used to rewind the tape to the start position of the next block -// // // after an auto pause. -// // lastBlockIndex = tapeManager.NextBlock.Index; - -// // // Skip forward to the end of the block which was just flash loaded into RAM. -// // tapeManager.GoToEndOfBlock(tapeManager.NextBlock.Index); - -// // // Skip to the end of the LD BYTES ROM routine (actually a RET, so it doesn't really matter which RET instruction we point to here). -// // z80.PC = 0x05E2; - -// } - -// // return lastBlockIndex; - -// // // Update the flags after loading a block of data. -// // void UpdateFlags(int checkSum) -// // { -// // // The flags are set by the CP 0x01 operation at 0x05E0, where A = the current checksum. -// // int flagTest = checkSum - 1; -// // z80.CarryFlag = BitOps.GetBit(flagTest, 8); -// // z80.SignFlag = Flags.SignFlag(flagTest); -// // z80.ZeroFlag = Flags.ZeroFlag(flagTest); -// // z80.HalfCarryFlag = Flags.HalfCarryFlagSub8(checkSum, 1, z80.CarryFlag); -// // z80.Parity_OverflowFlag = Flags.OverflowFlagSub8(checkSum, 1, flagTest); -// // z80.SubtractFlag = 1; -// // z80.F3Flag = 0; -// // z80.F5Flag = 0; - -// // z80.A = checkSum; -// // } -// // } -// // } -// // } - -// } - -// // public boolean flashLoad(Memory memory) { - -// // if (idxHeader >= nOffsetBlocks) { -// // // cpu.setCarryFlag(false); -// // return false; -// // } - -// // tapePos = offsetBlocks[idxHeader]; -// // blockLen = readInt(tapeBuffer, tapePos, 2); -// // // System.out.println(String.format("tapePos: %X. blockLen: %X", tapePos, blockLen)); -// // tapePos += 2; - -// // // ¿Coincide el flag? (está en el registro A) -// // if (cpu.getRegA() != (tapeBuffer[tapePos] & 0xff)) { -// // cpu.xor(tapeBuffer[tapePos]); -// // cpu.setCarryFlag(false); -// // idxHeader++; -// // return true; -// // } - -// // // La paridad incluye el byte de flag -// // cpu.setRegA(tapeBuffer[tapePos]); - -// // int count = 0; -// // int addr = cpu.getRegIX(); // Address start -// // int nBytes = cpu.getRegDE(); // Lenght -// // while (count < nBytes && count < blockLen - 1) { -// // memory.writeByte(addr, tapeBuffer[tapePos + count + 1]); -// // cpu.xor(tapeBuffer[tapePos + count + 1]); -// // addr = (addr + 1) & 0xffff; -// // count++; -// // } - -// // // Se cargarán los bytes pedidos en DE -// // if (count == nBytes) { -// // cpu.xor(tapeBuffer[tapePos + count + 1]); // Byte de paridad -// // cpu.cp(0x01); -// // } - -// // // Hay menos bytes en la cinta de los indicados en DE -// // // En ese caso habrá dado un error de timeout en LD-SAMPLE (0x05ED) -// // // que se señaliza con CARRY==reset & ZERO==set -// // if (count < nBytes) { -// // cpu.setFlags(0x50); // when B==0xFF, then INC B, B=0x00, F=0x50 -// // } - -// // cpu.setRegIX(addr); -// // cpu.setRegDE(nBytes - count); -// // idxHeader++; -// // fireTapeBlockChanged(idxHeader); - -// // // System.out.println(String.format("Salida -> IX: %04X DE: %04X AF: %04X", -// // // cpu.getRegIX(), cpu.getRegDE(), cpu.getRegAF())); -// // return true; -// // } - -// // private void fireTapeBlockChanged(final int block) { -// // blockListeners.forEach(listener -> { -// // listener.blockChanged(block); -// // }); -// // } - -// // saveTrap = settings.getTapeSettings().isEnableSaveTraps(); -// // z80.setBreakpoint(0x04D0, saveTrap); - -// // loadTrap = settings.getTapeSettings().isEnableLoadTraps(); -// // z80.setBreakpoint(0x0556, loadTrap); - -// // flashload = settings.getTapeSettings().isFlashLoad(); - - -// // case 0x04D0: -// // // SA_BYTES routine in Spectrum ROM at 0x04D0 -// // // SA_BYTES starts at 0x04C2, but the +3 ROM don't enter -// // // to SA_BYTES by his start address. -// // if (saveTrap && memory.isSpectrumRom() && tape.isTapeReady()) { -// // if (tape.saveTapeBlock(memory)) { -// // return 0xC9; // RET opcode -// // } -// // } -// // break; -// // case 0x0556: -// // // LD_BYTES routine in Spectrum ROM at address 0x0556 -// // if (loadTrap && memory.isSpectrumRom() && tape.isTapeReady()) { -// // if (flashload && tape.flashLoad(memory)) { -// // invalidateScreen(true); // thanks Andrew Owen -// // return 0xC9; // RET opcode -// // } else { -// // tape.play(false); -// // } -// // } -// // break; -// // } - - -// void Spectrum::trapLdStart() { - -// // ZF = 1 means treat the flag byte as a normal byte. This is -// // indicated by setting the number of flag bytes to zero. -// uint16_t flagByte = (z80.af_.b.l & FLAG_Z) ? 1 : 0; - -// // If either there are no flag bytes or the expected flag matches the -// // block's flag, we signal flag ok. Expected flag is in A'. -// bool flagOk = tape.foundTapBlock(z80.af_.b.h) || flagByte; - -// // CF = 1 means LOAD, CF = 0 means VERIFY. -// bool verify = !(z80.af_.b.l & FLAG_C); - -// if (flagOk) { -// // Get parameters from CPU registers -// uint16_t address = z80.ix.w; -// uint16_t bytes = z80.de.w; - -// uint16_t block = tape.getBlockLength() + flagByte - 1; // Include parity -// uint16_t offset = 3 - flagByte; -// uint8_t parity = flagByte ? 0 : tape.getBlockByte(2); - -// if (verify) { -// while (bytes && block) { -// uint8_t byte = tape.getBlockByte(offset++); -// uint8_t mem = readMemory(address++); -// block--; -// bytes--; -// parity ^= byte; -// if (byte != mem) break; -// } -// } else { -// while (bytes && block) { -// uint8_t byte = tape.getBlockByte(offset++); -// writeMemory(address++, byte); -// block--; -// bytes--; -// parity ^= byte; -// } -// } - -// if (block) { -// parity ^= tape.getBlockByte(offset); -// } - -// if (!bytes && block && !parity) { -// z80.af.b.l |= FLAG_C; -// } else { -// z80.af.b.l &= ~FLAG_C; -// if (!block) z80.af.b.l |= FLAG_Z; -// } - -// z80.hl.b.h = parity; -// z80.ix.w = address; -// z80.de.w = bytes; -// } - -// // Advance tape -// tape.nextTapBlock(); - -// // Force RET -// z80.decode(0xC9); -// z80.startInstruction(); - -// if (tape.tapPointer == 0) { -// tape.rewind(); -// } -// } From da19a2acf03b94d4d90ccb755359cafef7d7ffc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Sun, 13 Aug 2023 18:44:50 +0200 Subject: [PATCH 27/29] Road to rc2: refactoring and optimizing --- include/CPU.h | 12 +- include/FileSNA.h | 53 --- include/OSDMain.h | 5 +- include/{FileZ80.h => Snapshot.h} | 17 +- include/Z80_JLS/z80.h | 2 +- src/CPU.cpp | 25 +- src/ESPectrum.cpp | 10 +- src/FileSNA.cpp | 588 --------------------------- src/OSDMain.cpp | 60 ++- src/{FileZ80.cpp => Snapshot.cpp} | 651 +++++++++++++++++++++++------- src/Video.cpp | 14 - src/Z80_JLS.cpp | 2 +- 12 files changed, 554 insertions(+), 885 deletions(-) delete mode 100644 include/FileSNA.h rename include/{FileZ80.h => Snapshot.h} (83%) delete mode 100644 src/FileSNA.cpp rename src/{FileZ80.cpp => Snapshot.cpp} (67%) diff --git a/include/CPU.h b/include/CPU.h index 38255761..0dc024bd 100644 --- a/include/CPU.h +++ b/include/CPU.h @@ -39,6 +39,9 @@ visit https://zxespectrum.speccy.org/contacto #include #include "ESPectrum.h" +#define TSTATES_PER_FRAME_48 69888 +#define TSTATES_PER_FRAME_128 70908 + #define INT_START48 0 #define INT_END48 32 #define INT_START128 0 @@ -59,9 +62,6 @@ class CPU // Flush screen static void FlushOnHalt(); - // get the number of CPU Tstates per frame (machine dependant) - static uint32_t statesPerFrame(); - // get the number of microseconds per frame (machine dependant) static uint32_t microsPerFrame(); @@ -74,9 +74,6 @@ class CPU // CPU Tstates in frame static uint32_t statesInFrame; - // Frames elapsed - static uint32_t framecnt; - // Late timing static uint8_t latetiming; @@ -84,6 +81,9 @@ class CPU static uint8_t IntStart; static uint8_t IntEnd; + // Frames elapsed + static uint32_t framecnt; + }; static const unsigned char DRAM_ATTR wait_st[243] = { diff --git a/include/FileSNA.h b/include/FileSNA.h deleted file mode 100644 index 2d5ab668..00000000 --- a/include/FileSNA.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - -ESPectrum, a Sinclair ZX Spectrum emulator for Espressif ESP32 SoC - -Copyright (c) 2023 Víctor Iborra [Eremus] and David Crespo [dcrespo3d] -https://github.com/EremusOne/ZX-ESPectrum-IDF - -Based on ZX-ESPectrum-Wiimote -Copyright (c) 2020, 2022 David Crespo [dcrespo3d] -https://github.com/dcrespo3d/ZX-ESPectrum-Wiimote - -Based on previous work by Ramón Martinez and Jorge Fuertes -https://github.com/rampa069/ZX-ESPectrum - -Original project by Pete Todd -https://github.com/retrogubbins/paseVGA - -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 3 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, see . - -To Contact the dev team you can write to zxespectrum@gmail.com or -visit https://zxespectrum.speccy.org/contacto - -*/ - -#ifndef FileSNA_h -#define FileSNA_h - -#include -#include - -using namespace std; - -class FileSNA -{ -public: - static bool load(string sna_fn); - static bool save(string sna_fn); - static bool save(string sna_fn, bool blockMode); - static bool isPersistAvailable(string filename); -}; - -#endif \ No newline at end of file diff --git a/include/OSDMain.h b/include/OSDMain.h index 023972fa..7e6b80ff 100644 --- a/include/OSDMain.h +++ b/include/OSDMain.h @@ -107,13 +107,10 @@ class OSD static unsigned short menu_curopt; static unsigned int SaveRectpos; - // // Rows + // Rows static unsigned short rowCount(string menu); static string rowGet(string menu, unsigned short row_number); - // // Snapshot (SNA/Z80) Management - static void changeSnapshot(string sna_filename); - static void esp_hard_reset(); }; diff --git a/include/FileZ80.h b/include/Snapshot.h similarity index 83% rename from include/FileZ80.h rename to include/Snapshot.h index bd86b1d8..d739cf7c 100644 --- a/include/FileZ80.h +++ b/include/Snapshot.h @@ -33,8 +33,8 @@ visit https://zxespectrum.speccy.org/contacto */ -#ifndef FileZ80_h -#define FileZ80_h +#ifndef Snapshot_h +#define Snapshot_h #include #include @@ -42,10 +42,21 @@ visit https://zxespectrum.speccy.org/contacto using namespace std; +bool LoadSnapshot(string filename); + +class FileSNA +{ +public: + static string load(string sna_fn); + static bool save(string sna_fn); + static bool save(string sna_fn, bool blockMode); + static bool isPersistAvailable(string filename); +}; + class FileZ80 { public: - static bool load(string z80_fn); + static string load(string z80_fn); static void loader48(); static void loader128(); private: diff --git a/include/Z80_JLS/z80.h b/include/Z80_JLS/z80.h index 4f761c2a..29660c5d 100644 --- a/include/Z80_JLS/z80.h +++ b/include/Z80_JLS/z80.h @@ -218,7 +218,7 @@ class Z80 { #ifdef WITH_BREAKPOINT_SUPPORT static bool breakpointEnabled {false}; #endif - static void copyToRegister(uint8_t value); + static void IRAM_ATTR copyToRegister(uint8_t value); public: // Constructor de la clase diff --git a/src/CPU.cpp b/src/CPU.cpp index 0e68a33d..45f7695c 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -46,12 +46,6 @@ visit https://zxespectrum.speccy.org/contacto static bool createCalled = false; -uint32_t CPU::statesPerFrame() -{ - if (Config::getArch() == "48K") return 69888; - else return 70908; -} - uint32_t CPU::microsPerFrame() { if (Config::getArch() == "48K") return 19968; @@ -75,22 +69,22 @@ void CPU::setup() createCalled = true; } - statesInFrame = CPU::statesPerFrame(); - CPU::latetiming = Config::AluTiming; if (Config::getArch() == "48K") { VIDEO::getFloatBusData = &VIDEO::getFloatBusData48; Z80Ops::is48 = true; + statesInFrame = TSTATES_PER_FRAME_48; CPU::IntStart = INT_START48; CPU::IntEnd = INT_END48 + CPU::latetiming; } else { VIDEO::getFloatBusData = &VIDEO::getFloatBusData128; Z80Ops::is48 = false; + statesInFrame = TSTATES_PER_FRAME_128; CPU::IntStart = INT_START128; CPU::IntEnd = INT_END128 + CPU::latetiming; } - + tstates = 0; global_tstates = 0; @@ -102,18 +96,18 @@ void CPU::reset() { Z80::reset(); - statesInFrame = CPU::statesPerFrame(); - CPU::latetiming = Config::AluTiming; if (Config::getArch() == "48K") { VIDEO::getFloatBusData = &VIDEO::getFloatBusData48; Z80Ops::is48 = true; + statesInFrame = TSTATES_PER_FRAME_48; CPU::IntStart = INT_START48; CPU::IntEnd = INT_END48 + CPU::latetiming; } else { VIDEO::getFloatBusData = &VIDEO::getFloatBusData128; Z80Ops::is48 = false; + statesInFrame = TSTATES_PER_FRAME_128; CPU::IntStart = INT_START128; CPU::IntEnd = INT_END128 + CPU::latetiming; } @@ -128,15 +122,12 @@ void CPU::reset() { void IRAM_ATTR CPU::loop() { - while (tstates < IntEnd) - Z80::execute(); + while (tstates < IntEnd) Z80::execute(); uint32_t stFrame = statesInFrame - IntEnd; - while (tstates < stFrame) - Z80::exec_nocheck(); + while (tstates < stFrame) Z80::exec_nocheck(); - while (tstates < statesInFrame) - Z80::execute(); + while (tstates < statesInFrame) Z80::execute(); if (tstates & 0xFF000000) FlushOnHalt(); // If we're halted flush screen and update registers as needed diff --git a/src/ESPectrum.cpp b/src/ESPectrum.cpp index 9006d558..09a7c387 100644 --- a/src/ESPectrum.cpp +++ b/src/ESPectrum.cpp @@ -37,8 +37,7 @@ visit https://zxespectrum.speccy.org/contacto #include #include "ESPectrum.h" -#include "FileSNA.h" -#include "FileZ80.h" +#include "Snapshot.h" #include "Config.h" #include "FileUtils.h" #include "OSDMain.h" @@ -510,14 +509,9 @@ void ESPectrum::setup() // Load snapshot if present in Config::ram_file if (Config::ram_file != NO_RAM_FILE) { - if (FileUtils::hasSNAextension(Config::ram_file)) - FileSNA::load(Config::ram_file); - else if (FileUtils::hasZ80extension(Config::ram_file)) - FileZ80::load(Config::ram_file); + LoadSnapshot(Config::ram_file); Config::last_ram_file = Config::ram_file; - - // ESP host reset #ifndef SNAPSHOT_LOAD_LAST Config::ram_file = NO_RAM_FILE; Config::save("ram"); diff --git a/src/FileSNA.cpp b/src/FileSNA.cpp deleted file mode 100644 index e1b0b9a5..00000000 --- a/src/FileSNA.cpp +++ /dev/null @@ -1,588 +0,0 @@ -/* - -ESPectrum, a Sinclair ZX Spectrum emulator for Espressif ESP32 SoC - -Copyright (c) 2023 Víctor Iborra [Eremus] and David Crespo [dcrespo3d] -https://github.com/EremusOne/ZX-ESPectrum-IDF - -Based on ZX-ESPectrum-Wiimote -Copyright (c) 2020, 2022 David Crespo [dcrespo3d] -https://github.com/dcrespo3d/ZX-ESPectrum-Wiimote - -Based on previous work by Ramón Martinez and Jorge Fuertes -https://github.com/rampa069/ZX-ESPectrum - -Original project by Pete Todd -https://github.com/retrogubbins/paseVGA - -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 3 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, see . - -To Contact the dev team you can write to zxespectrum@gmail.com or -visit https://zxespectrum.speccy.org/contacto - -*/ - -#include "hardconfig.h" -#include "FileUtils.h" -#include "Config.h" -#include "CPU.h" -#include "Video.h" -#include "MemESP.h" -#include "ESPectrum.h" -#include "Ports.h" -#include "messages.h" -#include "OSDMain.h" -#include "FileSNA.h" -#include "Tape.h" -#include "AySound.h" -#include "pwm_audio.h" - -#include -#include -#include -#include -#include - -using namespace std; - -// /////////////////////////////////////////////////////////////////////////////// - -#include "Z80_JLS/z80.h" - -#define Z80_GET_AF() Z80::getRegAF() -#define Z80_GET_BC() Z80::getRegBC() -#define Z80_GET_DE() Z80::getRegDE() -#define Z80_GET_HL() Z80::getRegHL() - -#define Z80_GET_AFx() Z80::getRegAFx() -#define Z80_GET_BCx() Z80::getRegBCx() -#define Z80_GET_DEx() Z80::getRegDEx() -#define Z80_GET_HLx() Z80::getRegHLx() - -#define Z80_GET_IY() Z80::getRegIY() -#define Z80_GET_IX() Z80::getRegIX() - -#define Z80_GET_SP() Z80::getRegSP() -#define Z80_GET_PC() Z80::getRegPC() - -#define Z80_GET_I() Z80::getRegI() -#define Z80_GET_R() Z80::getRegR() -#define Z80_GET_IM() Z80::getIM() -#define Z80_GET_IFF1() Z80::isIFF1() -#define Z80_GET_IFF2() Z80::isIFF2() - -#define Z80_SET_AF(v) Z80::setRegAF(v) -#define Z80_SET_BC(v) Z80::setRegBC(v) -#define Z80_SET_DE(v) Z80::setRegDE(v) -#define Z80_SET_HL(v) Z80::setRegHL(v) - -#define Z80_SET_AFx(v) Z80::setRegAFx(v) -#define Z80_SET_BCx(v) Z80::setRegBCx(v) -#define Z80_SET_DEx(v) Z80::setRegDEx(v) -#define Z80_SET_HLx(v) Z80::setRegHLx(v) - -#define Z80_SET_IY(v) Z80::setRegIY(v) -#define Z80_SET_IX(v) Z80::setRegIX(v) - -#define Z80_SET_SP(v) Z80::setRegSP(v) -#define Z80_SET_PC(v) Z80::setRegPC(v) - -#define Z80_SET_I(v) Z80::setRegI(v) -#define Z80_SET_R(v) Z80::setRegR(v) -#define Z80_SET_IM(v) Z80::setIM((Z80::IntMode)(v)) -#define Z80_SET_IFF1(v) Z80::setIFF1(v) -#define Z80_SET_IFF2(v) Z80::setIFF2(v) - -// /////////////////////////////////////////////////////////////////////////////// - -bool FileSNA::load(string sna_fn) -{ - FILE *file; - int sna_size; - - // Stop keyboard input - ESPectrum::PS2Controller.keyboard()->suspendPort(); - // Stop audio - pwm_audio_stop(); - - file = fopen(sna_fn.c_str(), "rb"); - if (file==NULL) - { - printf("FileSNA: Error opening %s\n",sna_fn.c_str()); - - // Resume audio - pwm_audio_start(); - // Resume keyboard input - ESPectrum::PS2Controller.keyboard()->resumePort(); - - return false; - - } - - fseek(file,0,SEEK_END); - sna_size = ftell(file); - rewind (file); - - if (sna_size < SNA_48K_SIZE) { - printf("FileSNA::load: bad SNA %s: size = %d < %d\n", sna_fn.c_str(), sna_size, SNA_48K_SIZE); - - // Resume audio - pwm_audio_start(); - // Resume keyboard input - ESPectrum::PS2Controller.keyboard()->resumePort(); - - return false; - } - - printf("FileSNA::load: Opening %s: size = %d\n", sna_fn.c_str(), sna_size); - - string snapshotArch = "48K"; - - // Reset Z80 - Z80::reset(); - - MemESP::bankLatch = 0; - MemESP::pagingLock = 1; - MemESP::videoLatch = 0; - MemESP::romLatch = 0; - MemESP::romInUse = 0; - - // Read in the registers - Z80_SET_I(readByteFile(file)); - - Z80_SET_HLx(readWordFileLE(file)); - Z80_SET_DEx(readWordFileLE(file)); - Z80_SET_BCx(readWordFileLE(file)); - Z80_SET_AFx(readWordFileLE(file)); - - Z80_SET_HL(readWordFileLE(file)); - Z80_SET_DE(readWordFileLE(file)); - Z80_SET_BC(readWordFileLE(file)); - - Z80_SET_IY(readWordFileLE(file)); - Z80_SET_IX(readWordFileLE(file)); - - uint8_t inter = readByteFile(file); - Z80_SET_IFF2((inter & 0x04) ? true : false); - Z80_SET_IFF1(Z80_GET_IFF2()); - Z80_SET_R(readByteFile(file)); - - Z80_SET_AF(readWordFileLE(file)); - Z80_SET_SP(readWordFileLE(file)); - - Z80_SET_IM(readByteFile(file)); - - VIDEO::borderColor = readByteFile(file); - VIDEO::brd = VIDEO::border32[VIDEO::borderColor]; - - // read 48K memory - readBlockFile(file, MemESP::ram5, 0x4000); - readBlockFile(file, MemESP::ram2, 0x4000); - readBlockFile(file, MemESP::ram0, 0x4000); - - if (sna_size == SNA_48K_SIZE) - { - snapshotArch = "48K"; - - // in 48K mode, pop PC from stack - uint16_t SP = Z80_GET_SP(); - Z80_SET_PC(MemESP::readword(SP)); - Z80_SET_SP(SP + 2); - } - else - { - snapshotArch = "128K"; - - // in 128K mode, recover stored PC - Z80_SET_PC(readWordFileLE(file)); - - // tmp_port contains page switching status, including current page number (latch) - uint8_t tmp_port = readByteFile(file); - uint8_t tmp_latch = tmp_port & 0x07; - - // copy what was read into page 0 to correct page - memcpy(MemESP::ram[tmp_latch], MemESP::ram[0], 0x4000); - - uint8_t tr_dos = readByteFile(file); // unused - - // read remaining pages - for (int page = 0; page < 8; page++) { - if (page != tmp_latch && page != 2 && page != 5) { - readBlockFile(file, MemESP::ram[page], 0x4000); - } - } - - // decode tmp_port - MemESP::videoLatch = bitRead(tmp_port, 3); - MemESP::romLatch = bitRead(tmp_port, 4); - MemESP::pagingLock = bitRead(tmp_port, 5); - MemESP::bankLatch = tmp_latch; - MemESP::romInUse = MemESP::romLatch; - - } - - fclose(file); - - // Arch check - if (Config::getArch() == "128K") { - if (snapshotArch == "48K") { - #ifdef SNAPSHOT_LOAD_FORCE_ARCH - Config::requestMachine("48K", "SINCLAIR", true); - - // Condition this to 50hz mode - if(Config::videomode) { - Config::ram_file = sna_fn; - Config::save(); - OSD::esp_hard_reset(); - } - - MemESP::romInUse = 0; - #else - MemESP::romInUse = 1; - #endif - } - } - else if (Config::getArch() == "48K") { - if (snapshotArch == "128K") { - Config::requestMachine("128K", "SINCLAIR", true); - - // Condition this to 50hz mode - if(Config::videomode) { - Config::ram_file = sna_fn; - Config::save(); - OSD::esp_hard_reset(); - } - - MemESP::romInUse = 1; - } - } - - // Ports - for (int i = 0; i < 128; i++) Ports::port[i] = 0xBF; - if (Config::joystick) Ports::port[0x1f] = 0; // Kempston - - CPU::statesInFrame = CPU::statesPerFrame(); - CPU::tstates = 0; - CPU::global_tstates = 0; - ESPectrum::target = CPU::microsPerFrame(); - ESPectrum::ESPoffset = 0; - - if (Config::getArch() == "48K") { - - Z80Ops::is48 = true; - - VIDEO::tStatesPerLine = TSTATES_PER_LINE; - VIDEO::tStatesScreen = Config::aspect_16_9 ? TS_SCREEN_360x200 : TS_SCREEN_320x240; - VIDEO::getFloatBusData = &VIDEO::getFloatBusData48; - - ESPectrum::overSamplesPerFrame=ESP_AUDIO_OVERSAMPLES_48; - ESPectrum::samplesPerFrame=ESP_AUDIO_SAMPLES_48; - ESPectrum::AY_emu = Config::AY48; - ESPectrum::Audio_freq = ESP_AUDIO_FREQ_48; - - CPU::latetiming = Config::AluTiming; - - CPU::IntStart = INT_START48; - CPU::IntEnd = INT_END48 + CPU::latetiming; - - // VIDEO::contendMod=224; - // VIDEO::contendOffset=1; - - } else { - - Z80Ops::is48 = false; - - VIDEO::tStatesPerLine = TSTATES_PER_LINE_128; - VIDEO::tStatesScreen = Config::aspect_16_9 ? TS_SCREEN_360x200_128 : TS_SCREEN_320x240_128; - VIDEO::getFloatBusData = &VIDEO::getFloatBusData128; - - ESPectrum::overSamplesPerFrame=ESP_AUDIO_OVERSAMPLES_128; - ESPectrum::samplesPerFrame=ESP_AUDIO_SAMPLES_128; - ESPectrum::AY_emu = true; - ESPectrum::Audio_freq = ESP_AUDIO_FREQ_128; - - CPU::latetiming = Config::AluTiming; - - CPU::IntStart = INT_START128; - CPU::IntEnd = INT_END128 + CPU::latetiming; - - // VIDEO::contendMod=228; - // VIDEO::contendOffset=3; - - } - - VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; - VIDEO::Draw = &VIDEO::Blank; - - MemESP::ramCurrent[0] = (unsigned char *)MemESP::rom[MemESP::romInUse]; - MemESP::ramCurrent[1] = (unsigned char *)MemESP::ram[5]; - MemESP::ramCurrent[2] = (unsigned char *)MemESP::ram[2]; - MemESP::ramCurrent[3] = (unsigned char *)MemESP::ram[MemESP::bankLatch]; - - MemESP::ramContended[0] = false; - MemESP::ramContended[1] = true; - MemESP::ramContended[2] = false; - MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; - - Tape::tapeFileName = "none"; - if (Tape::tape != NULL) { - fclose(Tape::tape); - Tape::tape = NULL; - } - Tape::tapeStatus = TAPE_STOPPED; - Tape::SaveStatus = SAVE_STOPPED; - Tape::romLoading = false; - - // Empty audio buffers - for (int i=0;iresumePort(); - - return true; - -} - -// /////////////////////////////////////////////////////////////////////////////// - -bool FileSNA::isPersistAvailable(string filename) -{ - - bool res = true; - - pwm_audio_stop(); - - FILE *f = fopen(filename.c_str(), "rb"); - if (f == NULL) - res = false; - else - fclose(f); - - pwm_audio_start(); - - return res; - -} - -// /////////////////////////////////////////////////////////////////////////////// - -bool check_and_create_directory(const char* path) { - struct stat st; - if (stat(path, &st) == 0) { - if ((st.st_mode & S_IFDIR) != 0) { - printf("Directory exists\n"); - return true; - } else { - printf("Path exists but it is not a directory\n"); - // Create the directory - if (mkdir(path, 0755) == 0) { - printf("Directory created\n"); - return true; - } else { - printf("Failed to create directory\n"); - return false; - } - } - } else { - printf("Directory does not exist\n"); - // Create the directory - if (mkdir(path, 0755) == 0) { - printf("Directory created\n"); - return true; - } else { - printf("Failed to create directory\n"); - return false; - } - } -} - -// /////////////////////////////////////////////////////////////////////////////// - -static bool writeMemPage(uint8_t page, FILE *file, bool blockMode) -{ - page = page & 0x07; - uint8_t* buffer = MemESP::ram[page]; - - // printf("writing page %d in [%s] mode\n", page, blockMode ? "block" : "byte"); - - if (blockMode) { - // Writing blocks should be faster, but fails sometimes when flash is getting full. - for (int offset = 0; offset < MEM_PG_SZ; offset+=0x4000) { - // printf("writing block from page %d at offset %d\n", page, offset); - if (1 != fwrite(&buffer[offset],0x4000,1,file)) { - printf("error writing block from page %d at offset %d\n", page, offset); - return false; - } - } - } - else { - for (int offset = 0; offset < MEM_PG_SZ; offset++) { - uint8_t b = buffer[offset]; - if (1 != fwrite(&b,1,1,file)) { - printf("error writing byte from page %d at offset %d\n", page, offset); - return false; - } - } - } - return true; -} - -// /////////////////////////////////////////////////////////////////////////////// - -bool FileSNA::save(string sna_file) { - - // Try to save using pages - if (FileSNA::save(sna_file, true)) return true; - - OSD::osdCenteredMsg(OSD_PSNA_SAVE_WARN, LEVEL_WARN); - - // Try to save byte-by-byte - return FileSNA::save(sna_file, false); - -} - -// /////////////////////////////////////////////////////////////////////////////// - -bool FileSNA::save(string sna_file, bool blockMode) { - - FILE *file; - - // Stop keyboard input - ESPectrum::PS2Controller.keyboard()->suspendPort(); - - // Stop audio - pwm_audio_stop(); - - file = fopen(sna_file.c_str(), "wb"); - if (file==NULL) - { - printf("FileSNA: Error opening %s for writing",sna_file.c_str()); - - // Resume audio - pwm_audio_start(); - - // Resume keyboard input - ESPectrum::PS2Controller.keyboard()->resumePort(); - - return false; - } - - // write registers: begin with I - writeByteFile(Z80_GET_I(), file); - - writeWordFileLE(Z80_GET_HLx(), file); - writeWordFileLE(Z80_GET_DEx(), file); - writeWordFileLE(Z80_GET_BCx(), file); - writeWordFileLE(Z80_GET_AFx(), file); - - writeWordFileLE(Z80_GET_HL(), file); - writeWordFileLE(Z80_GET_DE(), file); - writeWordFileLE(Z80_GET_BC(), file); - - writeWordFileLE(Z80_GET_IY(), file); - writeWordFileLE(Z80_GET_IX(), file); - - uint8_t inter = Z80_GET_IFF2() ? 0x04 : 0; - writeByteFile(inter, file); - writeByteFile(Z80_GET_R(), file); - - writeWordFileLE(Z80_GET_AF(), file); - - uint16_t SP = Z80_GET_SP(); - if (Config::getArch() == "48K") { - // decrement stack pointer it for pushing PC to stack, only on 48K - SP -= 2; - MemESP::writeword(SP, Z80_GET_PC()); - } - writeWordFileLE(SP, file); - - writeByteFile(Z80_GET_IM(), file); - uint8_t bordercol = VIDEO::borderColor; - writeByteFile(bordercol, file); - - // write RAM pages in 48K address space (0x4000 - 0xFFFF) - uint8_t pages[3] = {5, 2, 0}; - if (Config::getArch() == "128K") - pages[2] = MemESP::bankLatch; - - for (uint8_t ipage = 0; ipage < 3; ipage++) { - uint8_t page = pages[ipage]; - if (!writeMemPage(page, file, blockMode)) { - fclose(file); - // Resume audio - pwm_audio_start(); - // Resume keyboard input - ESPectrum::PS2Controller.keyboard()->resumePort(); - return false; - } - } - - if (Config::getArch() == "48K") - { - // nothing to do here - } - else if (Config::getArch() == "128K") - { - // write pc - writeWordFileLE(Z80_GET_PC(), file); - - // write memESP bank control port - uint8_t tmp_port = MemESP::bankLatch; - bitWrite(tmp_port, 3, MemESP::videoLatch); - bitWrite(tmp_port, 4, MemESP::romLatch); - bitWrite(tmp_port, 5, MemESP::pagingLock); - writeByteFile(tmp_port, file); - - writeByteFile(0, file); // TR-DOS not paged - - // write remaining ram pages - for (int page = 0; page < 8; page++) { - if (page != MemESP::bankLatch && page != 2 && page != 5) { - if (!writeMemPage(page, file, blockMode)) { - fclose(file); - // Resume audio - pwm_audio_start(); - // Resume keyboard input - ESPectrum::PS2Controller.keyboard()->resumePort(); - return false; - } - } - } - } - - fclose(file); - - // Resume audio - pwm_audio_start(); - // Resume keyboard input - ESPectrum::PS2Controller.keyboard()->resumePort(); - - return true; -} diff --git a/src/OSDMain.cpp b/src/OSDMain.cpp index ee6d13b3..bd4af585 100644 --- a/src/OSDMain.cpp +++ b/src/OSDMain.cpp @@ -40,8 +40,7 @@ visit https://zxespectrum.speccy.org/contacto #include "ESPectrum.h" #include "messages.h" #include "Config.h" -#include "FileSNA.h" -#include "FileZ80.h" +#include "Snapshot.h" #include "MemESP.h" #include "Tape.h" #include "ZXKeyb.h" @@ -189,7 +188,7 @@ static bool persistLoad(uint8_t slotnumber) OSD::osdCenteredMsg(OSD_PSNA_NOT_AVAIL, LEVEL_INFO); return false; } else { - if (!FileSNA::load(FileUtils::MountPoint + DISK_PSNA_DIR + "/" + persistfname)) { + if (!LoadSnapshot(FileUtils::MountPoint + DISK_PSNA_DIR + "/" + persistfname)) { OSD::osdCenteredMsg(OSD_PSNA_LOAD_ERR, LEVEL_WARN); return false; } else { @@ -232,7 +231,13 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { string mFile = menuFile(FileUtils::MountPoint + DISK_SNA_DIR, MENU_SNA_TITLE[Config::lang],".sna.SNA.z80.Z80"); if (mFile != "") { mFile.erase(0, 1); - changeSnapshot(FileUtils::MountPoint + DISK_SNA_DIR + "/" + mFile); + string fname = FileUtils::MountPoint + DISK_SNA_DIR + "/" + mFile; + LoadSnapshot(fname); + Config::ram_file = fname; + #ifdef SNAPSHOT_LOAD_LAST + Config::save("ram"); + #endif + Config::last_ram_file = fname; } } else if (KeytoESP == fabgl::VK_F3) { @@ -463,7 +468,13 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { string mFile = menuFile(FileUtils::MountPoint + DISK_SNA_DIR, MENU_SNA_TITLE[Config::lang],".sna.SNA.z80.Z80"); if (mFile != "") { mFile.erase(0, 1); - changeSnapshot(FileUtils::MountPoint + DISK_SNA_DIR + "/" + mFile); + string fname = FileUtils::MountPoint + DISK_SNA_DIR + "/" + mFile; + LoadSnapshot(fname); + Config::ram_file = fname; + #ifdef SNAPSHOT_LOAD_LAST + Config::save("ram"); + #endif + Config::last_ram_file = fname; return; } } @@ -601,9 +612,13 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { uint8_t opt2 = menuRun(MENU_RESET[Config::lang]); if (opt2 == 1) { // Soft - if (Config::last_ram_file != NO_RAM_FILE) - changeSnapshot(Config::last_ram_file); - else ESPectrum::reset(); + if (Config::last_ram_file != NO_RAM_FILE) { + LoadSnapshot(Config::last_ram_file); + Config::ram_file = Config::last_ram_file; + #ifdef SNAPSHOT_LOAD_LAST + Config::save("ram"); + #endif + } else ESPectrum::reset(); return; } else if (opt2 == 2) { @@ -1266,32 +1281,3 @@ string OSD::rowGet(string menu, unsigned short row) { } return ""; } - -// Change running snapshot -void OSD::changeSnapshot(string filename) -{ - // string dir = FileUtils::MountPoint + DISK_SNA_DIR; - - if (FileUtils::hasSNAextension(filename)) - { - - osdCenteredMsg(MSG_LOADING_SNA + (string) ": " + filename, LEVEL_INFO, 0); - // printf("Loading SNA: <%s>\n", (dir + "/" + filename).c_str()); - FileSNA::load(filename); - - } - else if (FileUtils::hasZ80extension(filename)) - { - osdCenteredMsg(MSG_LOADING_Z80 + (string)": " + filename, LEVEL_INFO, 0); - // printf("Loading Z80: %s\n", filename.c_str()); - FileZ80::load(filename); - - } - - Config::ram_file = filename; - #ifdef SNAPSHOT_LOAD_LAST - Config::save("ram"); - #endif - Config::last_ram_file = filename; - -} diff --git a/src/FileZ80.cpp b/src/Snapshot.cpp similarity index 67% rename from src/FileZ80.cpp rename to src/Snapshot.cpp index 1a73243d..9b8637ff 100644 --- a/src/FileZ80.cpp +++ b/src/Snapshot.cpp @@ -33,54 +33,540 @@ visit https://zxespectrum.speccy.org/contacto */ +#include "Snapshot.h" #include "hardconfig.h" -#include "FileZ80.h" #include "FileUtils.h" +#include "Config.h" #include "CPU.h" #include "Video.h" -#include "Ports.h" #include "MemESP.h" #include "ESPectrum.h" +#include "Ports.h" #include "messages.h" #include "OSDMain.h" +#include "Tape.h" +#include "AySound.h" +#include "pwm_audio.h" +#include "Z80_JLS/z80.h" #include "Config.h" #include "Tape.h" #include "pwm_audio.h" #include "AySound.h" #include "loaders.h" -/////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include -#include "Z80_JLS/z80.h" +using namespace std; -/////////////////////////////////////////////////////////////////////////////// +// Change running snapshot +bool LoadSnapshot(string filename) +{ + + bool res = false; + string snapshotArch = ""; + + // Stop keyboard input + ESPectrum::PS2Controller.keyboard()->suspendPort(); + // Stop audio + pwm_audio_stop(); + + if (FileUtils::hasSNAextension(filename)) { + OSD::osdCenteredMsg(MSG_LOADING_SNA + (string) ": " + filename, LEVEL_INFO, 0); + snapshotArch = FileSNA::load(filename); + } else + if (FileUtils::hasZ80extension(filename)) { + OSD::osdCenteredMsg(MSG_LOADING_Z80 + (string)": " + filename, LEVEL_INFO, 0); + snapshotArch = FileZ80::load(filename); + } + + if (snapshotArch != "") { + + // Arch check + if (Config::getArch() == "128K") { + if (snapshotArch == "48K") { + #ifdef SNAPSHOT_LOAD_FORCE_ARCH + Config::requestMachine("48K", "SINCLAIR", true); + + // Condition this to 50hz mode + if(Config::videomode) { + Config::ram_file = filename; + Config::save(); + OSD::esp_hard_reset(); + } + + MemESP::romInUse = 0; + #else + MemESP::romInUse = 1; + #endif + } + } + else if (Config::getArch() == "48K") { + if (snapshotArch == "128K") { + Config::requestMachine("128K", "SINCLAIR", true); + + // Condition this to 50hz mode + if(Config::videomode) { + Config::ram_file = filename; + Config::save(); + OSD::esp_hard_reset(); + } + + MemESP::romInUse = 1; + } + } + + // Ports + for (int i = 0; i < 128; i++) Ports::port[i] = 0xBF; + if (Config::joystick) Ports::port[0x1f] = 0; // Kempston + + CPU::tstates = 0; + CPU::global_tstates = 0; + ESPectrum::target = CPU::microsPerFrame(); + ESPectrum::ESPoffset = 0; + + if (Config::getArch() == "48K") { + + Z80Ops::is48 = true; + + VIDEO::tStatesPerLine = TSTATES_PER_LINE; + VIDEO::tStatesScreen = Config::aspect_16_9 ? TS_SCREEN_360x200 : TS_SCREEN_320x240; + VIDEO::getFloatBusData = &VIDEO::getFloatBusData48; + + ESPectrum::overSamplesPerFrame=ESP_AUDIO_OVERSAMPLES_48; + ESPectrum::samplesPerFrame=ESP_AUDIO_SAMPLES_48; + ESPectrum::AY_emu = Config::AY48; + ESPectrum::Audio_freq = ESP_AUDIO_FREQ_48; + + CPU::latetiming = Config::AluTiming; + + CPU::statesInFrame = TSTATES_PER_FRAME_48; + CPU::IntStart = INT_START48; + CPU::IntEnd = INT_END48 + CPU::latetiming; + + } else { + + Z80Ops::is48 = false; + + VIDEO::tStatesPerLine = TSTATES_PER_LINE_128; + VIDEO::tStatesScreen = Config::aspect_16_9 ? TS_SCREEN_360x200_128 : TS_SCREEN_320x240_128; + VIDEO::getFloatBusData = &VIDEO::getFloatBusData128; + + ESPectrum::overSamplesPerFrame=ESP_AUDIO_OVERSAMPLES_128; + ESPectrum::samplesPerFrame=ESP_AUDIO_SAMPLES_128; + ESPectrum::AY_emu = true; + ESPectrum::Audio_freq = ESP_AUDIO_FREQ_128; + + CPU::latetiming = Config::AluTiming; + + CPU::statesInFrame = TSTATES_PER_FRAME_128; + CPU::IntStart = INT_START128; + CPU::IntEnd = INT_END128 + CPU::latetiming; + + } + + VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; + VIDEO::Draw = &VIDEO::Blank; + + MemESP::ramCurrent[0] = (unsigned char *)MemESP::rom[MemESP::romInUse]; + MemESP::ramCurrent[1] = (unsigned char *)MemESP::ram[5]; + MemESP::ramCurrent[2] = (unsigned char *)MemESP::ram[2]; + MemESP::ramCurrent[3] = (unsigned char *)MemESP::ram[MemESP::bankLatch]; + + MemESP::ramContended[0] = false; + MemESP::ramContended[1] = true; + MemESP::ramContended[2] = false; + MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; + + Tape::tapeFileName = "none"; + if (Tape::tape != NULL) { + fclose(Tape::tape); + Tape::tape = NULL; + } + Tape::tapeStatus = TAPE_STOPPED; + Tape::SaveStatus = SAVE_STOPPED; + Tape::romLoading = false; + + // Empty audio buffers + for (int i=0;iresumePort(); + + return res; -static uint16_t mkword(uint8_t lobyte, uint8_t hibyte) { - return lobyte | (hibyte << 8); } -bool FileZ80::load(string z80_fn) +string FileSNA::load(string sna_fn) { FILE *file; + int sna_size; + + file = fopen(sna_fn.c_str(), "rb"); + if (file==NULL) + { + printf("FileSNA: Error opening %s\n",sna_fn.c_str()); + return ""; + } + + fseek(file,0,SEEK_END); + sna_size = ftell(file); + rewind (file); + + if (sna_size < SNA_48K_SIZE) { + printf("FileSNA::load: bad SNA %s: size = %d < %d\n", sna_fn.c_str(), sna_size, SNA_48K_SIZE); + return ""; + } + + printf("FileSNA::load: Opening %s: size = %d\n", sna_fn.c_str(), sna_size); + + string snapshotArch = "48K"; + + // Reset Z80 + Z80::reset(); + + MemESP::bankLatch = 0; + MemESP::pagingLock = 1; + MemESP::videoLatch = 0; + MemESP::romLatch = 0; + MemESP::romInUse = 0; + + // Read in the registers + Z80::setRegI(readByteFile(file)); + + Z80::setRegHLx(readWordFileLE(file)); + Z80::setRegDEx(readWordFileLE(file)); + Z80::setRegBCx(readWordFileLE(file)); + Z80::setRegAFx(readWordFileLE(file)); + + Z80::setRegHL(readWordFileLE(file)); + Z80::setRegDE(readWordFileLE(file)); + Z80::setRegBC(readWordFileLE(file)); + + Z80::setRegIY(readWordFileLE(file)); + Z80::setRegIX(readWordFileLE(file)); + + uint8_t inter = readByteFile(file); + Z80::setIFF2(inter & 0x04 ? true : false); + Z80::setIFF1(Z80::isIFF2()); + Z80::setRegR(readByteFile(file)); + + Z80::setRegAF(readWordFileLE(file)); + Z80::setRegSP(readWordFileLE(file)); + + Z80::setIM((Z80::IntMode)(readByteFile(file))); + + VIDEO::borderColor = readByteFile(file); + VIDEO::brd = VIDEO::border32[VIDEO::borderColor]; + + // read 48K memory + readBlockFile(file, MemESP::ram5, 0x4000); + readBlockFile(file, MemESP::ram2, 0x4000); + readBlockFile(file, MemESP::ram0, 0x4000); + + if (sna_size == SNA_48K_SIZE) + { + snapshotArch = "48K"; + + // in 48K mode, pop PC from stack + uint16_t SP = Z80::getRegSP(); + Z80::setRegPC(MemESP::readword(SP)); + Z80::setRegSP(SP + 2); + } + else + { + snapshotArch = "128K"; + + // in 128K mode, recover stored PC + Z80::setRegPC(readWordFileLE(file)); + + // tmp_port contains page switching status, including current page number (latch) + uint8_t tmp_port = readByteFile(file); + uint8_t tmp_latch = tmp_port & 0x07; + + // copy what was read into page 0 to correct page + memcpy(MemESP::ram[tmp_latch], MemESP::ram[0], 0x4000); + + uint8_t tr_dos = readByteFile(file); // unused + + // read remaining pages + for (int page = 0; page < 8; page++) { + if (page != tmp_latch && page != 2 && page != 5) { + readBlockFile(file, MemESP::ram[page], 0x4000); + } + } + + // decode tmp_port + MemESP::videoLatch = bitRead(tmp_port, 3); + MemESP::romLatch = bitRead(tmp_port, 4); + MemESP::pagingLock = bitRead(tmp_port, 5); + MemESP::bankLatch = tmp_latch; + MemESP::romInUse = MemESP::romLatch; + + } + + fclose(file); + + return snapshotArch; + +} + +// /////////////////////////////////////////////////////////////////////////////// + +bool FileSNA::isPersistAvailable(string filename) +{ + + bool res = true; + + pwm_audio_stop(); + + FILE *f = fopen(filename.c_str(), "rb"); + if (f == NULL) + res = false; + else + fclose(f); + + pwm_audio_start(); + + return res; + +} + +// /////////////////////////////////////////////////////////////////////////////// + +bool check_and_create_directory(const char* path) { + struct stat st; + if (stat(path, &st) == 0) { + if ((st.st_mode & S_IFDIR) != 0) { + printf("Directory exists\n"); + return true; + } else { + printf("Path exists but it is not a directory\n"); + // Create the directory + if (mkdir(path, 0755) == 0) { + printf("Directory created\n"); + return true; + } else { + printf("Failed to create directory\n"); + return false; + } + } + } else { + printf("Directory does not exist\n"); + // Create the directory + if (mkdir(path, 0755) == 0) { + printf("Directory created\n"); + return true; + } else { + printf("Failed to create directory\n"); + return false; + } + } +} + +// /////////////////////////////////////////////////////////////////////////////// + +static bool writeMemPage(uint8_t page, FILE *file, bool blockMode) +{ + page = page & 0x07; + uint8_t* buffer = MemESP::ram[page]; + + // printf("writing page %d in [%s] mode\n", page, blockMode ? "block" : "byte"); + + if (blockMode) { + // Writing blocks should be faster, but fails sometimes when flash is getting full. + for (int offset = 0; offset < MEM_PG_SZ; offset+=0x4000) { + // printf("writing block from page %d at offset %d\n", page, offset); + if (1 != fwrite(&buffer[offset],0x4000,1,file)) { + printf("error writing block from page %d at offset %d\n", page, offset); + return false; + } + } + } + else { + for (int offset = 0; offset < MEM_PG_SZ; offset++) { + uint8_t b = buffer[offset]; + if (1 != fwrite(&b,1,1,file)) { + printf("error writing byte from page %d at offset %d\n", page, offset); + return false; + } + } + } + return true; +} + +// /////////////////////////////////////////////////////////////////////////////// + +bool FileSNA::save(string sna_file) { + + // Try to save using pages + if (FileSNA::save(sna_file, true)) return true; + + OSD::osdCenteredMsg(OSD_PSNA_SAVE_WARN, LEVEL_WARN); + + // Try to save byte-by-byte + return FileSNA::save(sna_file, false); + +} + +// /////////////////////////////////////////////////////////////////////////////// + +bool FileSNA::save(string sna_file, bool blockMode) { + + FILE *file; // Stop keyboard input ESPectrum::PS2Controller.keyboard()->suspendPort(); + // Stop audio pwm_audio_stop(); - file = fopen(z80_fn.c_str(), "rb"); + file = fopen(sna_file.c_str(), "wb"); if (file==NULL) { - printf("FileZ80: Error opening %s\n",z80_fn.c_str()); + printf("FileSNA: Error opening %s for writing",sna_file.c_str()); // Resume audio pwm_audio_start(); + // Resume keyboard input ESPectrum::PS2Controller.keyboard()->resumePort(); return false; } + // write registers: begin with I + writeByteFile(Z80::getRegI(), file); + + writeWordFileLE(Z80::getRegHLx(), file); + writeWordFileLE(Z80::getRegDEx(), file); + writeWordFileLE(Z80::getRegBCx(), file); + writeWordFileLE(Z80::getRegAFx(), file); + + writeWordFileLE(Z80::getRegHL(), file); + writeWordFileLE(Z80::getRegDE(), file); + writeWordFileLE(Z80::getRegBC(), file); + + writeWordFileLE(Z80::getRegIY(), file); + writeWordFileLE(Z80::getRegIX(), file); + + uint8_t inter = Z80::isIFF2() ? 0x04 : 0; + writeByteFile(inter, file); + writeByteFile(Z80::getRegR(), file); + + writeWordFileLE(Z80::getRegAF(), file); + + uint16_t SP = Z80::getRegSP(); + if (Config::getArch() == "48K") { + // decrement stack pointer it for pushing PC to stack, only on 48K + SP -= 2; + MemESP::writeword(SP, Z80::getRegPC()); + } + writeWordFileLE(SP, file); + + writeByteFile(Z80::getIM(), file); + uint8_t bordercol = VIDEO::borderColor; + writeByteFile(bordercol, file); + + // write RAM pages in 48K address space (0x4000 - 0xFFFF) + uint8_t pages[3] = {5, 2, 0}; + if (Config::getArch() == "128K") + pages[2] = MemESP::bankLatch; + + for (uint8_t ipage = 0; ipage < 3; ipage++) { + uint8_t page = pages[ipage]; + if (!writeMemPage(page, file, blockMode)) { + fclose(file); + // Resume audio + pwm_audio_start(); + // Resume keyboard input + ESPectrum::PS2Controller.keyboard()->resumePort(); + return false; + } + } + + if (Config::getArch() == "48K") + { + // nothing to do here + } + else if (Config::getArch() == "128K") + { + // write pc + writeWordFileLE( Z80::getRegPC(), file); + + // write memESP bank control port + uint8_t tmp_port = MemESP::bankLatch; + bitWrite(tmp_port, 3, MemESP::videoLatch); + bitWrite(tmp_port, 4, MemESP::romLatch); + bitWrite(tmp_port, 5, MemESP::pagingLock); + writeByteFile(tmp_port, file); + + writeByteFile(0, file); // TR-DOS not paged + + // write remaining ram pages + for (int page = 0; page < 8; page++) { + if (page != MemESP::bankLatch && page != 2 && page != 5) { + if (!writeMemPage(page, file, blockMode)) { + fclose(file); + // Resume audio + pwm_audio_start(); + // Resume keyboard input + ESPectrum::PS2Controller.keyboard()->resumePort(); + return false; + } + } + } + } + + fclose(file); + + // Resume audio + pwm_audio_start(); + // Resume keyboard input + ESPectrum::PS2Controller.keyboard()->resumePort(); + + return true; +} + +static uint16_t mkword(uint8_t lobyte, uint8_t hibyte) { + return lobyte | (hibyte << 8); +} + +string FileZ80::load(string z80_fn) +{ + FILE *file; + + file = fopen(z80_fn.c_str(), "rb"); + if (file == NULL) + { + printf("FileZ80: Error opening %s\n",z80_fn.c_str()); + return ""; + } + fseek(file,0,SEEK_END); uint32_t file_size = ftell(file); rewind (file); @@ -197,20 +683,11 @@ bool FileZ80::load(string z80_fn) else if (ahblen == 54 || ahblen == 55) version = 3; else { - OSD::osdCenteredMsg("Z80 load: unknown version", LEVEL_ERROR); // printf("Z80.load: unknown version, ahblen = %d\n", ahblen); - fclose(file); - - // Resume audio - pwm_audio_start(); - // Resume keyboard input - ESPectrum::PS2Controller.keyboard()->resumePort(); - ESPectrum::reset(); - - return false; + return ""; } // read additional header block @@ -328,139 +805,7 @@ bool FileZ80::load(string z80_fn) fclose(file); - // Arch check - if (Config::getArch() == "128K") { - if (fileArch == "48K") { - #ifdef SNAPSHOT_LOAD_FORCE_ARCH - Config::requestMachine("48K", "SINCLAIR", true); - - // Condition this to 50hz mode - if(Config::videomode) { - Config::ram_file = z80_fn; - Config::save(); - OSD::esp_hard_reset(); - } - - MemESP::romInUse = 0; - #else - MemESP::romInUse = 1; - #endif - } - } - else if (Config::getArch() == "48K") { - if (fileArch == "128K") { - Config::requestMachine("128K", "SINCLAIR", true); - - // Condition this to 50hz mode - if(Config::videomode) { - Config::ram_file = z80_fn; - Config::save(); - OSD::esp_hard_reset(); - } - - MemESP::romInUse = 1; - } - } - - // Ports - for (int i = 0; i < 128; i++) Ports::port[i] = 0xBF; - if (Config::joystick) Ports::port[0x1f] = 0; // Kempston - - CPU::statesInFrame = CPU::statesPerFrame(); - CPU::tstates = 0; - CPU::global_tstates = 0; - ESPectrum::target = CPU::microsPerFrame(); - ESPectrum::ESPoffset = 0; - - if (Config::getArch() == "48K") { - - Z80Ops::is48 = true; - - VIDEO::tStatesPerLine = TSTATES_PER_LINE; - VIDEO::tStatesScreen = Config::aspect_16_9 ? TS_SCREEN_360x200 : TS_SCREEN_320x240; - VIDEO::getFloatBusData = &VIDEO::getFloatBusData48; - - ESPectrum::overSamplesPerFrame=ESP_AUDIO_OVERSAMPLES_48; - ESPectrum::samplesPerFrame=ESP_AUDIO_SAMPLES_48; - ESPectrum::AY_emu = Config::AY48; - ESPectrum::Audio_freq = ESP_AUDIO_FREQ_48; - - CPU::latetiming = Config::AluTiming; - - CPU::IntStart = INT_START48; - CPU::IntEnd = INT_END48 + CPU::latetiming; - - // VIDEO::contendMod=224; - // VIDEO::contendOffset=1; - - } else { - - Z80Ops::is48 = false; - - VIDEO::tStatesPerLine = TSTATES_PER_LINE_128; - VIDEO::tStatesScreen = Config::aspect_16_9 ? TS_SCREEN_360x200_128 : TS_SCREEN_320x240_128; - VIDEO::getFloatBusData = &VIDEO::getFloatBusData128; - - ESPectrum::overSamplesPerFrame=ESP_AUDIO_OVERSAMPLES_128; - ESPectrum::samplesPerFrame=ESP_AUDIO_SAMPLES_128; - ESPectrum::AY_emu = true; - ESPectrum::Audio_freq = ESP_AUDIO_FREQ_128; - - CPU::latetiming = Config::AluTiming; - - CPU::IntStart = INT_START128; - CPU::IntEnd = INT_END128 + CPU::latetiming; - - // VIDEO::contendMod=228; - // VIDEO::contendOffset=3; - - } - - VIDEO::grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; - VIDEO::Draw = &VIDEO::Blank; - - MemESP::ramCurrent[0] = (unsigned char *)MemESP::rom[MemESP::romInUse]; - MemESP::ramCurrent[1] = (unsigned char *)MemESP::ram[5]; - MemESP::ramCurrent[2] = (unsigned char *)MemESP::ram[2]; - MemESP::ramCurrent[3] = (unsigned char *)MemESP::ram[MemESP::bankLatch]; - - MemESP::ramContended[0] = false; - MemESP::ramContended[1] = true; - MemESP::ramContended[2] = false; - MemESP::ramContended[3] = MemESP::bankLatch & 0x01 ? true: false; - - Tape::tapeFileName = "none"; - if (Tape::tape != NULL) { - fclose(Tape::tape); - Tape::tape = NULL; - } - Tape::tapeStatus = TAPE_STOPPED; - Tape::SaveStatus = SAVE_STOPPED; - Tape::romLoading = false; - - // Empty audio buffers - for (int i=0;iresumePort(); - - return true; + return fileArch; } diff --git a/src/Video.cpp b/src/Video.cpp index 02d1bbda..d5ba66ad 100644 --- a/src/Video.cpp +++ b/src/Video.cpp @@ -56,8 +56,6 @@ uint8_t* VIDEO::grmem; uint32_t* VIDEO::SaveRect; int VIDEO::VsyncFinetune[2]; // uint8_t VIDEO::dispUpdCycle; -// uint8_t VIDEO::contendOffset; -// uint8_t VIDEO::contendMod; void IRAM_ATTR VGA6Bit::interrupt(void *arg) { @@ -255,8 +253,6 @@ void VIDEO::Init() { VsyncFinetune[0] = is169 ? 0 : 0; VsyncFinetune[1] = is169 ? 0 : 0; } - // VIDEO::contendMod=224; - // VIDEO::contendOffset=1; } else { tStatesPerLine = TSTATES_PER_LINE_128; tStatesScreen = is169 ? TS_SCREEN_360x200_128 : TS_SCREEN_320x240_128; @@ -267,8 +263,6 @@ void VIDEO::Init() { VsyncFinetune[0] = is169 ? 0 : 0; VsyncFinetune[1] = is169 ? 0 : 0; } - // VIDEO::contendMod=228; - // VIDEO::contendOffset=3; } #ifdef NO_VIDEO @@ -296,8 +290,6 @@ void VIDEO::Reset() { VsyncFinetune[0] = is169 ? 0 : 0; VsyncFinetune[1] = is169 ? 0 : 0; } - // VIDEO::contendMod=224; - // VIDEO::contendOffset=1; } else { tStatesPerLine = TSTATES_PER_LINE_128; tStatesScreen = is169 ? TS_SCREEN_360x200_128 : TS_SCREEN_320x240_128; @@ -308,8 +300,6 @@ void VIDEO::Reset() { VsyncFinetune[0] = is169 ? 0 : 0; VsyncFinetune[1] = is169 ? 0 : 0; } - // VIDEO::contendMod=228; - // VIDEO::contendOffset=3; } grmem = MemESP::videoLatch ? MemESP::ram7 : MemESP::ram5; @@ -494,7 +484,6 @@ void IRAM_ATTR VIDEO::MainScreen_Blank(unsigned int statestoadd, bool contended) void IRAM_ATTR VIDEO::MainScreenLB(unsigned int statestoadd, bool contended) { - // if (contended) statestoadd += wait_st[(CPU::tstates + contendOffset) % contendMod]; if (contended) statestoadd += wait_st[CPU::tstates - tstateDraw]; CPU::tstates += statestoadd; @@ -535,7 +524,6 @@ void VIDEO::MainScreen(unsigned int statestoadd, bool contended) { uint8_t att, bmp; - // if (contended) statestoadd += wait_st[(CPU::tstates + contendOffset) % contendMod]; if (contended) statestoadd += wait_st[CPU::tstates - tstateDraw]; CPU::tstates += statestoadd; @@ -615,7 +603,6 @@ void VIDEO::MainScreen_OSD(unsigned int statestoadd, bool contended) { uint8_t att, bmp; - // if (contended) statestoadd += wait_st[(CPU::tstates + contendOffset) % contendMod]; if (contended) statestoadd += wait_st[CPU::tstates - tstateDraw]; CPU::tstates += statestoadd; @@ -661,7 +648,6 @@ void VIDEO::MainScreen_OSD(unsigned int statestoadd, bool contended) { void IRAM_ATTR VIDEO::MainScreenRB(unsigned int statestoadd, bool contended) { - // if (contended) statestoadd += wait_st[(CPU::tstates + contendOffset) % contendMod]; if (contended) statestoadd += wait_st[CPU::tstates - tstateDraw]; CPU::tstates += statestoadd; diff --git a/src/Z80_JLS.cpp b/src/Z80_JLS.cpp index f3902438..6f1d7d19 100644 --- a/src/Z80_JLS.cpp +++ b/src/Z80_JLS.cpp @@ -6003,7 +6003,7 @@ void Z80::decodeED(void) { } } -void Z80::copyToRegister(uint8_t value) +void IRAM_ATTR Z80::copyToRegister(uint8_t value) { switch (opCode & 0x07) { From 71e5341d287e06a50558d493330ca73360b50814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Tue, 22 Aug 2023 23:59:34 +0200 Subject: [PATCH 28/29] Refactoring and flashload fix for Bionic Commando --- include/FileUtils.h | 8 +- include/OSDMain.h | 16 +- src/FileUtils.cpp | 6 + src/OSDMain.cpp | 28 ++-- src/OSDMenu.cpp | 395 +++++++++++++++++++++++++++++++------------- src/Tape.cpp | 38 ++--- 6 files changed, 330 insertions(+), 161 deletions(-) diff --git a/include/FileUtils.h b/include/FileUtils.h index 2c8e35a1..92c6e187 100644 --- a/include/FileUtils.h +++ b/include/FileUtils.h @@ -47,8 +47,6 @@ using namespace std; // Defines #define ASCII_NL 10 -#define ON true -#define OFF false class FileUtils { @@ -71,6 +69,12 @@ class FileUtils static string MountPoint; static bool SDReady; + static string SNA_Path; // Current SNA path on the SD (for future folder support) + static string TAP_Path; // Current TAP path on the SD (for future folder support) + + static int curSNAFile; // Current SNA file index on browser + static int curTAPFile; // Current TAP file index on browser + private: friend class Config; static sdmmc_card_t *card; diff --git a/include/OSDMain.h b/include/OSDMain.h index 7e6b80ff..0da4e3c6 100644 --- a/include/OSDMain.h +++ b/include/OSDMain.h @@ -83,22 +83,24 @@ class OSD static void osdCenteredMsg(string msg, uint8_t warn_level, uint16_t millispause); // // Menu - static void newMenu(string new_menu); - static void menuRecalc(); + // static void newMenu(string new_menu); + // static void menuRecalc(); static unsigned short menuRealRowFor(uint8_t virtual_row_num); static bool menuIsSub(uint8_t virtual_row_num); static void menuPrintRow(uint8_t virtual_row_num, uint8_t line_type); - static void menuDraw(); + // static void menuDraw(); static void menuRedraw(); - static string getArchMenu(); - static string getRomsetMenu(string arch); + // static string getArchMenu(); + // static string getRomsetMenu(string arch); + static void WindowDraw(); static unsigned short menuRun(string new_menu); - static string menuFile(string new_menu, string title, string extensions); + static string menuFile(string new_menu, string title, string extensions, int currentFile); static int menuTape(string title); static void menuScroll(bool up); + // static void filemenuDraw(); static void filemenuRedraw(string title); static void tapemenuRedraw(string title); - static void filemenuPrintRow(uint8_t virtual_row_num, uint8_t line_type); + static void PrintRow(uint8_t virtual_row_num, uint8_t line_type); static void menuAt(short int row, short int col); static void menuScrollBar(); static void click(); diff --git a/src/FileUtils.cpp b/src/FileUtils.cpp index 2552aec2..7340455f 100644 --- a/src/FileUtils.cpp +++ b/src/FileUtils.cpp @@ -61,6 +61,12 @@ string FileUtils::MountPoint = MOUNT_POINT_SD; // Start with SD bool FileUtils::SDReady = false; sdmmc_card_t *FileUtils::card; +string FileUtils::SNA_Path = "/s"; // Current path on the SD (for future folder support) +string FileUtils::TAP_Path = "/t"; // Current path on the SD (for future folder support) + +int FileUtils::curSNAFile = 1; // Current SNA file index on browser +int FileUtils::curTAPFile = 1; // Current TAP file index on browser + void FileUtils::initFileSystem() { // Try to mount SD card on LILYGO TTGO VGA32 Board or ESPectrum Board diff --git a/src/OSDMain.cpp b/src/OSDMain.cpp index bd4af585..ce155edd 100644 --- a/src/OSDMain.cpp +++ b/src/OSDMain.cpp @@ -228,10 +228,10 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { else if (KeytoESP == fabgl::VK_F2) { menu_level = 0; menu_curopt = 1; - string mFile = menuFile(FileUtils::MountPoint + DISK_SNA_DIR, MENU_SNA_TITLE[Config::lang],".sna.SNA.z80.Z80"); + string mFile = menuFile(FileUtils::MountPoint + FileUtils::SNA_Path, MENU_SNA_TITLE[Config::lang],".sna.SNA.z80.Z80", FileUtils::curSNAFile); if (mFile != "") { mFile.erase(0, 1); - string fname = FileUtils::MountPoint + DISK_SNA_DIR + "/" + mFile; + string fname = FileUtils::MountPoint + FileUtils::SNA_Path + "/" + mFile; LoadSnapshot(fname); Config::ram_file = fname; #ifdef SNAPSHOT_LOAD_LAST @@ -261,7 +261,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { else if (KeytoESP == fabgl::VK_F5) { menu_level = 0; menu_curopt = 1; - string mFile = menuFile(FileUtils::MountPoint + DISK_TAP_DIR, MENU_TAP_TITLE[Config::lang],".tap.TAP"); + string mFile = menuFile(FileUtils::MountPoint + FileUtils::TAP_Path, MENU_TAP_TITLE[Config::lang],".tap.TAP",FileUtils::curTAPFile); if (mFile != "") { string keySel = mFile.substr(0,1); @@ -297,11 +297,11 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { Tape::TAP_Stop(); // Read and analyze tape file - Tape::Open(FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile); + Tape::Open(FileUtils::MountPoint + FileUtils::TAP_Path + "/" + mFile); ESPectrum::TapeNameScroller = 0; - // Tape::tapeFileName=FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile; + // Tape::tapeFileName=FileUtils::MountPoint + FileUtils::TAP_Path "/" + mFile; } @@ -465,10 +465,10 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { menu_saverect = true; if (sna_mnu == 1) { menu_curopt = 1; - string mFile = menuFile(FileUtils::MountPoint + DISK_SNA_DIR, MENU_SNA_TITLE[Config::lang],".sna.SNA.z80.Z80"); + string mFile = menuFile(FileUtils::MountPoint + FileUtils::SNA_Path, MENU_SNA_TITLE[Config::lang],".sna.SNA.z80.Z80",FileUtils::curSNAFile); if (mFile != "") { mFile.erase(0, 1); - string fname = FileUtils::MountPoint + DISK_SNA_DIR + "/" + mFile; + string fname = FileUtils::MountPoint + FileUtils::SNA_Path + "/" + mFile; LoadSnapshot(fname); Config::ram_file = fname; #ifdef SNAPSHOT_LOAD_LAST @@ -525,7 +525,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { if (tap_num == 1) { menu_curopt = 1; // Select TAP File - string mFile = menuFile(FileUtils::MountPoint + DISK_TAP_DIR, MENU_TAP_TITLE[Config::lang],".tap.TAP"); + string mFile = menuFile(FileUtils::MountPoint + FileUtils::TAP_Path, MENU_TAP_TITLE[Config::lang],".tap.TAP",FileUtils::curTAPFile); if (mFile != "") { string keySel = mFile.substr(0,1); @@ -561,7 +561,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { Tape::TAP_Stop(); // Read and analyze tape file - Tape::Open(FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile); + Tape::Open(FileUtils::MountPoint + FileUtils::TAP_Path + "/" + mFile); ESPectrum::TapeNameScroller = 0; @@ -702,11 +702,11 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { else if (opt2 == 2) { OSD::osdCenteredMsg("Refreshing snap dir", LEVEL_INFO, 0); - int chunks = FileUtils::DirToFile(FileUtils::MountPoint + DISK_SNA_DIR, ".sna.SNA.z80.Z80"); // Prepare sna filelist - if (chunks) FileUtils::Mergefiles(FileUtils::MountPoint + DISK_SNA_DIR,chunks); // Merge files + int chunks = FileUtils::DirToFile(FileUtils::MountPoint + FileUtils::SNA_Path, ".sna.SNA.z80.Z80"); // Prepare sna filelist + if (chunks) FileUtils::Mergefiles(FileUtils::MountPoint + FileUtils::SNA_Path,chunks); // Merge files OSD::osdCenteredMsg("Refreshing tape dir", LEVEL_INFO, 0); - chunks = FileUtils::DirToFile(FileUtils::MountPoint + DISK_TAP_DIR, ".tap.TAP"); // Prepare tap filelist - if (chunks) FileUtils::Mergefiles(FileUtils::MountPoint + DISK_TAP_DIR,chunks); // Merge files + chunks = FileUtils::DirToFile(FileUtils::MountPoint + FileUtils::TAP_Path, ".tap.TAP"); // Prepare tap filelist + if (chunks) FileUtils::Mergefiles(FileUtils::MountPoint + FileUtils::TAP_Path,chunks); // Merge files return; } menu_curopt = opt2; @@ -722,7 +722,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { menu_curopt = 1; menu_saverect = true; // Change ROM - string arch_menu = getArchMenu(); + string arch_menu = (string)MENU_ARCH[Config::lang]; uint8_t arch_num = menuRun(arch_menu); if (arch_num) { string arch = (arch_num==1 ? "48K" : "128K"); diff --git a/src/OSDMenu.cpp b/src/OSDMenu.cpp index c6c4118f..12b62c6d 100644 --- a/src/OSDMenu.cpp +++ b/src/OSDMenu.cpp @@ -81,6 +81,7 @@ static uint8_t last_focus; // To check for changes static unsigned short last_begin_row; // To check for changes uint8_t DRAM_ATTR click48[12]={0,0x16,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x16,0}; + uint8_t DRAM_ATTR click128[116]= { 0x00,0x16,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, 0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61,0x61, @@ -114,55 +115,64 @@ uint16_t OSD::zxColor(uint8_t color, uint8_t bright) { return spectrum_colors[color]; } -// Set menu and force recalc -void OSD::newMenu(string new_menu) { - menu = new_menu; - menuRecalc(); - menuDraw(); -} - -void OSD::menuRecalc() { - - // Position - if (menu_level == 0) { - x = (Config::aspect_16_9 ? 24 : 8); - y = 8; - } else { - x = (Config::aspect_16_9 ? 24 : 8) + (60 * menu_level); - if (menu_saverect) { - y += (8 + (8 * menu_prevopt)); - prev_y[menu_level] = y; - } else { - y = prev_y[menu_level]; - } - } - - // Rows - real_rows = rowCount(menu); - virtual_rows = (real_rows > MENU_MAX_ROWS ? MENU_MAX_ROWS : real_rows); - begin_row = last_begin_row = last_focus = focus = 1; - - // Columns - cols = 0; - uint8_t col_count = 0; - for (unsigned short i = 0; i < menu.length(); i++) { - if ((menu.at(i) == ASCII_TAB) || (menu.at(i) == ASCII_NL)) { - if (col_count > cols) { - cols = col_count; - } - while (menu.at(i) != ASCII_NL) i++; - col_count = 0; - } - col_count++; - } - cols += 8; - cols = (cols > 28 ? 28 : cols); - - // Size - w = (cols * OSD_FONT_W) + 2; - h = (virtual_rows * OSD_FONT_H) + 2; - -} +// // Set menu and force recalc +// void OSD::newMenu(string new_menu) { +// menu = new_menu; +// menuRecalc(); + +// // menuDraw(); + +// // focus = menu_curopt; +// // for (uint8_t r = 1; r < virtual_rows; r++) { +// // menuPrintRow(r, r == focus ? IS_FOCUSED : IS_NORMAL); +// // } + +// // menuScrollBar(); + +// } + +// void OSD::menuRecalc() { + +// // Position +// if (menu_level == 0) { +// x = (Config::aspect_16_9 ? 24 : 8); +// y = 8; +// } else { +// x = (Config::aspect_16_9 ? 24 : 8) + (60 * menu_level); +// if (menu_saverect) { +// y += (8 + (8 * menu_prevopt)); +// prev_y[menu_level] = y; +// } else { +// y = prev_y[menu_level]; +// } +// } + +// // Rows +// real_rows = rowCount(menu); +// virtual_rows = (real_rows > MENU_MAX_ROWS ? MENU_MAX_ROWS : real_rows); +// begin_row = last_begin_row = last_focus = focus = 1; + +// // Columns +// cols = 0; +// uint8_t col_count = 0; +// for (unsigned short i = 0; i < menu.length(); i++) { +// if ((menu.at(i) == ASCII_TAB) || (menu.at(i) == ASCII_NL)) { +// if (col_count > cols) { +// cols = col_count; +// } +// while (menu.at(i) != ASCII_NL) i++; +// col_count = 0; +// } +// col_count++; +// } +// cols += 8; +// cols = (cols > 28 ? 28 : cols); + +// // Size +// w = (cols * OSD_FONT_W) + 2; +// h = (virtual_rows * OSD_FONT_H) + 2; + +// } // Get real row number for a virtual one unsigned short OSD::menuRealRowFor(uint8_t virtual_row_num) { return begin_row + virtual_row_num - 1; } @@ -189,10 +199,7 @@ void OSD::menuPrintRow(uint8_t virtual_row_num, uint8_t line_type) { uint8_t margin; - // string line = rowGet(menu, menuRealRowFor(virtual_row_num)); - string line = rowGet(menu, virtual_row_num); - - // printf("%s\n",line.c_str()); + string line = rowGet(menu, menuRealRowFor(virtual_row_num)); switch (line_type) { case IS_TITLE: @@ -237,8 +244,103 @@ void OSD::menuPrintRow(uint8_t virtual_row_num, uint8_t line_type) { } +// // Draw the complete menu +// void OSD::menuDraw() { + +// // Set font +// VIDEO::vga.setFont(Font6x8); + +// if (menu_level!=0) { +// if (menu_saverect) { +// // Save backbuffer data +// VIDEO::SaveRect[SaveRectpos] = x; +// VIDEO::SaveRect[SaveRectpos + 1] = y; +// VIDEO::SaveRect[SaveRectpos + 2] = w; +// VIDEO::SaveRect[SaveRectpos + 3] = h; +// SaveRectpos += 4; +// for (int m = y; m < y + h; m++) { +// uint32_t *backbuffer32 = (uint32_t *)(VIDEO::vga.backBuffer[m]); +// for (int n = x >> 2; n < ((x + w) >> 2) + 1; n++) { +// VIDEO::SaveRect[SaveRectpos] = backbuffer32[n]; +// SaveRectpos++; +// } +// } +// //printf("Saverectpos after save: %d\n",SaveRectpos); +// } +// } else SaveRectpos = 0; + +// // Menu border +// VIDEO::vga.rect(x, y, w, h, OSD::zxColor(0, 0)); + +// // Title +// menuPrintRow(0, IS_TITLE); + +// // Rainbow +// unsigned short rb_y = y + 8; +// unsigned short rb_paint_x = x + w - 30; +// uint8_t rb_colors[] = {2, 6, 4, 5}; +// for (uint8_t c = 0; c < 4; c++) { +// for (uint8_t i = 0; i < 5; i++) { +// VIDEO::vga.line(rb_paint_x + i, rb_y, rb_paint_x + 8 + i, rb_y - 8, OSD::zxColor(rb_colors[c], 1)); +// } +// rb_paint_x += 5; +// } + +// // focus = menu_curopt; +// // for (uint8_t r = 1; r < virtual_rows; r++) { +// // menuPrintRow(r, r == focus ? IS_FOCUSED : IS_NORMAL); +// // } + +// // menuScrollBar(); + +// } + +// // Draw the complete menu +// void OSD::filemenuDraw() { + +// // Set font +// VIDEO::vga.setFont(Font6x8); + +// if (menu_level!=0) { +// if (menu_saverect) { +// // Save backbuffer data +// VIDEO::SaveRect[SaveRectpos] = x; +// VIDEO::SaveRect[SaveRectpos + 1] = y; +// VIDEO::SaveRect[SaveRectpos + 2] = w; +// VIDEO::SaveRect[SaveRectpos + 3] = h; +// SaveRectpos += 4; +// for (int m = y; m < y + h; m++) { +// uint32_t *backbuffer32 = (uint32_t *)(VIDEO::vga.backBuffer[m]); +// for (int n = x >> 2; n < ((x + w) >> 2) + 1; n++) { +// VIDEO::SaveRect[SaveRectpos] = backbuffer32[n]; +// SaveRectpos++; +// } +// } +// //printf("Saverectpos after save: %d\n",SaveRectpos); +// } +// } else SaveRectpos = 0; + +// // Menu border +// VIDEO::vga.rect(x, y, w, h, OSD::zxColor(0, 0)); + +// // Rainbow +// unsigned short rb_y = y + 8; +// unsigned short rb_paint_x = x + w - 30; +// uint8_t rb_colors[] = {2, 6, 4, 5}; +// for (uint8_t c = 0; c < 4; c++) { +// for (uint8_t i = 0; i < 5; i++) { +// VIDEO::vga.line(rb_paint_x + i, rb_y, rb_paint_x + 8 + i, rb_y - 8, OSD::zxColor(rb_colors[c], 1)); +// } +// rb_paint_x += 5; +// } + +// // Title +// PrintRow(0, IS_TITLE); + +// } + // Draw the complete menu -void OSD::menuDraw() { +void OSD::WindowDraw() { // Set font VIDEO::vga.setFont(Font6x8); @@ -266,7 +368,8 @@ void OSD::menuDraw() { VIDEO::vga.rect(x, y, w, h, OSD::zxColor(0, 0)); // Title - menuPrintRow(0, IS_TITLE); + PrintRow(0, IS_TITLE); + // Rainbow unsigned short rb_y = y + 8; unsigned short rb_paint_x = x + w - 30; @@ -277,31 +380,23 @@ void OSD::menuDraw() { } rb_paint_x += 5; } - // Focused first line - // menuPrintRow(1, IS_FOCUSED); - for (uint8_t r = 1; r < virtual_rows; r++) { - menuPrintRow(r, r == menu_curopt ? IS_FOCUSED : IS_NORMAL); - } - - focus = menu_curopt; - - menuScrollBar(); -} -string OSD::getArchMenu() { - string menu = (string)MENU_ARCH[Config::lang]; // + FileUtils::getFileEntriesFromDir(DISK_ROM_DIR); - return menu; } -string OSD::getRomsetMenu(string arch) { - string menu; - if (arch == "48K") { - menu = (string)MENU_ROMSET48[Config::lang]; // + FileUtils::getFileEntriesFromDir((string)DISK_ROM_DIR + "/" + arch); - } else { - menu = (string)MENU_ROMSET128[Config::lang]; - } - return menu; -} +// string OSD::getArchMenu() { +// string menu = (string)MENU_ARCH[Config::lang]; +// return menu; +// } + +// string OSD::getRomsetMenu(string arch) { +// string menu; +// if (arch == "48K") { +// menu = (string)MENU_ROMSET48[Config::lang]; // + FileUtils::getFileEntriesFromDir((string)DISK_ROM_DIR + "/" + arch); +// } else { +// menu = (string)MENU_ROMSET128[Config::lang]; +// } +// return menu; +// } #define REPDEL 140 // As in real ZX Spectrum (700 ms.) #define REPPER 20 // As in real ZX Spectrum (100 ms.) @@ -313,7 +408,56 @@ unsigned short OSD::menuRun(string new_menu) { fabgl::VirtualKeyItem Menukey; - newMenu(new_menu); + // newMenu(new_menu); + + menu = new_menu; + + // Position + if (menu_level == 0) { + x = (Config::aspect_16_9 ? 24 : 8); + y = 8; + } else { + x = (Config::aspect_16_9 ? 24 : 8) + (60 * menu_level); + if (menu_saverect) { + y += (8 + (8 * menu_prevopt)); + prev_y[menu_level] = y; + } else { + y = prev_y[menu_level]; + } + } + + // Rows + real_rows = rowCount(menu); + virtual_rows = (real_rows > MENU_MAX_ROWS ? MENU_MAX_ROWS : real_rows); + // begin_row = last_begin_row = last_focus = focus = 1; + + // Columns + cols = 0; + uint8_t col_count = 0; + for (unsigned short i = 0; i < menu.length(); i++) { + if ((menu.at(i) == ASCII_TAB) || (menu.at(i) == ASCII_NL)) { + if (col_count > cols) { + cols = col_count; + } + while (menu.at(i) != ASCII_NL) i++; + col_count = 0; + } + col_count++; + } + cols += 8; + cols = (cols > 28 ? 28 : cols); + + // Size + w = (cols * OSD_FONT_W) + 2; + h = (virtual_rows * OSD_FONT_H) + 2; + + WindowDraw(); // Draw menu outline + + begin_row = 1; + focus = menu_curopt; + last_begin_row = last_focus = 0; + + menuRedraw(); // Draw menu content zxDelay = REPDEL; lastzxKey = 0; @@ -532,6 +676,7 @@ void OSD::menuScroll(bool dir) { // Redraw inside rows void OSD::menuRedraw() { if ((focus != last_focus) || (begin_row != last_begin_row)) { + for (uint8_t row = 1; row < virtual_rows; row++) { if (row == focus) { menuPrintRow(row, IS_FOCUSED); @@ -542,7 +687,9 @@ void OSD::menuRedraw() { menuScrollBar(); last_focus = focus; last_begin_row = begin_row; + } + } // Draw menu scroll bar @@ -603,7 +750,7 @@ static inline void rtrim(std::string &s) { FILE *dirfile; // Run a new file menu -string OSD::menuFile(string filedir, string title, string extensions) { +string OSD::menuFile(string filedir, string title, string extensions, int currentFile) { fabgl::VirtualKeyItem Menukey; @@ -620,6 +767,7 @@ string OSD::menuFile(string filedir, string title, string extensions) { // OSD::osdCenteredMsg(" Done: directory index ready ", LEVEL_INFO); // precalcAluBytes(); rc = stat((filedir + "/.d").c_str(), &stat_buf); + currentFile = 1; } // Open dir file for read @@ -631,19 +779,17 @@ string OSD::menuFile(string filedir, string title, string extensions) { real_rows = (stat_buf.st_size / 32) + 1; // Add 1 for title virtual_rows = (real_rows > 19 ? 19 : real_rows); - begin_row = last_begin_row = last_focus = focus = 1; printf("Real rows: %d; st_size: %d\n",real_rows,stat_buf.st_size); - // Get first bunch of rows - menu = title + "\n"; - for (int i = 1; i < virtual_rows; i++) { - char buf[256]; - fgets(buf, sizeof(buf), dirfile); - if (feof(dirfile)) break; - menu += buf; - } - + // // Get first bunch of rows + // menu = title + "\n"; + // for (int i = 1; i < virtual_rows; i++) { + // char buf[256]; + // fgets(buf, sizeof(buf), dirfile); + // if (feof(dirfile)) break; + // menu += buf; + // } // Position if (menu_level == 0) { @@ -662,7 +808,13 @@ string OSD::menuFile(string filedir, string title, string extensions) { w = (cols * OSD_FONT_W) + 2; h = (virtual_rows * OSD_FONT_H) + 2; - menuDraw(); + menu = title + "\n"; + WindowDraw(); // Draw menu outline + + begin_row = focus = 1; + last_begin_row = last_focus = 0; + + filemenuRedraw(title); // Draw menu content zxDelay = REPDEL; lastzxKey = 0; @@ -790,14 +942,14 @@ string OSD::menuFile(string filedir, string title, string extensions) { if (begin_row > 1) { last_begin_row = begin_row; begin_row--; + filemenuRedraw(title); } - filemenuRedraw(title); } else if (focus > 1) { last_focus = focus; focus--; - filemenuPrintRow(focus, IS_FOCUSED); + PrintRow(focus, IS_FOCUSED); if (focus + 1 < virtual_rows) { - filemenuPrintRow(focus + 1, IS_NORMAL); + PrintRow(focus + 1, IS_NORMAL); } } click(); @@ -806,14 +958,14 @@ string OSD::menuFile(string filedir, string title, string extensions) { if ((begin_row + virtual_rows - 1) < real_rows) { last_begin_row = begin_row; begin_row++; + filemenuRedraw(title); } - filemenuRedraw(title); } else if (focus < virtual_rows - 1) { last_focus = focus; focus++; - filemenuPrintRow(focus, IS_FOCUSED); + PrintRow(focus, IS_FOCUSED); if (focus - 1 > 0) { - filemenuPrintRow(focus - 1, IS_NORMAL); + PrintRow(focus - 1, IS_NORMAL); } } click(); @@ -895,7 +1047,7 @@ string OSD::menuFile(string filedir, string title, string extensions) { } // Print a virtual row -void OSD::filemenuPrintRow(uint8_t virtual_row_num, uint8_t line_type) { +void OSD::PrintRow(uint8_t virtual_row_num, uint8_t line_type) { uint8_t margin; @@ -903,7 +1055,7 @@ void OSD::filemenuPrintRow(uint8_t virtual_row_num, uint8_t line_type) { switch (line_type) { case IS_TITLE: - VIDEO::vga.setTextColor(OSD::zxColor(7, 0), OSD::zxColor(0, 0)); + VIDEO::vga.setTextColor(OSD::zxColor(7, 1), OSD::zxColor(0, 0)); margin = 2; break; case IS_FOCUSED: @@ -937,6 +1089,7 @@ void OSD::filemenuPrintRow(uint8_t virtual_row_num, uint8_t line_type) { // Redraw inside rows void OSD::filemenuRedraw(string title) { + if ((focus != last_focus) || (begin_row != last_begin_row)) { // Read bunch of rows @@ -951,9 +1104,9 @@ void OSD::filemenuRedraw(string title) { for (uint8_t row = 1; row < virtual_rows; row++) { if (row == focus) { - filemenuPrintRow(row, IS_FOCUSED); + PrintRow(row, IS_FOCUSED); } else { - filemenuPrintRow(row, IS_NORMAL); + PrintRow(row, IS_NORMAL); } } @@ -962,6 +1115,7 @@ void OSD::filemenuRedraw(string title) { last_focus = focus; last_begin_row = begin_row; } + } string tapeBlockReadData(int Blocknum) { @@ -1059,9 +1213,9 @@ void OSD::tapemenuRedraw(string title) { for (uint8_t row = 1; row < virtual_rows; row++) { if (row == focus) { - filemenuPrintRow(row, IS_FOCUSED); + PrintRow(row, IS_FOCUSED); } else { - filemenuPrintRow(row, IS_NORMAL); + PrintRow(row, IS_NORMAL); } } @@ -1073,7 +1227,7 @@ void OSD::tapemenuRedraw(string title) { } } -// Run a new file menu +// Tape Browser Menu int OSD::menuTape(string title) { fabgl::VirtualKeyItem Menukey; @@ -1084,7 +1238,7 @@ int OSD::menuTape(string title) { real_rows = Tape::tapeNumBlocks + 1; virtual_rows = (real_rows > 19 ? 19 : real_rows); - begin_row = last_begin_row = last_focus = focus = 1; + // begin_row = last_begin_row = last_focus = focus = 1; if (Tape::tapeCurBlock > 17) { begin_row = Tape::tapeCurBlock - 16; @@ -1093,18 +1247,18 @@ int OSD::menuTape(string title) { begin_row = 1; focus = Tape::tapeCurBlock + 1; } - last_focus = focus; - last_begin_row = begin_row; + // last_focus = focus; + // last_begin_row = begin_row; menu_curopt = focus; - // Get first bunch of rows - menu = title + "\n"; - for (int i = (begin_row - 1); i < (begin_row - 1) + (virtual_rows - 1); i++) { - if (i > Tape::tapeNumBlocks) break; - menu += tapeBlockReadData(i); - } + // // Get first bunch of rows + // menu = title + "\n"; + // for (int i = (begin_row - 1); i < (begin_row - 1) + (virtual_rows - 1); i++) { + // if (i > Tape::tapeNumBlocks) break; + // menu += tapeBlockReadData(i); + // } - printf(menu.c_str()); + // printf(menu.c_str()); // Position if (menu_level == 0) { @@ -1122,7 +1276,12 @@ int OSD::menuTape(string title) { w = (cols * OSD_FONT_W) + 2; h = (virtual_rows * OSD_FONT_H) + 2; - menuDraw(); + menu = title + "\n"; + WindowDraw(); + + last_begin_row = last_focus = 0; + + tapemenuRedraw(title); zxDelay = REPDEL; lastzxKey = 0; @@ -1234,8 +1393,8 @@ int OSD::menuTape(string title) { } else if (focus > 1) { last_focus = focus; focus--; - filemenuPrintRow(focus, IS_FOCUSED); - filemenuPrintRow(focus + 1, IS_NORMAL); + PrintRow(focus, IS_FOCUSED); + PrintRow(focus + 1, IS_NORMAL); click(); } } else if (Menukey.vk == fabgl::VK_DOWN) { @@ -1249,8 +1408,8 @@ int OSD::menuTape(string title) { } else if (focus < virtual_rows - 1) { last_focus = focus; focus++; - filemenuPrintRow(focus, IS_FOCUSED); - filemenuPrintRow(focus - 1, IS_NORMAL); + PrintRow(focus, IS_FOCUSED); + PrintRow(focus - 1, IS_NORMAL); click(); } } else if ((Menukey.vk == fabgl::VK_PAGEUP) || (Menukey.vk == fabgl::VK_LEFT)) { diff --git a/src/Tape.cpp b/src/Tape.cpp index 4f12b7c6..8553d325 100644 --- a/src/Tape.cpp +++ b/src/Tape.cpp @@ -596,11 +596,18 @@ bool Tape::FlashLoad() { if (tape == NULL) { return false; } + CalcTapBlockPos(tapeCurBlock); } + // printf("--< BLOCK: %d >--------------------------------\n",(int)tapeCurBlock); + uint16_t blockLen=(readByteFile(tape) | (readByteFile(tape) <<8)); uint8_t tapeFlag = readByteFile(tape); + // printf("blockLen: %d\n",(int)blockLen - 2); + // printf("tapeFlag: %d\n",(int)tapeFlag); + // printf("AX: %d\n",(int)Z80::getRegAx()); + if (Z80::getRegAx() != tapeFlag) { // printf("No coincide el flag\n"); Z80::setFlags(0x00); @@ -625,6 +632,8 @@ bool Tape::FlashLoad() { int addr2 = addr & 0x3fff; uint8_t page = addr >> 14; + // printf("nBytes: %d\n",nBytes); + if ((addr2 + nBytes) <= 0x4000) { // printf("Case 1\n"); @@ -679,33 +688,22 @@ bool Tape::FlashLoad() { } - if (nBytes != (blockLen - 2)) { - - if (tapeCurBlock < (tapeNumBlocks - 1)) { - tapeCurBlock++; - } else { - tapeCurBlock = 0; - rewind(tape); - } - + if (nBytes > (blockLen - 2)) { // Hay menos bytes en la cinta de los indicados en DE // En ese caso habrá dado un error de timeout en LD-SAMPLE (0x05ED) // que se señaliza con CARRY==reset & ZERO==set - Z80::setFlags(0x50); // when B==0xFF, then INC B, B=0x00, F=0x50 - CalcTapBlockPos(tapeCurBlock); - + Z80::setFlags(0x50); } else { - Z80::Xor(readByteFile(tape)); // Byte de paridad Z80::Cp(0x01); + } - if (tapeCurBlock < (tapeNumBlocks - 1)) { - tapeCurBlock++; - } else { - tapeCurBlock = 0; - rewind(tape); - } - + if (tapeCurBlock < (tapeNumBlocks - 1)) { + tapeCurBlock++; + if (nBytes != (blockLen -2)) CalcTapBlockPos(tapeCurBlock); + } else { + tapeCurBlock = 0; + rewind(tape); } Z80::setRegIX(addr); From 545b325b5e434315f73fdc52f93b3cdd907332a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Iborra?= Date: Fri, 1 Sep 2023 01:56:24 +0200 Subject: [PATCH 29/29] RC2 version number & new Patreon in credits --- include/messages.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/messages.h b/include/messages.h index a57cd8a6..4633b03c 100644 --- a/include/messages.h +++ b/include/messages.h @@ -41,7 +41,7 @@ visit https://zxespectrum.speccy.org/contacto #define MSG_LOADING_Z80 "Loading Z80 file" #define MSG_SAVE_CONFIG "Saving config file" #define MSG_VGA_INIT "Initializing VGA" -#define EMU_VERSION "v1.0rc2pr3.2" +#define EMU_VERSION " v1.0rc2" // Error #define ERROR_TITLE " !!! ERROR - CLIVE MEDITATION !!! " @@ -393,10 +393,10 @@ static const char *MENU_JOY[2] = { MENU_JOY_EN, MENU_JOY_ES }; "\nD1Inacio Santos\r"\ "\r"\ "\nA1The Manic Miners:\r"\ - "\nE1Fernando Bonilla, \nB1M.Ignacio Monge\r"\ - "\nC1Jose Maria Rodriguez, \nD1Julia Salvador\r"\ - "\nB1Marta Sicilia, \nE1Radoslaw Wojciechowski\r"\ - "\r" + "\nE1Fernando Bonilla, \nB1Jorge Garcia\r"\ + "\nC1Ignacio Monge, \nD1Jose Maria Rodriguez\r"\ + "\nB1Julia Salvador, \nE1Marta Sicilia\r"\ + "\nC1Radoslaw Wojciechowski\r" static const char *AboutMsg[2][5] = { {