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 2e1cad92..0dc024bd 100644 --- a/include/CPU.h +++ b/include/CPU.h @@ -38,7 +38,14 @@ visit https://zxespectrum.speccy.org/contacto #include #include "ESPectrum.h" -#include "ESP32Lib/ESP32Lib.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 +#define INT_END128 36 class CPU { @@ -46,7 +53,7 @@ class CPU // call this for initializing CPU static void setup(); - // call this for executing a frame's worth of instructions + // // call this for executing a frame's worth of instructions static void IRAM_ATTR loop(); // call this for resetting the CPU @@ -55,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(); @@ -70,12 +74,20 @@ class CPU // CPU Tstates in frame static uint32_t statesInFrame; + // Late timing + static uint8_t latetiming; + + // INT signal lenght + static uint8_t IntStart; + static uint8_t IntEnd; + // Frames elapsed static uint32_t framecnt; }; -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/Config.h b/include/Config.h index d536b49d..e9f51ab3 100644 --- a/include/Config.h +++ b/include/Config.h @@ -61,12 +61,16 @@ class Config // static string kbd_layout; 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; // 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/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/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/FileUtils.h b/include/FileUtils.h index 4316c586..92c6e187 100644 --- a/include/FileUtils.h +++ b/include/FileUtils.h @@ -47,14 +47,12 @@ using namespace std; // Defines #define ASCII_NL 10 -#define ON true -#define OFF false 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(); @@ -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 c54b0a16..0da4e3c6 100644 --- a/include/OSDMain.h +++ b/include/OSDMain.h @@ -83,20 +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 filemenuPrintRow(uint8_t virtual_row_num, uint8_t line_type); + static void tapemenuRedraw(string title); + 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(); @@ -105,13 +109,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/Ports.h b/include/Ports.h index 5dfcaf32..d3ea5fa4 100644 --- a/include/Ports.h +++ b/include/Ports.h @@ -43,8 +43,10 @@ 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/FileZ80.h b/include/Snapshot.h similarity index 79% rename from include/FileZ80.h rename to include/Snapshot.h index f6641919..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,23 @@ 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: 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/Tape.h b/include/Tape.h index 34a9cf52..d891256c 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; // Start point of this block? + // uint16_t BlockLength; +}; + class Tape { public: @@ -79,16 +102,27 @@ class Tape // Tape static FILE *tape; static string tapeFileName; + static string tapeSaveName; static uint8_t tapeEarBit; static uint8_t tapeStatus; static uint8_t SaveStatus; static uint8_t romLoading; + static uint16_t tapeCurBlock; + static uint16_t tapeNumBlocks; + static uint32_t tapebufByteCount; + static uint32_t tapePlayOffset; + static size_t tapeFileSize; + static std::vector TapeListing; + 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 bool FlashLoad(); static void Save(); + static uint32_t CalcTapBlockPos(int block); }; diff --git a/include/Video.h b/include/Video.h index 81276cde..d40735c5 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 @@ -48,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: @@ -66,8 +90,8 @@ 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 IRAM_ATTR MainScreen_OSD(unsigned int statestoadd, bool contended); + static void MainScreen(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); @@ -103,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/include/Z80_JLS/z80.h b/include/Z80_JLS/z80.h index b60f125e..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 @@ -391,11 +391,16 @@ class Z80 { // Execute one instruction static void IRAM_ATTR execute(); + static void IRAM_ATTR exec_nocheck(); // 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); + + static void Xor(uint8_t oper8); + + static void Cp(uint8_t oper8); #ifdef WITH_BREAKPOINT_SUPPORT static bool isBreakpoint(void) { return breakpointEnabled; } @@ -509,6 +514,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); @@ -742,7 +749,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/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/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/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/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/include/messages.h b/include/messages.h index 41ddee5e..4633b03c 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.0rc2" // 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]=--" @@ -68,7 +69,9 @@ 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" #define OSD_TAPE_SELECT_ERR_EN "No TAP selected" #define OSD_TAPE_SELECT_ERR_ES "TAP no seleccionado" @@ -96,14 +99,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"*/ \ @@ -196,20 +199,46 @@ 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"\ +// "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"\ - "Internal\t[I]\n"\ - "SD Card\t[S]\n"\ + "Flash tape load\t>\n"\ "Refresh directories\n" #define MENU_STORAGE_ES "Almacenamiento\n"\ - "Interno\t[I]\n"\ - "Tarjeta SD\t[S]\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" + "AY on 48K\t>\n"\ + "ALU Timing\t>\n"\ + "48K Issue 2\t>\n" #define MENU_OTHER_ES "Otros\n"\ - "AY en 48K\t>\n" + "AY en 48K\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"\ @@ -220,6 +249,22 @@ 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_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" @@ -282,45 +327,175 @@ 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"\ - " Rampa, D. Carrion, A. Villena and\n"\ - " 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"\ - " Rampa, D. Carrion, A. Villena y\n"\ - " 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 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" + + #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, \nB1Jorge Garcia\r"\ + "\nC1Ignacio Monge, \nD1Jose Maria Rodriguez\r"\ + "\nB1Julia Salvador, \nE1Marta Sicilia\r"\ + "\nC1Radoslaw Wojciechowski\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"\ + PATREONS + , + "\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"\ + PATREONS + , + "\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"\ @@ -328,15 +503,15 @@ static const char *OSD_ABOUT[2] = { OSD_ABOUT_EN, OSD_ABOUT_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" @@ -346,18 +521,446 @@ static const char *OSD_ABOUT[2] = { OSD_ABOUT_EN, OSD_ABOUT_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" -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" }; + +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/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/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/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..0f562e26 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 @@ -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 @@ -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 @@ -1179,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.pico32.old b/sdkconfig.ESPectrum.old similarity index 97% rename from sdkconfig.pico32.old rename to sdkconfig.ESPectrum.old index 3d639627..2fc58636 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 @@ -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 @@ -526,7 +526,7 @@ 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 @@ -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 @@ -1091,6 +1088,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..edd3b36b 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 @@ -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; @@ -474,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; @@ -492,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; @@ -508,7 +524,7 @@ void AySound::selectRegister(uint8_t registerNumber) void AySound::setRegisterData(uint8_t data) { - if (selectedRegister < 14) { + if (selectedRegister < 16) { regs[selectedRegister] = data; updateReg[selectedRegister](); } @@ -534,23 +550,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 06c4fada..45f7695c 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -39,7 +39,6 @@ visit https://zxespectrum.speccy.org/contacto #include "Ports.h" #include "hardconfig.h" #include "Config.h" -#include "Tape.h" #include "Video.h" #include "Z80_JLS/z80.h" @@ -47,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; @@ -63,6 +56,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; @@ -73,16 +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; @@ -94,14 +96,20 @@ 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; } tstates = 0; @@ -114,27 +122,12 @@ 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(); + + uint32_t stFrame = statesInFrame - IntEnd; + while (tstates < stFrame) Z80::exec_nocheck(); - } + while (tstates < statesInFrame) Z80::execute(); if (tstates & 0xFF000000) FlushOnHalt(); // If we're halted flush screen and update registers as needed @@ -149,50 +142,30 @@ 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))) { - - 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); - } + uint8_t page = Z80::getRegPC() >> 14; + if (MemESP::ramContended[page]) { + uint32_t stFrame = statesInFrame - latetiming; + while (tstates < stFrame ) { + VIDEO::Draw(4,true); + Z80::incRegR(1); } } else { - // tstates + uint32_t pre_tstates = tstates; + VIDEO::Flush(); // Draw the rest of the frame + tstates = pre_tstates; + + 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(); } @@ -200,28 +173,26 @@ 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) { - // 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); @@ -242,13 +213,13 @@ 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; + + if (page == ((address + 1) >> 14)) { // Check if address is between two different pages - uint8_t page = address >> 14; - if (MemESP::ramContended[page]) { VIDEO::Draw(3, true); VIDEO::Draw(3, true); @@ -271,22 +242,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) { - - int tmp = CPU::tstates; + int tmp = CPU::tstates + CPU::latetiming; if (tmp >= CPU::statesInFrame) tmp -= CPU::statesInFrame; - return ((tmp >= 0) && (tmp < (is48 ? 32 : 36))); - + return ((tmp >= CPU::IntStart) && (tmp < CPU::IntEnd)); } + diff --git a/src/Config.cpp b/src/Config.cpp index 71cc473a..43de4327 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"; @@ -55,7 +62,10 @@ uint8_t Config::esp32rev = 0; // string Config::kbd_layout = "US"; 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; // erase control characters (in place) static inline void erase_cntrl(std::string &s) { @@ -90,140 +100,360 @@ 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_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_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); + } + + 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=="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); + + 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..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" @@ -60,29 +59,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 @@ -110,6 +91,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; @@ -182,21 +164,108 @@ 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; + + 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"; + } + } + + } + + string kbdstr=""; + + while (Kbd->virtualKeyAvailable()) { + r = Kbd->getNextVirtualKey(&NextKey); + if (r) { + // // 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 kbdstr; + +} + //======================================================================================= // SETUP //======================================================================================= @@ -205,24 +274,22 @@ 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 ZXKeyb::setup(); - #endif //======================================================================================= // FILESYSTEM @@ -232,6 +299,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 +376,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 +402,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"); @@ -420,7 +497,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 @@ -432,17 +509,12 @@ 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(); + Config::save("ram"); #endif } @@ -461,7 +533,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 @@ -488,6 +560,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; @@ -539,22 +615,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; + // } + // } + } } @@ -575,47 +660,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 @@ -624,11 +669,9 @@ 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; -#endif void IRAM_ATTR ESPectrum::processKeyboard() { @@ -743,136 +786,83 @@ void IRAM_ATTR ESPectrum::processKeyboard() { } - #ifdef ZXKEYB - - if (zxDelay > 0) - zxDelay--; - else - // Process physical keyboard - ZXKeyb::process(); + if (ZXKeyb::Exists) { // START - ZXKeyb Exists - // 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 > 0) + zxDelay--; + else + // Process physical keyboard + ZXKeyb::process(); - zxDelay = 15; + // Detect and process physical kbd menu key combinations + // 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))) { - 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; + zxDelay = 15; - if (zxDelay) { - // Set all keys as not pressed - for (uint8_t i = 0; i < 8; i++) ZXKeyb::ZXcols[i] = 0x1f; - return; - } - - } - - // 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)) { + 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; - 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] = 0xbf; + 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]; + } } - } - return ""; + } } @@ -1110,8 +1100,21 @@ 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), " %-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 + 18) > Tape::tapeFileName.length()) 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 deleted file mode 100644 index 74ec9bfd..00000000 --- a/src/FileSNA.cpp +++ /dev/null @@ -1,573 +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) - -// /////////////////////////////////////////////////////////////////////////////// - -// using internal storage (spi flash) -#include "esp_spiffs.h" - -// /////////////////////////////////////////////////////////////////////////////// - -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] = 0x1F; - 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; - - } 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; - - } - - 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(); - - 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/FileUtils.cpp b/src/FileUtils.cpp index c8c72de7..7340455f 100644 --- a/src/FileUtils.cpp +++ b/src/FileUtils.cpp @@ -47,9 +47,9 @@ visit https://zxespectrum.speccy.org/contacto #include "OSDMain.h" #include "roms.h" #include "Video.h" +#include "ZXKeyb.h" #include "esp_vfs.h" -#include "esp_spiffs.h" #include #include #include "esp_vfs_fat.h" @@ -57,46 +57,43 @@ 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() { +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) - // 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; - } +int FileUtils::curSNAFile = 1; // Current SNA file index on browser +int FileUtils::curTAPFile = 1; // Current TAP file index on browser - SDReady = mountSDCard(); +void FileUtils::initFileSystem() { + + // 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(2); + // 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; 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 }; 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, @@ -105,9 +102,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, @@ -115,7 +115,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); @@ -125,9 +125,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; } diff --git a/src/FileZ80.cpp b/src/FileZ80.cpp deleted file mode 100644 index 14f2646d..00000000 --- a/src/FileZ80.cpp +++ /dev/null @@ -1,528 +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 "FileZ80.h" -#include "FileUtils.h" -#include "CPU.h" -#include "Video.h" -#include "Ports.h" -#include "MemESP.h" -#include "ESPectrum.h" -#include "messages.h" -#include "OSDMain.h" -#include "Config.h" -#include "Tape.h" -#include "pwm_audio.h" -#include "AySound.h" - -/////////////////////////////////////////////////////////////////////////////// - -#include "Z80_JLS/z80.h" - -/////////////////////////////////////////////////////////////////////////////// - -// using internal storage (spi flash) -#include "esp_spiffs.h" - -/////////////////////////////////////////////////////////////////////////////// - -static uint16_t mkword(uint8_t lobyte, uint8_t hibyte) { - return lobyte | (hibyte << 8); -} - -bool FileZ80::load(string z80_fn) -{ - FILE *file; - - // Stop keyboard input - ESPectrum::PS2Controller.keyboard()->suspendPort(); - // Stop audio - pwm_audio_stop(); - - file = fopen(z80_fn.c_str(), "rb"); - if (file==NULL) - { - printf("FileZ80: Error opening %s\n",z80_fn.c_str()); - - // Resume audio - pwm_audio_start(); - // Resume keyboard input - ESPectrum::PS2Controller.keyboard()->resumePort(); - - return false; - } - - fseek(file,0,SEEK_END); - uint32_t file_size = ftell(file); - rewind (file); - - // 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 ( header[0]); - Z80::setFlags ( header[1]); - Z80::setRegBC (mkword(header[2], header[3])); - Z80::setRegHL (mkword(header[4], header[5])); - Z80::setRegPC (mkword(header[6], header[7])); - Z80::setRegSP (mkword(header[8], header[9])); - Z80::setRegI ( header[10]); - Z80::setRegR ( header[11]); - b12 = header[12]; - Z80::setRegDE (mkword(header[13], header[14])); - Z80::setRegBCx(mkword(header[15], header[16])); - Z80::setRegDEx(mkword(header[17], header[18])); - Z80::setRegHLx(mkword(header[19], header[20])); - Z80::setRegAFx(mkword(header[22], header[21])); // watch out for order!!! - Z80::setRegIY (mkword(header[23], header[24])); - Z80::setRegIX (mkword(header[25], header[26])); - Z80::setIFF1 ( header[27] ? true : false); - Z80::setIFF2 ( header[28] ? true : false); - b29 = header[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; - - // #define LOG_Z80_DETAILS - - if (RegPC != 0) { - - // version 1, the simplest, 48K only. - uint32_t memRawLength = file_size - dataOffset; - - #ifdef LOG_Z80_DETAILS - printf("Z80 format version: %d\n", version); - printf("machine type: %s\n", fileArch.c_str()); - printf("data offset: %d\n", dataOffset); - printf("data compressed: %s\n", dataCompressed ? "true" : "false"); - printf("file length: %d\n", file_size); - printf("data length: %d\n", memRawLength); - printf("b12: %d\n", b12); - printf("pc: %d\n", RegPC); - printf("border: %d\n", VIDEO::borderColor); - #endif - - if (dataCompressed) - { - // assuming stupid 00 ED ED 00 terminator present, should check for it instead of assuming - uint16_t dataLen = (uint16_t)(memRawLength - 4); - - // load compressed data into memory - loadCompressedMemData(file, dataLen, 0x4000, 0xC000); - } - else - { - uint16_t dataLen = (memRawLength < 0xC000) ? memRawLength : 0xC000; - - // load uncompressed data into memory - for (int i = 0; i < dataLen; i++) - MemESP::writebyte(0x4000 + i, readByteFile(file)); - } - - // latches for 48K - MemESP::romLatch = 0; - MemESP::romInUse = 0; - MemESP::bankLatch = 0; - MemESP::pagingLock = 1; - MemESP::videoLatch = 0; - } - else { - // 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(header[30], header[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); - - fclose(file); - - // Resume audio - pwm_audio_start(); - // Resume keyboard input - ESPectrum::PS2Controller.keyboard()->resumePort(); - - ESPectrum::reset(); - - return false; - } - - // read additional header block - for (uint8_t i = 32; i < 32 + ahblen; i++) { - header[i] = readByteFile(file); - dataOffset ++; - } - - // program counter - RegPC = mkword(header[32], header[33]); - Z80::setRegPC(RegPC); - - // hardware mode - uint8_t b34 = header[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 - - if (fileArch == "48K") { - 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 = readByteFile(file); dataOffset ++; - uint8_t hdr1 = readByteFile(file); dataOffset ++; - uint8_t hdr2 = readByteFile(file); dataOffset ++; - 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); - dataOffset += compDataLen; - } - - // great success!!! - } - else if (fileArch == "128K") { - MemESP::romInUse = 1; - - // paging register - uint8_t b35 = header[35]; - MemESP::pagingLock = bitRead(b35, 5); - MemESP::romLatch = bitRead(b35, 4); - MemESP::videoLatch = bitRead(b35, 3); - MemESP::bankLatch = b35 & 0x07; - - 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 = readByteFile(file); dataOffset ++; - uint8_t hdr1 = readByteFile(file); dataOffset ++; - uint8_t hdr2 = readByteFile(file); dataOffset ++; - 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); - dataOffset += compDataLen; - } - - // great success!!! - } - } - - 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] = 0x1F; - 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; - - } 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; - - } - - 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(); - - return true; - -} - -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 < dataLen && memidx < memlen) { - uint8_t databyte = readByteFile(f); - 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 -} - -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 < dataLen && memidx < memlen) { - uint8_t databyte = readByteFile(f); - 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; - } - } -} diff --git a/src/OSDMain.cpp b/src/OSDMain.cpp index 98e62155..ce155edd 100644 --- a/src/OSDMain.cpp +++ b/src/OSDMain.cpp @@ -40,12 +40,12 @@ 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" #include "pwm_audio.h" +#include "Z80_JLS/z80.h" #ifndef ESP32_SDL2_WRAPPER #include "esp_system.h" @@ -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(); } @@ -173,14 +173,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); @@ -188,16 +188,16 @@ 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 { 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); + // OSD::osdCenteredMsg(OSD_PSNA_LOADED, LEVEL_INFO); } } @@ -205,10 +205,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) { @@ -230,9 +228,16 @@ 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 != "") { - changeSnapshot(FileUtils::MountPoint + DISK_SNA_DIR + "/" + mFile); + mFile.erase(0, 1); + string fname = FileUtils::MountPoint + FileUtils::SNA_Path + "/" + 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) { @@ -256,27 +261,72 @@ 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 != "") { - Tape::tapeFileName=FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile; + + 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 + FileUtils::TAP_Path + "/" + mFile); + + ESPectrum::TapeNameScroller = 0; + + // Tape::tapeFileName=FileUtils::MountPoint + FileUtils::TAP_Path "/" + 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(); + } } } - 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) { @@ -291,27 +341,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(); @@ -319,16 +370,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(); @@ -336,7 +387,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { pwm_audio_set_volume(ESPectrum::aud_volume); } - #endif + // #endif } // else if (KeytoESP == fabgl::VK_F9) { @@ -345,7 +396,18 @@ 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; + #ifdef SNAPSHOT_LOAD_LAST + Config::save("ram"); + #endif + } + Config::last_ram_file = NO_RAM_FILE; + ESPectrum::reset(); + } + else if (KeytoESP == fabgl::VK_F12) { // ESP32 reset // // Switch boot partition // string splabel; @@ -361,7 +423,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(); @@ -403,9 +465,16 @@ 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 != "") { - changeSnapshot(FileUtils::MountPoint + DISK_SNA_DIR + "/" + mFile); + mFile.erase(0, 1); + string fname = FileUtils::MountPoint + FileUtils::SNA_Path + "/" + mFile; + LoadSnapshot(fname); + Config::ram_file = fname; + #ifdef SNAPSHOT_LOAD_LAST + Config::save("ram"); + #endif + Config::last_ram_file = fname; return; } } @@ -451,31 +520,79 @@ 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"); + string mFile = menuFile(FileUtils::MountPoint + FileUtils::TAP_Path, MENU_TAP_TITLE[Config::lang],".tap.TAP",FileUtils::curTAPFile); if (mFile != "") { - Tape::tapeFileName=FileUtils::MountPoint + DISK_TAP_DIR "/" + mFile; + + 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 + FileUtils::TAP_Path + "/" + mFile); + + ESPectrum::TapeNameScroller = 0; + 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(); + } return; } - } - else if (tap_num == 3) { - Tape::TAP_Stop(); - return; + } } else { menu_curopt = 2; @@ -495,15 +612,23 @@ 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) { // Hard - Config::ram_file = NO_RAM_FILE; - Config::save(); + 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(); return; @@ -512,7 +637,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 { @@ -537,33 +662,52 @@ 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) { - 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 - OSD::osdCenteredMsg("Refreshing tape dir", LEVEL_INFO); - 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 + 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, 0); + 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 + FileUtils::TAP_Path, ".tap.TAP"); // Prepare tap filelist + if (chunks) FileUtils::Mergefiles(FileUtils::MountPoint + FileUtils::TAP_Path,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; @@ -578,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"); @@ -653,7 +797,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 +829,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 +870,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 +881,73 @@ 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 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; @@ -753,41 +964,41 @@ 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; - #endif while (1) { - #ifdef ZXKEYB - - ZXKeyb::process(); + if (ZXKeyb::Exists) { - 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; + 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[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; + } } + } - #endif + // #endif if (ESPectrum::PS2Controller.keyboard()->virtualKeyAvailable()) { if (ESPectrum::readKbd(&Nextkey)) { @@ -798,9 +1009,7 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { vTaskDelay(5 / portTICK_PERIOD_MS); - #ifdef ZXKEYB if (zxDelay > 0) zxDelay--; - #endif } @@ -810,45 +1019,119 @@ 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(OSD_ABOUT[Config::lang]); - #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; ninjectVirtualKey(fabgl::VK_RETURN, true, false); - ESPectrum::PS2Controller.keyboard()->injectVirtualKey(fabgl::VK_RETURN, false, false); - zxDelay = REPDEL; + if (msgDelay == 0) { + nextChar = AboutMsg[Config::lang][msgIndex][msgChar]; + if (nextChar != 13) { + if (nextChar == 10) { + char fore = AboutMsg[Config::lang][msgIndex][++msgChar]; + char back = AboutMsg[Config::lang][msgIndex][++msgChar]; + int foreint = (fore >= '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) ); } - } 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; + 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 - 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; + } 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; } } - #endif + 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(); + + 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 = 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 = 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 = REPABOUT; + } + } + + } if (ESPectrum::PS2Controller.keyboard()->virtualKeyAvailable()) { if (ESPectrum::readKbd(&Nextkey)) { @@ -857,12 +1140,9 @@ void OSD::do_OSD(fabgl::VirtualKey KeytoESP) { } } - vTaskDelay(5 / portTICK_PERIOD_MS); - - #ifdef ZXKEYB + vTaskDelay(20 / portTICK_PERIOD_MS); + if (zxDelay > 0) zxDelay--; - #endif - } @@ -1001,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(); - #endif - Config::last_ram_file = filename; - -} diff --git a/src/OSDMenu.cpp b/src/OSDMenu.cpp index 7d671527..12b62c6d 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 @@ -80,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, @@ -113,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; } @@ -233,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); @@ -262,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; @@ -273,141 +380,178 @@ 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; +// } -#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) { 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 - #ifdef ZXKEYB zxDelay = REPDEL; lastzxKey = 0; - #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; + 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 - // Process external keyboard if (ESPectrum::PS2Controller.keyboard()->virtualKeyAvailable()) { if (ESPectrum::readKbd(&Menukey)) { @@ -509,9 +653,7 @@ unsigned short OSD::menuRun(string new_menu) { } vTaskDelay(5 / portTICK_PERIOD_MS); - #ifdef ZXKEYB if (zxDelay > 0) zxDelay--; - #endif } @@ -534,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); @@ -544,7 +687,9 @@ void OSD::menuRedraw() { menuScrollBar(); last_focus = focus; last_begin_row = begin_row; + } + } // Draw menu scroll bar @@ -605,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; @@ -616,12 +761,13 @@ 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); + currentFile = 1; } // Open dir file for read @@ -633,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) { @@ -664,103 +808,118 @@ 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 - #ifdef ZXKEYB zxDelay = REPDEL; lastzxKey = 0; - #endif while (1) { - #ifdef ZXKEYB + if (ZXKeyb::Exists) { - ZXKeyb::process(); + 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; + 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)) { // 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[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 == 5) + zxDelay = REPPER; + else + zxDelay = REPDEL; + 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 == 6) + zxDelay = REPPER; + else + zxDelay = REPDEL; + 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 == 7) + zxDelay = REPPER; + else + zxDelay = REPDEL; + 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 == 8) + zxDelay = REPPER; + else + zxDelay = REPDEL; + lastzxKey = 8; + } + } else + { + zxDelay = 0; + lastzxKey = 0; } - } else - { - zxDelay = 0; - lastzxKey = 0; + } - #endif - // Process external keyboard if (ESPectrum::PS2Controller.keyboard()->virtualKeyAvailable()) { if (ESPectrum::readKbd(&Menukey)) { @@ -783,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(); @@ -799,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(); @@ -842,10 +1001,18 @@ 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(); - 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) { @@ -865,6 +1032,7 @@ string OSD::menuFile(string filedir, string title, string extensions) { } fclose(dirfile); + dirfile = NULL; click(); return ""; } @@ -873,16 +1041,13 @@ string OSD::menuFile(string filedir, string title, string extensions) { vTaskDelay(5 / portTICK_PERIOD_MS); - #ifdef ZXKEYB if (zxDelay > 0) zxDelay--; - #endif - } } // 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; @@ -890,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: @@ -924,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 @@ -938,9 +1104,118 @@ 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 { + PrintRow(row, IS_NORMAL); + } + } + + menuScrollBar(); + + last_focus = focus; + last_begin_row = begin_row; + } + +} + +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"; + for (int i = begin_row - 1; i < virtual_rows + begin_row - 2; i++) { + if (i > Tape::tapeNumBlocks) break; + menu += tapeBlockReadData(i); + } + + for (uint8_t row = 1; row < virtual_rows; row++) { + if (row == focus) { + PrintRow(row, IS_FOCUSED); } else { - filemenuPrintRow(row, IS_NORMAL); + PrintRow(row, IS_NORMAL); } } @@ -948,5 +1223,277 @@ void OSD::filemenuRedraw(string title) { last_focus = focus; last_begin_row = begin_row; + } } + +// Tape Browser Menu +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::tapeNumBlocks + 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"; + // 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()); + + // 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 = 39; // 36 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; + + menu = title + "\n"; + WindowDraw(); + + last_begin_row = last_focus = 0; + + tapemenuRedraw(title); + + 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--; + PrintRow(focus, IS_FOCUSED); + PrintRow(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++; + PrintRow(focus, IS_FOCUSED); + PrintRow(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(); + 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); + 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/Ports.cpp b/src/Ports.cpp index bd4fe661..5ea53ac6 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") @@ -55,9 +56,10 @@ 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]; +uint8_t Ports::port254 = 0; uint8_t IRAM_ATTR Ports::input(uint16_t address) { @@ -78,13 +80,15 @@ uint8_t IRAM_ATTR Ports::input(uint16_t address) } // ** I/O Contention (Late) ************************** - if (((address & 0xff) == 0x1f) && (Config::joystick)) return port[0x1f]; // Kempston port + // The default port value is 0xBF. + uint8_t result = 0xbf; - if ((address & 0xff) == 0xfe) // ULA PORT - { - - uint8_t result = 0xbf; + // 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) { @@ -94,23 +98,29 @@ uint8_t IRAM_ATTR Ports::input(uint16_t address) if (Tape::tapeStatus==TAPE_LOADING) { Tape::TAP_Read(); - bitWrite(result,6,Tape::tapeEarBit); - } - - - return result | (0xa0); // OR 0xa0 -> ISSUE 2 + 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; + } + } + + return result; } // 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. @@ -120,8 +130,15 @@ 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); + // 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]; @@ -129,7 +146,7 @@ uint8_t IRAM_ATTR Ports::input(uint16_t address) } - return data & 0xff; + return data; } @@ -144,6 +161,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; @@ -173,34 +192,47 @@ 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)) { - if (MemESP::pagingLock) return; + if (!MemESP::pagingLock) { + + MemESP::pagingLock = bitRead(data, 5); - 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::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; - - MemESP::romLatch = bitRead(data, 4); - bitWrite(MemESP::romInUse, 0, MemESP::romLatch); - MemESP::ramCurrent[0] = (unsigned char *)MemESP::rom[MemESP::romInUse]; + 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, 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; + } + + } } - + } diff --git a/src/Snapshot.cpp b/src/Snapshot.cpp new file mode 100644 index 00000000..9b8637ff --- /dev/null +++ b/src/Snapshot.cpp @@ -0,0 +1,1378 @@ +/* + +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 "Snapshot.h" +#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 "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 + +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; + +} + +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(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::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); + + // 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 ( header[0]); + Z80::setFlags ( header[1]); + Z80::setRegBC (mkword(header[2], header[3])); + Z80::setRegHL (mkword(header[4], header[5])); + Z80::setRegPC (mkword(header[6], header[7])); + Z80::setRegSP (mkword(header[8], header[9])); + Z80::setRegI ( header[10]); + Z80::setRegR ( header[11]); + b12 = header[12]; + Z80::setRegDE (mkword(header[13], header[14])); + Z80::setRegBCx(mkword(header[15], header[16])); + Z80::setRegDEx(mkword(header[17], header[18])); + Z80::setRegHLx(mkword(header[19], header[20])); + Z80::setRegAFx(mkword(header[22], header[21])); // watch out for order!!! + Z80::setRegIY (mkword(header[23], header[24])); + Z80::setRegIX (mkword(header[25], header[26])); + Z80::setIFF1 ( header[27] ? true : false); + Z80::setIFF2 ( header[28] ? true : false); + b29 = header[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; + + // #define LOG_Z80_DETAILS + + if (RegPC != 0) { + + // version 1, the simplest, 48K only. + uint32_t memRawLength = file_size - dataOffset; + + #ifdef LOG_Z80_DETAILS + printf("Z80 format version: %d\n", version); + printf("machine type: %s\n", fileArch.c_str()); + printf("data offset: %d\n", dataOffset); + printf("data compressed: %s\n", dataCompressed ? "true" : "false"); + printf("file length: %d\n", file_size); + printf("data length: %d\n", memRawLength); + printf("b12: %d\n", b12); + printf("pc: %d\n", RegPC); + printf("border: %d\n", VIDEO::borderColor); + #endif + + if (dataCompressed) + { + // assuming stupid 00 ED ED 00 terminator present, should check for it instead of assuming + uint16_t dataLen = (uint16_t)(memRawLength - 4); + + // load compressed data into memory + loadCompressedMemData(file, dataLen, 0x4000, 0xC000); + } + else + { + uint16_t dataLen = (memRawLength < 0xC000) ? memRawLength : 0xC000; + + // load uncompressed data into memory + for (int i = 0; i < dataLen; i++) + MemESP::writebyte(0x4000 + i, readByteFile(file)); + } + + // latches for 48K + MemESP::romLatch = 0; + MemESP::romInUse = 0; + MemESP::bankLatch = 0; + MemESP::pagingLock = 1; + MemESP::videoLatch = 0; + } + else { + // 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(header[30], header[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); + fclose(file); + 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(header[32], header[33]); + Z80::setRegPC(RegPC); + + // hardware mode + uint8_t b34 = header[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 + + if (fileArch == "48K") { + 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 = readByteFile(file); dataOffset ++; + uint8_t hdr1 = readByteFile(file); dataOffset ++; + uint8_t hdr2 = readByteFile(file); dataOffset ++; + 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); + dataOffset += compDataLen; + } + + // great success!!! + } + else if (fileArch == "128K") { + MemESP::romInUse = 1; + + // paging register + uint8_t b35 = header[35]; + MemESP::pagingLock = bitRead(b35, 5); + MemESP::romLatch = bitRead(b35, 4); + MemESP::videoLatch = bitRead(b35, 3); + MemESP::bankLatch = b35 & 0x07; + + 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 = readByteFile(file); dataOffset ++; + uint8_t hdr1 = readByteFile(file); dataOffset ++; + uint8_t hdr2 = readByteFile(file); dataOffset ++; + 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); + dataOffset += compDataLen; + } + + // great success!!! + } + } + + fclose(file); + + return fileArch; + +} + +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 < dataLen && memidx < memlen) { + uint8_t databyte = readByteFile(f); + 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 +} + +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 < dataLen && memidx < memlen) { + uint8_t databyte = readByteFile(f); + 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; + } + } +} + +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 = sizeof(load48); + + // 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; + + // 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 = sizeof(load128); + + // Reset Z80 and set bankLatch to default + MemESP::bankLatch = 0; + Z80::reset(); + + uint32_t dataOffset = 0; + + // 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++) { + dataOffset ++; + } + + // additional header block length + uint16_t ahblen = mkword(z80_array[30], z80_array[31]); + + uint8_t version = 3; + + // read additional header block + for (uint8_t i = 32; i < 32 + ahblen; i++) { + 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"; + + #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/Tape.cpp b/src/Tape.cpp index 577ef553..8553d325 100644 --- a/src/Tape.cpp +++ b/src/Tape.cpp @@ -34,8 +34,9 @@ visit https://zxespectrum.speccy.org/contacto */ #include -#include +#include #include +#include using namespace std; @@ -48,12 +49,21 @@ 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"; 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; +uint16_t Tape::tapeNumBlocks; +uint32_t Tape::tapebufByteCount; +uint32_t Tape::tapePlayOffset; +size_t Tape::tapeFileSize; static uint8_t tapeCurByte; static uint8_t tapePhase; @@ -61,11 +71,10 @@ 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 tapeBitMask; + // static uint8_t tapeReadBuf[4096] = { 0 }; void Tape::Init() @@ -73,6 +82,334 @@ void Tape::Init() tape = NULL; } +void Tape::Open(string name) { + + if (tape != NULL) { + fclose(tape); + tape = NULL; + } + + tape = fopen(name.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); + if (tapeFileSize == 0) return; + + tapeFileName = name; + + 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(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(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. + TapeBlock::BlockType dataBlockType; + uint8_t blocktype = readByteFile(tape); + 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(tape); + } + // block.FileName[10]='\0'; + + fseek(tape,6,SEEK_CUR); + + // Get the checksum. + uint8_t checksum = readByteFile(tape); + + // 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 { + + // 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(tape,contentLength,SEEK_CUR); + + // Get the checksum. + 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); + } + + } + + tapeListIndex++; + + tapeContentIndex += tapeBlkLen + 2; + + } while(tapeContentIndex < tapeFileSize); + + // } while((tapeListIndex < 1000) && (tapeContentIndex < tapeFileSize)); + + tapeCurBlock = 0; + tapeNumBlocks = tapeListIndex; + + // 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"); + + // } + + 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() { @@ -81,15 +418,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; + tapePlayOffset = CalcTapBlockPos(tapeCurBlock); tapePhase=TAPE_PHASE_SYNC; tapePulseCount=0; @@ -97,31 +440,32 @@ void Tape::TAP_Play() 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; - fclose(tape); + tapeStatus=TAPE_STOPPED; + // fclose(tape); + // tape = NULL; } -void Tape::TAP_Read() +void IRAM_ATTR Tape::TAP_Read() { uint64_t tapeCurrent = (CPU::global_tstates + CPU::tstates) - tapeStart; @@ -165,6 +509,7 @@ void Tape::TAP_Read() tapebufByteCount++; if (tapebufByteCount == tapeBlockLen) { tapePhase=TAPE_PHASE_PAUSE; + tapeCurBlock++; tapeEarBit=0; break; } @@ -174,7 +519,7 @@ void 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; @@ -185,8 +530,8 @@ void Tape::TAP_Read() if (tapeCurByte) tapeHdrPulses=TAPE_HDR_SHORT; else tapeHdrPulses=TAPE_HDR_LONG; } } else { - Tape::tapeStatus=TAPE_STOPPED; - fclose(tape); + tapeCurBlock=0; + TAP_Stop(); } } @@ -199,10 +544,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; } @@ -238,3 +588,127 @@ void Tape::Save() { fclose(fichero); } + +bool Tape::FlashLoad() { + + if (tape == NULL) { + tape = fopen(Tape::tapeFileName.c_str(), "rb"); + 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); + Z80::setRegA(Z80::getRegAx() ^ tapeFlag); + if (tapeCurBlock < (tapeNumBlocks - 1)) { + tapeCurBlock++; + CalcTapBlockPos(tapeCurBlock); + return true; + } else { + tapeCurBlock = 0; + rewind(tape); + return false; + } + } + + // 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; + + // printf("nBytes: %d\n",nBytes); + + 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 > (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 { + + 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); + + } + + 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); + } else { + Z80::Xor(readByteFile(tape)); // Byte de paridad + Z80::Cp(0x01); + } + + if (tapeCurBlock < (tapeNumBlocks - 1)) { + tapeCurBlock++; + if (nBytes != (blockLen -2)) CalcTapBlockPos(tapeCurBlock); + } else { + tapeCurBlock = 0; + rewind(tape); + } + + Z80::setRegIX(addr); + Z80::setRegDE(nBytes - (blockLen - 2)); + + return true; + +} diff --git a/src/Video.cpp b/src/Video.cpp index 28e6eaab..d5ba66ad 100644 --- a/src/Video.cpp +++ b/src/Video.cpp @@ -55,6 +55,7 @@ int VIDEO::tStatesScreen; uint8_t* VIDEO::grmem; uint32_t* VIDEO::SaveRect; int VIDEO::VsyncFinetune[2]; +// uint8_t VIDEO::dispUpdCycle; void IRAM_ATTR VGA6Bit::interrupt(void *arg) { @@ -311,79 +312,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; + unsigned int currentTstates = CPU::tstates - 1; - currentTstates--; - - 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]); } @@ -431,8 +468,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; @@ -446,8 +484,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 - tstateDraw]; CPU::tstates += statestoadd; statestoadd += video_rest; @@ -459,26 +496,42 @@ 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; } } } - -void IRAM_ATTR VIDEO::MainScreen(unsigned int statestoadd, bool contended) { +// ------------------------------- +// Non ptime-128 compliant version +// ------------------------------- +void 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 - 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 @@ -498,17 +551,66 @@ void IRAM_ATTR VIDEO::MainScreen(unsigned int statestoadd, bool contended) { } -void IRAM_ATTR VIDEO::MainScreen_OSD(unsigned int statestoadd, bool contended) { +// // --------------------------- +// // ptime-128 compliant version +// // --------------------------- +// void IRAM_ATTR VIDEO::MainScreen(unsigned int statestoadd, bool contended) { + +// static uint8_t att1,bmp1; + +// if (contended) statestoadd += wait_st[CPU::tstates - tstateDraw]; + +// CPU::tstates += statestoadd; + +// statestoadd += video_rest; + +// for (int i=0; i < statestoadd; i++) { + +// switch(dispUpdCycle) { +// case 0: +// case 2: +// bmp1 = grmem[bmpOffset++]; +// break; +// case 1: +// att1 = grmem[attOffset++]; // get attribute byte +// case 5: + +// 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 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 - tstateDraw]; 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)) { @@ -528,11 +630,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; } @@ -543,8 +648,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 - tstateDraw]; CPU::tstates += statestoadd; statestoadd += video_rest; @@ -555,6 +659,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 40d1e34f..6f1d7d19 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") @@ -559,6 +564,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 +601,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; @@ -752,7 +765,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 +796,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 +925,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 +955,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; @@ -979,52 +997,46 @@ void Z80::incRegR(uint8_t inc) { void IRAM_ATTR Z80::execute() { - // opCode = Z80Ops::fetchOpcode(REG_PC); - FETCH_OPCODE(opCode,REG_PC); - regR++; + uint8_t pg = REG_PC >> 14; + VIDEO::Draw(4,MemESP::ramContended[pg]); + opCode = MemESP::ramCurrent[pg][REG_PC & 0x3fff]; - #ifdef WITH_BREAKPOINT_SUPPORT - if (breakpointEnabled && prefixOpcode == 0) { - opCode = Z80Ops::breakpoint(REG_PC, opCode); - } - #endif - - REG_PC++; + regR++; - // 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 (!halted) { - 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 - + // Primero se comprueba NMI // Si se activa NMI no se comprueba INT porque la siguiente // instrucción debe ser la de 0x0066. @@ -1036,12 +1048,54 @@ void IRAM_ATTR Z80::execute() { // } // Ahora se comprueba si está activada la señal INT - if (ffIFF1 && !pendingEI && Z80Ops::isActiveINT()) { - interrupt(); - } + 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() { /* NOP */ } @@ -1803,12 +1857,14 @@ void Z80::decodeOpcode75() void Z80::decodeOpcode76() { /* HALT */ - REG_PC--; + + // REG_PC--; // Signal HALT to CPU Loop - CPU::tstates |= 0xFF000000; - + CPU::tstates |= 0xFF000000; + halted = true; + } void Z80::decodeOpcode77() @@ -2206,10 +2262,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() @@ -4288,6 +4356,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 @@ -4368,6 +4443,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: @@ -5771,6 +5906,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 +5919,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 +5930,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 +5940,7 @@ void Z80::decodeED(void) { if (REG_B != 0) { REG_PC = REG_PC - 2; Z80Ops::addressOnBus(REG_BC, 5); + SetAbortedINxR_OTxRFlags(); } break; } @@ -5810,6 +5951,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 +5964,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 +5975,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 +5985,7 @@ void Z80::decodeED(void) { if (REG_B != 0) { REG_PC = REG_PC - 2; Z80Ops::addressOnBus(REG_BC, 5); + SetAbortedINxR_OTxRFlags(); } break; } @@ -5856,7 +6003,7 @@ void Z80::decodeED(void) { } } -void Z80::copyToRegister(uint8_t value) +void IRAM_ATTR Z80::copyToRegister(uint8_t value) { switch (opCode & 0x07) { @@ -5884,3 +6031,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..fffa2e39 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] = 0xbf; + } // row order depends on actual row association with address lines, see @@ -153,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; } 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 00000000..05bb95f3 Binary files /dev/null and b/tools/EBF-convert/espectrum-logo-cropped.ebf4 differ diff --git a/tools/EBF-convert/espectrum-logo-cropped.ebf8 b/tools/EBF-convert/espectrum-logo-cropped.ebf8 new file mode 100644 index 00000000..63a5af90 Binary files /dev/null and b/tools/EBF-convert/espectrum-logo-cropped.ebf8 differ diff --git a/tools/EBF-convert/espectrum-logo-cropped.png b/tools/EBF-convert/espectrum-logo-cropped.png new file mode 100644 index 00000000..3b8eabb0 Binary files /dev/null and b/tools/EBF-convert/espectrum-logo-cropped.png differ