diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fe3bae1..718611a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,24 +32,56 @@ jobs: directory: pico, pico_board: pico, pico_platform: rp2040, + withemulator: 0, } - { buildname: Pico_W, directory: picow, pico_board: pico_w, pico_platform: rp2040, + withemulator: 0, } - { buildname: Pico2, directory: pico2, pico_board: pico2, pico_platform: rp2350-arm-s, + withemulator: 0, } - { buildname: Pico2_W, directory: pico2w, pico_board: pico2_w, pico_platform: rp2350-arm-s, + withemulator: 0, + } + - { + buildname: Pico_Emulator, + directory: pico_em, + pico_board: pico, + pico_platform: rp2040, + withemulator: 1, + } + - { + buildname: Pico2_Emulator, + directory: pico2_em, + pico_board: pico2, + pico_platform: rp2350-arm-s, + withemulator: 1, + } + - { + buildname: Pico_W_Emulator, + directory: pico_w_em, + pico_board: pico_w, + pico_platform: rp2040, + withemulator: 1, + } + - { + buildname: Pico2_W_Emulator, + directory: pico2_w_em, + pico_board: pico2_w, + pico_platform: rp2350-arm-s, + withemulator: 1, } fail-fast: false @@ -146,6 +178,13 @@ jobs: with: path: master + - name: 📇 Checkout emudore-embedded + if: ${{matrix.withemulator == 1 }} + uses: actions/checkout@v4 + with: + repository: loudnl/emudore-embedded + path: master/lib/emudore-embedded + - name: 🏭 Create build directory run: | mkdir -p ${{github.workspace}}/master/build_${{matrix.directory}} @@ -154,7 +193,7 @@ jobs: run: | unset PICO_PLATFORM unset PICO_BOARD - cmake -S master -B ${{github.workspace}}/master/build_${{matrix.directory}} -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DPICO_PLATFORM=${{matrix.pico_platform}} -DPICO_BOARD=${{matrix.pico_board}} -Dpicotool_DIR=${{github.workspace}}/picotool/picotool $extra_arg + cmake -S master -B ${{github.workspace}}/master/build_${{matrix.directory}} -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DPICO_PLATFORM=${{matrix.pico_platform}} -DPICO_BOARD=${{matrix.pico_board}} -Dpicotool_DIR=${{github.workspace}}/picotool/picotool -DONBOARD_EMULATOR=${{matrix.withemulator}} $extra_arg - name: 🏭 Build ${{matrix.name}} run: | @@ -181,5 +220,5 @@ jobs: - name: 💾 Upload Artifacts uses: actions/upload-artifact@v4 with: - name: usbsid${{matrix.pico_board}}-${{env.BRANCHNAME}}-autobuild-${{github.run_number}}-${{env.DATETIME}} + name: usbsid${{matrix.directory}}-${{env.BRANCHNAME}}-autobuild-${{github.run_number}}-${{env.DATETIME}} path: ${{github.workspace}}/master/dist diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 07f6212..1da75d6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -60,7 +60,7 @@ jobs: pattern: releasebuild-usbsid* merge-multiple: true - - name: View folder content + - name: View directory content env: IS_TAG: ${{ steps.branch_name.outputs.IS_TAG }} SOURCE_TAG: ${{ steps.branch_name.outputs.SOURCE_TAG }} @@ -96,24 +96,56 @@ jobs: directory: pico, pico_board: pico, pico_platform: rp2040, + withemulator: 0, } - { buildname: Pico_W, directory: picow, pico_board: pico_w, pico_platform: rp2040, + withemulator: 0, } - { buildname: Pico2, directory: pico2, pico_board: pico2, pico_platform: rp2350-arm-s, + withemulator: 0, } - { buildname: Pico2_W, directory: pico2w, pico_board: pico2_w, pico_platform: rp2350-arm-s, + withemulator: 0, + } + - { + buildname: Pico_Emulator, + directory: pico_em, + pico_board: pico, + pico_platform: rp2040, + withemulator: 1, + } + - { + buildname: Pico2_Emulator, + directory: pico2_em, + pico_board: pico2, + pico_platform: rp2350-arm-s, + withemulator: 1, + } + - { + buildname: Pico_W_Emulator, + directory: pico_w_em, + pico_board: pico_w, + pico_platform: rp2040, + withemulator: 1, + } + - { + buildname: Pico2_W_Emulator, + directory: pico2_w_em, + pico_board: pico2_w, + pico_platform: rp2350-arm-s, + withemulator: 1, } fail-fast: false @@ -211,7 +243,14 @@ jobs: with: path: master - - name: 🏭 Create build folders + - name: 📇 Checkout emudore-embedded + if: ${{matrix.withemulator == 1 }} + uses: actions/checkout@v4 + with: + repository: loudnl/emudore-embedded + path: master/lib/emudore-embedded + + - name: 🏭 Create build directory run: | mkdir -p ${{github.workspace}}/master/build_${{matrix.directory}} @@ -219,7 +258,7 @@ jobs: run: | unset PICO_PLATFORM unset PICO_BOARD - cmake -S master -B ${{github.workspace}}/master/build_${{matrix.directory}} -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DPICO_PLATFORM=${{matrix.pico_platform}} -DPICO_BOARD=${{matrix.pico_board}} -Dpicotool_DIR=${{github.workspace}}/picotool/picotool $extra_arg + cmake -S master -B ${{github.workspace}}/master/build_${{matrix.directory}} -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DPICO_PLATFORM=${{matrix.pico_platform}} -DPICO_BOARD=${{matrix.pico_board}} -Dpicotool_DIR=${{github.workspace}}/picotool/picotool -DONBOARD_EMULATOR=${{matrix.withemulator}} $extra_arg - name: 🏭 Build ${{matrix.name}} run: | @@ -246,5 +285,5 @@ jobs: - name: 💾 Upload Artifacts uses: actions/upload-artifact@v4 with: - name: releasebuild-usbsid${{matrix.pico_board}} + name: releasebuild-usbsid${{matrix.directory}} path: ${{github.workspace}}/master/dist diff --git a/.github/workflows/tagged_build.yml b/.github/workflows/tagged_build.yml index fddfda9..89b8185 100644 --- a/.github/workflows/tagged_build.yml +++ b/.github/workflows/tagged_build.yml @@ -134,24 +134,56 @@ jobs: directory: pico, pico_board: pico, pico_platform: rp2040, + withemulator: 0, } - { buildname: Pico_W, - directory: picow, + directory: pico_w, pico_board: pico_w, pico_platform: rp2040, + withemulator: 0, } - { buildname: Pico2, directory: pico2, pico_board: pico2, pico_platform: rp2350-arm-s, + withemulator: 0, } - { buildname: Pico2_W, - directory: pico2w, + directory: pico2_w, pico_board: pico2_w, pico_platform: rp2350-arm-s, + withemulator: 0, + } + - { + buildname: Pico_Emulator, + directory: pico_em, + pico_board: pico, + pico_platform: rp2040, + withemulator: 1, + } + - { + buildname: Pico2_Emulator, + directory: pico2_em, + pico_board: pico2, + pico_platform: rp2350-arm-s, + withemulator: 1, + } + - { + buildname: Pico_W_Emulator, + directory: pico_w_em, + pico_board: pico_w, + pico_platform: rp2040, + withemulator: 1, + } + - { + buildname: Pico2_W_Emulator, + directory: pico2_w_em, + pico_board: pico2_w, + pico_platform: rp2350-arm-s, + withemulator: 1, } fail-fast: false steps: @@ -257,6 +289,13 @@ jobs: with: path: master + - name: 📇 Checkout emudore-embedded + if: ${{matrix.withemulator == 1 }} + uses: actions/checkout@v4 + with: + repository: loudnl/emudore-embedded + path: master/lib/emudore-embedded + - name: 🏭 Create build directory run: | mkdir -p ${{github.workspace}}/master/build_${{matrix.directory}} @@ -265,7 +304,7 @@ jobs: run: | unset PICO_PLATFORM unset PICO_BOARD - cmake -S master -B ${{github.workspace}}/master/build_${{matrix.directory}} -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DPICO_PLATFORM=${{matrix.pico_platform}} -DPICO_BOARD=${{matrix.pico_board}} -Dpicotool_DIR=${{github.workspace}}/picotool/picotool $extra_arg + cmake -S master -B ${{github.workspace}}/master/build_${{matrix.directory}} -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DPICO_PLATFORM=${{matrix.pico_platform}} -DPICO_BOARD=${{matrix.pico_board}} -Dpicotool_DIR=${{github.workspace}}/picotool/picotool -DONBOARD_EMULATOR=${{matrix.withemulator}} $extra_arg - name: 🏭 Build ${{matrix.buildname}} run: | @@ -278,9 +317,9 @@ jobs: - name: 💾 Gather Artifact Files working-directory: ${{github.workspace}}/master run: | - mkdir usbsid${{matrix.pico_board}} - cp -av build_${{matrix.directory}}/*.uf2 usbsid${{matrix.pico_board}}/ - zip -r usbsid${{matrix.pico_board}}-taggedbuild-${{ steps.vars.outputs.tag }}.zip usbsid${{matrix.pico_board}}/ + mkdir usbsid${{matrix.directory}} + cp -av build_${{matrix.directory}}/*.uf2 usbsid${{matrix.directory}}/ + zip -r usbsid${{matrix.directory}}-taggedbuild-${{ steps.vars.outputs.tag }}.zip usbsid${{matrix.directory}}/ - name: Get current branch run: | @@ -295,8 +334,8 @@ jobs: uses: actions/github-script@v7 env: UPLOAD_URL: ${{ needs.create_release.outputs.upload_url }} - ASSET_PATH: ${{github.workspace}}/master/usbsid${{matrix.pico_board}}-taggedbuild-${{ steps.vars.outputs.tag }}.zip - ASSET_NAME: usbsid${{matrix.pico_board}}-taggedbuild-${{ steps.vars.outputs.tag }}.zip + ASSET_PATH: ${{github.workspace}}/master/usbsid${{matrix.directory}}-taggedbuild-${{ steps.vars.outputs.tag }}.zip + ASSET_NAME: usbsid${{matrix.directory}}-taggedbuild-${{ steps.vars.outputs.tag }}.zip ASSET_CONTENT_TYPE: application/zip with: github-token: ${{secrets.GITHUB_TOKEN}} diff --git a/.gitignore b/.gitignore index 91322bf..de2def2 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,10 @@ !.github/** !src !src/pio +!lib +!lib/emulator +!lib/emulator/flash +!lib/emulator/sidtunes !doc !doc/images !doc/images/firmware diff --git a/CMakeLists.txt b/CMakeLists.txt old mode 100755 new mode 100644 index 66d4845..826e7a0 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,15 +30,16 @@ set(PROJECT_NAME usbsidpico) set(PROJECT_MANUFACTURER "LouD") set(PRODUCT_STRING "USBSID-Pico") string(TIMESTAMP MAGIC_SMOKE "%Y%m%d") # Auto generate dated version -set(PROJECT_VERSION "0.5.1-BETA.${MAGIC_SMOKE}") # Generate compile version +set(PROJECT_VERSION "0.6.0-BETA.${MAGIC_SMOKE}") # Generate compile version ### Want a cookie? # NOTICE: ENABLING THESE DEBUGGING DEFINITIONS WILL HAVE SIGNIFICANT IMPACT AND WILL DELAY PLAYING! # NOTICE: UART AND USBCDC ARE MUTUALLY EXCLUSIVE! if(NOT DEFINED $ENV{DISABLE_DEBUGGING}) # MATCHES + set(BUILD_DEBUGGING DEBUG) # Set loglevel from CMake build steps (STATUS,DEBUG,TRACE) override with --log-level set(USBSID_DEBUGGING 1) # Enable debugging ~ mandatory enable for all other logging types - set(UART_DEBUGGING 1) # Enable debugging over uart pins - set(USBCDC_DEBUGGING 0) # Enable debugging over cdc port 2 + set(UART_DEBUGGING 1) # Enable debugging over uart pins ~ USBCDC must be 0! + set(USBCDC_DEBUGGING 0) # Enable debugging over cdc port 2 ~ UART must be 0! set(DEFAULT_DEBUGGING 1) # Enable debugging in usbsid.c set(CONFIG_DEBUGGING 1) # Enable debugging in config.c set(USBIO_DEBUGGING 0) # Enable debugging in usbsid.c @@ -47,41 +48,78 @@ if(NOT DEFINED $ENV{DISABLE_DEBUGGING}) # MATCHES set(MIDIVOICE_DEBUGGING 0) # Enable debugging in midi.c set(MEMORY_LOGGING 0) # Enable memory map of SID 1 voices printing set(SIDWRITES_DEBUGGING 0) # Enable logging of SID writes one core 2 + set(EMULATOR_DEBUGGING 0) # Enable debugging in emulator endif() +### Enable / Disable build with embedded emulator for Midi +set(ONBOARD_EMULATOR 0 CACHE STRING "ONBOARD_EMULATOR") +set(ONBOARD_SIDPLAYER 0) # Not functional yet! + +### Enable/ Disable build with PIO Uart on unused pins 26/27 +set(USE_PIO_UART 0) + +### Information on the use of CDC callback +## This is turned on/off by changing USE_CDC_CALLBACK in globals.h + +### Information on the use of Vendor buffer +## This is turned on/off by setting both vendor buffer size +## defines in tusb_config.h and by changing USE_VENDOR_BUFFER in globals.h +# CFG_TUD_VENDOR_TX_BUFSIZE +# CFG_TUD_VENDOR_RX_BUFSIZE + ####################################### #### You no touchy after this line #### ####################################### +### Build notes +# Do not use the below setting, this _will_ break compilation on both +# rp2040 and rp2350 +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -std=c++11") +# rp2040 will bug out complaining about assembly calls not being available +# rp2350 will bug out on PICO_USE_SW_SPIN_LOCK not being available + +### Build steps log level +set(CMAKE_MESSAGE_LOG_LEVEL ${BUILD_DEBUGGING}) +message(DEBUG "Starting compilation of ${PRODUCT_STRING} firmware version ${PROJECT_VERSION}") +if(ONBOARD_EMULATOR EQUAL 1) + message(DEBUG "Firmware is built with ONBOARD_EMULATOR") +endif() +if(ONBOARD_SIDPLAYER EQUAL 1) + message(DEBUG "Firmware is built with ONBOARD_SIDPLAYER") +endif() +message(DEBUG "LOG_LEVEL is ${CMAKE_MESSAGE_LOG_LEVEL}") + ### Optimization and debugging # remember that enabling debugging and disabling optimizations # will weird out tune playing and reading from and writing to # SKPico will stop functioning -SET(DEBUG_SYMBOLS 0) # 0 default, 1 debug symbols & debug build enabled -SET(DEBUGGING 0) # 0 default, 1~3 equals -g1~3 -SET(OPTIMIZATIONS 2) # 2 default, 1 ~ -O1 for debugging, 3 causes desync with DMA read_address and chain_to! -SET(TUSB_DEBUG 0) # 0 default, 0~3 non verbose to very verbose +set(DEBUG_SYMBOLS 0) # 0 default, 1 debug symbols & debug build enabled +set(DEBUGGING 0) # 0 default, 1~3 equals -g1~3 +set(OPTIMIZATIONS 2) # 2 default, 2 ~ -O1 for debugging *3 causes desync with DMA read_address and chain_to!() +set(WARNINGS_ONLY 0) # 0 default, 0 error on warnings +set(TUSB_DEBUG 0) # 0 default, 0~3 non verbose to very verbose +set(ANALYSE_STACKUSAGE 0) # 0 default, 1 enabled, 0 disabled ### Target board pico, pico_w, pico2 if(DEFINED PICO_BOARD) - message("PICO_BOARD is defined as ${PICO_BOARD}") + message(STATUS "PICO_BOARD is defined as ${PICO_BOARD}") else() - message("PICO_BOARD not defined, defaulting to 'pico'") + message(WARNING "PICO_BOARD not defined, defaulting to 'pico'") set(PICO_BOARD pico) endif() ### Target platform rp2040, rp2350 (rp2350-arm-s) if(DEFINED PICO_PLATFORM) - message("PICO_PLATFORM is defined as ${PICO_PLATFORM}") + message(STATUS "PICO_PLATFORM is defined as ${PICO_PLATFORM}") else() if(DEFINED PICO_BOARD) if(PICO_BOARD STREQUAL "pico2") set(PICO_PLATFORM rp2350) - message("PICO_PLATFORM not defined, board is ${PICO_BOARD} setting PICO_PLATFORM to ${PICO_PLATFORM}") + message(STATUS "PICO_PLATFORM not defined, board is ${PICO_BOARD} setting PICO_PLATFORM to ${PICO_PLATFORM}") endif() else() - message("PICO_PLATFORM not defined, defaulting to 'rp2040'") + message(WARNING "PICO_PLATFORM not defined, defaulting to 'rp2040'") set(PICO_PLATFORM rp2040) endif() endif() @@ -98,7 +136,7 @@ if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/src/globals.h) string(REGEX MATCH "^#define PROJECT_VERSION" VALIDATED ${LINE}) if(${VALIDATED} MATCHES ${VALIDATION_LINE}) set(REDUCTION_SUCCESS True) - message("VALIDATED header line '${VALIDATION_LINE}'") + message(DEBUG "VALIDATED header line '${VALIDATION_LINE}'") set(USBSID_MANUFACTURER "${PROJECT_MANUFACTURER} (v${PROJECT_VERSION})") add_compile_definitions(USBSID_MANUFACTURER="${USBSID_MANUFACTURER}") ### CMake shenanigens @@ -106,30 +144,34 @@ if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/src/globals.h) add_compile_definitions(PROJECT_VERSION="${PJVER}") break() else() - message("ERROR header validation line is present but incorrect") + message(SEND_ERROR "ERROR header validation line is present but incorrect") set(REDUCTION_SUCCESS False) return() endif() endif() endwhile() if(NOT REDUCTION_SUCCESS) - message("ERROR header validation fallback line not present") + message(SEND_ERROR "ERROR header validation fallback line not present") return() endif() else() - message("ERROR globals.h missing") + message(SEND_ERROR "ERROR globals.h missing") return() endif() -### Cmake compiler standard versions -set(CMAKE_C_STANDARD 11) -set(CMAKE_CXX_STANDARD 17) - -### Compilers to use +# ### Compilers to use if(${PICO_PLATFORM} MATCHES rp2040) + set(PICO_COMPILER pico_arm_cortex_m0plus_gcc) +elseif(${PICO_PLATFORM} MATCHES rp2350) + set(PICO_COMPILER pico_arm_cortex_m33_gcc) +else() set(PICO_COMPILER pico_arm_gcc) # required for mem_ops on rp2040 endif() +### Cmake compiler standard versions +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + ### Target environment path set(CMAKE_FIND_ROOT_PATH $ENV{PICO_ENV_PATH}) set(TINYUSB_PATH ${PICO_SDK_PATH}/lib/tinyusb) @@ -153,7 +195,7 @@ else() set(PICO_DEOPTIMIZED_DEBUG 0) ### TinyUSB debug logging if(TUSB_DEBUG GREATER 0) - message("TinyUSB debugging set to ${TUSB_DEBUG}") + message(DEBUG "TinyUSB debugging set to ${TUSB_DEBUG}") set(CFG_TUSB_DEBUG ${TUSB_DEBUG}) # add_compile_definitions(CFG_TUSB_DEBUG=${TUSB_DEBUG}) else() @@ -161,6 +203,8 @@ else() endif() endif() +message(STATUS "Firmware build type is ${CMAKE_BUILD_TYPE}") + ### Define compile time debugging if(DEBUGGING EQUAL 0) set(D_OPT -DNDEBUG) @@ -174,32 +218,46 @@ endif() ### Define compile time optimizations if(OPTIMIZATIONS EQUAL 0) - set(C_OPT -O0) + set(O_OPT -O0) elseif(OPTIMIZATIONS EQUAL 1) - set(C_OPT -Og) + set(O_OPT -Og) elseif(OPTIMIZATIONS EQUAL 2) - set(C_OPT -Ofast) + set(O_OPT -Ofast) elseif(OPTIMIZATIONS EQUAL 3) - set(C_OPT -O3) + set(O_OPT -O3) +endif() + +if(WARNINGS_ONLY EQUAL 1) + set(W_OPT + -Wall + -Wextra + -Wunused + ) +else() + set(W_OPT + -Werror + -Wno-format # int != int32_t as far as the compiler is concerned because gcc has int32_t as long int + -Wno-unused-function # extra check to verify no unused lingering code is present + -Wno-maybe-uninitialized + -Wno-unused + -Wno-misleading-indentation + -Wno-implicit-fallthrough + ) endif() ### Compiler flags and options set(COMPILE_OPTS PRIVATE ${D_OPT} - -Wall - -Wunused - -Werror - -Wno-format # int != int32_t as far as the compiler is concerned because gcc has int32_t as long int - -Wno-unused-function # extra check to verify no unused lingering code is present - -Wno-maybe-uninitialized + ${W_OPT} + ${O_OPT} -save-temps - ${C_OPT} -fverbose-asm -Wl,--wrap=ceil -Wl,--wrap=memcpy -Wl,--wrap=memset -Wl,--wrap=__aeabi_memcpy -Wl,--wrap=__aeabi_memset + -Wl,--wrap=__aeabi_memcmp -Wl,--wrap=__aeabi_memcpy4 -Wl,--wrap=__aeabi_memset4 -Wl,--wrap=__aeabi_memcpy8 @@ -208,7 +266,14 @@ set(COMPILE_OPTS PRIVATE -Wl,--wrap=vprintf -Wl,--wrap=puts ) -message("Compile time flags: ${COMPILE_OPTS}") + +if(ANALYSE_STACKUSAGE EQUAL 1) + set(COMPILE_OPTS + ${COMPILE_OPTS} + -fstack-usage + -fcallgraph-info + -DANALYSE_STACKUSAGE=1) +endif() ### Target product & output filename if(${PICO_BOARD} STREQUAL "pico") @@ -253,7 +318,6 @@ if(${PICO_BOARD} STREQUAL "pico") ) endif() - ### Source files to compile set(SOURCEFILES ${CMAKE_CURRENT_LIST_DIR}/src/usbsid_doubletap.c @@ -265,8 +329,7 @@ set(SOURCEFILES ${CMAKE_CURRENT_LIST_DIR}/src/gpio.c ${CMAKE_CURRENT_LIST_DIR}/src/vu.c ${CMAKE_CURRENT_LIST_DIR}/src/midi.c - # ${CMAKE_CURRENT_LIST_DIR}/src/midi_patches.c - # ${CMAKE_CURRENT_LIST_DIR}/src/midi_bankmsb0.c + ${CMAKE_CURRENT_LIST_DIR}/src/midi_handler.c ${CMAKE_CURRENT_LIST_DIR}/src/asid.c ${CMAKE_CURRENT_LIST_DIR}/src/sysex.c ${CMAKE_CURRENT_LIST_DIR}/src/sid.c @@ -277,10 +340,65 @@ set(SOURCEFILES ${CMAKE_CURRENT_LIST_DIR}/src/usb_descriptors.c ) +### Header folders to include +set(TARGET_INCLUDE_DIRS PRIVATE + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/src + ${TINYUSB_PATH}/hw + ${TINYUSB_PATH}/src +) + +### Emulator compilation additions +if(ONBOARD_EMULATOR EQUAL 1) + set(COMPILE_OPTS ${COMPILE_OPTS} -DEMBEDDED=1) + add_compile_definitions(ONBOARD_EMULATOR=1) + if(ONBOARD_SIDPLAYER EQUAL 1) + add_compile_definitions(ONBOARD_SIDPLAYER=1) + endif() + set(EMULATOR_LIST_DIR ${CMAKE_CURRENT_LIST_DIR}/lib/emulator) + set(EMUDORE_LIST_DIR ${CMAKE_CURRENT_LIST_DIR}/lib/emudore-embedded) + set(SOURCEFILES + ${SOURCEFILES} + ${EMULATOR_LIST_DIR}/emudore_emulator.c + ${EMULATOR_LIST_DIR}/interface.cpp + ${EMUDORE_LIST_DIR}/src/sidfile.cpp + ${EMUDORE_LIST_DIR}/src/cpu.cpp + ${EMUDORE_LIST_DIR}/src/memory.cpp + ${EMUDORE_LIST_DIR}/src/c64.cpp + ${EMUDORE_LIST_DIR}/src/cia1.cpp + ${EMUDORE_LIST_DIR}/src/cia2.cpp + ${EMUDORE_LIST_DIR}/src/io.cpp + ${EMUDORE_LIST_DIR}/src/vic.cpp + ${EMUDORE_LIST_DIR}/src/sidadapter.cpp + ${EMUDORE_LIST_DIR}/src/pla.cpp + ${EMUDORE_LIST_DIR}/src/cart.cpp + ${EMUDORE_LIST_DIR}/src/cart/MC68B50.cpp + ) + set(TARGET_INCLUDE_DIRS + ${TARGET_INCLUDE_DIRS} + ${EMUDORE_LIST_DIR}/src + ${EMUDORE_LIST_DIR}/src/cart + ${EMULATOR_LIST_DIR} + ${EMULATOR_LIST_DIR}/flash + ${EMULATOR_LIST_DIR}/sidtunes + ) + set(PICO_CXX_ENABLE_EXCEPTIONS 1) +endif() + +### PIO Uart compilation additions +if(USE_PIO_UART EQUAL 1) + add_compile_definitions(USE_PIO_UART=1) + set(SOURCEFILES + ${SOURCEFILES} + ${CMAKE_CURRENT_LIST_DIR}/src/uart.c + ) +endif() + ### Libraries to link set(TARGET_LL hardware_clocks hardware_dma + hardware_exception hardware_flash hardware_gpio hardware_pio @@ -289,10 +407,15 @@ set(TARGET_LL hardware_sync hardware_timer hardware_uart + # hardware_interp + pico_atomic # memcmp + pico_cxx_options pico_flash pico_mem_ops pico_mem_ops_compiler + pico_malloc pico_multicore + pico_rand pico_stdlib pico_unique_id pico_usb_reset_interface @@ -306,17 +429,13 @@ set(PIO_BUS ${CMAKE_CURRENT_LIST_DIR}/src/pio/bus_control.pio) set(PIO_CLOCK ${CMAKE_CURRENT_LIST_DIR}/src/pio/clock.pio) set(PIO_VU ${CMAKE_CURRENT_LIST_DIR}/src/pio/vu.pio) set(PIO_RGB ${CMAKE_CURRENT_LIST_DIR}/src/pio/vu_rgb.pio) - -### Header folders to include -set(TARGET_INCLUDE_DIRS PRIVATE - . - src - ${TINYUSB_PATH}/hw - ${TINYUSB_PATH}/src -) +if(USE_PIO_UART EQUAL 1) +set(PIO_UART ${CMAKE_CURRENT_LIST_DIR}/src/pio/uart_rx.pio) +endif() ### Pico sdk path include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake) +#include($ENV{PICO_EXTRAS_PATH}/external/pico_extras_import.cmake) # i2s audio ### Project type project(${PROJECT_NAME} C CXX ASM) @@ -329,7 +448,7 @@ include_directories(".") ### Double check debugging types if(UART_DEBUGGING EQUAL 1 AND USBCDC_DEBUGGING EQUAL 1) - message("ERROR cannot have both UART_DEBUGGING and USBCDC_DEBUGGING enabled!") + message(SEND_ERROR "ERROR cannot have both UART_DEBUGGING and USBCDC_DEBUGGING enabled!") return() endif() @@ -365,22 +484,38 @@ if(USBSID_DEBUGGING EQUAL 1) if(GPIOBUS_DEBUGGING EQUAL 1) add_compile_definitions(USBSIDGPIO_DEBUG=1) endif() + if(EMULATOR_DEBUGGING EQUAL 1) + add_compile_definitions(EMUDEBUG=1) + endif() endif() ### It escapes every damn time! add_compile_definitions(MAGIC_SMOKE=${MAGIC_SMOKE}) +### Captain I canna change the options anymore! +message(TRACE "C Compiler root: " ${CMAKE_FIND_ROOT_PATH}) +message(TRACE "CXX Compiler root: " ${CMAKE_FIND_ROOT_PATH}) +message(TRACE "C Compile time flags:") +message(TRACE "${CMAKE_C_FLAGS}") +message(TRACE "CXX Compile time flags:") +message(TRACE "${CMAKE_CXX_FLAGS}") +message(TRACE "Compile time options:") +message(TRACE "${COMPILE_OPTS}") +message(TRACE "Compile time source files:") +message(TRACE "${SOURCEFILES}") +message(TRACE "Compile time include dirs:") +message(TRACE "${TARGET_INCLUDE_DIRS}") + ### Compile targets foreach(FILENAME PICOTYPE PCBVERSION IN ZIP_LISTS FILENAMES PICOTYPES PCBVERSIONS) # set filename set(BUILD ${FILENAME}) set(BUILD_VERSION "") string(CONCAT BUILD_VERSION ${PROJECT_PRODUCT} " v" ${PCBVERSION}) - message(STATUS "Building ${FILENAME} with PICOTYPE=${PICOTYPE} and MAGIC_SMOKE=${MAGIC_SMOKE}") - message("Set USB manufacturer: ${USBSID_MANUFACTURER}") - message("Set USB product: ${BUILD_VERSION}") + message(DEBUG "Building ${FILENAME} with PICOTYPE=${PICOTYPE} and MAGIC_SMOKE=${MAGIC_SMOKE}") + message(DEBUG "Set USB manufacturer: ${USBSID_MANUFACTURER}") + message(DEBUG "Set USB product: ${BUILD_VERSION}") # executable - # add_executable(${BUILD} ${SOURCEFILES} ${LIBSOURCEFILES}) add_executable(${BUILD} ${SOURCEFILES}) # BUILD TYPES if(PICOTYPE STREQUAL "RGB") @@ -399,6 +534,9 @@ foreach(FILENAME PICOTYPE PCBVERSION IN ZIP_LISTS FILENAMES PICOTYPES PCBVERSION pico_generate_pio_header(${BUILD} ${PIO_BUS}) pico_generate_pio_header(${BUILD} ${PIO_CLOCK}) pico_generate_pio_header(${BUILD} ${PIO_VU}) + if(USE_PIO_UART EQUAL 1) + pico_generate_pio_header(${BUILD} ${PIO_UART}) + endif() if(PICOTYPE STREQUAL "RGB") pico_generate_pio_header(${BUILD} ${PIO_RGB}) endif() @@ -408,11 +546,11 @@ foreach(FILENAME PICOTYPE PCBVERSION IN ZIP_LISTS FILENAMES PICOTYPES PCBVERSION target_link_options(${BUILD} PRIVATE -Xlinker --print-memory-usage) # memory map linkers if(${PICO_PLATFORM} MATCHES rp2350) - message("Memmap linker, platform ${PICO_PLATFORM} MATCHES rp2350") + message(TRACE "Memmap linker, platform ${PICO_PLATFORM} MATCHES rp2350") target_compile_definitions(${BUILD} PRIVATE USBSID PICO_EMBED_XIP_SETUP=1) set_target_properties(${BUILD} PROPERTIES PICO_TARGET_LINKER_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/src/usbsidpico-rp2350.ld) else() - message("Memmap linker, platform ${PICO_PLATFORM} EQUALS rp2040") + message(TRACE "Memmap linker, platform ${PICO_PLATFORM} EQUALS rp2040") set_target_properties(${BUILD} PROPERTIES PICO_TARGET_LINKER_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/src/usbsidpico-rp2040.ld) endif() # tell the linker what libraries to link diff --git a/README.md b/README.md index e886088..88d5b02 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ USBSID-Pico is a RaspberryPi Pico/PicoW (RP2040) & Pico2/Pico2W (RP2350) based b # This is USBSID-Pico! :) -| **“Raster Bar” (8-bit)** | **Van Halen's Jump
dual SID in Stereo!** | **Flamethrower** | **Multiverse 100%
in Stereo!** | +| **“Raster Bar” (8-bit)** | **Van Halen's Jump
dual SID in Stereo!** | **Next Level** | **Coma Light 13** | |:-:|:-:|:-:|:-:| -| [![MOS6581](https://img.youtube.com/vi/nh0SxO1y6I0/1.jpg)](https://www.youtube.com/watch?v=nh0SxO1y6I0)
by LukHash | [![Dual MOS8580](https://img.youtube.com/vi/lzvkWlDq2TM/1.jpg)](https://www.youtube.com/watch?v=lzvkWlDq2TM)
by Nordischsound | [![MOS8580](https://img.youtube.com/vi/Mfbj21ntQXA/1.jpg)](https://www.youtube.com/watch?v=Mfbj21ntQXA)
by Reed | [![Dual MOS8580](https://img.youtube.com/vi/Rr-oq5jBeDg/1.jpg)](https://www.youtube.com/watch?v=Rr-oq5jBeDg)
by Nah-Kolor | +| [](https://www.youtube.com/watch?v=nh0SxO1y6I0)
by LukHash | [](https://www.youtube.com/watch?v=lzvkWlDq2TM)
by Nordischsound | [](https://www.youtube.com/watch?v=ER8v2g7TlwA)
by Performers | [](https://www.youtube.com/watch?v=iXviof4ZtIg)
by Oxyron | # Index @@ -44,21 +44,27 @@ USBSID-Pico is a RaspberryPi Pico/PicoW (RP2040) & Pico2/Pico2W (RP2350) based b ![USBSID-Pico](images/pcbv1.3-neon.png) See the [Software manual](doc/USBSID-Pico-software-manual.adoc) for more information on how to use supported software! #### SID Playing -USBSID-Pico supports various ways of playing SID files. -Out-of-the box playing is supported by using [Deepsid by Chordian](https://deepsid.chordian.net) -by selecting `WebUSB (Hermit)` as player in the pulldown menu or -by selecting `ASID (MIDI)` as player in the pulldown menu. -Out-of-the box playing is also supported by using [C64jukebox by Kenchis](https://haendel.ddns.net:8443/static/c64jukebox.vue), note that this is still in BETA. -[SidBerry](https://github.com/LouDnl/SidBerry) is a command line SID file player for Linux & Windows with up to 4 SIDs supported (Windows version is buggy). -Unofficial support is added to a fork of [Vice](https://github.com/LouDnl/Vice-USBSID), up to 3 SIDs are supported in vsid and up to 4 in x64sc. -Unofficial support is added to a fork of [sidplayfp](https://github.com/LouDnl/sidplayfp-usbsid) which requires a fork of [libsidplayfp](https://github.com/LouDnl/libsidplayfp-usbsid). -Unofficial support is added to a fork of [RetroDebugger](https://github.com/LouDnl/RetroDebugger), up to 4 SIDs are supported. +USBSID-Pico supports various ways of playing SID files. +- Out-of-the box playing is supported by using [Deepsid by Chordian](https://deepsid.chordian.net) + by selecting `WebUSB (Hermit)` as player in the pulldown menu or + by selecting `ASID (MIDI)` as player in the pulldown menu. +- Out-of-the box playing is also supported by using [C64jukebox by Kenchis](https://haendel.ddns.net:8443/static/c64jukebox.vue), note that this is still in BETA. +- [SidBerry](https://github.com/LouDnl/SidBerry) is a command line SID file player for Linux & Windows with up to 4 SIDs supported (Windows version is buggy). +#### C64 emulators +- [Vice](https://github.com/VICE-Team/svn-mirror/releases) has official support starting at tag [r45763](https://github.com/VICE-Team/svn-mirror/releases/tag/r45763) and up, up to 3 SIDs are supported in vsid and up to 4 in x64sc. +- [JSidplay2](https://haendel.ddns.net/~ken/#_latest_beta_versions) has official support in latest Java beta versions, up to 4 sids. +- [Denise](https://sourceforge.net/projects/deniseemu/) has official support in [Windows](https://ci.appveyor.com/project/piciji/denise/history) and [Linux](https://sourceforge.net/projects/deniseemu/files/nightlies/) nightly builds and in [code repo](https://bitbucket.org/piciji/denise/src/master/), up to 4 sids. +- Unofficial support is added to a fork of [sidplayfp](https://github.com/LouDnl/sidplayfp-usbsid) which requires a fork of [libsidplayfp](https://github.com/LouDnl/libsidplayfp-usbsid). +- Unofficial support is added to a fork of [RetroDebugger](https://github.com/LouDnl/RetroDebugger), up to 4 SIDs are supported. + ##### Amiga -[erique](https://github.com/erique) and [koobo](https://github.com/koobo) have added support to [playsid](https://github.com/erique/playsid.library) -##### C64 Music trackers -You should be able to use the ASID fork of [sidfactory2](https://github.com/Chordian/sidfactory2/tree/asid-support) without issues. -When using Vice or RetroDebugger you can freely use applications like [SID-Wizard](https://sourceforge.net/projects/sid-wizard/) for music creation. -There is also work being done in my forks of [Goattracker2](https://github.com/LouDnl/goattracker2) and [GTUltra](https://github.com/LouDnl/GTUltra-USBSID). Ask on Discord for latest binaries :) +- [erique](https://github.com/erique) and [koobo](https://github.com/koobo) have added support to [playsid](https://github.com/erique/playsid.library) + +#### C64 Music trackers +- You should be able to use the ASID fork of [sidfactory2](https://github.com/Chordian/sidfactory2/tree/asid-support) without issues. +- When using Vice or RetroDebugger you can freely use applications like [SID-Wizard](https://sourceforge.net/projects/sid-wizard/) for music creation. +- There is also work being done in my forks of [Goattracker2](https://github.com/LouDnl/goattracker2) and [GTUltra](https://github.com/LouDnl/GTUltra-USBSID). + Ask on Discord for latest binaries :) #### Midi USBSID-Pico acts as Midi device and supports basic Midi in ~ note that Midi is still in development and in Beta phase. @@ -72,7 +78,6 @@ Any questions about or support with USBSID-Pico can be asked # Project status Visit the [Project Page](https://github.com/users/LouDnl/projects/1) for an up-to-date list of things being worked on. -Firmware is in beta stage and still in development. While in development any mentioned features, options, etc. are subject to change. ### Code status | | Master | Dev | @@ -112,8 +117,8 @@ While in development any mentioned features, options, etc. are subject to change ### Supported platforms See the [Software manual](doc/USBSID-Pico-software-manual.adoc) for driver installation and supported software information! _In development_ -Linux: Vice, JSidplay2, SidplayFp, RetroDebugger, SidBerry, USB Midi, WebUSB & ASID (in webbrowser) SID Play -Windows: Vice, JSidplay2, SidBerry, USB Midi, WebUSB & ASID (in webbrowser) SID Play +Linux: Vice, JSidplay2, Denise, SidplayFp, RetroDebugger, SidBerry, USB Midi, WebUSB & ASID (in webbrowser) SID Play +Windows: Vice, JSidplay2, Denise, SidBerry, USB Midi, WebUSB & ASID (in webbrowser) SID Play Android: USB Midi, WebUSB & ASID (in webbrowser) SID Play Amiga: PlaySID library @@ -187,12 +192,12 @@ Your USBSID-Pico PCB has several hardware features like jumpers and pins that re ## Cases All USBSID-Pico community created cases are available in the [cases](cases/) directory, direct links below. _Cases for PCB revision v1.0:_ -* [Cartridge case](cases/v1.0/spotUP) by @spotUP -* [boxy case](cases/v1.0/schorsch3000) by @schorsch3000 +* [Cartridge case](cases/v1.0/spotUP) by [@spotUP](https://github.com/spotUP/) +* [boxy case](cases/v1.0/schorsch3000) by [@schorsch3000](https://github.com/schorsch3000/) _Cases for PCB revision v1.3:_ -* [spotUP Cartridge case revisited](cases/v1.3/spotUP-revisited) by @LouD -* [Dual USBSID-Pico Commodore 64 Case](cases/v1.3/Dual_USBSID-Pico_Commodore_64_Case) by @OlefinMakes +* [spotUP Cartridge case revisited](cases/v1.3/spotUP-revisited) by [@LouD](https://github.com/LouDnl/) +* [Dual USBSID-Pico Commodore 64 Case](cases/v1.3/Dual_USBSID-Pico_Commodore_64_Case) by [@OlefinMakes](https://github.com/OlefinMakes/) ### Schematic and BOM If you want and are up to it you can solder your own PCB or create your own development board using the documents below @@ -275,10 +280,11 @@ _Available examples with USBSID-Pico support:_
Pre compiled Vice binaries are available in my fork @ https://github.com/LouDnl/Vice-USBSID/releases # Acknowledgements -Special thanks goes out to [Tobozo](https://github.com/tobozo/) for making the USBSID-Pico logo and for his (mental🤣) support since starting this project. -Thanks to [erique](https://github.com/erique) and [koobo](https://github.com/koobo) for creating and implementing Amiga support! -Thanks to [Chordian](https://github.com/Chordian) for implementing my crappy webusb solution into deepsid. -Thanks to [Ken](https://sourceforge.net/u/kenchis/profile/) for adding webusb support to jsidplay2's c64jukebox. +Special thanks goes out to [@tobozo](https://github.com/tobozo/) for making the USBSID-Pico logo and for his (mental🤣) support since starting this project. +Thanks to [@erique](https://github.com/erique) and [@koobo](https://github.com/koobo) for creating and implementing Amiga support! +Thanks to [@Chordian](https://github.com/Chordian) for implementing my crappy webusb solution into deepsid. +Thanks to [@kenchis](https://sourceforge.net/u/kenchis/profile/) for adding webusb support to jsidplay2's c64jukebox. +Thanks to [PiCiJi](https://bitbucket.org/piciji/workspace/overview) for adding support to Denise. Some portions of this code and board are heavily inspired on projects by other great people. Some of those projects are - in no particular order: diff --git a/SHOWCASE.md b/SHOWCASE.md index c9e8b75..65396ed 100644 --- a/SHOWCASE.md +++ b/SHOWCASE.md @@ -18,7 +18,7 @@ Visit my [Youtube channel](https://www.youtube.com/channel/UCOu1hPBTsEbG7ZFnk9-2 |:-:|:-:|:-:| | [![MOS8580](https://img.youtube.com/vi/UQVDTNV3mgs/1.jpg)](https://www.youtube.com/watch?v=UQVDTNV3mgs) | [![MOS8580](https://img.youtube.com/vi/lXxlArB3VS4/1.jpg)](https://www.youtube.com/watch?v=lXxlArB3VS4) | [![MOS8580](https://img.youtube.com/vi/B4iYnZELbSc/1.jpg)](https://www.youtube.com/watch?v=B4iYnZELbSc) | -| **Codeboys & Endians** | **No Limit** | **Multiverse 100%
in Stereo!** | +| **Codeboys & Endians** | **No Limit** | **Multiverse 100%
with mirrored SID's!** | |:-:|:-:|:-:| | [![MOS8580](https://img.youtube.com/vi/sSDsOih1Wbw/1.jpg)](https://www.youtube.com/watch?v=sSDsOih1Wbw)
by Booze Design | [![MOS8580](https://img.youtube.com/vi/hJit04tWUaM/1.jpg)](https://www.youtube.com/watch?v=hJit04tWUaM)
Quantum tracker demo | [![Dual MOS8580](https://img.youtube.com/vi/Rr-oq5jBeDg/1.jpg)](https://www.youtube.com/watch?v=Rr-oq5jBeDg)
by Nah-Kolor | diff --git a/doc/USBSID-Pico-PCBv1.0-manual.adoc b/doc/USBSID-Pico-PCBv1.0-manual.adoc index 0777a51..eafdbbd 100644 --- a/doc/USBSID-Pico-PCBv1.0-manual.adoc +++ b/doc/USBSID-Pico-PCBv1.0-manual.adoc @@ -12,6 +12,9 @@ toc::[] [%always] <<< +== Disclaimer +include::disclaimer.adoc[] + == PCB top overview .Click image for larger view [#img-v13top,link=images/v1.0/v1.0-explained.png] @@ -104,9 +107,6 @@ Ground and S1 as labeled == 14. Reset button image:images/v1.0/reset-button-smaller.png[title=Reset button] -== Disclaimer -include::disclaimer.adoc[] - == License === Software License ~ GNUv2 include::license-software.adoc[] diff --git a/doc/USBSID-Pico-PCBv1.0-manual.pdf b/doc/USBSID-Pico-PCBv1.0-manual.pdf index 72fa9e6..ce602bc 100644 Binary files a/doc/USBSID-Pico-PCBv1.0-manual.pdf and b/doc/USBSID-Pico-PCBv1.0-manual.pdf differ diff --git a/doc/USBSID-Pico-PCBv1.3-manual.adoc b/doc/USBSID-Pico-PCBv1.3-manual.adoc index 80606e4..f166e1a 100644 --- a/doc/USBSID-Pico-PCBv1.3-manual.adoc +++ b/doc/USBSID-Pico-PCBv1.3-manual.adoc @@ -12,6 +12,9 @@ toc::[] [%always] <<< +== Disclaimer +include::disclaimer.adoc[] + == PCB top overview .Click image for larger view [#img-v13top,link=images/v1.3/v1.3b-top-marked.png] @@ -164,9 +167,6 @@ Last but not least, the digital audio switch IC. Switching from mono (both SID c [#img-v13bottom,link=images/v1.3/v1.3b-bottom.png] image::images/v1.3/v1.3b-bottom.png[title=PCB bottom overview] -== Disclaimer -include::disclaimer.adoc[] - == License === Software License ~ GNUv2 include::license-software.adoc[] diff --git a/doc/USBSID-Pico-PCBv1.3-manual.pdf b/doc/USBSID-Pico-PCBv1.3-manual.pdf index 9752032..e949bd3 100644 Binary files a/doc/USBSID-Pico-PCBv1.3-manual.pdf and b/doc/USBSID-Pico-PCBv1.3-manual.pdf differ diff --git a/doc/USBSID-Pico-firmware-manual.adoc b/doc/USBSID-Pico-firmware-manual.adoc index 3b5c140..0a30f69 100644 --- a/doc/USBSID-Pico-firmware-manual.adoc +++ b/doc/USBSID-Pico-firmware-manual.adoc @@ -14,6 +14,9 @@ toc::[] [%always] <<< +== Disclaimer +include::disclaimer.adoc[] + == Firmware types image:images/firmware/logo-v1.0.jpg[Title=PCB logo v1.0] image:images/firmware/logo-v1.3.jpg[Title=PCB logo v1.3] + @@ -259,9 +262,6 @@ _This config setting is intended for future use_ Available options are: + `False`, `True` -== Disclaimer -include::disclaimer.adoc[] - == License === Software License ~ GNUv2 include::license-software.adoc[] diff --git a/doc/USBSID-Pico-firmware-manual.pdf b/doc/USBSID-Pico-firmware-manual.pdf index 107f3fc..e1c257b 100644 Binary files a/doc/USBSID-Pico-firmware-manual.pdf and b/doc/USBSID-Pico-firmware-manual.pdf differ diff --git a/doc/USBSID-Pico-software-manual.adoc b/doc/USBSID-Pico-software-manual.adoc index 3f7047f..3d43c7b 100644 --- a/doc/USBSID-Pico-software-manual.adoc +++ b/doc/USBSID-Pico-software-manual.adoc @@ -14,6 +14,9 @@ toc::[] [%always] <<< +== Disclaimer +include::disclaimer.adoc[] + == Supported platforms _In active development_ + *Linux:* Vice, JSidplay2, SidplayFp, RetroDebugger, SidBerry, USB Midi, WebUSB & ASID (in webbrowser) SID Play + @@ -102,47 +105,54 @@ usbsidberry.exe -asid 1 path/to/sidfile.sid === Vice This section covers the use of USBSID-Pico with Vice under Linux, Windows and MacOS for the GTK and SDL2 versions of `vsid` and `x64sc` +WARNING: Switching on readmode and then switching it off again without restarting the PCB and Vice _will_ result in distorted audio + ==== Command-line arguments Command-line arguments override any previously configured items in your `vicerc` config file. + All three OS support the same command-line arguments for both `vsid` and `x64sc`. + However, the sound device argument is OS specific and `vsid` supports a maximum of 3 SID chips + -*Note* that if you define extra SID's and their addresses, these addresses need to point to the required address for the SID tune or Software you want to use. The Vice USBSID-Pico driver will automatically convert each write to the in firmware configured SID chip. +*Note* that if you define extra SID's and their addresses, these addresses need to point to the required address for the SID tune or Software you want to use. The Vice USBSID-Pico driver will automatically convert each write to the in firmware configured SID chip. + +Below is an excerpt from the Vice manual with information about each command-line option [source,shell] ---- -# vsid with usbsid enabled -vsid -sidenginemodel usbsid -# Define extra SID chips and their respective addresses in de Commodore 64 memory space -vsid -sidenginemodel usbsid -sidextra 2 -sid2address 0xD420 -sid3address 0xD440 +-usreadmode <0 or 1> + Enable USBSID-Pico read mode. When enabled, this mode allows for reading from SID registers that provides a means to configure an FPGASID that is seated on USBSID-Pico. This mode is not suited for regular audio use as it disables cycle exact writing & digiplay. Default is (SidUSBSIDReadMode=0) for off, (SidUSBSIDReadMode=1) for on. + +-usaudiomode <0 or 1> + Set USBSID-Pico PCB (v1.3) audio mode to Stereo or Mono. When enabled the audio of SID socket 1 will be output over the left audio channel and the audio of SID socket 2 over the right channel of USBSID-Pico's audio out. Default is (SidUSBSIDAudioMode=0) for Mono, (SidUSBSIDAudioMode=1) for Stereo. -# vsid with linux Alsa driver and usbsid enabled -vsid -sounddev alsa -sidenginemodel usbsid +-usdiffsize + Specifies the minimal difference in bytes to use between the head and tail of the drivers ringbuffer, this allows for some audio quality tuning on slower systems. In most cases the default value of 64 bytes (also the size of a USB packet) is the right setting for best audio quality. (SidUSBSIDDiffSize=32-256). + +-usbuffsize + Specifies the size in bytes to use as ringbuffer to store temporary data when sending SID writes to USBSID-Pico, this allows for some audio quality tuning on slower systems. In most cases the default value of 8192 bytes is the right setting for best audio quality. (SidUSBSIDBufferSize=512-16384). ---- [%always] <<< -==== vsid GTK +==== x64sc GTK ALT+O or click Preferences/Settings to open the settings menu. + *Sound configuration* + The sound configuration will require tuning for the computer you use it on. + In the screenshot below you can see that for this system I use the `pulse` audio driver and have the `Buffer size` set to 1 millisecond and `Fragment size` set to very small. + These 3 settings can make or break the audio quality. + -image:images/software/vsid-soundsettings-linux-gtk.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/vsid-soundsettings-linux-gtk.png",width="600"] + +image:images/software/x64sc-soundsettings-linux-gtk.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/x64sc-soundsettings-linux-gtk.png",width="600"] + *SID configuration* + For any audio to come out of the board you _need_ to select USBSID-Pico as SID engine. + If you want to use more the one SID then you need to select the amount of `Extra SIDs` and set their I/O addresses. + -image:images/software/vsid-sidsettings-linux-gtk.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/vsid-sidsettings-linux-gtk.png",width="600"] +image:images/software/x64sc-sidsettings-linux-gtk.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/x64sc-sidsettings-linux-gtk.png",width="600"] [%always] <<< -==== vsid SDL2 -F12 to open the settings menu. + +==== x64sc SDL2 +Press F12 (Linux/Windows) / F10 (MacOs) to open the settings menu. + *Sound configuration* + The sound configuration will require tuning for the computer you use it on. + -In the screenshot below you can see that for this system I use the `pulse` audio driver and have the `Buffer size` set to 10 milliseconds and `Fragment size` set to very small. + +In the screenshot below you can see that for this system I use the `pulse` audio driver and have the `Buffer size` set to 25 milliseconds and `Fragment size` set to very small. + These 3 settings can make or break the audio quality. + -image:images/software/vsid-soundsettings-linux-sdl2.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/vsid-soundsettings-linux-sdl2.png",width="600"] + +image:images/software/x64sc-soundsettings-linux-sdl2.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/x64sc-soundsettings-linux-sdl2.png",width="600"] + To get to these settings follow the following settings path: + `Sound settings` => `Output driver` => Select the driver you want to use + `Sound settings` => `Buffer size` => Select the milliseconds you want to use + @@ -150,36 +160,36 @@ To get to these settings follow the following settings path: + *SID configuration* + For any audio to come out of the board you _need_ to select USBSID-Pico as SID engine. + If you want to use more the one SID then you need to select the amount of `Extra SIDs` and set their I/O addresses. + -image:images/software/vsid-sidsettings-linux-sdl2.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/vsid-sidsettings-linux-sdl2.png",width="600"] +image:images/software/x64sc-sidsettings-linux-sdl2.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/x64sc-sidsettings-linux-sdl2.png",width="600"] + To get to these settings follow the following settings path: + -`SID settings` => `SID model` => `USBSID-Pico` + -`SID settings` => `Extra SIDs` => select the amount of extra SID's and set their addresses + +`Machine settings` => `Model settings` => `SID settings` => `SID model` => `USBSID-Pico` + +`Machine settings` => `Model settings` => `SID settings` => `Extra SIDs` => select the amount of extra SID's and set their addresses [%always] <<< -==== x64sc GTK +==== vsid GTK ALT+O or click Preferences/Settings to open the settings menu. + *Sound configuration* + The sound configuration will require tuning for the computer you use it on. + In the screenshot below you can see that for this system I use the `pulse` audio driver and have the `Buffer size` set to 1 millisecond and `Fragment size` set to very small. + These 3 settings can make or break the audio quality. + -image:images/software/x64sc-soundsettings-linux-gtk.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/x64sc-soundsettings-linux-gtk.png",width="600"] + +image:images/software/vsid-soundsettings-linux-gtk.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/vsid-soundsettings-linux-gtk.png",width="600"] + *SID configuration* + For any audio to come out of the board you _need_ to select USBSID-Pico as SID engine. + If you want to use more the one SID then you need to select the amount of `Extra SIDs` and set their I/O addresses. + -image:images/software/x64sc-sidsettings-linux-gtk.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/x64sc-sidsettings-linux-gtk.png",width="600"] +image:images/software/vsid-sidsettings-linux-gtk.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/vsid-sidsettings-linux-gtk.png",width="600"] [%always] <<< -==== x64sc SDL2 -F12 to open the settings menu. + +==== vsid SDL2 +Press F12 (Linux/Windows) / F10 (MacOs) to open the settings menu. + *Sound configuration* + The sound configuration will require tuning for the computer you use it on. + -In the screenshot below you can see that for this system I use the `pulse` audio driver and have the `Buffer size` set to 25 milliseconds and `Fragment size` set to very small. + +In the screenshot below you can see that for this system I use the `pulse` audio driver and have the `Buffer size` set to 10 milliseconds and `Fragment size` set to very small. + These 3 settings can make or break the audio quality. + -image:images/software/x64sc-soundsettings-linux-sdl2.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/x64sc-soundsettings-linux-sdl2.png",width="600"] + +image:images/software/vsid-soundsettings-linux-sdl2.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/vsid-soundsettings-linux-sdl2.png",width="600"] + To get to these settings follow the following settings path: + `Sound settings` => `Output driver` => Select the driver you want to use + `Sound settings` => `Buffer size` => Select the milliseconds you want to use + @@ -187,28 +197,56 @@ To get to these settings follow the following settings path: + *SID configuration* + For any audio to come out of the board you _need_ to select USBSID-Pico as SID engine. + If you want to use more the one SID then you need to select the amount of `Extra SIDs` and set their I/O addresses. + -image:images/software/x64sc-sidsettings-linux-sdl2.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/x64sc-sidsettings-linux-sdl2.png",width="600"] + +image:images/software/vsid-sidsettings-linux-sdl2.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/vsid-sidsettings-linux-sdl2.png",width="600"] To get to these settings follow the following settings path: + -`Machine settings` => `Model settings` => `SID settings` => `SID model` => `USBSID-Pico` + -`Machine settings` => `Model settings` => `SID settings` => `Extra SIDs` => select the amount of extra SID's and set their addresses +`SID settings` => `SID model` => `USBSID-Pico` + +`SID settings` => `Extra SIDs` => select the amount of extra SID's and set their addresses + [%always] <<< -=== Retrodebugger -t.b.d. - === jsidplay2 This section covers the use of USBSID-Pico with `jsidplay2` +==== Settings +After starting JSidplay2 you can choose USBSID-Pico from the dropdown menu that says emulation and set the board to mono or stereo using the settings dropdown + +image:images/software/jsidplay2-sid-config.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/jsidplay2-sid-config.png",width="600"] +image:images/software/jsidplay2-usbsid-config.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/jsidplay2-usbsid-config.png",width="600"] + ==== c64jukebox -`c64jukebox` website that runs on `jsidplay2` +`c64jukebox` website that runs on `jsidplay2` available at https://haendel.ddns.net:8443/static/c64jukebox.vue -=== sidplayfp +To enable USBSID-Pico in a WebUSB supporting browser (like Chrome) click on the `Hardware` tab and then click `Connect` in the USBSID-Pico box. After connecting search for any SID file in the search tab and click the play button. + +WARNING: Because this play method is not perfected yet there will be delays when selecting a follow up tune and pressing stop or pause. This can be circumvented enabling `use await for USBSID write` on the Hardware tab, but this will severely impact playing tunes that rely on timing + +image:images/software/c64jukebox-usbsid-config.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/c64jukebox-usbsid-config.png",width="600"] + +[%always] +<<< + +=== Denise +This section covers the use of USBSID-Pico with the C64 emulator of `Denise` + +==== USBSID settings +Open the C64 settings menu and go to the audio tab. Under this tab on the left side you will see an `USBSID-Pico` option + +Here you can enable or disable the use of USBSID-Pico. If you have any audio issue you can try to increase the buffer and diff sizes. +image:images/software/denise-usbsid-config.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/denise-usbsid-config.png",width="600"] + +==== SID settings +Open the C64 settings menu and go to the audio tab. Under this tab on the left side you will see a `Chip` option + +Here you can configure the amount of SID's you have on the board. Be sure to try the different settings for better output. +image:images/software/denise-sid-config.png[link="https://github.com/LouDnl/USBSID-Pico/blob/master/doc/images/software/denise-sid-config.png",width="600"] + +[%always] +<<< + +=== Retrodebugger t.b.d. -== Disclaimer -include::disclaimer.adoc[] +=== sidplayfp +t.b.d. == License === Software License ~ GNUv2 diff --git a/doc/USBSID-Pico-software-manual.pdf b/doc/USBSID-Pico-software-manual.pdf index d9a6209..7149583 100644 Binary files a/doc/USBSID-Pico-software-manual.pdf and b/doc/USBSID-Pico-software-manual.pdf differ diff --git a/doc/images/software/c64jukebox-usbsid-config.png b/doc/images/software/c64jukebox-usbsid-config.png new file mode 100644 index 0000000..5bc5413 Binary files /dev/null and b/doc/images/software/c64jukebox-usbsid-config.png differ diff --git a/doc/images/software/denise-sid-config.png b/doc/images/software/denise-sid-config.png new file mode 100644 index 0000000..14c2248 Binary files /dev/null and b/doc/images/software/denise-sid-config.png differ diff --git a/doc/images/software/denise-usbsid-config.png b/doc/images/software/denise-usbsid-config.png new file mode 100644 index 0000000..f3b8f11 Binary files /dev/null and b/doc/images/software/denise-usbsid-config.png differ diff --git a/doc/images/software/jsidplay2-sid-config.png b/doc/images/software/jsidplay2-sid-config.png new file mode 100644 index 0000000..fe299fb Binary files /dev/null and b/doc/images/software/jsidplay2-sid-config.png differ diff --git a/doc/images/software/jsidplay2-usbsid-config.png b/doc/images/software/jsidplay2-usbsid-config.png new file mode 100644 index 0000000..3036f5a Binary files /dev/null and b/doc/images/software/jsidplay2-usbsid-config.png differ diff --git a/doc/images/software/vsid-sidsettings-linux-gtk.png b/doc/images/software/vsid-sidsettings-linux-gtk.png index b2d5ca8..76be5d8 100644 Binary files a/doc/images/software/vsid-sidsettings-linux-gtk.png and b/doc/images/software/vsid-sidsettings-linux-gtk.png differ diff --git a/doc/images/software/vsid-sidsettings-linux-sdl2.png b/doc/images/software/vsid-sidsettings-linux-sdl2.png index 312f7f2..bfa2315 100644 Binary files a/doc/images/software/vsid-sidsettings-linux-sdl2.png and b/doc/images/software/vsid-sidsettings-linux-sdl2.png differ diff --git a/doc/images/software/x64sc-sidsettings-linux-gtk.png b/doc/images/software/x64sc-sidsettings-linux-gtk.png index e97f10f..5caeeb3 100644 Binary files a/doc/images/software/x64sc-sidsettings-linux-gtk.png and b/doc/images/software/x64sc-sidsettings-linux-gtk.png differ diff --git a/doc/images/software/x64sc-sidsettings-linux-sdl2.png b/doc/images/software/x64sc-sidsettings-linux-sdl2.png index 40650f5..3f09bd0 100644 Binary files a/doc/images/software/x64sc-sidsettings-linux-sdl2.png and b/doc/images/software/x64sc-sidsettings-linux-sdl2.png differ diff --git a/examples/config-tool/cfg_usbsid b/examples/config-tool/cfg_usbsid index 8d29f2b..082de2f 100755 Binary files a/examples/config-tool/cfg_usbsid and b/examples/config-tool/cfg_usbsid differ diff --git a/examples/config-tool/cfg_usbsid.c b/examples/config-tool/cfg_usbsid.c index f7b4854..1c18200 100644 --- a/examples/config-tool/cfg_usbsid.c +++ b/examples/config-tool/cfg_usbsid.c @@ -42,15 +42,18 @@ #include "cfg_skpico.h" #include "macros.h" -/* Compile with: - * gcc -g3 -L/usr/local/lib inih/ini.c cfg_usbsid.c -o cfg_usbsid $(pkg-config --libs --cflags libusb-1.0) -I./examples/config-tool/ini +/** + * Compile from config-tool directory: + * gcc -g3 -L/usr/local/lib inih/ini.c cfg_usbsid.c -o cfg_usbsid $(pkg-config --libs --cflags libusb-1.0) -I./inih + * Compile from repo root directory and copy to ~/.local/bin: * gcc -g3 -L/usr/local/lib examples/config-tool/inih/ini.c examples/config-tool/cfg_usbsid.c -o examples/config-tool/cfg_usbsid $(pkg-config --libs --cflags libusb-1.0) -I./examples/config-tool/inih ; cp examples/config-tool/cfg_usbsid ~/.local/bin + * Compile with mingw from config-tool directory: * /usr/bin/x86_64-w64-mingw32-gcc -g3 \ -L/usr/x86_64-w64-mingw32/sys-root/mingw/lib \ inih/ini.c cfg_usbsid.c -o cfg_usbsid.exe \ -lusb-1.0 \ - -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/libusb-1.0 - -I./examples/config-tool/inih + -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/libusb-1.0 \ + -I./inih */ /* ---------------------- */ @@ -1453,7 +1456,7 @@ void print_help(void) printf(" 2: Detection routine (Clones)\n"); printf(" 3: Unsafe detection routine\n"); printf(" -dclone, --detect-clone-types: Send clone autodetect command to device, returns the config as with '-r' afterwards\n"); - printf(" -auto, ----auto-detect-all : Send run autodetection routine command to device and reboot\n"); + printf(" -auto, --auto-detect-all : Send run autodetection routine command to device and reboot\n"); printf(" -w, --write-config : Write single config item to USBSID-Pico (will read the full config first!)\n"); printf(" -a, --apply-config : Apply the current config settings (from USBSID-Pico memory) that you changed with '-w'\n"); printf(" -s, --save-config : Send the save config command to USBSID-Pico\n"); diff --git a/examples/config-tool/cfg_usbsid.exe b/examples/config-tool/cfg_usbsid.exe index 0d68217..a79d9bd 100755 Binary files a/examples/config-tool/cfg_usbsid.exe and b/examples/config-tool/cfg_usbsid.exe differ diff --git a/examples/config-tool/cfg_usbsid_GUI.py b/examples/config-tool/cfg_usbsid_GUI.py index 55380d3..4eda4f1 100755 --- a/examples/config-tool/cfg_usbsid_GUI.py +++ b/examples/config-tool/cfg_usbsid_GUI.py @@ -5,21 +5,38 @@ import subprocess import os import threading -from pathlib import Path -from sys import argv, platform +import shlex +import tempfile +from sys import argv, platform # <-- CHANGE: Added import for platform check -class USBSidPicoConfigGUI:# {} +class USBSidPicoConfigGUI: def __init__(self, root): self.root = root - self.root.title("USBSID-Pico Config Tool GUI v0.1 ~ by ISL/Samar") + self.root.title("USBSID-Pico Config Tool GUI v0.2.1 ~ by ISL/Samar") self.root.geometry("800x800") - # Ścieżki - względne do lokalizacji tego pliku + style = ttk.Style(self.root) + # --- CHANGE --- Define the appearance of the button in the new 'selected' state + style.map('Active.TButton', + font=[('selected', ('Arial', 10, 'bold'))], + relief=[('selected', 'raised')], + highlightbackground=[('selected', 'gray')], + highlightcolor=[('selected', 'gray')], + borderwidth=[('selected', 7)], + background=[('selected', 'lightgreen')], + foreground=[('selected', 'green')]) + script_dir = os.path.dirname(os.path.abspath(__file__)) + + # --- START OF CHANGE: Multi-platform logic implementation --- if platform == "linux" or platform == "linux2" or platform == "darwin": toolexe = "cfg_usbsid" elif platform == "win32": toolexe = "cfg_usbsid.exe" + else: + # Default value for other, unforeseen systems + toolexe = "cfg_usbsid" + argc = len(argv) if (argc > 1): toolini = argv[1] @@ -27,30 +44,27 @@ def __init__(self, root): toolini = "default.ini" if not ".ini" in toolini: toolini = "default.ini" + self.exe_path = os.path.join(script_dir, toolexe) self.default_ini_path = os.path.join(script_dir, toolini) - # self.exe_path = os.path.join(script_dir, "cfg_usbsid.exe") - # self.default_ini_path = os.path.join(script_dir, "default.ini") # Sprawdź czy pliki istnieją if not os.path.exists(self.exe_path): messagebox.showerror("Error", f"{toolexe} not found at: {self.exe_path}") - if not os.path.exists(self.default_ini_path): - messagebox.showwarning("Warning", f"{toolini} not found at: {self.default_ini_path}") + root.destroy() + return + # --- END OF CHANGE --- - # Konfiguracja self.config = configparser.ConfigParser() + self.preset_buttons = {} self.current_ini_path = self.default_ini_path self.setup_ui() - self.load_config() + self._initial_load() def setup_ui(self): - # Main notebook self.notebook = ttk.Notebook(self.root) self.notebook.pack(fill='both', expand=True, padx=10, pady=10) - - # Tabs self.setup_general_tab() self.setup_socket_tab() self.setup_led_tab() @@ -60,513 +74,393 @@ def setup_ui(self): def setup_general_tab(self): general_frame = ttk.Frame(self.notebook) self.notebook.add(general_frame, text="General") - - # General controls ttk.Label(general_frame, text="General Configuration", font=('Arial', 12, 'bold')).pack(pady=10) - - # Clock rate clock_frame = ttk.LabelFrame(general_frame, text="SID Clock Rate") clock_frame.pack(fill='x', padx=10, pady=5) - self.clock_var = tk.StringVar(value="1000000") clock_rates = [("1.000 MHz", "1000000"), ("0.985 MHz", "985248"), - ("1.023 MHz", "1022727"), ("1.023 MHz (Alt)", "1023440")] - + ("1.023 MHz", "1022727"), ("1.023 MHz (Alt)", "1023440")] for text, value in clock_rates: - ttk.Radiobutton(clock_frame, text=text, variable=self.clock_var, - value=value).pack(anchor='w', padx=10, pady=2) - - # Lock clock rate + ttk.Radiobutton(clock_frame, text=text, variable=self.clock_var, value=value).pack(anchor='w', padx=10, pady=2) self.lock_clock_var = tk.BooleanVar() - ttk.Checkbutton(general_frame, text="Lock clock rate", - variable=self.lock_clock_var).pack(pady=5) - - # Audio switch + ttk.Checkbutton(general_frame, text="Lock clock rate", variable=self.lock_clock_var).pack(pady=5) audio_frame = ttk.LabelFrame(general_frame, text="Audio Switch") audio_frame.pack(fill='x', padx=10, pady=5) - self.audio_var = tk.StringVar(value="Stereo") - ttk.Radiobutton(audio_frame, text="Mono", variable=self.audio_var, - value="Mono").pack(anchor='w', padx=10, pady=2) - ttk.Radiobutton(audio_frame, text="Stereo", variable=self.audio_var, - value="Stereo").pack(anchor='w', padx=10, pady=2) - + ttk.Radiobutton(audio_frame, text="Mono", variable=self.audio_var, value="Mono").pack(anchor='w', padx=10, pady=2) + ttk.Radiobutton(audio_frame, text="Stereo", variable=self.audio_var, value="Stereo").pack(anchor='w', padx=20, pady=1) self.lock_audio_var = tk.BooleanVar() - ttk.Checkbutton(audio_frame, text="Lock audio switch", - variable=self.lock_audio_var).pack(pady=5) - - # FMOPL + ttk.Checkbutton(audio_frame, text="Lock audio switch", variable=self.lock_audio_var).pack(pady=5) fmopl_frame = ttk.LabelFrame(general_frame, text="FMOPL") fmopl_frame.pack(fill='x', padx=10, pady=5) - self.fmopl_var = tk.BooleanVar() ttk.Checkbutton(fmopl_frame, text="Enable FMOPL", variable=self.fmopl_var).pack(pady=5) def setup_socket_tab(self): socket_frame = ttk.Frame(self.notebook) self.notebook.add(socket_frame, text="SID Sockets") - - # Create a frame to hold both sockets side by side sockets_container = ttk.Frame(socket_frame) sockets_container.pack(fill='both', expand=True, padx=10, pady=5) - - # Socket 1 - socket1_frame = ttk.LabelFrame(sockets_container, text="Socket 1") - socket1_frame.pack(side='left', fill='both', expand=True, padx=(0, 5)) - - self.socket1_enabled = tk.BooleanVar(value=True) - ttk.Checkbutton(socket1_frame, text="Enabled", variable=self.socket1_enabled).pack(anchor='w', padx=10, pady=2) - - self.socket1_dualsid = tk.StringVar(value="Disabled") - ttk.Label(socket1_frame, text="Dual SID:").pack(anchor='w', padx=10, pady=2) - ttk.Radiobutton(socket1_frame, text="Disabled", variable=self.socket1_dualsid, - value="Disabled").pack(anchor='w', padx=20, pady=1) - ttk.Radiobutton(socket1_frame, text="Enabled", variable=self.socket1_dualsid, - value="Enabled").pack(anchor='w', padx=20, pady=1) - - self.socket1_chiptype = tk.StringVar(value="Real") - ttk.Label(socket1_frame, text="Chip type:").pack(anchor='w', padx=10, pady=2) - ttk.Radiobutton(socket1_frame, text="Real", variable=self.socket1_chiptype, - value="Real").pack(anchor='w', padx=20, pady=1) - ttk.Radiobutton(socket1_frame, text="Clone", variable=self.socket1_chiptype, - value="Clone").pack(anchor='w', padx=20, pady=1) - - self.socket1_clonetype = tk.StringVar(value="Disabled") - ttk.Label(socket1_frame, text="Clone type:").pack(anchor='w', padx=10, pady=2) clone_types = ["Disabled", "Other", "SKPico", "ARMSID", "FPGASID", "RedipSID"] - for clone_type in clone_types: - ttk.Radiobutton(socket1_frame, text=clone_type, variable=self.socket1_clonetype, - value=clone_type).pack(anchor='w', padx=20, pady=1) - - self.socket1_sid1type = tk.StringVar(value="MOS8580") - ttk.Label(socket1_frame, text="SID 1 type:").pack(anchor='w', padx=10, pady=2) sid_types = ["Unknown", "N/A", "MOS8580", "MOS6581", "FMopl"] - for sid_type in sid_types: - ttk.Radiobutton(socket1_frame, text=sid_type, variable=self.socket1_sid1type, - value=sid_type).pack(anchor='w', padx=20, pady=1) - - self.socket1_sid2type = tk.StringVar(value="N/A") - ttk.Label(socket1_frame, text="SID 2 type:").pack(anchor='w', padx=10, pady=2) - for sid_type in sid_types: - ttk.Radiobutton(socket1_frame, text=sid_type, variable=self.socket1_sid2type, - value=sid_type).pack(anchor='w', padx=20, pady=1) - - # Socket 2 - socket2_frame = ttk.LabelFrame(sockets_container, text="Socket 2") - socket2_frame.pack(side='right', fill='both', expand=True, padx=(5, 0)) - - self.socket2_enabled = tk.BooleanVar(value=True) - ttk.Checkbutton(socket2_frame, text="Enabled", variable=self.socket2_enabled).pack(anchor='w', padx=10, pady=2) - - self.socket2_dualsid = tk.StringVar(value="Disabled") - ttk.Label(socket2_frame, text="Dual SID:").pack(anchor='w', padx=10, pady=2) - ttk.Radiobutton(socket2_frame, text="Disabled", variable=self.socket2_dualsid, - value="Disabled").pack(anchor='w', padx=20, pady=1) - ttk.Radiobutton(socket2_frame, text="Enabled", variable=self.socket2_dualsid, - value="Enabled").pack(anchor='w', padx=20, pady=1) - - self.socket2_chiptype = tk.StringVar(value="Real") - ttk.Label(socket2_frame, text="Chip type:").pack(anchor='w', padx=10, pady=2) - ttk.Radiobutton(socket2_frame, text="Real", variable=self.socket2_chiptype, - value="Real").pack(anchor='w', padx=20, pady=1) - ttk.Radiobutton(socket2_frame, text="Clone", variable=self.socket2_chiptype, - value="Clone").pack(anchor='w', padx=20, pady=1) - - self.socket2_clonetype = tk.StringVar(value="Disabled") - ttk.Label(socket2_frame, text="Clone type:").pack(anchor='w', padx=10, pady=2) - for clone_type in clone_types: - ttk.Radiobutton(socket2_frame, text=clone_type, variable=self.socket2_clonetype, - value=clone_type).pack(anchor='w', padx=20, pady=1) - - self.socket2_sid1type = tk.StringVar(value="MOS8580") - ttk.Label(socket2_frame, text="SID 1 type:").pack(anchor='w', padx=10, pady=2) - for sid_type in sid_types: - ttk.Radiobutton(socket2_frame, text=sid_type, variable=self.socket2_sid1type, - value=sid_type).pack(anchor='w', padx=20, pady=1) - - self.socket2_sid2type = tk.StringVar(value="N/A") - ttk.Label(socket2_frame, text="SID 2 type:").pack(anchor='w', padx=10, pady=2) - for sid_type in sid_types: - ttk.Radiobutton(socket2_frame, text=sid_type, variable=self.socket2_sid2type, - value=sid_type).pack(anchor='w', padx=20, pady=1) - + self.socket1_vars = self._create_socket_widgets(sockets_container, "Socket 1", clone_types, sid_types) + self.socket1_vars["frame"].pack(side='left', fill='both', expand=True, padx=(0, 5)) + self.socket2_vars = self._create_socket_widgets(sockets_container, "Socket 2", clone_types, sid_types) + self.socket2_vars["frame"].pack(side='right', fill='both', expand=True, padx=(5, 0)) self.socket2_act_as_one = tk.BooleanVar(value=True) - ttk.Checkbutton(socket2_frame, text="Act as one (mirror socket 1)", - variable=self.socket2_act_as_one).pack(pady=5) + ttk.Checkbutton(self.socket2_vars["frame"], text="Act as one (mirror socket 1)", variable=self.socket2_act_as_one).pack(pady=5) + + def _create_socket_widgets(self, parent, title, clone_types, sid_types): + frame = ttk.LabelFrame(parent, text=title) + vars = {"frame": frame, "enabled": tk.BooleanVar(value=True), "dualsid": tk.StringVar(value="Disabled"), + "chiptype": tk.StringVar(value="Real"), "clonetype": tk.StringVar(value="Disabled"), + "sid1type": tk.StringVar(value="MOS8580"), "sid2type": tk.StringVar(value="N/A")} + ttk.Checkbutton(frame, text="Enabled", variable=vars["enabled"]).pack(anchor='w', padx=10, pady=2) + ttk.Label(frame, text="Dual SID:").pack(anchor='w', padx=10, pady=2) + ttk.Radiobutton(frame, text="Disabled", variable=vars["dualsid"], value="Disabled").pack(anchor='w', padx=20, pady=1) + ttk.Radiobutton(frame, text="Enabled", variable=vars["dualsid"], value="Enabled").pack(anchor='w', padx=20, pady=1) + ttk.Label(frame, text="Chip type:").pack(anchor='w', padx=10, pady=2) + ttk.Radiobutton(frame, text="Real", variable=vars["chiptype"], value="Real").pack(anchor='w', padx=20, pady=1) + ttk.Radiobutton(frame, text="Clone", variable=vars["chiptype"], value="Clone").pack(anchor='w', padx=20, pady=1) + ttk.Label(frame, text="Clone type:").pack(anchor='w', padx=10, pady=2) + for t in clone_types: ttk.Radiobutton(frame, text=t, variable=vars["clonetype"], value=t).pack(anchor='w', padx=20, pady=1) + ttk.Label(frame, text="SID 1 type:").pack(anchor='w', padx=10, pady=2) + for t in sid_types: ttk.Radiobutton(frame, text=t, variable=vars["sid1type"], value=t).pack(anchor='w', padx=20, pady=1) + ttk.Label(frame, text="SID 2 type:").pack(anchor='w', padx=10, pady=2) + for t in sid_types: ttk.Radiobutton(frame, text=t, variable=vars["sid2type"], value=t).pack(anchor='w', padx=20, pady=1) + return vars def setup_led_tab(self): led_frame = ttk.Frame(self.notebook) self.notebook.add(led_frame, text="LED") - - # LED led_config_frame = ttk.LabelFrame(led_frame, text="LED") led_config_frame.pack(fill='x', padx=10, pady=5) - self.led_enabled = tk.BooleanVar(value=True) ttk.Checkbutton(led_config_frame, text="Enabled", variable=self.led_enabled).pack(anchor='w', padx=10, pady=2) - self.led_breathe = tk.BooleanVar(value=True) ttk.Checkbutton(led_config_frame, text="Idle breathing", variable=self.led_breathe).pack(anchor='w', padx=10, pady=2) - - # RGB LED rgb_frame = ttk.LabelFrame(led_frame, text="RGB LED") rgb_frame.pack(fill='x', padx=10, pady=5) - self.rgb_enabled = tk.BooleanVar(value=True) ttk.Checkbutton(rgb_frame, text="Enabled", variable=self.rgb_enabled).pack(anchor='w', padx=10, pady=2) - self.rgb_breathe = tk.BooleanVar(value=True) ttk.Checkbutton(rgb_frame, text="Idle breathing", variable=self.rgb_breathe).pack(anchor='w', padx=10, pady=2) - - # Brightness ttk.Label(rgb_frame, text="Brightness (0-255):").pack(anchor='w', padx=10, pady=2) self.rgb_brightness = tk.Scale(rgb_frame, from_=0, to=255, orient='horizontal') self.rgb_brightness.set(1) self.rgb_brightness.pack(fill='x', padx=10, pady=2) - - # SID to use ttk.Label(rgb_frame, text="SID to use:").pack(anchor='w', padx=10, pady=2) self.rgb_sid_to_use = tk.StringVar(value="1") for i in range(1, 5): - ttk.Radiobutton(rgb_frame, text=f"SID {i}", variable=self.rgb_sid_to_use, - value=str(i)).pack(anchor='w', padx=20, pady=1) + ttk.Radiobutton(rgb_frame, text=f"SID {i}", variable=self.rgb_sid_to_use, value=str(i)).pack(anchor='w', padx=20, pady=1) def setup_actions_tab(self): actions_frame = ttk.Frame(self.notebook) self.notebook.add(actions_frame, text="Actions") - # Presets presets_frame = ttk.LabelFrame(actions_frame, text="Presets") presets_frame.pack(fill='x', padx=10, pady=5) + preset_buttons_data = [("Single SID", "--single-sid"), ("Dual SID", "--dual-sid"), ("Dual SID Socket 1", "--dual-sid-socket1"), + ("Dual SID Socket 2", "--dual-sid-socket2"), ("Triple SID 1", "--triple-sid1"), ("Triple SID 2", "--triple-sid2"), + ("Quad SID", "--quad-sid"), ("Mirrored SID", "--mirrored-sid")] + for i, (text, command_tag) in enumerate(preset_buttons_data): + # --- CHANGE --- All preset buttons now use the new style + button = ttk.Button(presets_frame, text=text, command=lambda cmd=text: self.apply_preset(cmd), style='Active.TButton') + button.grid(row=i // 2, column=i % 2, padx=5, pady=2, sticky='ew') + self.preset_buttons[text] = button - preset_buttons = [ - ("Single SID", "--single-sid"), - ("Dual SID", "--dual-sid"), - ("Dual SID Socket 1", "--dual-sid-socket1"), - ("Dual SID Socket 2", "--dual-sid-socket2"), - ("Triple SID 1", "--triple-sid1"), - ("Triple SID 2", "--triple-sid2"), - ("Quad SID", "--quad-sid"), - ("Mirrored SID", "--mirrored-sid") - ] - - for i, (text, command) in enumerate(preset_buttons): - row = i // 2 - col = i % 2 - ttk.Button(presets_frame, text=text, - command=lambda cmd=command: self.run_command(cmd)).grid(row=row, column=col, padx=5, pady=2, sticky='ew') - - # Device actions device_frame = ttk.LabelFrame(actions_frame, text="Device Actions") device_frame.pack(fill='x', padx=10, pady=5) - - # Create a frame for device buttons and results - device_content_frame = ttk.Frame(device_frame) - device_content_frame.pack(fill='both', expand=True, padx=5, pady=5) - - # Left side - buttons - device_buttons_frame = ttk.Frame(device_content_frame) - device_buttons_frame.pack(side='left', fill='y', padx=(0, 10)) - - device_buttons = [ - ("Read Configuration", "--read-config"), - ("Read Version", "--version"), - ("Read Clock Speed", "--read-clock-speed"), - ("Reset SID", "--reset-sids"), - ("Reset SID Registers", "--reset-sid-registers"), - ("Reboot USBSID-Pico", "--reboot-usp"), - ("Bootloader for FW update", "--bootloader"), - ("Auto-detect All", "--auto-detect-all"), - ("Apply Configuration", "--apply-config"), - ("Save Configuration", "--save-config"), - ("Save and Reboot", "--save-reboot") - ] - - for i, (text, command) in enumerate(device_buttons): - ttk.Button(device_buttons_frame, text=text, - command=lambda cmd=command: self.run_device_command(cmd)).pack(fill='x', padx=5, pady=2) - - # Right side - results display - device_results_frame = ttk.LabelFrame(device_content_frame, text="Device Results") - device_results_frame.pack(side='right', fill='both', expand=True) - - # Results text area - self.device_results_text = tk.Text(device_results_frame, height=15, width=50) - device_scrollbar = ttk.Scrollbar(device_results_frame, orient="vertical", command=self.device_results_text.yview) - self.device_results_text.configure(yscrollcommand=device_scrollbar.set) - - self.device_results_text.pack(side="left", fill="both", expand=True, padx=5, pady=5) - device_scrollbar.pack(side="right", fill="y") - - # Clear results button - ttk.Button(device_results_frame, text="Clear Results", - command=self.clear_device_results).pack(pady=2) - - # File actions - file_frame = ttk.LabelFrame(actions_frame, text="File Actions") + device_buttons = [("Read Device settings", self.load_from_device), + ("Write current settings to Device", self.send_to_device), + ("Read Version [console]", lambda: self.run_command_threaded("--version")), + ("Start SID configuration autodetect", self.execute_auto_detect), + ("Reboot USBSID-Pico", lambda: self.run_command_threaded("--reboot-usp")), + ("Save and Reboot", lambda: self.run_command_threaded("--save-reboot"))] + for text, command in device_buttons: ttk.Button(device_frame, text=text, command=command).pack(fill='x', padx=5, pady=2) + + file_frame = ttk.LabelFrame(actions_frame, text="File Operations") file_frame.pack(fill='x', padx=10, pady=5) - - ttk.Button(file_frame, text="Generate Default INI", - command=self.generate_default_ini).pack(fill='x', padx=5, pady=2) - ttk.Button(file_frame, text="Export Configuration", - command=self.export_config).pack(fill='x', padx=5, pady=2) - ttk.Button(file_frame, text="Import Configuration", - command=self.import_config).pack(fill='x', padx=5, pady=2) - ttk.Button(file_frame, text="Save Settings to INI", - command=self.save_to_ini).pack(fill='x', padx=5, pady=2) - ttk.Button(file_frame, text="Load Settings from INI", - command=self.load_from_ini).pack(fill='x', padx=5, pady=2) + ttk.Button(file_frame, text="Dump settings from device to .ini File", command=self.export_config).pack(fill='x', padx=5, pady=2) + ttk.Button(file_frame, text="Write settings to Device from .ini File", command=self.import_config).pack(fill='x', padx=5, pady=2) + ttk.Button(file_frame, text="Export GUI settings to .ini File", command=self.save_to_ini).pack(fill='x', padx=5, pady=2) + ttk.Button(file_frame, text="Import .ini File to GUI", command=self.load_from_ini).pack(fill='x', padx=5, pady=2) def setup_console_tab(self): console_frame = ttk.Frame(self.notebook) self.notebook.add(console_frame, text="Console") - - # Console output - self.console_text = tk.Text(console_frame, height=20, width=80) + self.console_text = tk.Text(console_frame, height=20, width=80, wrap='word') scrollbar = ttk.Scrollbar(console_frame, orient="vertical", command=self.console_text.yview) self.console_text.configure(yscrollcommand=scrollbar.set) - self.console_text.pack(side="left", fill="both", expand=True, padx=10, pady=10) scrollbar.pack(side="right", fill="y") + ttk.Button(console_frame, text="Clear Console", command=self.clear_console).pack(pady=5) - # Clear button - ttk.Button(console_frame, text="Clear Console", - command=self.clear_console).pack(pady=5) - - def log_to_console(self, message): - self.console_text.insert(tk.END, f"{message}\n") - self.console_text.see(tk.END) - - def clear_console(self): - self.console_text.delete(1.0, tk.END) - - def run_command(self, command): - def run(): - try: - self.log_to_console(f"Executing: {command}") - result = subprocess.run([self.exe_path, command], - capture_output=True, text=True, timeout=10) - - if result.stdout: - self.log_to_console(f"STDOUT: {result.stdout}") - if result.stderr: - self.log_to_console(f"STDERR: {result.stderr}") - - self.log_to_console(f"Exit code: {result.returncode}") - - except subprocess.TimeoutExpired: - self.log_to_console("Command timed out") - except Exception as e: - self.log_to_console(f"Error: {e}") - - threading.Thread(target=run, daemon=True).start() - - def run_device_command(self, command): - """Run device command and display results in device results area""" - def run(): - try: - self.log_to_device_results(f"Executing: {command}") - result = subprocess.run([self.exe_path, command], - capture_output=True, text=True, timeout=10) + def _initial_load(self): + self.log_to_console("--- Application Start ---") + self.log_to_console("Attempting to auto-load configuration from device...") + temp_filepath = None + try: + with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.ini', encoding='utf-8') as temp_file: + temp_filepath = temp_file.name - if result.stdout: - self.log_to_device_results(f"STDOUT:\n{result.stdout}") - if result.stderr: - self.log_to_device_results(f"STDERR:\n{result.stderr}") + command = f'--export-config "{temp_filepath}"' + self.run_command_blocking(command, silent=True) + self.load_config(temp_filepath) + messagebox.showinfo("Device Connected", "Successfully connected and loaded settings from the USBSID-Pico device.") + except Exception as e: + self.log_to_console(f"Auto-load from device failed. This is normal if the device is not connected. Details: {e}") + messagebox.showwarning("Device Not Found", "Could not automatically load settings from the USBSID-Pico device.\n\nPlease ensure the device is connected \n\nAnd NOT playing SID music.\n\nLoading default settings from file instead.") + self.load_config(self.default_ini_path) + finally: + if temp_filepath and os.path.exists(temp_filepath): + os.remove(temp_filepath) + + def apply_preset(self, preset_name): + self.log_to_console(f"Preset button clicked: {preset_name}") + self._set_gui_for_preset(preset_name) + + if messagebox.askyesno("Apply Preset", f"Apply the '{preset_name}' preset and write it to the device?"): + self.send_to_device(confirm=False) + else: + self.log_to_console("Preset application cancelled by user. Reverting to last known device state.") + self.update_ui_from_config() + + def _set_gui_for_preset(self, preset_name): + preset_map = { + "Single SID": (True, False, False, False, False), "Dual SID": (True, False, True, False, False), + "Dual SID Socket 1": (True, True, False, False, False), "Dual SID Socket 2": (False,False, True, True, False), + "Triple SID 1": (True, True, True, False, False), "Triple SID 2": (True, False, True, True, False), + "Quad SID": (True, True, True, True, False), "Mirrored SID": (True, False, True, False, True), + } + state = preset_map.get(preset_name) + if not state: return + + s1_en, s1_dual, s2_en, s2_dual, s2_mirror = state + self.socket1_vars["enabled"].set(s1_en) + self.socket1_vars["dualsid"].set("Enabled" if s1_dual else "Disabled") + self.socket2_vars["enabled"].set(s2_en) + self.socket2_vars["dualsid"].set("Enabled" if s2_dual else "Disabled") + self.socket2_act_as_one.set(s2_mirror) + self.log_to_console(f"GUI controls set to '{preset_name}' state.") + self._update_preset_highlighting() + + def execute_auto_detect(self, confirm=True): + if confirm and not messagebox.askyesno("Confirm Autodetection", "Are you sure? Current settings in the GUI will no longer match device settings. You must reload the configuration afterwards!"): + self.log_to_console("Autodetection cancelled by user.") + return + + self.log_to_console("Attempting send auto detect command to device...") + try: + command = f'--auto-detect-all' + self.run_command_blocking(command) + if confirm: messagebox.showinfo("Success", "Autodetect command sent!") + except Exception as e: + self.log_to_console(f"Operation failed: {e}") + messagebox.showerror("Error", f"Failed to send autodetect command.\n\nDetails: {e}") - self.log_to_device_results(f"Exit code: {result.returncode}") + def load_from_device(self, confirm=True): + if confirm and not messagebox.askyesno("Confirm Refresh", "Are you sure? All current settings in the GUI will be overwritten by the settings from the device."): + self.log_to_console("Refresh operation cancelled by user.") + return - except subprocess.TimeoutExpired: - self.log_to_device_results("Command timed out") - except Exception as e: - self.log_to_device_results(f"Error: {e}") + self.log_to_console("Attempting to refresh settings from device...") + temp_filepath = None + try: + with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.ini', encoding='utf-8') as temp_file: + temp_filepath = temp_file.name - threading.Thread(target=run, daemon=True).start() + command = f'--export-config "{temp_filepath}"' + self.run_command_blocking(command) + self.load_config(temp_filepath) + if confirm: messagebox.showinfo("Success", "Settings have been successfully refreshed from the device.") + except Exception as e: + self.log_to_console(f"Operation failed: {e}") + messagebox.showerror("Error", f"Failed to refresh settings from device.\n\nDetails: {e}") + finally: + if temp_filepath and os.path.exists(temp_filepath): os.remove(temp_filepath) + + def send_to_device(self, confirm=True): + if confirm and not messagebox.askyesno("Confirm Write", "Are you sure? All settings on the device will be overwritten."): + self.log_to_console("Write operation cancelled by user.") + return + + self.log_to_console("Attempting to write current GUI settings to device...") + temp_filepath = None + try: + self._update_config_from_ui() + with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.ini', encoding='utf-8', newline='') as temp_file: + temp_filepath = temp_file.name + self.config.write(temp_file) + + command = f'--import-config "{temp_filepath}"' + self.run_command_blocking(command) + messagebox.showinfo("Success", "Successfully wrote GUI settings to the device.") + except Exception as e: + self.log_to_console(f"Operation failed: {e}") + messagebox.showerror("Error", f"Failed to write settings to device.\n\nDetails: {e}") + finally: + if temp_filepath and os.path.exists(temp_filepath): os.remove(temp_filepath) - def log_to_device_results(self, message): - """Log message to device results area""" - self.device_results_text.insert(tk.END, f"{message}\n") - self.device_results_text.see(tk.END) + def log_to_console(self, message): + self.console_text.insert(tk.END, f"{message}\n") + self.console_text.see(tk.END) - def clear_device_results(self): - """Clear device results area""" - self.device_results_text.delete(1.0, tk.END) + def clear_console(self): self.console_text.delete(1.0, tk.END) + def run_command_threaded(self, command_string): threading.Thread(target=self.run_command_blocking, args=(command_string,), daemon=True).start() - def load_config(self): + def run_command_blocking(self, command_string, silent=False): + try: + cmd_list = [self.exe_path] + shlex.split(command_string) + if not silent: self.log_to_console(f"Executing: {cmd_list}") + result = subprocess.run(cmd_list, capture_output=True, text=True, timeout=15, check=True, encoding='utf-8', errors='ignore') + if not silent: + if result.stdout: self.log_to_console(f"STDOUT: {result.stdout}") + if result.stderr: self.log_to_console(f"STDERR: {result.stderr}") + return True + except FileNotFoundError: raise Exception(f"Executable not found at: {self.exe_path}") # CHANGE: Better error message + except subprocess.TimeoutExpired: raise Exception("The operation timed out. Is the device connected and responsive?") + except subprocess.CalledProcessError as e: + error_details = f"Command failed with exit code {e.returncode}.\n\nSTDERR:\n{e.stderr or 'N/A'}\n\nSTDOUT:\n{e.stdout or 'N/A'}" + raise Exception(error_details) + except Exception as e: raise Exception(f"An unexpected error occurred during command execution: {e}") + + def load_config(self, file_path): try: - if os.path.exists(self.current_ini_path): - self.config.read(self.current_ini_path) + if os.path.exists(file_path): + config = configparser.ConfigParser() + config.read(file_path) + self.config = config self.update_ui_from_config() - self.log_to_console(f"Loaded configuration from: {self.current_ini_path}") - else: - self.log_to_console(f"Configuration file does not exist: {self.current_ini_path}") - except Exception as e: - self.log_to_console(f"Error loading configuration: {e}") + self.current_ini_path = file_path + self.log_to_console(f"Successfully loaded and applied config from: {file_path}") + except Exception as e: self.log_to_console(f"Error loading INI file {file_path}: {e}") def update_ui_from_config(self): try: - # General - if 'General' in self.config: + if self.config.has_section('General'): gen = self.config['General'] self.clock_var.set(gen.get('clock_rate', '1000000')) - self.lock_clock_var.set(gen.get('lock_clockrate', 'False').lower() == 'true') - - # Socket 1 - if 'socketOne' in self.config: - s1 = self.config['socketOne'] - self.socket1_enabled.set(s1.get('enabled', 'True').lower() == 'true') - self.socket1_dualsid.set(s1.get('dualsid', 'Disabled')) - self.socket1_chiptype.set(s1.get('chiptype', 'Real')) - self.socket1_clonetype.set(s1.get('clonetype', 'Disabled')) - self.socket1_sid1type.set(s1.get('sid1type', 'MOS8580')) - self.socket1_sid2type.set(s1.get('sid2type', 'N/A')) - - # Socket 2 - if 'socketTwo' in self.config: - s2 = self.config['socketTwo'] - self.socket2_enabled.set(s2.get('enabled', 'True').lower() == 'true') - self.socket2_dualsid.set(s2.get('dualsid', 'Disabled')) - self.socket2_chiptype.set(s2.get('chiptype', 'Real')) - self.socket2_clonetype.set(s2.get('clonetype', 'Disabled')) - self.socket2_sid1type.set(s2.get('sid1type', 'MOS8580')) - self.socket2_sid2type.set(s2.get('sid2type', 'N/A')) - self.socket2_act_as_one.set(s2.get('act_as_one', 'True').lower() == 'true') - - # LED - if 'LED' in self.config: - led = self.config['LED'] - self.led_enabled.set(led.get('enabled', 'True').lower() == 'true') - self.led_breathe.set(led.get('idle_breathe', 'True').lower() == 'true') - - # RGB LED - if 'RGBLED' in self.config: + self.lock_clock_var.set(gen.getboolean('lock_clockrate', fallback=False)) + if self.config.has_section('Audioswitch'): + self.audio_var.set(self.config['Audioswitch'].get('set_to', 'Stereo')) + self.lock_audio_var.set(self.config['Audioswitch'].getboolean('lock_audio_switch', fallback=False)) + if self.config.has_section('FMOPL'): self.fmopl_var.set(self.config['FMOPL'].getboolean('enabled', fallback=False)) + if self.config.has_section('socketOne'): self._update_socket_ui(self.socket1_vars, self.config['socketOne']) + if self.config.has_section('socketTwo'): + self._update_socket_ui(self.socket2_vars, self.config['socketTwo']) + self.socket2_act_as_one.set(self.config['socketTwo'].getboolean('act_as_one', fallback=True)) + if self.config.has_section('LED'): + self.led_enabled.set(self.config['LED'].getboolean('enabled', fallback=True)) + self.led_breathe.set(self.config['LED'].getboolean('idle_breathe', fallback=True)) + if self.config.has_section('RGBLED'): rgb = self.config['RGBLED'] - self.rgb_enabled.set(rgb.get('enabled', 'True').lower() == 'true') - self.rgb_breathe.set(rgb.get('idle_breathe', 'True').lower() == 'true') - self.rgb_brightness.set(int(rgb.get('brightness', '1'))) + self.rgb_enabled.set(rgb.getboolean('enabled', fallback=True)) + self.rgb_breathe.set(rgb.getboolean('idle_breathe', fallback=True)) + self.rgb_brightness.set(rgb.getint('brightness', fallback=1)) self.rgb_sid_to_use.set(rgb.get('sid_to_use', '1')) - - # FMOPL - if 'FMOPL' in self.config: - self.fmopl_var.set(self.config['FMOPL'].get('enabled', 'False').lower() == 'true') - - # Audio switch - if 'Audioswitch' in self.config: - audio = self.config['Audioswitch'] - self.audio_var.set(audio.get('set_to', 'Stereo')) - self.lock_audio_var.set(audio.get('lock_audio_switch', 'False').lower() == 'true') - - except Exception as e: - self.log_to_console(f"Error updating UI: {e}") + self.root.after(50, self._update_preset_highlighting) + except Exception as e: self.log_to_console(f"CRITICAL ERROR updating UI from config: {e}") + + def _update_preset_highlighting(self): + # --- CHANGE --- Managing the 'selected' state instead of changing the style + for button in self.preset_buttons.values(): + button.state(['!selected']) + + preset_map = { + "Single SID": (True, False, False, False, False), "Dual SID": (True, False, True, False, False), + "Dual SID Socket 1": (True, True, False, False, False), "Dual SID Socket 2": (False,False, True, True, False), + "Triple SID 1": (True, True, True, False, False), "Triple SID 2": (True, False, True, True, False), + "Quad SID": (True, True, True, True, False), "Mirrored SID": (True, False, True, False, True), + } + + s1_en = self.socket1_vars["enabled"].get() + s1_dual = self.socket1_vars["dualsid"].get() == 'Enabled' + s2_en = self.socket2_vars["enabled"].get() + s2_dual = self.socket2_vars["dualsid"].get() == 'Enabled' + s2_mirror = self.socket2_act_as_one.get() + current_state = (s1_en, s1_dual, s2_en, s2_dual, s2_mirror) + + active_preset_name = None + for name, state in preset_map.items(): + if state == current_state: + active_preset_name = name + break + + if active_preset_name and self.preset_buttons.get(active_preset_name): + self.preset_buttons[active_preset_name].state(['selected']) + self.log_to_console(f"Active preset detected: {active_preset_name}") + + def _update_socket_ui(self, uivars, config_section): + uivars["enabled"].set(config_section.getboolean('enabled', fallback=True)) + uivars["dualsid"].set(config_section.get('dualsid', 'Disabled')) + uivars["chiptype"].set(config_section.get('chiptype', 'Real')) + uivars["clonetype"].set(config_section.get('clonetype', 'Disabled')) + uivars["sid1type"].set(config_section.get('sid1type', 'MOS8580')) + uivars["sid2type"].set(config_section.get('sid2type', 'N/A')) def save_to_ini(self): try: - # General - if 'General' not in self.config: - self.config['General'] = {} - - self.config['General']['clock_rate'] = self.clock_var.get() - self.config['General']['lock_clockrate'] = str(self.lock_clock_var.get()) - - # Socket 1 - if 'socketOne' not in self.config: - self.config['socketOne'] = {} - - self.config['socketOne']['enabled'] = str(self.socket1_enabled.get()) - self.config['socketOne']['dualsid'] = self.socket1_dualsid.get() - self.config['socketOne']['chiptype'] = self.socket1_chiptype.get() - self.config['socketOne']['clonetype'] = self.socket1_clonetype.get() - self.config['socketOne']['sid1type'] = self.socket1_sid1type.get() - self.config['socketOne']['sid2type'] = self.socket1_sid2type.get() - - # Socket 2 - if 'socketTwo' not in self.config: - self.config['socketTwo'] = {} - - self.config['socketTwo']['enabled'] = str(self.socket2_enabled.get()) - self.config['socketTwo']['dualsid'] = self.socket2_dualsid.get() - self.config['socketTwo']['chiptype'] = self.socket2_chiptype.get() - self.config['socketTwo']['clonetype'] = self.socket2_clonetype.get() - self.config['socketTwo']['sid1type'] = self.socket2_sid1type.get() - self.config['socketTwo']['sid2type'] = self.socket2_sid2type.get() - self.config['socketTwo']['act_as_one'] = str(self.socket2_act_as_one.get()) - - # LED - if 'LED' not in self.config: - self.config['LED'] = {} - - self.config['LED']['enabled'] = str(self.led_enabled.get()) - self.config['LED']['idle_breathe'] = str(self.led_breathe.get()) - - # RGB LED - if 'RGBLED' not in self.config: - self.config['RGBLED'] = {} - - self.config['RGBLED']['enabled'] = str(self.rgb_enabled.get()) - self.config['RGBLED']['idle_breathe'] = str(self.rgb_breathe.get()) - self.config['RGBLED']['brightness'] = str(self.rgb_brightness.get()) - self.config['RGBLED']['sid_to_use'] = self.rgb_sid_to_use.get() - - # FMOPL - if 'FMOPL' not in self.config: - self.config['FMOPL'] = {} - - self.config['FMOPL']['enabled'] = str(self.fmopl_var.get()) - - # Audio switch - if 'Audioswitch' not in self.config: - self.config['Audioswitch'] = {} - - self.config['Audioswitch']['set_to'] = self.audio_var.get() - self.config['Audioswitch']['lock_audio_switch'] = str(self.lock_audio_var.get()) - - # Save to file - with open(self.current_ini_path, 'w') as configfile: - self.config.write(configfile) - - self.log_to_console(f"Saved configuration to: {self.current_ini_path}") - messagebox.showinfo("Success", "Configuration has been saved") - - except Exception as e: - self.log_to_console(f"Error saving: {e}") - messagebox.showerror("Error", f"Failed to save configuration: {e}") + file_path = filedialog.asksaveasfilename(title="Export GUI settings to .ini File", defaultextension=".ini", filetypes=[("INI files", "*.ini"), ("All files", "*.*")]) + if not file_path: return + self._update_config_from_ui() + with open(file_path, 'w') as configfile: self.config.write(configfile) + messagebox.showinfo("Success", f"GUI settings have been exported to\n{file_path}") + except Exception as e: messagebox.showerror("Error", f"Failed to export configuration: {e}") + + def _update_config_from_ui(self): + if not self.config.has_section('General'): self.config.add_section('General') + self.config['General']['clock_rate'] = self.clock_var.get() + self.config['General']['lock_clockrate'] = str(self.lock_clock_var.get()) + self._update_socket_config(self.socket1_vars, 'socketOne') + self._update_socket_config(self.socket2_vars, 'socketTwo') + if not self.config.has_section('socketTwo'): self.config.add_section('socketTwo') + self.config['socketTwo']['act_as_one'] = str(self.socket2_act_as_one.get()) + if not self.config.has_section('LED'): self.config.add_section('LED') + self.config['LED']['enabled'] = str(self.led_enabled.get()) + self.config['LED']['idle_breathe'] = str(self.led_breathe.get()) + if not self.config.has_section('RGBLED'): self.config.add_section('RGBLED') + self.config['RGBLED']['enabled'] = str(self.rgb_enabled.get()) + self.config['RGBLED']['idle_breathe'] = str(self.rgb_breathe.get()) + self.config['RGBLED']['brightness'] = str(self.rgb_brightness.get()) + self.config['RGBLED']['sid_to_use'] = self.rgb_sid_to_use.get() + if not self.config.has_section('FMOPL'): self.config.add_section('FMOPL') + self.config['FMOPL']['enabled'] = str(self.fmopl_var.get()) + if not self.config.has_section('Audioswitch'): self.config.add_section('Audioswitch') + self.config['Audioswitch']['set_to'] = self.audio_var.get() + self.config['Audioswitch']['lock_audio_switch'] = str(self.lock_audio_var.get()) + + def _update_socket_config(self, uivars, section_name): + if not self.config.has_section(section_name): self.config.add_section(section_name) + s = self.config[section_name] + s['enabled'], s['dualsid'], s['chiptype'], s['clonetype'], s['sid1type'], s['sid2type'] = \ + str(uivars["enabled"].get()), uivars["dualsid"].get(), uivars["chiptype"].get(), \ + uivars["clonetype"].get(), uivars["sid1type"].get(), uivars["sid2type"].get() def load_from_ini(self): - file_path = filedialog.askopenfilename( - title="Select INI file", - filetypes=[("INI files", "*.ini"), ("All files", "*.*")] - ) - - if file_path: - self.current_ini_path = file_path - self.load_config() - - def generate_default_ini(self): - self.run_command("--default-ini") + file_path = filedialog.askopenfilename(title="Import .ini File to GUI", filetypes=[("INI files", "*.ini"), ("All files", "*.*")]) + if file_path: self.load_config(file_path) def export_config(self): - file_path = filedialog.asksaveasfilename( - title="Export Configuration", - defaultextension=".ini", - filetypes=[("INI files", "*.ini"), ("All files", "*.*")] - ) - - if file_path: - self.run_command(f"--export-config {file_path}") + file_path = filedialog.asksaveasfilename(title="Dump settings from device to .ini File", defaultextension=".ini", filetypes=[("INI files", "*.ini"), ("All files", "*.*")]) + if not file_path: return + try: + self.run_command_blocking(f'--export-config "{file_path}"') + messagebox.showinfo("Success", f"Successfully dumped device configuration to\n{file_path}") + except Exception as e: messagebox.showerror("Error", f"Failed to dump configuration from device.\n\nDetails: {e}") def import_config(self): - file_path = filedialog.askopenfilename( - title="Import Configuration", - filetypes=[("INI files", "*.ini"), ("All files", "*.*")] - ) - - if file_path: - self.run_command(f"--import-config {file_path}") + file_path = filedialog.askopenfilename(title="Write settings to Device from .ini File", filetypes=[("INI files", "*.ini"), ("All files", "*.*")]) + if not file_path: return + try: + self.run_command_blocking(f'--import-config "{file_path}"') + messagebox.showinfo("Success", f"Successfully wrote configuration to device from\n{file_path}") + except Exception as e: messagebox.showerror("Error", f"Failed to write configuration to device.\n\nDetails: {e}") def main(): root = tk.Tk() app = USBSidPicoConfigGUI(root) - root.mainloop() + if app.root.winfo_exists(): root.mainloop() if __name__ == "__main__": main() diff --git a/lib/emulator/emudore_emulator.c b/lib/emulator/emudore_emulator.c new file mode 100644 index 0000000..ab7b102 --- /dev/null +++ b/lib/emulator/emudore_emulator.c @@ -0,0 +1,187 @@ +/* + * USBSID-Pico is a RPi Pico/PicoW (RP2040) & Pico2/Pico2W (RP2350) based board + * for interfacing one or two MOS SID chips and/or hardware SID emulators over + * (WEB)USB with your computer, phone or ASID supporting player + * + * emulator_emodure.c + * This file is part of USBSID-Pico (https://github.com/LouDnl/USBSID-Pico) + * File author: LouD + * + * Any licensing conditions from the above named source automatically + * apply to this code + * + * Copyright (c) 2024-2025 LouD + * + * 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, version 2. + * + * 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 . + * + */ + +#include +#include +#include +#include + +#include "logging.h" +#include "config.h" +#include "globals.h" + +#ifdef ONBOARD_EMULATOR +#include +#include +#include +#include +#endif + +#ifdef ONBOARD_SIDPLAYER +#include +#endif + + +/* config.c */ +extern RuntimeCFG cfg; +extern void apply_clockrate(int n_clock, bool suspend_sids); + +/* gpio.c */ +extern void mute_sid(void); +extern void unmute_sid(void); + + +#ifdef ONBOARD_EMULATOR +/* interface.h */ +extern void start_emudore_cynthcart( + uint8_t * basic_, uint8_t * chargen_, + uint8_t * kernal_, uint8_t * binary_, + bool run_continuously +); +extern void start_emudore_prgtuneplayer( + uint8_t * basic_, uint8_t * chargen_, + uint8_t * kernal_, uint8_t * binary_, + size_t binsize_, bool run_continuously +); +extern void start_emudore_sidtuneplayer( + uint8_t * basic_, uint8_t * chargen_, + uint8_t * kernal_, uint8_t * binary_, + size_t binsize_, bool run_continuously +); +extern unsigned int run_emulation_cycle(void); +extern unsigned int run_specified_cycle( + bool cpu, bool cia1, bool cia2, + bool vic, bool io, bool cart); + +extern bool stop_emudore(void); +extern bool is_looping(void); +extern bool disable_looping(void); +extern void _set_logging(void); +extern void logging_enable(int logid); +extern void logging_disable(int logid); +#endif + +#ifdef ONBOARD_SIDPLAYER +/* Declare variables */ +bool sidplayer_init = false, sidplayer_playing = false; + +/* Declare local variables */ +static int sidfile_size = 0; +static int subtune = 0; +#endif + + +#ifdef ONBOARD_EMULATOR +void set_logging(int logid) +{ + logging_enable(logid); + _set_logging(); + return; +} + +void unset_logging(int logid) +{ + logging_disable(logid); + _set_logging(); + return; +} + +void start_emulator(void) +{ + apply_clockrate(1,true); /* Fixed to PAL */ + start_emudore_cynthcart(basic,chargen,kernal,cynthcart,true); + return; +} + +void stop_emulator(void) +{ + stop_emudore(); + return; +} + +unsigned int run_emulator(void) +{ + return run_emulation_cycle(); +} + +#ifdef ONBOARD_SIDPLAYER +static void print_tune_info() +{ + return; +} + +static void set_tune_config() +{ + return; +} + +void start_sidplayer(void) +{ /* BUG: Still has issues */ + size_t filesize = count_of(supremacyprg); /* 4382 */ + start_emudore_prgtuneplayer( + basic,chargen,kernal, + supremacyprg,filesize, + false); +} + +static int init_sidplayer(uint8_t * sidfile) +{ + return 0; +} + +int load_sidtune(uint8_t * sidfile, int sidfilesize, char tuneno) +{ + return 0; +} + +int load_sidtune_fromflash(int sidflashid, char tuneno) +{ + return 0; +} + +void reset_sidplayer(void) +{ + return; +} + +void next_subtune(void) +{ + return; +} + +void previous_subtune(void) +{ + return; +} + +uint16_t playtime(void) +{ + return 0; +} +#endif /* ONBOARD_SIDPLAYER */ +#endif /* ONBOARD_EMULATOR */ diff --git a/lib/emulator/flash/basic.h b/lib/emulator/flash/basic.h new file mode 100644 index 0000000..6d81472 --- /dev/null +++ b/lib/emulator/flash/basic.h @@ -0,0 +1,4 @@ +#ifndef _BIN_BASIC_ +#define _BIN_BASIC_ +unsigned char __in_flash("usbsid_binary") basic[] = {0x94, 0xE3, 0x7B, 0xE3, 0x43, 0x42, 0x4D, 0x42, 0x41, 0x53, 0x49, 0x43, 0x30, 0xA8, 0x41, 0xA7, 0x1D, 0xAD, 0xF7, 0xA8, 0xA4, 0xAB, 0xBE, 0xAB, 0x80, 0xB0, 0x05, 0xAC, 0xA4, 0xA9, 0x9F, 0xA8, 0x70, 0xA8, 0x27, 0xA9, 0x1C, 0xA8, 0x82, 0xA8, 0xD1, 0xA8, 0x3A, 0xA9, 0x2E, 0xA8, 0x4A, 0xA9, 0x2C, 0xB8, 0x67, 0xE1, 0x55, 0xE1, 0x64, 0xE1, 0xB2, 0xB3, 0x23, 0xB8, 0x7F, 0xAA, 0x9F, 0xAA, 0x56, 0xA8, 0x9B, 0xA6, 0x5D, 0xA6, 0x85, 0xAA, 0x29, 0xE1, 0xBD, 0xE1, 0xC6, 0xE1, 0x7A, 0xAB, 0x41, 0xA6, 0x39, 0xBC, 0xCC, 0xBC, 0x58, 0xBC, 0x10, 0x03, 0x7D, 0xB3, 0x9E, 0xB3, 0x71, 0xBF, 0x97, 0xE0, 0xEA, 0xB9, 0xED, 0xBF, 0x64, 0xE2, 0x6B, 0xE2, 0xB4, 0xE2, 0x0E, 0xE3, 0x0D, 0xB8, 0x7C, 0xB7, 0x65, 0xB4, 0xAD, 0xB7, 0x8B, 0xB7, 0xEC, 0xB6, 0x00, 0xB7, 0x2C, 0xB7, 0x37, 0xB7, 0x79, 0x69, 0xB8, 0x79, 0x52, 0xB8, 0x7B, 0x2A, 0xBA, 0x7B, 0x11, 0xBB, 0x7F, 0x7A, 0xBF, 0x50, 0xE8, 0xAF, 0x46, 0xE5, 0xAF, 0x7D, 0xB3, 0xBF, 0x5A, 0xD3, 0xAE, 0x64, 0x15, 0xB0, 0x45, 0x4E, 0xC4, 0x46, 0x4F, 0xD2, 0x4E, 0x45, 0x58, 0xD4, 0x44, 0x41, 0x54, 0xC1, 0x49, 0x4E, 0x50, 0x55, 0x54, 0xA3, 0x49, 0x4E, 0x50, 0x55, 0xD4, 0x44, 0x49, 0xCD, 0x52, 0x45, 0x41, 0xC4, 0x4C, 0x45, 0xD4, 0x47, 0x4F, 0x54, 0xCF, 0x52, 0x55, 0xCE, 0x49, 0xC6, 0x52, 0x45, 0x53, 0x54, 0x4F, 0x52, 0xC5, 0x47, 0x4F, 0x53, 0x55, 0xC2, 0x52, 0x45, 0x54, 0x55, 0x52, 0xCE, 0x52, 0x45, 0xCD, 0x53, 0x54, 0x4F, 0xD0, 0x4F, 0xCE, 0x57, 0x41, 0x49, 0xD4, 0x4C, 0x4F, 0x41, 0xC4, 0x53, 0x41, 0x56, 0xC5, 0x56, 0x45, 0x52, 0x49, 0x46, 0xD9, 0x44, 0x45, 0xC6, 0x50, 0x4F, 0x4B, 0xC5, 0x50, 0x52, 0x49, 0x4E, 0x54, 0xA3, 0x50, 0x52, 0x49, 0x4E, 0xD4, 0x43, 0x4F, 0x4E, 0xD4, 0x4C, 0x49, 0x53, 0xD4, 0x43, 0x4C, 0xD2, 0x43, 0x4D, 0xC4, 0x53, 0x59, 0xD3, 0x4F, 0x50, 0x45, 0xCE, 0x43, 0x4C, 0x4F, 0x53, 0xC5, 0x47, 0x45, 0xD4, 0x4E, 0x45, 0xD7, 0x54, 0x41, 0x42, 0xA8, 0x54, 0xCF, 0x46, 0xCE, 0x53, 0x50, 0x43, 0xA8, 0x54, 0x48, 0x45, 0xCE, 0x4E, 0x4F, 0xD4, 0x53, 0x54, 0x45, 0xD0, 0xAB, 0xAD, 0xAA, 0xAF, 0xDE, 0x41, 0x4E, 0xC4, 0x4F, 0xD2, 0xBE, 0xBD, 0xBC, 0x53, 0x47, 0xCE, 0x49, 0x4E, 0xD4, 0x41, 0x42, 0xD3, 0x55, 0x53, 0xD2, 0x46, 0x52, 0xC5, 0x50, 0x4F, 0xD3, 0x53, 0x51, 0xD2, 0x52, 0x4E, 0xC4, 0x4C, 0x4F, 0xC7, 0x45, 0x58, 0xD0, 0x43, 0x4F, 0xD3, 0x53, 0x49, 0xCE, 0x54, 0x41, 0xCE, 0x41, 0x54, 0xCE, 0x50, 0x45, 0x45, 0xCB, 0x4C, 0x45, 0xCE, 0x53, 0x54, 0x52, 0xA4, 0x56, 0x41, 0xCC, 0x41, 0x53, 0xC3, 0x43, 0x48, 0x52, 0xA4, 0x4C, 0x45, 0x46, 0x54, 0xA4, 0x52, 0x49, 0x47, 0x48, 0x54, 0xA4, 0x4D, 0x49, 0x44, 0xA4, 0x47, 0xCF, 0x00, 0x54, 0x4F, 0x4F, 0x20, 0x4D, 0x41, 0x4E, 0x59, 0x20, 0x46, 0x49, 0x4C, 0x45, 0xD3, 0x46, 0x49, 0x4C, 0x45, 0x20, 0x4F, 0x50, 0x45, 0xCE, 0x46, 0x49, 0x4C, 0x45, 0x20, 0x4E, 0x4F, 0x54, 0x20, 0x4F, 0x50, 0x45, 0xCE, 0x46, 0x49, 0x4C, 0x45, 0x20, 0x4E, 0x4F, 0x54, 0x20, 0x46, 0x4F, 0x55, 0x4E, 0xC4, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x20, 0x4E, 0x4F, 0x54, 0x20, 0x50, 0x52, 0x45, 0x53, 0x45, 0x4E, 0xD4, 0x4E, 0x4F, 0x54, 0x20, 0x49, 0x4E, 0x50, 0x55, 0x54, 0x20, 0x46, 0x49, 0x4C, 0xC5, 0x4E, 0x4F, 0x54, 0x20, 0x4F, 0x55, 0x54, 0x50, 0x55, 0x54, 0x20, 0x46, 0x49, 0x4C, 0xC5, 0x4D, 0x49, 0x53, 0x53, 0x49, 0x4E, 0x47, 0x20, 0x46, 0x49, 0x4C, 0x45, 0x20, 0x4E, 0x41, 0x4D, 0xC5, 0x49, 0x4C, 0x4C, 0x45, 0x47, 0x41, 0x4C, 0x20, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x20, 0x4E, 0x55, 0x4D, 0x42, 0x45, 0xD2, 0x4E, 0x45, 0x58, 0x54, 0x20, 0x57, 0x49, 0x54, 0x48, 0x4F, 0x55, 0x54, 0x20, 0x46, 0x4F, 0xD2, 0x53, 0x59, 0x4E, 0x54, 0x41, 0xD8, 0x52, 0x45, 0x54, 0x55, 0x52, 0x4E, 0x20, 0x57, 0x49, 0x54, 0x48, 0x4F, 0x55, 0x54, 0x20, 0x47, 0x4F, 0x53, 0x55, 0xC2, 0x4F, 0x55, 0x54, 0x20, 0x4F, 0x46, 0x20, 0x44, 0x41, 0x54, 0xC1, 0x49, 0x4C, 0x4C, 0x45, 0x47, 0x41, 0x4C, 0x20, 0x51, 0x55, 0x41, 0x4E, 0x54, 0x49, 0x54, 0xD9, 0x4F, 0x56, 0x45, 0x52, 0x46, 0x4C, 0x4F, 0xD7, 0x4F, 0x55, 0x54, 0x20, 0x4F, 0x46, 0x20, 0x4D, 0x45, 0x4D, 0x4F, 0x52, 0xD9, 0x55, 0x4E, 0x44, 0x45, 0x46, 0x27, 0x44, 0x20, 0x53, 0x54, 0x41, 0x54, 0x45, 0x4D, 0x45, 0x4E, 0xD4, 0x42, 0x41, 0x44, 0x20, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x50, 0xD4, 0x52, 0x45, 0x44, 0x49, 0x4D, 0x27, 0x44, 0x20, 0x41, 0x52, 0x52, 0x41, 0xD9, 0x44, 0x49, 0x56, 0x49, 0x53, 0x49, 0x4F, 0x4E, 0x20, 0x42, 0x59, 0x20, 0x5A, 0x45, 0x52, 0xCF, 0x49, 0x4C, 0x4C, 0x45, 0x47, 0x41, 0x4C, 0x20, 0x44, 0x49, 0x52, 0x45, 0x43, 0xD4, 0x54, 0x59, 0x50, 0x45, 0x20, 0x4D, 0x49, 0x53, 0x4D, 0x41, 0x54, 0x43, 0xC8, 0x53, 0x54, 0x52, 0x49, 0x4E, 0x47, 0x20, 0x54, 0x4F, 0x4F, 0x20, 0x4C, 0x4F, 0x4E, 0xC7, 0x46, 0x49, 0x4C, 0x45, 0x20, 0x44, 0x41, 0x54, 0xC1, 0x46, 0x4F, 0x52, 0x4D, 0x55, 0x4C, 0x41, 0x20, 0x54, 0x4F, 0x4F, 0x20, 0x43, 0x4F, 0x4D, 0x50, 0x4C, 0x45, 0xD8, 0x43, 0x41, 0x4E, 0x27, 0x54, 0x20, 0x43, 0x4F, 0x4E, 0x54, 0x49, 0x4E, 0x55, 0xC5, 0x55, 0x4E, 0x44, 0x45, 0x46, 0x27, 0x44, 0x20, 0x46, 0x55, 0x4E, 0x43, 0x54, 0x49, 0x4F, 0xCE, 0x56, 0x45, 0x52, 0x49, 0x46, 0xD9, 0x4C, 0x4F, 0x41, 0xC4, 0x9E, 0xA1, 0xAC, 0xA1, 0xB5, 0xA1, 0xC2, 0xA1, 0xD0, 0xA1, 0xE2, 0xA1, 0xF0, 0xA1, 0xFF, 0xA1, 0x10, 0xA2, 0x25, 0xA2, 0x35, 0xA2, 0x3B, 0xA2, 0x4F, 0xA2, 0x5A, 0xA2, 0x6A, 0xA2, 0x72, 0xA2, 0x7F, 0xA2, 0x90, 0xA2, 0x9D, 0xA2, 0xAA, 0xA2, 0xBA, 0xA2, 0xC8, 0xA2, 0xD5, 0xA2, 0xE4, 0xA2, 0xED, 0xA2, 0x00, 0xA3, 0x0E, 0xA3, 0x1E, 0xA3, 0x24, 0xA3, 0x83, 0xA3, 0x0D, 0x4F, 0x4B, 0x0D, 0x00, 0x20, 0x20, 0x45, 0x52, 0x52, 0x4F, 0x52, 0x00, 0x20, 0x49, 0x4E, 0x20, 0x00, 0x0D, 0x0A, 0x52, 0x45, 0x41, 0x44, 0x59, 0x2E, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x42, 0x52, 0x45, 0x41, 0x4B, 0x00, 0xA0, 0xBA, 0xE8, 0xE8, 0xE8, 0xE8, 0xBD, 0x01, 0x01, 0xC9, 0x81, 0xD0, 0x21, 0xA5, 0x4A, 0xD0, 0x0A, 0xBD, 0x02, 0x01, 0x85, 0x49, 0xBD, 0x03, 0x01, 0x85, 0x4A, 0xDD, 0x03, 0x01, 0xD0, 0x07, 0xA5, 0x49, 0xDD, 0x02, 0x01, 0xF0, 0x07, 0x8A, 0x18, 0x69, 0x12, 0xAA, 0xD0, 0xD8, 0x60, 0x20, 0x08, 0xA4, 0x85, 0x31, 0x84, 0x32, 0x38, 0xA5, 0x5A, 0xE5, 0x5F, 0x85, 0x22, 0xA8, 0xA5, 0x5B, 0xE5, 0x60, 0xAA, 0xE8, 0x98, 0xF0, 0x23, 0xA5, 0x5A, 0x38, 0xE5, 0x22, 0x85, 0x5A, 0xB0, 0x03, 0xC6, 0x5B, 0x38, 0xA5, 0x58, 0xE5, 0x22, 0x85, 0x58, 0xB0, 0x08, 0xC6, 0x59, 0x90, 0x04, 0xB1, 0x5A, 0x91, 0x58, 0x88, 0xD0, 0xF9, 0xB1, 0x5A, 0x91, 0x58, 0xC6, 0x5B, 0xC6, 0x59, 0xCA, 0xD0, 0xF2, 0x60, 0x0A, 0x69, 0x3E, 0xB0, 0x35, 0x85, 0x22, 0xBA, 0xE4, 0x22, 0x90, 0x2E, 0x60, 0xC4, 0x34, 0x90, 0x28, 0xD0, 0x04, 0xC5, 0x33, 0x90, 0x22, 0x48, 0xA2, 0x09, 0x98, 0x48, 0xB5, 0x57, 0xCA, 0x10, 0xFA, 0x20, 0x26, 0xB5, 0xA2, 0xF7, 0x68, 0x95, 0x61, 0xE8, 0x30, 0xFA, 0x68, 0xA8, 0x68, 0xC4, 0x34, 0x90, 0x06, 0xD0, 0x05, 0xC5, 0x33, 0xB0, 0x01, 0x60, 0xA2, 0x10, 0x6C, 0x00, 0x03, 0x8A, 0x0A, 0xAA, 0xBD, 0x26, 0xA3, 0x85, 0x22, 0xBD, 0x27, 0xA3, 0x85, 0x23, 0x20, 0xCC, 0xFF, 0xA9, 0x00, 0x85, 0x13, 0x20, 0xD7, 0xAA, 0x20, 0x45, 0xAB, 0xA0, 0x00, 0xB1, 0x22, 0x48, 0x29, 0x7F, 0x20, 0x47, 0xAB, 0xC8, 0x68, 0x10, 0xF4, 0x20, 0x7A, 0xA6, 0xA9, 0x69, 0xA0, 0xA3, 0x20, 0x1E, 0xAB, 0xA4, 0x3A, 0xC8, 0xF0, 0x03, 0x20, 0xC2, 0xBD, 0xA9, 0x76, 0xA0, 0xA3, 0x20, 0x1E, 0xAB, 0xA9, 0x80, 0x20, 0x90, 0xFF, 0x6C, 0x02, 0x03, 0x20, 0x60, 0xA5, 0x86, 0x7A, 0x84, 0x7B, 0x20, 0x73, 0x00, 0xAA, 0xF0, 0xF0, 0xA2, 0xFF, 0x86, 0x3A, 0x90, 0x06, 0x20, 0x79, 0xA5, 0x4C, 0xE1, 0xA7, 0x20, 0x6B, 0xA9, 0x20, 0x79, 0xA5, 0x84, 0x0B, 0x20, 0x13, 0xA6, 0x90, 0x44, 0xA0, 0x01, 0xB1, 0x5F, 0x85, 0x23, 0xA5, 0x2D, 0x85, 0x22, 0xA5, 0x60, 0x85, 0x25, 0xA5, 0x5F, 0x88, 0xF1, 0x5F, 0x18, 0x65, 0x2D, 0x85, 0x2D, 0x85, 0x24, 0xA5, 0x2E, 0x69, 0xFF, 0x85, 0x2E, 0xE5, 0x60, 0xAA, 0x38, 0xA5, 0x5F, 0xE5, 0x2D, 0xA8, 0xB0, 0x03, 0xE8, 0xC6, 0x25, 0x18, 0x65, 0x22, 0x90, 0x03, 0xC6, 0x23, 0x18, 0xB1, 0x22, 0x91, 0x24, 0xC8, 0xD0, 0xF9, 0xE6, 0x23, 0xE6, 0x25, 0xCA, 0xD0, 0xF2, 0x20, 0x59, 0xA6, 0x20, 0x33, 0xA5, 0xAD, 0x00, 0x02, 0xF0, 0x88, 0x18, 0xA5, 0x2D, 0x85, 0x5A, 0x65, 0x0B, 0x85, 0x58, 0xA4, 0x2E, 0x84, 0x5B, 0x90, 0x01, 0xC8, 0x84, 0x59, 0x20, 0xB8, 0xA3, 0xA5, 0x14, 0xA4, 0x15, 0x8D, 0xFE, 0x01, 0x8C, 0xFF, 0x01, 0xA5, 0x31, 0xA4, 0x32, 0x85, 0x2D, 0x84, 0x2E, 0xA4, 0x0B, 0x88, 0xB9, 0xFC, 0x01, 0x91, 0x5F, 0x88, 0x10, 0xF8, 0x20, 0x59, 0xA6, 0x20, 0x33, 0xA5, 0x4C, 0x80, 0xA4, 0xA5, 0x2B, 0xA4, 0x2C, 0x85, 0x22, 0x84, 0x23, 0x18, 0xA0, 0x01, 0xB1, 0x22, 0xF0, 0x1D, 0xA0, 0x04, 0xC8, 0xB1, 0x22, 0xD0, 0xFB, 0xC8, 0x98, 0x65, 0x22, 0xAA, 0xA0, 0x00, 0x91, 0x22, 0xA5, 0x23, 0x69, 0x00, 0xC8, 0x91, 0x22, 0x86, 0x22, 0x85, 0x23, 0x90, 0xDD, 0x60, 0xA2, 0x00, 0x20, 0x12, 0xE1, 0xC9, 0x0D, 0xF0, 0x0D, 0x9D, 0x00, 0x02, 0xE8, 0xE0, 0x59, 0x90, 0xF1, 0xA2, 0x17, 0x4C, 0x37, 0xA4, 0x4C, 0xCA, 0xAA, 0x6C, 0x04, 0x03, 0xA6, 0x7A, 0xA0, 0x04, 0x84, 0x0F, 0xBD, 0x00, 0x02, 0x10, 0x07, 0xC9, 0xFF, 0xF0, 0x3E, 0xE8, 0xD0, 0xF4, 0xC9, 0x20, 0xF0, 0x37, 0x85, 0x08, 0xC9, 0x22, 0xF0, 0x56, 0x24, 0x0F, 0x70, 0x2D, 0xC9, 0x3F, 0xD0, 0x04, 0xA9, 0x99, 0xD0, 0x25, 0xC9, 0x30, 0x90, 0x04, 0xC9, 0x3C, 0x90, 0x1D, 0x84, 0x71, 0xA0, 0x00, 0x84, 0x0B, 0x88, 0x86, 0x7A, 0xCA, 0xC8, 0xE8, 0xBD, 0x00, 0x02, 0x38, 0xF9, 0x9E, 0xA0, 0xF0, 0xF5, 0xC9, 0x80, 0xD0, 0x30, 0x05, 0x0B, 0xA4, 0x71, 0xE8, 0xC8, 0x99, 0xFB, 0x01, 0xB9, 0xFB, 0x01, 0xF0, 0x36, 0x38, 0xE9, 0x3A, 0xF0, 0x04, 0xC9, 0x49, 0xD0, 0x02, 0x85, 0x0F, 0x38, 0xE9, 0x55, 0xD0, 0x9F, 0x85, 0x08, 0xBD, 0x00, 0x02, 0xF0, 0xDF, 0xC5, 0x08, 0xF0, 0xDB, 0xC8, 0x99, 0xFB, 0x01, 0xE8, 0xD0, 0xF0, 0xA6, 0x7A, 0xE6, 0x0B, 0xC8, 0xB9, 0x9D, 0xA0, 0x10, 0xFA, 0xB9, 0x9E, 0xA0, 0xD0, 0xB4, 0xBD, 0x00, 0x02, 0x10, 0xBE, 0x99, 0xFD, 0x01, 0xC6, 0x7B, 0xA9, 0xFF, 0x85, 0x7A, 0x60, 0xA5, 0x2B, 0xA6, 0x2C, 0xA0, 0x01, 0x85, 0x5F, 0x86, 0x60, 0xB1, 0x5F, 0xF0, 0x1F, 0xC8, 0xC8, 0xA5, 0x15, 0xD1, 0x5F, 0x90, 0x18, 0xF0, 0x03, 0x88, 0xD0, 0x09, 0xA5, 0x14, 0x88, 0xD1, 0x5F, 0x90, 0x0C, 0xF0, 0x0A, 0x88, 0xB1, 0x5F, 0xAA, 0x88, 0xB1, 0x5F, 0xB0, 0xD7, 0x18, 0x60, 0xD0, 0xFD, 0xA9, 0x00, 0xA8, 0x91, 0x2B, 0xC8, 0x91, 0x2B, 0xA5, 0x2B, 0x18, 0x69, 0x02, 0x85, 0x2D, 0xA5, 0x2C, 0x69, 0x00, 0x85, 0x2E, 0x20, 0x8E, 0xA6, 0xA9, 0x00, 0xD0, 0x2D, 0x20, 0xE7, 0xFF, 0xA5, 0x37, 0xA4, 0x38, 0x85, 0x33, 0x84, 0x34, 0xA5, 0x2D, 0xA4, 0x2E, 0x85, 0x2F, 0x84, 0x30, 0x85, 0x31, 0x84, 0x32, 0x20, 0x1D, 0xA8, 0xA2, 0x19, 0x86, 0x16, 0x68, 0xA8, 0x68, 0xA2, 0xFA, 0x9A, 0x48, 0x98, 0x48, 0xA9, 0x00, 0x85, 0x3E, 0x85, 0x10, 0x60, 0x18, 0xA5, 0x2B, 0x69, 0xFF, 0x85, 0x7A, 0xA5, 0x2C, 0x69, 0xFF, 0x85, 0x7B, 0x60, 0x90, 0x06, 0xF0, 0x04, 0xC9, 0xAB, 0xD0, 0xE9, 0x20, 0x6B, 0xA9, 0x20, 0x13, 0xA6, 0x20, 0x79, 0x00, 0xF0, 0x0C, 0xC9, 0xAB, 0xD0, 0x8E, 0x20, 0x73, 0x00, 0x20, 0x6B, 0xA9, 0xD0, 0x86, 0x68, 0x68, 0xA5, 0x14, 0x05, 0x15, 0xD0, 0x06, 0xA9, 0xFF, 0x85, 0x14, 0x85, 0x15, 0xA0, 0x01, 0x84, 0x0F, 0xB1, 0x5F, 0xF0, 0x43, 0x20, 0x2C, 0xA8, 0x20, 0xD7, 0xAA, 0xC8, 0xB1, 0x5F, 0xAA, 0xC8, 0xB1, 0x5F, 0xC5, 0x15, 0xD0, 0x04, 0xE4, 0x14, 0xF0, 0x02, 0xB0, 0x2C, 0x84, 0x49, 0x20, 0xCD, 0xBD, 0xA9, 0x20, 0xA4, 0x49, 0x29, 0x7F, 0x20, 0x47, 0xAB, 0xC9, 0x22, 0xD0, 0x06, 0xA5, 0x0F, 0x49, 0xFF, 0x85, 0x0F, 0xC8, 0xF0, 0x11, 0xB1, 0x5F, 0xD0, 0x10, 0xA8, 0xB1, 0x5F, 0xAA, 0xC8, 0xB1, 0x5F, 0x86, 0x5F, 0x85, 0x60, 0xD0, 0xB5, 0x4C, 0x86, 0xE3, 0x6C, 0x06, 0x03, 0x10, 0xD7, 0xC9, 0xFF, 0xF0, 0xD3, 0x24, 0x0F, 0x30, 0xCF, 0x38, 0xE9, 0x7F, 0xAA, 0x84, 0x49, 0xA0, 0xFF, 0xCA, 0xF0, 0x08, 0xC8, 0xB9, 0x9E, 0xA0, 0x10, 0xFA, 0x30, 0xF5, 0xC8, 0xB9, 0x9E, 0xA0, 0x30, 0xB2, 0x20, 0x47, 0xAB, 0xD0, 0xF5, 0xA9, 0x80, 0x85, 0x10, 0x20, 0xA5, 0xA9, 0x20, 0x8A, 0xA3, 0xD0, 0x05, 0x8A, 0x69, 0x0F, 0xAA, 0x9A, 0x68, 0x68, 0xA9, 0x09, 0x20, 0xFB, 0xA3, 0x20, 0x06, 0xA9, 0x18, 0x98, 0x65, 0x7A, 0x48, 0xA5, 0x7B, 0x69, 0x00, 0x48, 0xA5, 0x3A, 0x48, 0xA5, 0x39, 0x48, 0xA9, 0xA4, 0x20, 0xFF, 0xAE, 0x20, 0x8D, 0xAD, 0x20, 0x8A, 0xAD, 0xA5, 0x66, 0x09, 0x7F, 0x25, 0x62, 0x85, 0x62, 0xA9, 0x8B, 0xA0, 0xA7, 0x85, 0x22, 0x84, 0x23, 0x4C, 0x43, 0xAE, 0xA9, 0xBC, 0xA0, 0xB9, 0x20, 0xA2, 0xBB, 0x20, 0x79, 0x00, 0xC9, 0xA9, 0xD0, 0x06, 0x20, 0x73, 0x00, 0x20, 0x8A, 0xAD, 0x20, 0x2B, 0xBC, 0x20, 0x38, 0xAE, 0xA5, 0x4A, 0x48, 0xA5, 0x49, 0x48, 0xA9, 0x81, 0x48, 0x20, 0x2C, 0xA8, 0xA5, 0x7A, 0xA4, 0x7B, 0xC0, 0x02, 0xEA, 0xF0, 0x04, 0x85, 0x3D, 0x84, 0x3E, 0xA0, 0x00, 0xB1, 0x7A, 0xD0, 0x43, 0xA0, 0x02, 0xB1, 0x7A, 0x18, 0xD0, 0x03, 0x4C, 0x4B, 0xA8, 0xC8, 0xB1, 0x7A, 0x85, 0x39, 0xC8, 0xB1, 0x7A, 0x85, 0x3A, 0x98, 0x65, 0x7A, 0x85, 0x7A, 0x90, 0x02, 0xE6, 0x7B, 0x6C, 0x08, 0x03, 0x20, 0x73, 0x00, 0x20, 0xED, 0xA7, 0x4C, 0xAE, 0xA7, 0xF0, 0x3C, 0xE9, 0x80, 0x90, 0x11, 0xC9, 0x23, 0xB0, 0x17, 0x0A, 0xA8, 0xB9, 0x0D, 0xA0, 0x48, 0xB9, 0x0C, 0xA0, 0x48, 0x4C, 0x73, 0x00, 0x4C, 0xA5, 0xA9, 0xC9, 0x3A, 0xF0, 0xD6, 0x4C, 0x08, 0xAF, 0xC9, 0x4B, 0xD0, 0xF9, 0x20, 0x73, 0x00, 0xA9, 0xA4, 0x20, 0xFF, 0xAE, 0x4C, 0xA0, 0xA8, 0x38, 0xA5, 0x2B, 0xE9, 0x01, 0xA4, 0x2C, 0xB0, 0x01, 0x88, 0x85, 0x41, 0x84, 0x42, 0x60, 0x20, 0xE1, 0xFF, 0xB0, 0x01, 0x18, 0xD0, 0x3C, 0xA5, 0x7A, 0xA4, 0x7B, 0xA6, 0x3A, 0xE8, 0xF0, 0x0C, 0x85, 0x3D, 0x84, 0x3E, 0xA5, 0x39, 0xA4, 0x3A, 0x85, 0x3B, 0x84, 0x3C, 0x68, 0x68, 0xA9, 0x81, 0xA0, 0xA3, 0x90, 0x03, 0x4C, 0x69, 0xA4, 0x4C, 0x86, 0xE3, 0xD0, 0x17, 0xA2, 0x1A, 0xA4, 0x3E, 0xD0, 0x03, 0x4C, 0x37, 0xA4, 0xA5, 0x3D, 0x85, 0x7A, 0x84, 0x7B, 0xA5, 0x3B, 0xA4, 0x3C, 0x85, 0x39, 0x84, 0x3A, 0x60, 0x08, 0xA9, 0x00, 0x20, 0x90, 0xFF, 0x28, 0xD0, 0x03, 0x4C, 0x59, 0xA6, 0x20, 0x60, 0xA6, 0x4C, 0x97, 0xA8, 0xA9, 0x03, 0x20, 0xFB, 0xA3, 0xA5, 0x7B, 0x48, 0xA5, 0x7A, 0x48, 0xA5, 0x3A, 0x48, 0xA5, 0x39, 0x48, 0xA9, 0x8D, 0x48, 0x20, 0x79, 0x00, 0x20, 0xA0, 0xA8, 0x4C, 0xAE, 0xA7, 0x20, 0x6B, 0xA9, 0x20, 0x09, 0xA9, 0x38, 0xA5, 0x39, 0xE5, 0x14, 0xA5, 0x3A, 0xE5, 0x15, 0xB0, 0x0B, 0x98, 0x38, 0x65, 0x7A, 0xA6, 0x7B, 0x90, 0x07, 0xE8, 0xB0, 0x04, 0xA5, 0x2B, 0xA6, 0x2C, 0x20, 0x17, 0xA6, 0x90, 0x1E, 0xA5, 0x5F, 0xE9, 0x01, 0x85, 0x7A, 0xA5, 0x60, 0xE9, 0x00, 0x85, 0x7B, 0x60, 0xD0, 0xFD, 0xA9, 0xFF, 0x85, 0x4A, 0x20, 0x8A, 0xA3, 0x9A, 0xC9, 0x8D, 0xF0, 0x0B, 0xA2, 0x0C, 0x2C, 0xA2, 0x11, 0x4C, 0x37, 0xA4, 0x4C, 0x08, 0xAF, 0x68, 0x68, 0x85, 0x39, 0x68, 0x85, 0x3A, 0x68, 0x85, 0x7A, 0x68, 0x85, 0x7B, 0x20, 0x06, 0xA9, 0x98, 0x18, 0x65, 0x7A, 0x85, 0x7A, 0x90, 0x02, 0xE6, 0x7B, 0x60, 0xA2, 0x3A, 0x2C, 0xA2, 0x00, 0x86, 0x07, 0xA0, 0x00, 0x84, 0x08, 0xA5, 0x08, 0xA6, 0x07, 0x85, 0x07, 0x86, 0x08, 0xB1, 0x7A, 0xF0, 0xE8, 0xC5, 0x08, 0xF0, 0xE4, 0xC8, 0xC9, 0x22, 0xD0, 0xF3, 0xF0, 0xE9, 0x20, 0x9E, 0xAD, 0x20, 0x79, 0x00, 0xC9, 0x89, 0xF0, 0x05, 0xA9, 0xA7, 0x20, 0xFF, 0xAE, 0xA5, 0x61, 0xD0, 0x05, 0x20, 0x09, 0xA9, 0xF0, 0xBB, 0x20, 0x79, 0x00, 0xB0, 0x03, 0x4C, 0xA0, 0xA8, 0x4C, 0xED, 0xA7, 0x20, 0x9E, 0xB7, 0x48, 0xC9, 0x8D, 0xF0, 0x04, 0xC9, 0x89, 0xD0, 0x91, 0xC6, 0x65, 0xD0, 0x04, 0x68, 0x4C, 0xEF, 0xA7, 0x20, 0x73, 0x00, 0x20, 0x6B, 0xA9, 0xC9, 0x2C, 0xF0, 0xEE, 0x68, 0x60, 0xA2, 0x00, 0x86, 0x14, 0x86, 0x15, 0xB0, 0xF7, 0xE9, 0x2F, 0x85, 0x07, 0xA5, 0x15, 0x85, 0x22, 0xC9, 0x19, 0xB0, 0xD4, 0xA5, 0x14, 0x0A, 0x26, 0x22, 0x0A, 0x26, 0x22, 0x65, 0x14, 0x85, 0x14, 0xA5, 0x22, 0x65, 0x15, 0x85, 0x15, 0x06, 0x14, 0x26, 0x15, 0xA5, 0x14, 0x65, 0x07, 0x85, 0x14, 0x90, 0x02, 0xE6, 0x15, 0x20, 0x73, 0x00, 0x4C, 0x71, 0xA9, 0x20, 0x8B, 0xB0, 0x85, 0x49, 0x84, 0x4A, 0xA9, 0xB2, 0x20, 0xFF, 0xAE, 0xA5, 0x0E, 0x48, 0xA5, 0x0D, 0x48, 0x20, 0x9E, 0xAD, 0x68, 0x2A, 0x20, 0x90, 0xAD, 0xD0, 0x18, 0x68, 0x10, 0x12, 0x20, 0x1B, 0xBC, 0x20, 0xBF, 0xB1, 0xA0, 0x00, 0xA5, 0x64, 0x91, 0x49, 0xC8, 0xA5, 0x65, 0x91, 0x49, 0x60, 0x4C, 0xD0, 0xBB, 0x68, 0xA4, 0x4A, 0xC0, 0xBF, 0xD0, 0x4C, 0x20, 0xA6, 0xB6, 0xC9, 0x06, 0xD0, 0x3D, 0xA0, 0x00, 0x84, 0x61, 0x84, 0x66, 0x84, 0x71, 0x20, 0x1D, 0xAA, 0x20, 0xE2, 0xBA, 0xE6, 0x71, 0xA4, 0x71, 0x20, 0x1D, 0xAA, 0x20, 0x0C, 0xBC, 0xAA, 0xF0, 0x05, 0xE8, 0x8A, 0x20, 0xED, 0xBA, 0xA4, 0x71, 0xC8, 0xC0, 0x06, 0xD0, 0xDF, 0x20, 0xE2, 0xBA, 0x20, 0x9B, 0xBC, 0xA6, 0x64, 0xA4, 0x63, 0xA5, 0x65, 0x4C, 0xDB, 0xFF, 0xB1, 0x22, 0x20, 0x80, 0x00, 0x90, 0x03, 0x4C, 0x48, 0xB2, 0xE9, 0x2F, 0x4C, 0x7E, 0xBD, 0xA0, 0x02, 0xB1, 0x64, 0xC5, 0x34, 0x90, 0x17, 0xD0, 0x07, 0x88, 0xB1, 0x64, 0xC5, 0x33, 0x90, 0x0E, 0xA4, 0x65, 0xC4, 0x2E, 0x90, 0x08, 0xD0, 0x0D, 0xA5, 0x64, 0xC5, 0x2D, 0xB0, 0x07, 0xA5, 0x64, 0xA4, 0x65, 0x4C, 0x68, 0xAA, 0xA0, 0x00, 0xB1, 0x64, 0x20, 0x75, 0xB4, 0xA5, 0x50, 0xA4, 0x51, 0x85, 0x6F, 0x84, 0x70, 0x20, 0x7A, 0xB6, 0xA9, 0x61, 0xA0, 0x00, 0x85, 0x50, 0x84, 0x51, 0x20, 0xDB, 0xB6, 0xA0, 0x00, 0xB1, 0x50, 0x91, 0x49, 0xC8, 0xB1, 0x50, 0x91, 0x49, 0xC8, 0xB1, 0x50, 0x91, 0x49, 0x60, 0x20, 0x86, 0xAA, 0x4C, 0xB5, 0xAB, 0x20, 0x9E, 0xB7, 0xF0, 0x05, 0xA9, 0x2C, 0x20, 0xFF, 0xAE, 0x08, 0x86, 0x13, 0x20, 0x18, 0xE1, 0x28, 0x4C, 0xA0, 0xAA, 0x20, 0x21, 0xAB, 0x20, 0x79, 0x00, 0xF0, 0x35, 0xF0, 0x43, 0xC9, 0xA3, 0xF0, 0x50, 0xC9, 0xA6, 0x18, 0xF0, 0x4B, 0xC9, 0x2C, 0xF0, 0x37, 0xC9, 0x3B, 0xF0, 0x5E, 0x20, 0x9E, 0xAD, 0x24, 0x0D, 0x30, 0xDE, 0x20, 0xDD, 0xBD, 0x20, 0x87, 0xB4, 0x20, 0x21, 0xAB, 0x20, 0x3B, 0xAB, 0xD0, 0xD3, 0xA9, 0x00, 0x9D, 0x00, 0x02, 0xA2, 0xFF, 0xA0, 0x01, 0xA5, 0x13, 0xD0, 0x10, 0xA9, 0x0D, 0x20, 0x47, 0xAB, 0x24, 0x13, 0x10, 0x05, 0xA9, 0x0A, 0x20, 0x47, 0xAB, 0x49, 0xFF, 0x60, 0x38, 0x20, 0xF0, 0xFF, 0x98, 0x38, 0xE9, 0x0A, 0xB0, 0xFC, 0x49, 0xFF, 0x69, 0x01, 0xD0, 0x16, 0x08, 0x38, 0x20, 0xF0, 0xFF, 0x84, 0x09, 0x20, 0x9B, 0xB7, 0xC9, 0x29, 0xD0, 0x59, 0x28, 0x90, 0x06, 0x8A, 0xE5, 0x09, 0x90, 0x05, 0xAA, 0xE8, 0xCA, 0xD0, 0x06, 0x20, 0x73, 0x00, 0x4C, 0xA2, 0xAA, 0x20, 0x3B, 0xAB, 0xD0, 0xF2, 0x20, 0x87, 0xB4, 0x20, 0xA6, 0xB6, 0xAA, 0xA0, 0x00, 0xE8, 0xCA, 0xF0, 0xBC, 0xB1, 0x22, 0x20, 0x47, 0xAB, 0xC8, 0xC9, 0x0D, 0xD0, 0xF3, 0x20, 0xE5, 0xAA, 0x4C, 0x28, 0xAB, 0xA5, 0x13, 0xF0, 0x03, 0xA9, 0x20, 0x2C, 0xA9, 0x1D, 0x2C, 0xA9, 0x3F, 0x20, 0x0C, 0xE1, 0x29, 0xFF, 0x60, 0xA5, 0x11, 0xF0, 0x11, 0x30, 0x04, 0xA0, 0xFF, 0xD0, 0x04, 0xA5, 0x3F, 0xA4, 0x40, 0x85, 0x39, 0x84, 0x3A, 0x4C, 0x08, 0xAF, 0xA5, 0x13, 0xF0, 0x05, 0xA2, 0x18, 0x4C, 0x37, 0xA4, 0xA9, 0x0C, 0xA0, 0xAD, 0x20, 0x1E, 0xAB, 0xA5, 0x3D, 0xA4, 0x3E, 0x85, 0x7A, 0x84, 0x7B, 0x60, 0x20, 0xA6, 0xB3, 0xC9, 0x23, 0xD0, 0x10, 0x20, 0x73, 0x00, 0x20, 0x9E, 0xB7, 0xA9, 0x2C, 0x20, 0xFF, 0xAE, 0x86, 0x13, 0x20, 0x1E, 0xE1, 0xA2, 0x01, 0xA0, 0x02, 0xA9, 0x00, 0x8D, 0x01, 0x02, 0xA9, 0x40, 0x20, 0x0F, 0xAC, 0xA6, 0x13, 0xD0, 0x13, 0x60, 0x20, 0x9E, 0xB7, 0xA9, 0x2C, 0x20, 0xFF, 0xAE, 0x86, 0x13, 0x20, 0x1E, 0xE1, 0x20, 0xCE, 0xAB, 0xA5, 0x13, 0x20, 0xCC, 0xFF, 0xA2, 0x00, 0x86, 0x13, 0x60, 0xC9, 0x22, 0xD0, 0x0B, 0x20, 0xBD, 0xAE, 0xA9, 0x3B, 0x20, 0xFF, 0xAE, 0x20, 0x21, 0xAB, 0x20, 0xA6, 0xB3, 0xA9, 0x2C, 0x8D, 0xFF, 0x01, 0x20, 0xF9, 0xAB, 0xA5, 0x13, 0xF0, 0x0D, 0x20, 0xB7, 0xFF, 0x29, 0x02, 0xF0, 0x06, 0x20, 0xB5, 0xAB, 0x4C, 0xF8, 0xA8, 0xAD, 0x00, 0x02, 0xD0, 0x1E, 0xA5, 0x13, 0xD0, 0xE3, 0x20, 0x06, 0xA9, 0x4C, 0xFB, 0xA8, 0xA5, 0x13, 0xD0, 0x06, 0x20, 0x45, 0xAB, 0x20, 0x3B, 0xAB, 0x4C, 0x60, 0xA5, 0xA6, 0x41, 0xA4, 0x42, 0xA9, 0x98, 0x2C, 0xA9, 0x00, 0x85, 0x11, 0x86, 0x43, 0x84, 0x44, 0x20, 0x8B, 0xB0, 0x85, 0x49, 0x84, 0x4A, 0xA5, 0x7A, 0xA4, 0x7B, 0x85, 0x4B, 0x84, 0x4C, 0xA6, 0x43, 0xA4, 0x44, 0x86, 0x7A, 0x84, 0x7B, 0x20, 0x79, 0x00, 0xD0, 0x20, 0x24, 0x11, 0x50, 0x0C, 0x20, 0x24, 0xE1, 0x8D, 0x00, 0x02, 0xA2, 0xFF, 0xA0, 0x01, 0xD0, 0x0C, 0x30, 0x75, 0xA5, 0x13, 0xD0, 0x03, 0x20, 0x45, 0xAB, 0x20, 0xF9, 0xAB, 0x86, 0x7A, 0x84, 0x7B, 0x20, 0x73, 0x00, 0x24, 0x0D, 0x10, 0x31, 0x24, 0x11, 0x50, 0x09, 0xE8, 0x86, 0x7A, 0xA9, 0x00, 0x85, 0x07, 0xF0, 0x0C, 0x85, 0x07, 0xC9, 0x22, 0xF0, 0x07, 0xA9, 0x3A, 0x85, 0x07, 0xA9, 0x2C, 0x18, 0x85, 0x08, 0xA5, 0x7A, 0xA4, 0x7B, 0x69, 0x00, 0x90, 0x01, 0xC8, 0x20, 0x8D, 0xB4, 0x20, 0xE2, 0xB7, 0x20, 0xDA, 0xA9, 0x4C, 0x91, 0xAC, 0x20, 0xF3, 0xBC, 0xA5, 0x0E, 0x20, 0xC2, 0xA9, 0x20, 0x79, 0x00, 0xF0, 0x07, 0xC9, 0x2C, 0xF0, 0x03, 0x4C, 0x4D, 0xAB, 0xA5, 0x7A, 0xA4, 0x7B, 0x85, 0x43, 0x84, 0x44, 0xA5, 0x4B, 0xA4, 0x4C, 0x85, 0x7A, 0x84, 0x7B, 0x20, 0x79, 0x00, 0xF0, 0x2D, 0x20, 0xFD, 0xAE, 0x4C, 0x15, 0xAC, 0x20, 0x06, 0xA9, 0xC8, 0xAA, 0xD0, 0x12, 0xA2, 0x0D, 0xC8, 0xB1, 0x7A, 0xF0, 0x6C, 0xC8, 0xB1, 0x7A, 0x85, 0x3F, 0xC8, 0xB1, 0x7A, 0xC8, 0x85, 0x40, 0x20, 0xFB, 0xA8, 0x20, 0x79, 0x00, 0xAA, 0xE0, 0x83, 0xD0, 0xDC, 0x4C, 0x51, 0xAC, 0xA5, 0x43, 0xA4, 0x44, 0xA6, 0x11, 0x10, 0x03, 0x4C, 0x27, 0xA8, 0xA0, 0x00, 0xB1, 0x43, 0xF0, 0x0B, 0xA5, 0x13, 0xD0, 0x07, 0xA9, 0xFC, 0xA0, 0xAC, 0x4C, 0x1E, 0xAB, 0x60, 0x3F, 0x45, 0x58, 0x54, 0x52, 0x41, 0x20, 0x49, 0x47, 0x4E, 0x4F, 0x52, 0x45, 0x44, 0x0D, 0x00, 0x3F, 0x52, 0x45, 0x44, 0x4F, 0x20, 0x46, 0x52, 0x4F, 0x4D, 0x20, 0x53, 0x54, 0x41, 0x52, 0x54, 0x0D, 0x00, 0xD0, 0x04, 0xA0, 0x00, 0xF0, 0x03, 0x20, 0x8B, 0xB0, 0x85, 0x49, 0x84, 0x4A, 0x20, 0x8A, 0xA3, 0xF0, 0x05, 0xA2, 0x0A, 0x4C, 0x37, 0xA4, 0x9A, 0x8A, 0x18, 0x69, 0x04, 0x48, 0x69, 0x06, 0x85, 0x24, 0x68, 0xA0, 0x01, 0x20, 0xA2, 0xBB, 0xBA, 0xBD, 0x09, 0x01, 0x85, 0x66, 0xA5, 0x49, 0xA4, 0x4A, 0x20, 0x67, 0xB8, 0x20, 0xD0, 0xBB, 0xA0, 0x01, 0x20, 0x5D, 0xBC, 0xBA, 0x38, 0xFD, 0x09, 0x01, 0xF0, 0x17, 0xBD, 0x0F, 0x01, 0x85, 0x39, 0xBD, 0x10, 0x01, 0x85, 0x3A, 0xBD, 0x12, 0x01, 0x85, 0x7A, 0xBD, 0x11, 0x01, 0x85, 0x7B, 0x4C, 0xAE, 0xA7, 0x8A, 0x69, 0x11, 0xAA, 0x9A, 0x20, 0x79, 0x00, 0xC9, 0x2C, 0xD0, 0xF1, 0x20, 0x73, 0x00, 0x20, 0x24, 0xAD, 0x20, 0x9E, 0xAD, 0x18, 0x24, 0x38, 0x24, 0x0D, 0x30, 0x03, 0xB0, 0x03, 0x60, 0xB0, 0xFD, 0xA2, 0x16, 0x4C, 0x37, 0xA4, 0xA6, 0x7A, 0xD0, 0x02, 0xC6, 0x7B, 0xC6, 0x7A, 0xA2, 0x00, 0x24, 0x48, 0x8A, 0x48, 0xA9, 0x01, 0x20, 0xFB, 0xA3, 0x20, 0x83, 0xAE, 0xA9, 0x00, 0x85, 0x4D, 0x20, 0x79, 0x00, 0x38, 0xE9, 0xB1, 0x90, 0x17, 0xC9, 0x03, 0xB0, 0x13, 0xC9, 0x01, 0x2A, 0x49, 0x01, 0x45, 0x4D, 0xC5, 0x4D, 0x90, 0x61, 0x85, 0x4D, 0x20, 0x73, 0x00, 0x4C, 0xBB, 0xAD, 0xA6, 0x4D, 0xD0, 0x2C, 0xB0, 0x7B, 0x69, 0x07, 0x90, 0x77, 0x65, 0x0D, 0xD0, 0x03, 0x4C, 0x3D, 0xB6, 0x69, 0xFF, 0x85, 0x22, 0x0A, 0x65, 0x22, 0xA8, 0x68, 0xD9, 0x80, 0xA0, 0xB0, 0x67, 0x20, 0x8D, 0xAD, 0x48, 0x20, 0x20, 0xAE, 0x68, 0xA4, 0x4B, 0x10, 0x17, 0xAA, 0xF0, 0x56, 0xD0, 0x5F, 0x46, 0x0D, 0x8A, 0x2A, 0xA6, 0x7A, 0xD0, 0x02, 0xC6, 0x7B, 0xC6, 0x7A, 0xA0, 0x1B, 0x85, 0x4D, 0xD0, 0xD7, 0xD9, 0x80, 0xA0, 0xB0, 0x48, 0x90, 0xD9, 0xB9, 0x82, 0xA0, 0x48, 0xB9, 0x81, 0xA0, 0x48, 0x20, 0x33, 0xAE, 0xA5, 0x4D, 0x4C, 0xA9, 0xAD, 0x4C, 0x08, 0xAF, 0xA5, 0x66, 0xBE, 0x80, 0xA0, 0xA8, 0x68, 0x85, 0x22, 0xE6, 0x22, 0x68, 0x85, 0x23, 0x98, 0x48, 0x20, 0x1B, 0xBC, 0xA5, 0x65, 0x48, 0xA5, 0x64, 0x48, 0xA5, 0x63, 0x48, 0xA5, 0x62, 0x48, 0xA5, 0x61, 0x48, 0x6C, 0x22, 0x00, 0xA0, 0xFF, 0x68, 0xF0, 0x23, 0xC9, 0x64, 0xF0, 0x03, 0x20, 0x8D, 0xAD, 0x84, 0x4B, 0x68, 0x4A, 0x85, 0x12, 0x68, 0x85, 0x69, 0x68, 0x85, 0x6A, 0x68, 0x85, 0x6B, 0x68, 0x85, 0x6C, 0x68, 0x85, 0x6D, 0x68, 0x85, 0x6E, 0x45, 0x66, 0x85, 0x6F, 0xA5, 0x61, 0x60, 0x6C, 0x0A, 0x03, 0xA9, 0x00, 0x85, 0x0D, 0x20, 0x73, 0x00, 0xB0, 0x03, 0x4C, 0xF3, 0xBC, 0x20, 0x13, 0xB1, 0x90, 0x03, 0x4C, 0x28, 0xAF, 0xC9, 0xFF, 0xD0, 0x0F, 0xA9, 0xA8, 0xA0, 0xAE, 0x20, 0xA2, 0xBB, 0x4C, 0x73, 0x00, 0x82, 0x49, 0x0F, 0xDA, 0xA1, 0xC9, 0x2E, 0xF0, 0xDE, 0xC9, 0xAB, 0xF0, 0x58, 0xC9, 0xAA, 0xF0, 0xD1, 0xC9, 0x22, 0xD0, 0x0F, 0xA5, 0x7A, 0xA4, 0x7B, 0x69, 0x00, 0x90, 0x01, 0xC8, 0x20, 0x87, 0xB4, 0x4C, 0xE2, 0xB7, 0xC9, 0xA8, 0xD0, 0x13, 0xA0, 0x18, 0xD0, 0x3B, 0x20, 0xBF, 0xB1, 0xA5, 0x65, 0x49, 0xFF, 0xA8, 0xA5, 0x64, 0x49, 0xFF, 0x4C, 0x91, 0xB3, 0xC9, 0xA5, 0xD0, 0x03, 0x4C, 0xF4, 0xB3, 0xC9, 0xB4, 0x90, 0x03, 0x4C, 0xA7, 0xAF, 0x20, 0xFA, 0xAE, 0x20, 0x9E, 0xAD, 0xA9, 0x29, 0x2C, 0xA9, 0x28, 0x2C, 0xA9, 0x2C, 0xA0, 0x00, 0xD1, 0x7A, 0xD0, 0x03, 0x4C, 0x73, 0x00, 0xA2, 0x0B, 0x4C, 0x37, 0xA4, 0xA0, 0x15, 0x68, 0x68, 0x4C, 0xFA, 0xAD, 0x38, 0xA5, 0x64, 0xE9, 0x00, 0xA5, 0x65, 0xE9, 0xA0, 0x90, 0x08, 0xA9, 0xA2, 0xE5, 0x64, 0xA9, 0xE3, 0xE5, 0x65, 0x60, 0x20, 0x8B, 0xB0, 0x85, 0x64, 0x84, 0x65, 0xA6, 0x45, 0xA4, 0x46, 0xA5, 0x0D, 0xF0, 0x26, 0xA9, 0x00, 0x85, 0x70, 0x20, 0x14, 0xAF, 0x90, 0x1C, 0xE0, 0x54, 0xD0, 0x18, 0xC0, 0xC9, 0xD0, 0x14, 0x20, 0x84, 0xAF, 0x84, 0x5E, 0x88, 0x84, 0x71, 0xA0, 0x06, 0x84, 0x5D, 0xA0, 0x24, 0x20, 0x68, 0xBE, 0x4C, 0x6F, 0xB4, 0x60, 0x24, 0x0E, 0x10, 0x0D, 0xA0, 0x00, 0xB1, 0x64, 0xAA, 0xC8, 0xB1, 0x64, 0xA8, 0x8A, 0x4C, 0x91, 0xB3, 0x20, 0x14, 0xAF, 0x90, 0x2D, 0xE0, 0x54, 0xD0, 0x1B, 0xC0, 0x49, 0xD0, 0x25, 0x20, 0x84, 0xAF, 0x98, 0xA2, 0xA0, 0x4C, 0x4F, 0xBC, 0x20, 0xDE, 0xFF, 0x86, 0x64, 0x84, 0x63, 0x85, 0x65, 0xA0, 0x00, 0x84, 0x62, 0x60, 0xE0, 0x53, 0xD0, 0x0A, 0xC0, 0x54, 0xD0, 0x06, 0x20, 0xB7, 0xFF, 0x4C, 0x3C, 0xBC, 0xA5, 0x64, 0xA4, 0x65, 0x4C, 0xA2, 0xBB, 0x0A, 0x48, 0xAA, 0x20, 0x73, 0x00, 0xE0, 0x8F, 0x90, 0x20, 0x20, 0xFA, 0xAE, 0x20, 0x9E, 0xAD, 0x20, 0xFD, 0xAE, 0x20, 0x8F, 0xAD, 0x68, 0xAA, 0xA5, 0x65, 0x48, 0xA5, 0x64, 0x48, 0x8A, 0x48, 0x20, 0x9E, 0xB7, 0x68, 0xA8, 0x8A, 0x48, 0x4C, 0xD6, 0xAF, 0x20, 0xF1, 0xAE, 0x68, 0xA8, 0xB9, 0xEA, 0x9F, 0x85, 0x55, 0xB9, 0xEB, 0x9F, 0x85, 0x56, 0x20, 0x54, 0x00, 0x4C, 0x8D, 0xAD, 0xA0, 0xFF, 0x2C, 0xA0, 0x00, 0x84, 0x0B, 0x20, 0xBF, 0xB1, 0xA5, 0x64, 0x45, 0x0B, 0x85, 0x07, 0xA5, 0x65, 0x45, 0x0B, 0x85, 0x08, 0x20, 0xFC, 0xBB, 0x20, 0xBF, 0xB1, 0xA5, 0x65, 0x45, 0x0B, 0x25, 0x08, 0x45, 0x0B, 0xA8, 0xA5, 0x64, 0x45, 0x0B, 0x25, 0x07, 0x45, 0x0B, 0x4C, 0x91, 0xB3, 0x20, 0x90, 0xAD, 0xB0, 0x13, 0xA5, 0x6E, 0x09, 0x7F, 0x25, 0x6A, 0x85, 0x6A, 0xA9, 0x69, 0xA0, 0x00, 0x20, 0x5B, 0xBC, 0xAA, 0x4C, 0x61, 0xB0, 0xA9, 0x00, 0x85, 0x0D, 0xC6, 0x4D, 0x20, 0xA6, 0xB6, 0x85, 0x61, 0x86, 0x62, 0x84, 0x63, 0xA5, 0x6C, 0xA4, 0x6D, 0x20, 0xAA, 0xB6, 0x86, 0x6C, 0x84, 0x6D, 0xAA, 0x38, 0xE5, 0x61, 0xF0, 0x08, 0xA9, 0x01, 0x90, 0x04, 0xA6, 0x61, 0xA9, 0xFF, 0x85, 0x66, 0xA0, 0xFF, 0xE8, 0xC8, 0xCA, 0xD0, 0x07, 0xA6, 0x66, 0x30, 0x0F, 0x18, 0x90, 0x0C, 0xB1, 0x6C, 0xD1, 0x62, 0xF0, 0xEF, 0xA2, 0xFF, 0xB0, 0x02, 0xA2, 0x01, 0xE8, 0x8A, 0x2A, 0x25, 0x12, 0xF0, 0x02, 0xA9, 0xFF, 0x4C, 0x3C, 0xBC, 0x20, 0xFD, 0xAE, 0xAA, 0x20, 0x90, 0xB0, 0x20, 0x79, 0x00, 0xD0, 0xF4, 0x60, 0xA2, 0x00, 0x20, 0x79, 0x00, 0x86, 0x0C, 0x85, 0x45, 0x20, 0x79, 0x00, 0x20, 0x13, 0xB1, 0xB0, 0x03, 0x4C, 0x08, 0xAF, 0xA2, 0x00, 0x86, 0x0D, 0x86, 0x0E, 0x20, 0x73, 0x00, 0x90, 0x05, 0x20, 0x13, 0xB1, 0x90, 0x0B, 0xAA, 0x20, 0x73, 0x00, 0x90, 0xFB, 0x20, 0x13, 0xB1, 0xB0, 0xF6, 0xC9, 0x24, 0xD0, 0x06, 0xA9, 0xFF, 0x85, 0x0D, 0xD0, 0x10, 0xC9, 0x25, 0xD0, 0x13, 0xA5, 0x10, 0xD0, 0xD0, 0xA9, 0x80, 0x85, 0x0E, 0x05, 0x45, 0x85, 0x45, 0x8A, 0x09, 0x80, 0xAA, 0x20, 0x73, 0x00, 0x86, 0x46, 0x38, 0x05, 0x10, 0xE9, 0x28, 0xD0, 0x03, 0x4C, 0xD1, 0xB1, 0xA0, 0x00, 0x84, 0x10, 0xA5, 0x2D, 0xA6, 0x2E, 0x86, 0x60, 0x85, 0x5F, 0xE4, 0x30, 0xD0, 0x04, 0xC5, 0x2F, 0xF0, 0x22, 0xA5, 0x45, 0xD1, 0x5F, 0xD0, 0x08, 0xA5, 0x46, 0xC8, 0xD1, 0x5F, 0xF0, 0x7D, 0x88, 0x18, 0xA5, 0x5F, 0x69, 0x07, 0x90, 0xE1, 0xE8, 0xD0, 0xDC, 0xC9, 0x41, 0x90, 0x05, 0xE9, 0x5B, 0x38, 0xE9, 0xA5, 0x60, 0x68, 0x48, 0xC9, 0x2A, 0xD0, 0x05, 0xA9, 0x13, 0xA0, 0xBF, 0x60, 0xA5, 0x45, 0xA4, 0x46, 0xC9, 0x54, 0xD0, 0x0B, 0xC0, 0xC9, 0xF0, 0xEF, 0xC0, 0x49, 0xD0, 0x03, 0x4C, 0x08, 0xAF, 0xC9, 0x53, 0xD0, 0x04, 0xC0, 0x54, 0xF0, 0xF5, 0xA5, 0x2F, 0xA4, 0x30, 0x85, 0x5F, 0x84, 0x60, 0xA5, 0x31, 0xA4, 0x32, 0x85, 0x5A, 0x84, 0x5B, 0x18, 0x69, 0x07, 0x90, 0x01, 0xC8, 0x85, 0x58, 0x84, 0x59, 0x20, 0xB8, 0xA3, 0xA5, 0x58, 0xA4, 0x59, 0xC8, 0x85, 0x2F, 0x84, 0x30, 0xA0, 0x00, 0xA5, 0x45, 0x91, 0x5F, 0xC8, 0xA5, 0x46, 0x91, 0x5F, 0xA9, 0x00, 0xC8, 0x91, 0x5F, 0xC8, 0x91, 0x5F, 0xC8, 0x91, 0x5F, 0xC8, 0x91, 0x5F, 0xC8, 0x91, 0x5F, 0xA5, 0x5F, 0x18, 0x69, 0x02, 0xA4, 0x60, 0x90, 0x01, 0xC8, 0x85, 0x47, 0x84, 0x48, 0x60, 0xA5, 0x0B, 0x0A, 0x69, 0x05, 0x65, 0x5F, 0xA4, 0x60, 0x90, 0x01, 0xC8, 0x85, 0x58, 0x84, 0x59, 0x60, 0x90, 0x80, 0x00, 0x00, 0x00, 0x20, 0xBF, 0xB1, 0xA5, 0x64, 0xA4, 0x65, 0x60, 0x20, 0x73, 0x00, 0x20, 0x9E, 0xAD, 0x20, 0x8D, 0xAD, 0xA5, 0x66, 0x30, 0x0D, 0xA5, 0x61, 0xC9, 0x90, 0x90, 0x09, 0xA9, 0xA5, 0xA0, 0xB1, 0x20, 0x5B, 0xBC, 0xD0, 0x7A, 0x4C, 0x9B, 0xBC, 0xA5, 0x0C, 0x05, 0x0E, 0x48, 0xA5, 0x0D, 0x48, 0xA0, 0x00, 0x98, 0x48, 0xA5, 0x46, 0x48, 0xA5, 0x45, 0x48, 0x20, 0xB2, 0xB1, 0x68, 0x85, 0x45, 0x68, 0x85, 0x46, 0x68, 0xA8, 0xBA, 0xBD, 0x02, 0x01, 0x48, 0xBD, 0x01, 0x01, 0x48, 0xA5, 0x64, 0x9D, 0x02, 0x01, 0xA5, 0x65, 0x9D, 0x01, 0x01, 0xC8, 0x20, 0x79, 0x00, 0xC9, 0x2C, 0xF0, 0xD2, 0x84, 0x0B, 0x20, 0xF7, 0xAE, 0x68, 0x85, 0x0D, 0x68, 0x85, 0x0E, 0x29, 0x7F, 0x85, 0x0C, 0xA6, 0x2F, 0xA5, 0x30, 0x86, 0x5F, 0x85, 0x60, 0xC5, 0x32, 0xD0, 0x04, 0xE4, 0x31, 0xF0, 0x39, 0xA0, 0x00, 0xB1, 0x5F, 0xC8, 0xC5, 0x45, 0xD0, 0x06, 0xA5, 0x46, 0xD1, 0x5F, 0xF0, 0x16, 0xC8, 0xB1, 0x5F, 0x18, 0x65, 0x5F, 0xAA, 0xC8, 0xB1, 0x5F, 0x65, 0x60, 0x90, 0xD7, 0xA2, 0x12, 0x2C, 0xA2, 0x0E, 0x4C, 0x37, 0xA4, 0xA2, 0x13, 0xA5, 0x0C, 0xD0, 0xF7, 0x20, 0x94, 0xB1, 0xA5, 0x0B, 0xA0, 0x04, 0xD1, 0x5F, 0xD0, 0xE7, 0x4C, 0xEA, 0xB2, 0x20, 0x94, 0xB1, 0x20, 0x08, 0xA4, 0xA0, 0x00, 0x84, 0x72, 0xA2, 0x05, 0xA5, 0x45, 0x91, 0x5F, 0x10, 0x01, 0xCA, 0xC8, 0xA5, 0x46, 0x91, 0x5F, 0x10, 0x02, 0xCA, 0xCA, 0x86, 0x71, 0xA5, 0x0B, 0xC8, 0xC8, 0xC8, 0x91, 0x5F, 0xA2, 0x0B, 0xA9, 0x00, 0x24, 0x0C, 0x50, 0x08, 0x68, 0x18, 0x69, 0x01, 0xAA, 0x68, 0x69, 0x00, 0xC8, 0x91, 0x5F, 0xC8, 0x8A, 0x91, 0x5F, 0x20, 0x4C, 0xB3, 0x86, 0x71, 0x85, 0x72, 0xA4, 0x22, 0xC6, 0x0B, 0xD0, 0xDC, 0x65, 0x59, 0xB0, 0x5D, 0x85, 0x59, 0xA8, 0x8A, 0x65, 0x58, 0x90, 0x03, 0xC8, 0xF0, 0x52, 0x20, 0x08, 0xA4, 0x85, 0x31, 0x84, 0x32, 0xA9, 0x00, 0xE6, 0x72, 0xA4, 0x71, 0xF0, 0x05, 0x88, 0x91, 0x58, 0xD0, 0xFB, 0xC6, 0x59, 0xC6, 0x72, 0xD0, 0xF5, 0xE6, 0x59, 0x38, 0xA5, 0x31, 0xE5, 0x5F, 0xA0, 0x02, 0x91, 0x5F, 0xA5, 0x32, 0xC8, 0xE5, 0x60, 0x91, 0x5F, 0xA5, 0x0C, 0xD0, 0x62, 0xC8, 0xB1, 0x5F, 0x85, 0x0B, 0xA9, 0x00, 0x85, 0x71, 0x85, 0x72, 0xC8, 0x68, 0xAA, 0x85, 0x64, 0x68, 0x85, 0x65, 0xD1, 0x5F, 0x90, 0x0E, 0xD0, 0x06, 0xC8, 0x8A, 0xD1, 0x5F, 0x90, 0x07, 0x4C, 0x45, 0xB2, 0x4C, 0x35, 0xA4, 0xC8, 0xA5, 0x72, 0x05, 0x71, 0x18, 0xF0, 0x0A, 0x20, 0x4C, 0xB3, 0x8A, 0x65, 0x64, 0xAA, 0x98, 0xA4, 0x22, 0x65, 0x65, 0x86, 0x71, 0xC6, 0x0B, 0xD0, 0xCA, 0x85, 0x72, 0xA2, 0x05, 0xA5, 0x45, 0x10, 0x01, 0xCA, 0xA5, 0x46, 0x10, 0x02, 0xCA, 0xCA, 0x86, 0x28, 0xA9, 0x00, 0x20, 0x55, 0xB3, 0x8A, 0x65, 0x58, 0x85, 0x47, 0x98, 0x65, 0x59, 0x85, 0x48, 0xA8, 0xA5, 0x47, 0x60, 0x84, 0x22, 0xB1, 0x5F, 0x85, 0x28, 0x88, 0xB1, 0x5F, 0x85, 0x29, 0xA9, 0x10, 0x85, 0x5D, 0xA2, 0x00, 0xA0, 0x00, 0x8A, 0x0A, 0xAA, 0x98, 0x2A, 0xA8, 0xB0, 0xA4, 0x06, 0x71, 0x26, 0x72, 0x90, 0x0B, 0x18, 0x8A, 0x65, 0x28, 0xAA, 0x98, 0x65, 0x29, 0xA8, 0xB0, 0x93, 0xC6, 0x5D, 0xD0, 0xE3, 0x60, 0xA5, 0x0D, 0xF0, 0x03, 0x20, 0xA6, 0xB6, 0x20, 0x26, 0xB5, 0x38, 0xA5, 0x33, 0xE5, 0x31, 0xA8, 0xA5, 0x34, 0xE5, 0x32, 0xA2, 0x00, 0x86, 0x0D, 0x85, 0x62, 0x84, 0x63, 0xA2, 0x90, 0x4C, 0x44, 0xBC, 0x38, 0x20, 0xF0, 0xFF, 0xA9, 0x00, 0xF0, 0xEB, 0xA6, 0x3A, 0xE8, 0xD0, 0xA0, 0xA2, 0x15, 0x2C, 0xA2, 0x1B, 0x4C, 0x37, 0xA4, 0x20, 0xE1, 0xB3, 0x20, 0xA6, 0xB3, 0x20, 0xFA, 0xAE, 0xA9, 0x80, 0x85, 0x10, 0x20, 0x8B, 0xB0, 0x20, 0x8D, 0xAD, 0x20, 0xF7, 0xAE, 0xA9, 0xB2, 0x20, 0xFF, 0xAE, 0x48, 0xA5, 0x48, 0x48, 0xA5, 0x47, 0x48, 0xA5, 0x7B, 0x48, 0xA5, 0x7A, 0x48, 0x20, 0xF8, 0xA8, 0x4C, 0x4F, 0xB4, 0xA9, 0xA5, 0x20, 0xFF, 0xAE, 0x09, 0x80, 0x85, 0x10, 0x20, 0x92, 0xB0, 0x85, 0x4E, 0x84, 0x4F, 0x4C, 0x8D, 0xAD, 0x20, 0xE1, 0xB3, 0xA5, 0x4F, 0x48, 0xA5, 0x4E, 0x48, 0x20, 0xF1, 0xAE, 0x20, 0x8D, 0xAD, 0x68, 0x85, 0x4E, 0x68, 0x85, 0x4F, 0xA0, 0x02, 0xB1, 0x4E, 0x85, 0x47, 0xAA, 0xC8, 0xB1, 0x4E, 0xF0, 0x99, 0x85, 0x48, 0xC8, 0xB1, 0x47, 0x48, 0x88, 0x10, 0xFA, 0xA4, 0x48, 0x20, 0xD4, 0xBB, 0xA5, 0x7B, 0x48, 0xA5, 0x7A, 0x48, 0xB1, 0x4E, 0x85, 0x7A, 0xC8, 0xB1, 0x4E, 0x85, 0x7B, 0xA5, 0x48, 0x48, 0xA5, 0x47, 0x48, 0x20, 0x8A, 0xAD, 0x68, 0x85, 0x4E, 0x68, 0x85, 0x4F, 0x20, 0x79, 0x00, 0xF0, 0x03, 0x4C, 0x08, 0xAF, 0x68, 0x85, 0x7A, 0x68, 0x85, 0x7B, 0xA0, 0x00, 0x68, 0x91, 0x4E, 0x68, 0xC8, 0x91, 0x4E, 0x68, 0xC8, 0x91, 0x4E, 0x68, 0xC8, 0x91, 0x4E, 0x68, 0xC8, 0x91, 0x4E, 0x60, 0x20, 0x8D, 0xAD, 0xA0, 0x00, 0x20, 0xDF, 0xBD, 0x68, 0x68, 0xA9, 0xFF, 0xA0, 0x00, 0xF0, 0x12, 0xA6, 0x64, 0xA4, 0x65, 0x86, 0x50, 0x84, 0x51, 0x20, 0xF4, 0xB4, 0x86, 0x62, 0x84, 0x63, 0x85, 0x61, 0x60, 0xA2, 0x22, 0x86, 0x07, 0x86, 0x08, 0x85, 0x6F, 0x84, 0x70, 0x85, 0x62, 0x84, 0x63, 0xA0, 0xFF, 0xC8, 0xB1, 0x6F, 0xF0, 0x0C, 0xC5, 0x07, 0xF0, 0x04, 0xC5, 0x08, 0xD0, 0xF3, 0xC9, 0x22, 0xF0, 0x01, 0x18, 0x84, 0x61, 0x98, 0x65, 0x6F, 0x85, 0x71, 0xA6, 0x70, 0x90, 0x01, 0xE8, 0x86, 0x72, 0xA5, 0x70, 0xF0, 0x04, 0xC9, 0x02, 0xD0, 0x0B, 0x98, 0x20, 0x75, 0xB4, 0xA6, 0x6F, 0xA4, 0x70, 0x20, 0x88, 0xB6, 0xA6, 0x16, 0xE0, 0x22, 0xD0, 0x05, 0xA2, 0x19, 0x4C, 0x37, 0xA4, 0xA5, 0x61, 0x95, 0x00, 0xA5, 0x62, 0x95, 0x01, 0xA5, 0x63, 0x95, 0x02, 0xA0, 0x00, 0x86, 0x64, 0x84, 0x65, 0x84, 0x70, 0x88, 0x84, 0x0D, 0x86, 0x17, 0xE8, 0xE8, 0xE8, 0x86, 0x16, 0x60, 0x46, 0x0F, 0x48, 0x49, 0xFF, 0x38, 0x65, 0x33, 0xA4, 0x34, 0xB0, 0x01, 0x88, 0xC4, 0x32, 0x90, 0x11, 0xD0, 0x04, 0xC5, 0x31, 0x90, 0x0B, 0x85, 0x33, 0x84, 0x34, 0x85, 0x35, 0x84, 0x36, 0xAA, 0x68, 0x60, 0xA2, 0x10, 0xA5, 0x0F, 0x30, 0xB6, 0x20, 0x26, 0xB5, 0xA9, 0x80, 0x85, 0x0F, 0x68, 0xD0, 0xD0, 0xA6, 0x37, 0xA5, 0x38, 0x86, 0x33, 0x85, 0x34, 0xA0, 0x00, 0x84, 0x4F, 0x84, 0x4E, 0xA5, 0x31, 0xA6, 0x32, 0x85, 0x5F, 0x86, 0x60, 0xA9, 0x19, 0xA2, 0x00, 0x85, 0x22, 0x86, 0x23, 0xC5, 0x16, 0xF0, 0x05, 0x20, 0xC7, 0xB5, 0xF0, 0xF7, 0xA9, 0x07, 0x85, 0x53, 0xA5, 0x2D, 0xA6, 0x2E, 0x85, 0x22, 0x86, 0x23, 0xE4, 0x30, 0xD0, 0x04, 0xC5, 0x2F, 0xF0, 0x05, 0x20, 0xBD, 0xB5, 0xF0, 0xF3, 0x85, 0x58, 0x86, 0x59, 0xA9, 0x03, 0x85, 0x53, 0xA5, 0x58, 0xA6, 0x59, 0xE4, 0x32, 0xD0, 0x07, 0xC5, 0x31, 0xD0, 0x03, 0x4C, 0x06, 0xB6, 0x85, 0x22, 0x86, 0x23, 0xA0, 0x00, 0xB1, 0x22, 0xAA, 0xC8, 0xB1, 0x22, 0x08, 0xC8, 0xB1, 0x22, 0x65, 0x58, 0x85, 0x58, 0xC8, 0xB1, 0x22, 0x65, 0x59, 0x85, 0x59, 0x28, 0x10, 0xD3, 0x8A, 0x30, 0xD0, 0xC8, 0xB1, 0x22, 0xA0, 0x00, 0x0A, 0x69, 0x05, 0x65, 0x22, 0x85, 0x22, 0x90, 0x02, 0xE6, 0x23, 0xA6, 0x23, 0xE4, 0x59, 0xD0, 0x04, 0xC5, 0x58, 0xF0, 0xBA, 0x20, 0xC7, 0xB5, 0xF0, 0xF3, 0xB1, 0x22, 0x30, 0x35, 0xC8, 0xB1, 0x22, 0x10, 0x30, 0xC8, 0xB1, 0x22, 0xF0, 0x2B, 0xC8, 0xB1, 0x22, 0xAA, 0xC8, 0xB1, 0x22, 0xC5, 0x34, 0x90, 0x06, 0xD0, 0x1E, 0xE4, 0x33, 0xB0, 0x1A, 0xC5, 0x60, 0x90, 0x16, 0xD0, 0x04, 0xE4, 0x5F, 0x90, 0x10, 0x86, 0x5F, 0x85, 0x60, 0xA5, 0x22, 0xA6, 0x23, 0x85, 0x4E, 0x86, 0x4F, 0xA5, 0x53, 0x85, 0x55, 0xA5, 0x53, 0x18, 0x65, 0x22, 0x85, 0x22, 0x90, 0x02, 0xE6, 0x23, 0xA6, 0x23, 0xA0, 0x00, 0x60, 0xA5, 0x4F, 0x05, 0x4E, 0xF0, 0xF5, 0xA5, 0x55, 0x29, 0x04, 0x4A, 0xA8, 0x85, 0x55, 0xB1, 0x4E, 0x65, 0x5F, 0x85, 0x5A, 0xA5, 0x60, 0x69, 0x00, 0x85, 0x5B, 0xA5, 0x33, 0xA6, 0x34, 0x85, 0x58, 0x86, 0x59, 0x20, 0xBF, 0xA3, 0xA4, 0x55, 0xC8, 0xA5, 0x58, 0x91, 0x4E, 0xAA, 0xE6, 0x59, 0xA5, 0x59, 0xC8, 0x91, 0x4E, 0x4C, 0x2A, 0xB5, 0xA5, 0x65, 0x48, 0xA5, 0x64, 0x48, 0x20, 0x83, 0xAE, 0x20, 0x8F, 0xAD, 0x68, 0x85, 0x6F, 0x68, 0x85, 0x70, 0xA0, 0x00, 0xB1, 0x6F, 0x18, 0x71, 0x64, 0x90, 0x05, 0xA2, 0x17, 0x4C, 0x37, 0xA4, 0x20, 0x75, 0xB4, 0x20, 0x7A, 0xB6, 0xA5, 0x50, 0xA4, 0x51, 0x20, 0xAA, 0xB6, 0x20, 0x8C, 0xB6, 0xA5, 0x6F, 0xA4, 0x70, 0x20, 0xAA, 0xB6, 0x20, 0xCA, 0xB4, 0x4C, 0xB8, 0xAD, 0xA0, 0x00, 0xB1, 0x6F, 0x48, 0xC8, 0xB1, 0x6F, 0xAA, 0xC8, 0xB1, 0x6F, 0xA8, 0x68, 0x86, 0x22, 0x84, 0x23, 0xA8, 0xF0, 0x0A, 0x48, 0x88, 0xB1, 0x22, 0x91, 0x35, 0x98, 0xD0, 0xF8, 0x68, 0x18, 0x65, 0x35, 0x85, 0x35, 0x90, 0x02, 0xE6, 0x36, 0x60, 0x20, 0x8F, 0xAD, 0xA5, 0x64, 0xA4, 0x65, 0x85, 0x22, 0x84, 0x23, 0x20, 0xDB, 0xB6, 0x08, 0xA0, 0x00, 0xB1, 0x22, 0x48, 0xC8, 0xB1, 0x22, 0xAA, 0xC8, 0xB1, 0x22, 0xA8, 0x68, 0x28, 0xD0, 0x13, 0xC4, 0x34, 0xD0, 0x0F, 0xE4, 0x33, 0xD0, 0x0B, 0x48, 0x18, 0x65, 0x33, 0x85, 0x33, 0x90, 0x02, 0xE6, 0x34, 0x68, 0x86, 0x22, 0x84, 0x23, 0x60, 0xC4, 0x18, 0xD0, 0x0C, 0xC5, 0x17, 0xD0, 0x08, 0x85, 0x16, 0xE9, 0x03, 0x85, 0x17, 0xA0, 0x00, 0x60, 0x20, 0xA1, 0xB7, 0x8A, 0x48, 0xA9, 0x01, 0x20, 0x7D, 0xB4, 0x68, 0xA0, 0x00, 0x91, 0x62, 0x68, 0x68, 0x4C, 0xCA, 0xB4, 0x20, 0x61, 0xB7, 0xD1, 0x50, 0x98, 0x90, 0x04, 0xB1, 0x50, 0xAA, 0x98, 0x48, 0x8A, 0x48, 0x20, 0x7D, 0xB4, 0xA5, 0x50, 0xA4, 0x51, 0x20, 0xAA, 0xB6, 0x68, 0xA8, 0x68, 0x18, 0x65, 0x22, 0x85, 0x22, 0x90, 0x02, 0xE6, 0x23, 0x98, 0x20, 0x8C, 0xB6, 0x4C, 0xCA, 0xB4, 0x20, 0x61, 0xB7, 0x18, 0xF1, 0x50, 0x49, 0xFF, 0x4C, 0x06, 0xB7, 0xA9, 0xFF, 0x85, 0x65, 0x20, 0x79, 0x00, 0xC9, 0x29, 0xF0, 0x06, 0x20, 0xFD, 0xAE, 0x20, 0x9E, 0xB7, 0x20, 0x61, 0xB7, 0xF0, 0x4B, 0xCA, 0x8A, 0x48, 0x18, 0xA2, 0x00, 0xF1, 0x50, 0xB0, 0xB6, 0x49, 0xFF, 0xC5, 0x65, 0x90, 0xB1, 0xA5, 0x65, 0xB0, 0xAD, 0x20, 0xF7, 0xAE, 0x68, 0xA8, 0x68, 0x85, 0x55, 0x68, 0x68, 0x68, 0xAA, 0x68, 0x85, 0x50, 0x68, 0x85, 0x51, 0xA5, 0x55, 0x48, 0x98, 0x48, 0xA0, 0x00, 0x8A, 0x60, 0x20, 0x82, 0xB7, 0x4C, 0xA2, 0xB3, 0x20, 0xA3, 0xB6, 0xA2, 0x00, 0x86, 0x0D, 0xA8, 0x60, 0x20, 0x82, 0xB7, 0xF0, 0x08, 0xA0, 0x00, 0xB1, 0x22, 0xA8, 0x4C, 0xA2, 0xB3, 0x4C, 0x48, 0xB2, 0x20, 0x73, 0x00, 0x20, 0x8A, 0xAD, 0x20, 0xB8, 0xB1, 0xA6, 0x64, 0xD0, 0xF0, 0xA6, 0x65, 0x4C, 0x79, 0x00, 0x20, 0x82, 0xB7, 0xD0, 0x03, 0x4C, 0xF7, 0xB8, 0xA6, 0x7A, 0xA4, 0x7B, 0x86, 0x71, 0x84, 0x72, 0xA6, 0x22, 0x86, 0x7A, 0x18, 0x65, 0x22, 0x85, 0x24, 0xA6, 0x23, 0x86, 0x7B, 0x90, 0x01, 0xE8, 0x86, 0x25, 0xA0, 0x00, 0xB1, 0x24, 0x48, 0x98, 0x91, 0x24, 0x20, 0x79, 0x00, 0x20, 0xF3, 0xBC, 0x68, 0xA0, 0x00, 0x91, 0x24, 0xA6, 0x71, 0xA4, 0x72, 0x86, 0x7A, 0x84, 0x7B, 0x60, 0x20, 0x8A, 0xAD, 0x20, 0xF7, 0xB7, 0x20, 0xFD, 0xAE, 0x4C, 0x9E, 0xB7, 0xA5, 0x66, 0x30, 0x9D, 0xA5, 0x61, 0xC9, 0x91, 0xB0, 0x97, 0x20, 0x9B, 0xBC, 0xA5, 0x64, 0xA4, 0x65, 0x84, 0x14, 0x85, 0x15, 0x60, 0xA5, 0x15, 0x48, 0xA5, 0x14, 0x48, 0x20, 0xF7, 0xB7, 0xA0, 0x00, 0xB1, 0x14, 0xA8, 0x68, 0x85, 0x14, 0x68, 0x85, 0x15, 0x4C, 0xA2, 0xB3, 0x20, 0xEB, 0xB7, 0x8A, 0xA0, 0x00, 0x91, 0x14, 0x60, 0x20, 0xEB, 0xB7, 0x86, 0x49, 0xA2, 0x00, 0x20, 0x79, 0x00, 0xF0, 0x03, 0x20, 0xF1, 0xB7, 0x86, 0x4A, 0xA0, 0x00, 0xB1, 0x14, 0x45, 0x4A, 0x25, 0x49, 0xF0, 0xF8, 0x60, 0xA9, 0x11, 0xA0, 0xBF, 0x4C, 0x67, 0xB8, 0x20, 0x8C, 0xBA, 0xA5, 0x66, 0x49, 0xFF, 0x85, 0x66, 0x45, 0x6E, 0x85, 0x6F, 0xA5, 0x61, 0x4C, 0x6A, 0xB8, 0x20, 0x99, 0xB9, 0x90, 0x3C, 0x20, 0x8C, 0xBA, 0xD0, 0x03, 0x4C, 0xFC, 0xBB, 0xA6, 0x70, 0x86, 0x56, 0xA2, 0x69, 0xA5, 0x69, 0xA8, 0xF0, 0xCE, 0x38, 0xE5, 0x61, 0xF0, 0x24, 0x90, 0x12, 0x84, 0x61, 0xA4, 0x6E, 0x84, 0x66, 0x49, 0xFF, 0x69, 0x00, 0xA0, 0x00, 0x84, 0x56, 0xA2, 0x61, 0xD0, 0x04, 0xA0, 0x00, 0x84, 0x70, 0xC9, 0xF9, 0x30, 0xC7, 0xA8, 0xA5, 0x70, 0x56, 0x01, 0x20, 0xB0, 0xB9, 0x24, 0x6F, 0x10, 0x57, 0xA0, 0x61, 0xE0, 0x69, 0xF0, 0x02, 0xA0, 0x69, 0x38, 0x49, 0xFF, 0x65, 0x56, 0x85, 0x70, 0xB9, 0x04, 0x00, 0xF5, 0x04, 0x85, 0x65, 0xB9, 0x03, 0x00, 0xF5, 0x03, 0x85, 0x64, 0xB9, 0x02, 0x00, 0xF5, 0x02, 0x85, 0x63, 0xB9, 0x01, 0x00, 0xF5, 0x01, 0x85, 0x62, 0xB0, 0x03, 0x20, 0x47, 0xB9, 0xA0, 0x00, 0x98, 0x18, 0xA6, 0x62, 0xD0, 0x4A, 0xA6, 0x63, 0x86, 0x62, 0xA6, 0x64, 0x86, 0x63, 0xA6, 0x65, 0x86, 0x64, 0xA6, 0x70, 0x86, 0x65, 0x84, 0x70, 0x69, 0x08, 0xC9, 0x20, 0xD0, 0xE4, 0xA9, 0x00, 0x85, 0x61, 0x85, 0x66, 0x60, 0x65, 0x56, 0x85, 0x70, 0xA5, 0x65, 0x65, 0x6D, 0x85, 0x65, 0xA5, 0x64, 0x65, 0x6C, 0x85, 0x64, 0xA5, 0x63, 0x65, 0x6B, 0x85, 0x63, 0xA5, 0x62, 0x65, 0x6A, 0x85, 0x62, 0x4C, 0x36, 0xB9, 0x69, 0x01, 0x06, 0x70, 0x26, 0x65, 0x26, 0x64, 0x26, 0x63, 0x26, 0x62, 0x10, 0xF2, 0x38, 0xE5, 0x61, 0xB0, 0xC7, 0x49, 0xFF, 0x69, 0x01, 0x85, 0x61, 0x90, 0x0E, 0xE6, 0x61, 0xF0, 0x42, 0x66, 0x62, 0x66, 0x63, 0x66, 0x64, 0x66, 0x65, 0x66, 0x70, 0x60, 0xA5, 0x66, 0x49, 0xFF, 0x85, 0x66, 0xA5, 0x62, 0x49, 0xFF, 0x85, 0x62, 0xA5, 0x63, 0x49, 0xFF, 0x85, 0x63, 0xA5, 0x64, 0x49, 0xFF, 0x85, 0x64, 0xA5, 0x65, 0x49, 0xFF, 0x85, 0x65, 0xA5, 0x70, 0x49, 0xFF, 0x85, 0x70, 0xE6, 0x70, 0xD0, 0x0E, 0xE6, 0x65, 0xD0, 0x0A, 0xE6, 0x64, 0xD0, 0x06, 0xE6, 0x63, 0xD0, 0x02, 0xE6, 0x62, 0x60, 0xA2, 0x0F, 0x4C, 0x37, 0xA4, 0xA2, 0x25, 0xB4, 0x04, 0x84, 0x70, 0xB4, 0x03, 0x94, 0x04, 0xB4, 0x02, 0x94, 0x03, 0xB4, 0x01, 0x94, 0x02, 0xA4, 0x68, 0x94, 0x01, 0x69, 0x08, 0x30, 0xE8, 0xF0, 0xE6, 0xE9, 0x08, 0xA8, 0xA5, 0x70, 0xB0, 0x14, 0x16, 0x01, 0x90, 0x02, 0xF6, 0x01, 0x76, 0x01, 0x76, 0x01, 0x76, 0x02, 0x76, 0x03, 0x76, 0x04, 0x6A, 0xC8, 0xD0, 0xEC, 0x18, 0x60, 0x81, 0x00, 0x00, 0x00, 0x00, 0x03, 0x7F, 0x5E, 0x56, 0xCB, 0x79, 0x80, 0x13, 0x9B, 0x0B, 0x64, 0x80, 0x76, 0x38, 0x93, 0x16, 0x82, 0x38, 0xAA, 0x3B, 0x20, 0x80, 0x35, 0x04, 0xF3, 0x34, 0x81, 0x35, 0x04, 0xF3, 0x34, 0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0x31, 0x72, 0x17, 0xF8, 0x20, 0x2B, 0xBC, 0xF0, 0x02, 0x10, 0x03, 0x4C, 0x48, 0xB2, 0xA5, 0x61, 0xE9, 0x7F, 0x48, 0xA9, 0x80, 0x85, 0x61, 0xA9, 0xD6, 0xA0, 0xB9, 0x20, 0x67, 0xB8, 0xA9, 0xDB, 0xA0, 0xB9, 0x20, 0x0F, 0xBB, 0xA9, 0xBC, 0xA0, 0xB9, 0x20, 0x50, 0xB8, 0xA9, 0xC1, 0xA0, 0xB9, 0x20, 0x43, 0xE0, 0xA9, 0xE0, 0xA0, 0xB9, 0x20, 0x67, 0xB8, 0x68, 0x20, 0x7E, 0xBD, 0xA9, 0xE5, 0xA0, 0xB9, 0x20, 0x8C, 0xBA, 0xD0, 0x03, 0x4C, 0x8B, 0xBA, 0x20, 0xB7, 0xBA, 0xA9, 0x00, 0x85, 0x26, 0x85, 0x27, 0x85, 0x28, 0x85, 0x29, 0xA5, 0x70, 0x20, 0x59, 0xBA, 0xA5, 0x65, 0x20, 0x59, 0xBA, 0xA5, 0x64, 0x20, 0x59, 0xBA, 0xA5, 0x63, 0x20, 0x59, 0xBA, 0xA5, 0x62, 0x20, 0x5E, 0xBA, 0x4C, 0x8F, 0xBB, 0xD0, 0x03, 0x4C, 0x83, 0xB9, 0x4A, 0x09, 0x80, 0xA8, 0x90, 0x19, 0x18, 0xA5, 0x29, 0x65, 0x6D, 0x85, 0x29, 0xA5, 0x28, 0x65, 0x6C, 0x85, 0x28, 0xA5, 0x27, 0x65, 0x6B, 0x85, 0x27, 0xA5, 0x26, 0x65, 0x6A, 0x85, 0x26, 0x66, 0x26, 0x66, 0x27, 0x66, 0x28, 0x66, 0x29, 0x66, 0x70, 0x98, 0x4A, 0xD0, 0xD6, 0x60, 0x85, 0x22, 0x84, 0x23, 0xA0, 0x04, 0xB1, 0x22, 0x85, 0x6D, 0x88, 0xB1, 0x22, 0x85, 0x6C, 0x88, 0xB1, 0x22, 0x85, 0x6B, 0x88, 0xB1, 0x22, 0x85, 0x6E, 0x45, 0x66, 0x85, 0x6F, 0xA5, 0x6E, 0x09, 0x80, 0x85, 0x6A, 0x88, 0xB1, 0x22, 0x85, 0x69, 0xA5, 0x61, 0x60, 0xA5, 0x69, 0xF0, 0x1F, 0x18, 0x65, 0x61, 0x90, 0x04, 0x30, 0x1D, 0x18, 0x2C, 0x10, 0x14, 0x69, 0x80, 0x85, 0x61, 0xD0, 0x03, 0x4C, 0xFB, 0xB8, 0xA5, 0x6F, 0x85, 0x66, 0x60, 0xA5, 0x66, 0x49, 0xFF, 0x30, 0x05, 0x68, 0x68, 0x4C, 0xF7, 0xB8, 0x4C, 0x7E, 0xB9, 0x20, 0x0C, 0xBC, 0xAA, 0xF0, 0x10, 0x18, 0x69, 0x02, 0xB0, 0xF2, 0xA2, 0x00, 0x86, 0x6F, 0x20, 0x77, 0xB8, 0xE6, 0x61, 0xF0, 0xE7, 0x60, 0x84, 0x20, 0x00, 0x00, 0x00, 0x20, 0x0C, 0xBC, 0xA9, 0xF9, 0xA0, 0xBA, 0xA2, 0x00, 0x86, 0x6F, 0x20, 0xA2, 0xBB, 0x4C, 0x12, 0xBB, 0x20, 0x8C, 0xBA, 0xF0, 0x76, 0x20, 0x1B, 0xBC, 0xA9, 0x00, 0x38, 0xE5, 0x61, 0x85, 0x61, 0x20, 0xB7, 0xBA, 0xE6, 0x61, 0xF0, 0xBA, 0xA2, 0xFC, 0xA9, 0x01, 0xA4, 0x6A, 0xC4, 0x62, 0xD0, 0x10, 0xA4, 0x6B, 0xC4, 0x63, 0xD0, 0x0A, 0xA4, 0x6C, 0xC4, 0x64, 0xD0, 0x04, 0xA4, 0x6D, 0xC4, 0x65, 0x08, 0x2A, 0x90, 0x09, 0xE8, 0x95, 0x29, 0xF0, 0x32, 0x10, 0x34, 0xA9, 0x01, 0x28, 0xB0, 0x0E, 0x06, 0x6D, 0x26, 0x6C, 0x26, 0x6B, 0x26, 0x6A, 0xB0, 0xE6, 0x30, 0xCE, 0x10, 0xE2, 0xA8, 0xA5, 0x6D, 0xE5, 0x65, 0x85, 0x6D, 0xA5, 0x6C, 0xE5, 0x64, 0x85, 0x6C, 0xA5, 0x6B, 0xE5, 0x63, 0x85, 0x6B, 0xA5, 0x6A, 0xE5, 0x62, 0x85, 0x6A, 0x98, 0x4C, 0x4F, 0xBB, 0xA9, 0x40, 0xD0, 0xCE, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x85, 0x70, 0x28, 0x4C, 0x8F, 0xBB, 0xA2, 0x14, 0x4C, 0x37, 0xA4, 0xA5, 0x26, 0x85, 0x62, 0xA5, 0x27, 0x85, 0x63, 0xA5, 0x28, 0x85, 0x64, 0xA5, 0x29, 0x85, 0x65, 0x4C, 0xD7, 0xB8, 0x85, 0x22, 0x84, 0x23, 0xA0, 0x04, 0xB1, 0x22, 0x85, 0x65, 0x88, 0xB1, 0x22, 0x85, 0x64, 0x88, 0xB1, 0x22, 0x85, 0x63, 0x88, 0xB1, 0x22, 0x85, 0x66, 0x09, 0x80, 0x85, 0x62, 0x88, 0xB1, 0x22, 0x85, 0x61, 0x84, 0x70, 0x60, 0xA2, 0x5C, 0x2C, 0xA2, 0x57, 0xA0, 0x00, 0xF0, 0x04, 0xA6, 0x49, 0xA4, 0x4A, 0x20, 0x1B, 0xBC, 0x86, 0x22, 0x84, 0x23, 0xA0, 0x04, 0xA5, 0x65, 0x91, 0x22, 0x88, 0xA5, 0x64, 0x91, 0x22, 0x88, 0xA5, 0x63, 0x91, 0x22, 0x88, 0xA5, 0x66, 0x09, 0x7F, 0x25, 0x62, 0x91, 0x22, 0x88, 0xA5, 0x61, 0x91, 0x22, 0x84, 0x70, 0x60, 0xA5, 0x6E, 0x85, 0x66, 0xA2, 0x05, 0xB5, 0x68, 0x95, 0x60, 0xCA, 0xD0, 0xF9, 0x86, 0x70, 0x60, 0x20, 0x1B, 0xBC, 0xA2, 0x06, 0xB5, 0x60, 0x95, 0x68, 0xCA, 0xD0, 0xF9, 0x86, 0x70, 0x60, 0xA5, 0x61, 0xF0, 0xFB, 0x06, 0x70, 0x90, 0xF7, 0x20, 0x6F, 0xB9, 0xD0, 0xF2, 0x4C, 0x38, 0xB9, 0xA5, 0x61, 0xF0, 0x09, 0xA5, 0x66, 0x2A, 0xA9, 0xFF, 0xB0, 0x02, 0xA9, 0x01, 0x60, 0x20, 0x2B, 0xBC, 0x85, 0x62, 0xA9, 0x00, 0x85, 0x63, 0xA2, 0x88, 0xA5, 0x62, 0x49, 0xFF, 0x2A, 0xA9, 0x00, 0x85, 0x65, 0x85, 0x64, 0x86, 0x61, 0x85, 0x70, 0x85, 0x66, 0x4C, 0xD2, 0xB8, 0x46, 0x66, 0x60, 0x85, 0x24, 0x84, 0x25, 0xA0, 0x00, 0xB1, 0x24, 0xC8, 0xAA, 0xF0, 0xC4, 0xB1, 0x24, 0x45, 0x66, 0x30, 0xC2, 0xE4, 0x61, 0xD0, 0x21, 0xB1, 0x24, 0x09, 0x80, 0xC5, 0x62, 0xD0, 0x19, 0xC8, 0xB1, 0x24, 0xC5, 0x63, 0xD0, 0x12, 0xC8, 0xB1, 0x24, 0xC5, 0x64, 0xD0, 0x0B, 0xC8, 0xA9, 0x7F, 0xC5, 0x70, 0xB1, 0x24, 0xE5, 0x65, 0xF0, 0x28, 0xA5, 0x66, 0x90, 0x02, 0x49, 0xFF, 0x4C, 0x31, 0xBC, 0xA5, 0x61, 0xF0, 0x4A, 0x38, 0xE9, 0xA0, 0x24, 0x66, 0x10, 0x09, 0xAA, 0xA9, 0xFF, 0x85, 0x68, 0x20, 0x4D, 0xB9, 0x8A, 0xA2, 0x61, 0xC9, 0xF9, 0x10, 0x06, 0x20, 0x99, 0xB9, 0x84, 0x68, 0x60, 0xA8, 0xA5, 0x66, 0x29, 0x80, 0x46, 0x62, 0x05, 0x62, 0x85, 0x62, 0x20, 0xB0, 0xB9, 0x84, 0x68, 0x60, 0xA5, 0x61, 0xC9, 0xA0, 0xB0, 0x20, 0x20, 0x9B, 0xBC, 0x84, 0x70, 0xA5, 0x66, 0x84, 0x66, 0x49, 0x80, 0x2A, 0xA9, 0xA0, 0x85, 0x61, 0xA5, 0x65, 0x85, 0x07, 0x4C, 0xD2, 0xB8, 0x85, 0x62, 0x85, 0x63, 0x85, 0x64, 0x85, 0x65, 0xA8, 0x60, 0xA0, 0x00, 0xA2, 0x0A, 0x94, 0x5D, 0xCA, 0x10, 0xFB, 0x90, 0x0F, 0xC9, 0x2D, 0xD0, 0x04, 0x86, 0x67, 0xF0, 0x04, 0xC9, 0x2B, 0xD0, 0x05, 0x20, 0x73, 0x00, 0x90, 0x5B, 0xC9, 0x2E, 0xF0, 0x2E, 0xC9, 0x45, 0xD0, 0x30, 0x20, 0x73, 0x00, 0x90, 0x17, 0xC9, 0xAB, 0xF0, 0x0E, 0xC9, 0x2D, 0xF0, 0x0A, 0xC9, 0xAA, 0xF0, 0x08, 0xC9, 0x2B, 0xF0, 0x04, 0xD0, 0x07, 0x66, 0x60, 0x20, 0x73, 0x00, 0x90, 0x5C, 0x24, 0x60, 0x10, 0x0E, 0xA9, 0x00, 0x38, 0xE5, 0x5E, 0x4C, 0x49, 0xBD, 0x66, 0x5F, 0x24, 0x5F, 0x50, 0xC3, 0xA5, 0x5E, 0x38, 0xE5, 0x5D, 0x85, 0x5E, 0xF0, 0x12, 0x10, 0x09, 0x20, 0xFE, 0xBA, 0xE6, 0x5E, 0xD0, 0xF9, 0xF0, 0x07, 0x20, 0xE2, 0xBA, 0xC6, 0x5E, 0xD0, 0xF9, 0xA5, 0x67, 0x30, 0x01, 0x60, 0x4C, 0xB4, 0xBF, 0x48, 0x24, 0x5F, 0x10, 0x02, 0xE6, 0x5D, 0x20, 0xE2, 0xBA, 0x68, 0x38, 0xE9, 0x30, 0x20, 0x7E, 0xBD, 0x4C, 0x0A, 0xBD, 0x48, 0x20, 0x0C, 0xBC, 0x68, 0x20, 0x3C, 0xBC, 0xA5, 0x6E, 0x45, 0x66, 0x85, 0x6F, 0xA6, 0x61, 0x4C, 0x6A, 0xB8, 0xA5, 0x5E, 0xC9, 0x0A, 0x90, 0x09, 0xA9, 0x64, 0x24, 0x60, 0x30, 0x11, 0x4C, 0x7E, 0xB9, 0x0A, 0x0A, 0x18, 0x65, 0x5E, 0x0A, 0x18, 0xA0, 0x00, 0x71, 0x7A, 0x38, 0xE9, 0x30, 0x85, 0x5E, 0x4C, 0x30, 0xBD, 0x9B, 0x3E, 0xBC, 0x1F, 0xFD, 0x9E, 0x6E, 0x6B, 0x27, 0xFD, 0x9E, 0x6E, 0x6B, 0x28, 0x00, 0xA9, 0x71, 0xA0, 0xA3, 0x20, 0xDA, 0xBD, 0xA5, 0x3A, 0xA6, 0x39, 0x85, 0x62, 0x86, 0x63, 0xA2, 0x90, 0x38, 0x20, 0x49, 0xBC, 0x20, 0xDF, 0xBD, 0x4C, 0x1E, 0xAB, 0xA0, 0x01, 0xA9, 0x20, 0x24, 0x66, 0x10, 0x02, 0xA9, 0x2D, 0x99, 0xFF, 0x00, 0x85, 0x66, 0x84, 0x71, 0xC8, 0xA9, 0x30, 0xA6, 0x61, 0xD0, 0x03, 0x4C, 0x04, 0xBF, 0xA9, 0x00, 0xE0, 0x80, 0xF0, 0x02, 0xB0, 0x09, 0xA9, 0xBD, 0xA0, 0xBD, 0x20, 0x28, 0xBA, 0xA9, 0xF7, 0x85, 0x5D, 0xA9, 0xB8, 0xA0, 0xBD, 0x20, 0x5B, 0xBC, 0xF0, 0x1E, 0x10, 0x12, 0xA9, 0xB3, 0xA0, 0xBD, 0x20, 0x5B, 0xBC, 0xF0, 0x02, 0x10, 0x0E, 0x20, 0xE2, 0xBA, 0xC6, 0x5D, 0xD0, 0xEE, 0x20, 0xFE, 0xBA, 0xE6, 0x5D, 0xD0, 0xDC, 0x20, 0x49, 0xB8, 0x20, 0x9B, 0xBC, 0xA2, 0x01, 0xA5, 0x5D, 0x18, 0x69, 0x0A, 0x30, 0x09, 0xC9, 0x0B, 0xB0, 0x06, 0x69, 0xFF, 0xAA, 0xA9, 0x02, 0x38, 0xE9, 0x02, 0x85, 0x5E, 0x86, 0x5D, 0x8A, 0xF0, 0x02, 0x10, 0x13, 0xA4, 0x71, 0xA9, 0x2E, 0xC8, 0x99, 0xFF, 0x00, 0x8A, 0xF0, 0x06, 0xA9, 0x30, 0xC8, 0x99, 0xFF, 0x00, 0x84, 0x71, 0xA0, 0x00, 0xA2, 0x80, 0xA5, 0x65, 0x18, 0x79, 0x19, 0xBF, 0x85, 0x65, 0xA5, 0x64, 0x79, 0x18, 0xBF, 0x85, 0x64, 0xA5, 0x63, 0x79, 0x17, 0xBF, 0x85, 0x63, 0xA5, 0x62, 0x79, 0x16, 0xBF, 0x85, 0x62, 0xE8, 0xB0, 0x04, 0x10, 0xDE, 0x30, 0x02, 0x30, 0xDA, 0x8A, 0x90, 0x04, 0x49, 0xFF, 0x69, 0x0A, 0x69, 0x2F, 0xC8, 0xC8, 0xC8, 0xC8, 0x84, 0x47, 0xA4, 0x71, 0xC8, 0xAA, 0x29, 0x7F, 0x99, 0xFF, 0x00, 0xC6, 0x5D, 0xD0, 0x06, 0xA9, 0x2E, 0xC8, 0x99, 0xFF, 0x00, 0x84, 0x71, 0xA4, 0x47, 0x8A, 0x49, 0xFF, 0x29, 0x80, 0xAA, 0xC0, 0x24, 0xF0, 0x04, 0xC0, 0x3C, 0xD0, 0xA6, 0xA4, 0x71, 0xB9, 0xFF, 0x00, 0x88, 0xC9, 0x30, 0xF0, 0xF8, 0xC9, 0x2E, 0xF0, 0x01, 0xC8, 0xA9, 0x2B, 0xA6, 0x5E, 0xF0, 0x2E, 0x10, 0x08, 0xA9, 0x00, 0x38, 0xE5, 0x5E, 0xAA, 0xA9, 0x2D, 0x99, 0x01, 0x01, 0xA9, 0x45, 0x99, 0x00, 0x01, 0x8A, 0xA2, 0x2F, 0x38, 0xE8, 0xE9, 0x0A, 0xB0, 0xFB, 0x69, 0x3A, 0x99, 0x03, 0x01, 0x8A, 0x99, 0x02, 0x01, 0xA9, 0x00, 0x99, 0x04, 0x01, 0xF0, 0x08, 0x99, 0xFF, 0x00, 0xA9, 0x00, 0x99, 0x00, 0x01, 0xA9, 0x00, 0xA0, 0x01, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x0A, 0x1F, 0x00, 0x00, 0x98, 0x96, 0x80, 0xFF, 0xF0, 0xBD, 0xC0, 0x00, 0x01, 0x86, 0xA0, 0xFF, 0xFF, 0xD8, 0xF0, 0x00, 0x00, 0x03, 0xE8, 0xFF, 0xFF, 0xFF, 0x9C, 0x00, 0x00, 0x00, 0x0A, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0x0A, 0x80, 0x00, 0x03, 0x4B, 0xC0, 0xFF, 0xFF, 0x73, 0x60, 0x00, 0x00, 0x0E, 0x10, 0xFF, 0xFF, 0xFD, 0xA8, 0x00, 0x00, 0x00, 0x3C, 0xEC, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x20, 0x0C, 0xBC, 0xA9, 0x11, 0xA0, 0xBF, 0x20, 0xA2, 0xBB, 0xF0, 0x70, 0xA5, 0x69, 0xD0, 0x03, 0x4C, 0xF9, 0xB8, 0xA2, 0x4E, 0xA0, 0x00, 0x20, 0xD4, 0xBB, 0xA5, 0x6E, 0x10, 0x0F, 0x20, 0xCC, 0xBC, 0xA9, 0x4E, 0xA0, 0x00, 0x20, 0x5B, 0xBC, 0xD0, 0x03, 0x98, 0xA4, 0x07, 0x20, 0xFE, 0xBB, 0x98, 0x48, 0x20, 0xEA, 0xB9, 0xA9, 0x4E, 0xA0, 0x00, 0x20, 0x28, 0xBA, 0x20, 0xED, 0xBF, 0x68, 0x4A, 0x90, 0x0A, 0xA5, 0x61, 0xF0, 0x06, 0xA5, 0x66, 0x49, 0xFF, 0x85, 0x66, 0x60, 0x81, 0x38, 0xAA, 0x3B, 0x29, 0x07, 0x71, 0x34, 0x58, 0x3E, 0x56, 0x74, 0x16, 0x7E, 0xB3, 0x1B, 0x77, 0x2F, 0xEE, 0xE3, 0x85, 0x7A, 0x1D, 0x84, 0x1C, 0x2A, 0x7C, 0x63, 0x59, 0x58, 0x0A, 0x7E, 0x75, 0xFD, 0xE7, 0xC6, 0x80, 0x31, 0x72, 0x18, 0x10, 0x81, 0x00, 0x00, 0x00, 0x00, 0xA9, 0xBF, 0xA0, 0xBF, 0x20, 0x28, 0xBA, 0xA5, 0x70, 0x69, 0x50, 0x90, 0x03, 0x20, 0x23, 0xBC, 0x4C, 0x00, 0xE0}; +#endif /* _BIN_BASIC_ */ diff --git a/lib/emulator/flash/chargen.h b/lib/emulator/flash/chargen.h new file mode 100644 index 0000000..971e30a --- /dev/null +++ b/lib/emulator/flash/chargen.h @@ -0,0 +1,4 @@ +#ifndef _BIN_CHARGEN_ +#define _BIN_CHARGEN_ +unsigned char __in_flash("usbsid_binary") chargen[] = {0x3C, 0x66, 0x6E, 0x6E, 0x60, 0x62, 0x3C, 0x00, 0x18, 0x3C, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00, 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00, 0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00, 0x7E, 0x60, 0x60, 0x78, 0x60, 0x60, 0x7E, 0x00, 0x7E, 0x60, 0x60, 0x78, 0x60, 0x60, 0x60, 0x00, 0x3C, 0x66, 0x60, 0x6E, 0x66, 0x66, 0x3C, 0x00, 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x6C, 0x38, 0x00, 0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00, 0x63, 0x77, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x00, 0x66, 0x76, 0x7E, 0x7E, 0x6E, 0x66, 0x66, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x0E, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x78, 0x6C, 0x66, 0x00, 0x3C, 0x66, 0x60, 0x3C, 0x06, 0x66, 0x3C, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x7E, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x0C, 0x12, 0x30, 0x7C, 0x30, 0x62, 0xFC, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, 0x10, 0x30, 0x7F, 0x7F, 0x30, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0xFF, 0x66, 0xFF, 0x66, 0x66, 0x00, 0x18, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x18, 0x00, 0x62, 0x66, 0x0C, 0x18, 0x30, 0x66, 0x46, 0x00, 0x3C, 0x66, 0x3C, 0x38, 0x67, 0x66, 0x3F, 0x00, 0x06, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x3C, 0x66, 0x6E, 0x76, 0x66, 0x66, 0x3C, 0x00, 0x18, 0x18, 0x38, 0x18, 0x18, 0x18, 0x7E, 0x00, 0x3C, 0x66, 0x06, 0x0C, 0x30, 0x60, 0x7E, 0x00, 0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00, 0x06, 0x0E, 0x1E, 0x66, 0x7F, 0x06, 0x06, 0x00, 0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0x00, 0x3C, 0x66, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00, 0x7E, 0x66, 0x0C, 0x18, 0x18, 0x18, 0x18, 0x00, 0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, 0x3C, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30, 0x0E, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x70, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x70, 0x00, 0x3C, 0x66, 0x06, 0x0C, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x3E, 0x7F, 0x7F, 0x1C, 0x3E, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x00, 0x00, 0x00, 0xE0, 0xF0, 0x38, 0x18, 0x18, 0x18, 0x18, 0x1C, 0x0F, 0x07, 0x00, 0x00, 0x00, 0x18, 0x18, 0x38, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x03, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x3C, 0x7E, 0x7E, 0x7E, 0x7E, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x36, 0x7F, 0x7F, 0x7F, 0x3E, 0x1C, 0x08, 0x00, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x07, 0x0F, 0x1C, 0x18, 0x18, 0xC3, 0xE7, 0x7E, 0x3C, 0x3C, 0x7E, 0xE7, 0xC3, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x18, 0x18, 0x66, 0x66, 0x18, 0x18, 0x3C, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x08, 0x1C, 0x3E, 0x7F, 0x3E, 0x1C, 0x08, 0x00, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18, 0x18, 0x18, 0xC0, 0xC0, 0x30, 0x30, 0xC0, 0xC0, 0x30, 0x30, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x03, 0x3E, 0x76, 0x36, 0x36, 0x00, 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0x33, 0x33, 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xF8, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0xF8, 0x18, 0x18, 0x18, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xF8, 0xF8, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0xC3, 0x99, 0x91, 0x91, 0x9F, 0x99, 0xC3, 0xFF, 0xE7, 0xC3, 0x99, 0x81, 0x99, 0x99, 0x99, 0xFF, 0x83, 0x99, 0x99, 0x83, 0x99, 0x99, 0x83, 0xFF, 0xC3, 0x99, 0x9F, 0x9F, 0x9F, 0x99, 0xC3, 0xFF, 0x87, 0x93, 0x99, 0x99, 0x99, 0x93, 0x87, 0xFF, 0x81, 0x9F, 0x9F, 0x87, 0x9F, 0x9F, 0x81, 0xFF, 0x81, 0x9F, 0x9F, 0x87, 0x9F, 0x9F, 0x9F, 0xFF, 0xC3, 0x99, 0x9F, 0x91, 0x99, 0x99, 0xC3, 0xFF, 0x99, 0x99, 0x99, 0x81, 0x99, 0x99, 0x99, 0xFF, 0xC3, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xC3, 0xFF, 0xE1, 0xF3, 0xF3, 0xF3, 0xF3, 0x93, 0xC7, 0xFF, 0x99, 0x93, 0x87, 0x8F, 0x87, 0x93, 0x99, 0xFF, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x81, 0xFF, 0x9C, 0x88, 0x80, 0x94, 0x9C, 0x9C, 0x9C, 0xFF, 0x99, 0x89, 0x81, 0x81, 0x91, 0x99, 0x99, 0xFF, 0xC3, 0x99, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xFF, 0x83, 0x99, 0x99, 0x83, 0x9F, 0x9F, 0x9F, 0xFF, 0xC3, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xF1, 0xFF, 0x83, 0x99, 0x99, 0x83, 0x87, 0x93, 0x99, 0xFF, 0xC3, 0x99, 0x9F, 0xC3, 0xF9, 0x99, 0xC3, 0xFF, 0x81, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xFF, 0x99, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xE7, 0xFF, 0x9C, 0x9C, 0x9C, 0x94, 0x80, 0x88, 0x9C, 0xFF, 0x99, 0x99, 0xC3, 0xE7, 0xC3, 0x99, 0x99, 0xFF, 0x99, 0x99, 0x99, 0xC3, 0xE7, 0xE7, 0xE7, 0xFF, 0x81, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x81, 0xFF, 0xC3, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xC3, 0xFF, 0xF3, 0xED, 0xCF, 0x83, 0xCF, 0x9D, 0x03, 0xFF, 0xC3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xC3, 0xFF, 0xFF, 0xE7, 0xC3, 0x81, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, 0xEF, 0xCF, 0x80, 0x80, 0xCF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, 0xFF, 0xE7, 0xFF, 0x99, 0x99, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x99, 0x99, 0x00, 0x99, 0x00, 0x99, 0x99, 0xFF, 0xE7, 0xC1, 0x9F, 0xC3, 0xF9, 0x83, 0xE7, 0xFF, 0x9D, 0x99, 0xF3, 0xE7, 0xCF, 0x99, 0xB9, 0xFF, 0xC3, 0x99, 0xC3, 0xC7, 0x98, 0x99, 0xC0, 0xFF, 0xF9, 0xF3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xE7, 0xCF, 0xCF, 0xCF, 0xE7, 0xF3, 0xFF, 0xCF, 0xE7, 0xF3, 0xF3, 0xF3, 0xE7, 0xCF, 0xFF, 0xFF, 0x99, 0xC3, 0x00, 0xC3, 0x99, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0x81, 0xE7, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xCF, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xFF, 0xFF, 0xFC, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0xFF, 0xC3, 0x99, 0x91, 0x89, 0x99, 0x99, 0xC3, 0xFF, 0xE7, 0xE7, 0xC7, 0xE7, 0xE7, 0xE7, 0x81, 0xFF, 0xC3, 0x99, 0xF9, 0xF3, 0xCF, 0x9F, 0x81, 0xFF, 0xC3, 0x99, 0xF9, 0xE3, 0xF9, 0x99, 0xC3, 0xFF, 0xF9, 0xF1, 0xE1, 0x99, 0x80, 0xF9, 0xF9, 0xFF, 0x81, 0x9F, 0x83, 0xF9, 0xF9, 0x99, 0xC3, 0xFF, 0xC3, 0x99, 0x9F, 0x83, 0x99, 0x99, 0xC3, 0xFF, 0x81, 0x99, 0xF3, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, 0xC3, 0x99, 0x99, 0xC3, 0x99, 0x99, 0xC3, 0xFF, 0xC3, 0x99, 0x99, 0xC1, 0xF9, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0xE7, 0xE7, 0xCF, 0xF1, 0xE7, 0xCF, 0x9F, 0xCF, 0xE7, 0xF1, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0x8F, 0xE7, 0xF3, 0xF9, 0xF3, 0xE7, 0x8F, 0xFF, 0xC3, 0x99, 0xF9, 0xF3, 0xE7, 0xFF, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xF7, 0xE3, 0xC1, 0x80, 0x80, 0xE3, 0xC1, 0xFF, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xFF, 0xFF, 0xFF, 0x1F, 0x0F, 0xC7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE3, 0xF0, 0xF8, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xC7, 0x0F, 0x1F, 0xFF, 0xFF, 0xFF, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0x3F, 0x1F, 0x8F, 0xC7, 0xE3, 0xF1, 0xF8, 0xFC, 0xFC, 0xF8, 0xF1, 0xE3, 0xC7, 0x8F, 0x1F, 0x3F, 0x00, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x00, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFF, 0xC3, 0x81, 0x81, 0x81, 0x81, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xC9, 0x80, 0x80, 0x80, 0xC1, 0xE3, 0xF7, 0xFF, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0xFF, 0xFF, 0xFF, 0xF8, 0xF0, 0xE3, 0xE7, 0xE7, 0x3C, 0x18, 0x81, 0xC3, 0xC3, 0x81, 0x18, 0x3C, 0xFF, 0xC3, 0x81, 0x99, 0x99, 0x81, 0xC3, 0xFF, 0xE7, 0xE7, 0x99, 0x99, 0xE7, 0xE7, 0xC3, 0xFF, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF7, 0xE3, 0xC1, 0x80, 0xC1, 0xE3, 0xF7, 0xFF, 0xE7, 0xE7, 0xE7, 0x00, 0x00, 0xE7, 0xE7, 0xE7, 0x3F, 0x3F, 0xCF, 0xCF, 0x3F, 0x3F, 0xCF, 0xCF, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, 0xFF, 0xFC, 0xC1, 0x89, 0xC9, 0xC9, 0xFF, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x33, 0x33, 0xCC, 0xCC, 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xE7, 0xE7, 0xE7, 0xE0, 0xE0, 0xE7, 0xE7, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xE7, 0xE7, 0xE7, 0xE0, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x07, 0xE7, 0xE7, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xE0, 0xE0, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0x07, 0x07, 0xE7, 0xE7, 0xE7, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xE7, 0x07, 0x07, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0x3C, 0x66, 0x6E, 0x6E, 0x60, 0x62, 0x3C, 0x00, 0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00, 0x3C, 0x60, 0x60, 0x60, 0x3C, 0x00, 0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00, 0x00, 0x0E, 0x18, 0x3E, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x7C, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x00, 0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x3C, 0x00, 0x60, 0x60, 0x6C, 0x78, 0x6C, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x66, 0x7F, 0x7F, 0x6B, 0x63, 0x00, 0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x00, 0x00, 0x7C, 0x66, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x00, 0x00, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x0E, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x3E, 0x36, 0x00, 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x0C, 0x78, 0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x0C, 0x12, 0x30, 0x7C, 0x30, 0x62, 0xFC, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, 0x10, 0x30, 0x7F, 0x7F, 0x30, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0xFF, 0x66, 0xFF, 0x66, 0x66, 0x00, 0x18, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x18, 0x00, 0x62, 0x66, 0x0C, 0x18, 0x30, 0x66, 0x46, 0x00, 0x3C, 0x66, 0x3C, 0x38, 0x67, 0x66, 0x3F, 0x00, 0x06, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x3C, 0x66, 0x6E, 0x76, 0x66, 0x66, 0x3C, 0x00, 0x18, 0x18, 0x38, 0x18, 0x18, 0x18, 0x7E, 0x00, 0x3C, 0x66, 0x06, 0x0C, 0x30, 0x60, 0x7E, 0x00, 0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00, 0x06, 0x0E, 0x1E, 0x66, 0x7F, 0x06, 0x06, 0x00, 0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0x00, 0x3C, 0x66, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00, 0x7E, 0x66, 0x0C, 0x18, 0x18, 0x18, 0x18, 0x00, 0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, 0x3C, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30, 0x0E, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0E, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x70, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x70, 0x00, 0x3C, 0x66, 0x06, 0x0C, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00, 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00, 0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00, 0x7E, 0x60, 0x60, 0x78, 0x60, 0x60, 0x7E, 0x00, 0x7E, 0x60, 0x60, 0x78, 0x60, 0x60, 0x60, 0x00, 0x3C, 0x66, 0x60, 0x6E, 0x66, 0x66, 0x3C, 0x00, 0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x6C, 0x38, 0x00, 0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00, 0x63, 0x77, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x00, 0x66, 0x76, 0x7E, 0x7E, 0x6E, 0x66, 0x66, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x0E, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x78, 0x6C, 0x66, 0x00, 0x3C, 0x66, 0x60, 0x3C, 0x06, 0x66, 0x3C, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x7E, 0x00, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18, 0x18, 0x18, 0xC0, 0xC0, 0x30, 0x30, 0xC0, 0xC0, 0x30, 0x30, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x99, 0xCC, 0x66, 0x33, 0x99, 0xCC, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0x99, 0x33, 0x66, 0xCC, 0x99, 0x33, 0x66, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x18, 0x18, 0x18, 0x1F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xF8, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0xF8, 0x18, 0x18, 0x18, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0x03, 0x06, 0x6C, 0x78, 0x70, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xF8, 0xF8, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F, 0xC3, 0x99, 0x91, 0x91, 0x9F, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0xC3, 0xF9, 0xC1, 0x99, 0xC1, 0xFF, 0xFF, 0x9F, 0x9F, 0x83, 0x99, 0x99, 0x83, 0xFF, 0xFF, 0xFF, 0xC3, 0x9F, 0x9F, 0x9F, 0xC3, 0xFF, 0xFF, 0xF9, 0xF9, 0xC1, 0x99, 0x99, 0xC1, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0x81, 0x9F, 0xC3, 0xFF, 0xFF, 0xF1, 0xE7, 0xC1, 0xE7, 0xE7, 0xE7, 0xFF, 0xFF, 0xFF, 0xC1, 0x99, 0x99, 0xC1, 0xF9, 0x83, 0xFF, 0x9F, 0x9F, 0x83, 0x99, 0x99, 0x99, 0xFF, 0xFF, 0xE7, 0xFF, 0xC7, 0xE7, 0xE7, 0xC3, 0xFF, 0xFF, 0xF9, 0xFF, 0xF9, 0xF9, 0xF9, 0xF9, 0xC3, 0xFF, 0x9F, 0x9F, 0x93, 0x87, 0x93, 0x99, 0xFF, 0xFF, 0xC7, 0xE7, 0xE7, 0xE7, 0xE7, 0xC3, 0xFF, 0xFF, 0xFF, 0x99, 0x80, 0x80, 0x94, 0x9C, 0xFF, 0xFF, 0xFF, 0x83, 0x99, 0x99, 0x99, 0x99, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0x99, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0x83, 0x99, 0x99, 0x83, 0x9F, 0x9F, 0xFF, 0xFF, 0xC1, 0x99, 0x99, 0xC1, 0xF9, 0xF9, 0xFF, 0xFF, 0x83, 0x99, 0x9F, 0x9F, 0x9F, 0xFF, 0xFF, 0xFF, 0xC1, 0x9F, 0xC3, 0xF9, 0x83, 0xFF, 0xFF, 0xE7, 0x81, 0xE7, 0xE7, 0xE7, 0xF1, 0xFF, 0xFF, 0xFF, 0x99, 0x99, 0x99, 0x99, 0xC1, 0xFF, 0xFF, 0xFF, 0x99, 0x99, 0x99, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0x9C, 0x94, 0x80, 0xC1, 0xC9, 0xFF, 0xFF, 0xFF, 0x99, 0xC3, 0xE7, 0xC3, 0x99, 0xFF, 0xFF, 0xFF, 0x99, 0x99, 0x99, 0xC1, 0xF3, 0x87, 0xFF, 0xFF, 0x81, 0xF3, 0xE7, 0xCF, 0x81, 0xFF, 0xC3, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xC3, 0xFF, 0xF3, 0xED, 0xCF, 0x83, 0xCF, 0x9D, 0x03, 0xFF, 0xC3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xC3, 0xFF, 0xFF, 0xE7, 0xC3, 0x81, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, 0xEF, 0xCF, 0x80, 0x80, 0xCF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, 0xFF, 0xE7, 0xFF, 0x99, 0x99, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x99, 0x99, 0x00, 0x99, 0x00, 0x99, 0x99, 0xFF, 0xE7, 0xC1, 0x9F, 0xC3, 0xF9, 0x83, 0xE7, 0xFF, 0x9D, 0x99, 0xF3, 0xE7, 0xCF, 0x99, 0xB9, 0xFF, 0xC3, 0x99, 0xC3, 0xC7, 0x98, 0x99, 0xC0, 0xFF, 0xF9, 0xF3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xE7, 0xCF, 0xCF, 0xCF, 0xE7, 0xF3, 0xFF, 0xCF, 0xE7, 0xF3, 0xF3, 0xF3, 0xE7, 0xCF, 0xFF, 0xFF, 0x99, 0xC3, 0x00, 0xC3, 0x99, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0x81, 0xE7, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xCF, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xFF, 0xFF, 0xFC, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0xFF, 0xC3, 0x99, 0x91, 0x89, 0x99, 0x99, 0xC3, 0xFF, 0xE7, 0xE7, 0xC7, 0xE7, 0xE7, 0xE7, 0x81, 0xFF, 0xC3, 0x99, 0xF9, 0xF3, 0xCF, 0x9F, 0x81, 0xFF, 0xC3, 0x99, 0xF9, 0xE3, 0xF9, 0x99, 0xC3, 0xFF, 0xF9, 0xF1, 0xE1, 0x99, 0x80, 0xF9, 0xF9, 0xFF, 0x81, 0x9F, 0x83, 0xF9, 0xF9, 0x99, 0xC3, 0xFF, 0xC3, 0x99, 0x9F, 0x83, 0x99, 0x99, 0xC3, 0xFF, 0x81, 0x99, 0xF3, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, 0xC3, 0x99, 0x99, 0xC3, 0x99, 0x99, 0xC3, 0xFF, 0xC3, 0x99, 0x99, 0xC1, 0xF9, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0xE7, 0xE7, 0xCF, 0xF1, 0xE7, 0xCF, 0x9F, 0xCF, 0xE7, 0xF1, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0x8F, 0xE7, 0xF3, 0xF9, 0xF3, 0xE7, 0x8F, 0xFF, 0xC3, 0x99, 0xF9, 0xF3, 0xE7, 0xFF, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xE7, 0xC3, 0x99, 0x81, 0x99, 0x99, 0x99, 0xFF, 0x83, 0x99, 0x99, 0x83, 0x99, 0x99, 0x83, 0xFF, 0xC3, 0x99, 0x9F, 0x9F, 0x9F, 0x99, 0xC3, 0xFF, 0x87, 0x93, 0x99, 0x99, 0x99, 0x93, 0x87, 0xFF, 0x81, 0x9F, 0x9F, 0x87, 0x9F, 0x9F, 0x81, 0xFF, 0x81, 0x9F, 0x9F, 0x87, 0x9F, 0x9F, 0x9F, 0xFF, 0xC3, 0x99, 0x9F, 0x91, 0x99, 0x99, 0xC3, 0xFF, 0x99, 0x99, 0x99, 0x81, 0x99, 0x99, 0x99, 0xFF, 0xC3, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xC3, 0xFF, 0xE1, 0xF3, 0xF3, 0xF3, 0xF3, 0x93, 0xC7, 0xFF, 0x99, 0x93, 0x87, 0x8F, 0x87, 0x93, 0x99, 0xFF, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x81, 0xFF, 0x9C, 0x88, 0x80, 0x94, 0x9C, 0x9C, 0x9C, 0xFF, 0x99, 0x89, 0x81, 0x81, 0x91, 0x99, 0x99, 0xFF, 0xC3, 0x99, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xFF, 0x83, 0x99, 0x99, 0x83, 0x9F, 0x9F, 0x9F, 0xFF, 0xC3, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xF1, 0xFF, 0x83, 0x99, 0x99, 0x83, 0x87, 0x93, 0x99, 0xFF, 0xC3, 0x99, 0x9F, 0xC3, 0xF9, 0x99, 0xC3, 0xFF, 0x81, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xFF, 0x99, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xE7, 0xFF, 0x9C, 0x9C, 0x9C, 0x94, 0x80, 0x88, 0x9C, 0xFF, 0x99, 0x99, 0xC3, 0xE7, 0xC3, 0x99, 0x99, 0xFF, 0x99, 0x99, 0x99, 0xC3, 0xE7, 0xE7, 0xE7, 0xFF, 0x81, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x81, 0xFF, 0xE7, 0xE7, 0xE7, 0x00, 0x00, 0xE7, 0xE7, 0xE7, 0x3F, 0x3F, 0xCF, 0xCF, 0x3F, 0x3F, 0xCF, 0xCF, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0x66, 0x33, 0x99, 0xCC, 0x66, 0x33, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x66, 0xCC, 0x99, 0x33, 0x66, 0xCC, 0x99, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xE7, 0xE7, 0xE7, 0xE0, 0xE0, 0xE7, 0xE7, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xE7, 0xE7, 0xE7, 0xE0, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x07, 0xE7, 0xE7, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xE0, 0xE0, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0x07, 0x07, 0xE7, 0xE7, 0xE7, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFE, 0xFC, 0xF9, 0x93, 0x87, 0x8F, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xE7, 0x07, 0x07, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xF0, 0xF0, 0xF0, 0xF0}; +#endif /* _BIN_CHARGEN_ */ diff --git a/lib/emulator/flash/cynthcart.h b/lib/emulator/flash/cynthcart.h new file mode 100644 index 0000000..918bae6 --- /dev/null +++ b/lib/emulator/flash/cynthcart.h @@ -0,0 +1,4 @@ +#ifndef _BIN_CYNTHCART_ +#define _BIN_CYNTHCART_ +unsigned char __in_flash("usbsid_binary") cynthcart[] = {0x01, 0x08, 0x0B, 0x08, 0x0A, 0x00, 0x9E, 0x32, 0x30, 0x36, 0x31, 0x00, 0x00, 0x00, 0xA9, 0x17, 0x8D, 0x18, 0xD0, 0xA9, 0xC1, 0x8D, 0x18, 0x03, 0xA9, 0x00, 0xA2, 0x00, 0x9D, 0x00, 0xD4, 0xE8, 0xE0, 0x19, 0xD0, 0xF8, 0xA9, 0x0F, 0x8D, 0x18, 0xD4, 0xA9, 0x01, 0x8D, 0x03, 0xD4, 0x20, 0xFA, 0x39, 0x8D, 0x50, 0x71, 0x20, 0x72, 0x3A, 0xA9, 0x0E, 0x8D, 0x8D, 0x70, 0x20, 0x08, 0x0B, 0xAD, 0x11, 0xD0, 0x29, 0xEF, 0x8D, 0x11, 0xD0, 0xA9, 0xC1, 0x8D, 0x18, 0x03, 0xA9, 0x00, 0x8D, 0x20, 0xD0, 0x8D, 0x21, 0xD0, 0x78, 0xAD, 0x12, 0xD0, 0xD0, 0xFB, 0xAD, 0x11, 0xD0, 0x10, 0xFB, 0xA0, 0x00, 0xAD, 0x12, 0xD0, 0xC9, 0x37, 0xD0, 0xF9, 0xAD, 0x12, 0xD0, 0xCD, 0x12, 0xD0, 0xF0, 0xFB, 0xAD, 0x12, 0xD0, 0x58, 0x8D, 0x61, 0x70, 0xA9, 0x00, 0x8D, 0x97, 0x70, 0x8D, 0x8C, 0x70, 0x8D, 0x8B, 0x70, 0x20, 0xFE, 0x10, 0x20, 0x80, 0x0A, 0x20, 0xF5, 0x0B, 0xA2, 0x08, 0xA9, 0xFF, 0xCA, 0x9D, 0xA0, 0x70, 0xD0, 0xFA, 0xA9, 0x00, 0xA0, 0x00, 0x20, 0xAA, 0x13, 0xA9, 0x00, 0x8D, 0xF0, 0x70, 0xA9, 0xFF, 0x20, 0x04, 0x12, 0xEE, 0x03, 0x70, 0xAD, 0x03, 0x70, 0x29, 0x3F, 0xD0, 0x03, 0xEE, 0x02, 0x70, 0x20, 0xF0, 0x08, 0x20, 0x78, 0x0D, 0x20, 0x61, 0x1C, 0x20, 0xD6, 0x1A, 0x20, 0xB2, 0x09, 0x20, 0x07, 0x15, 0x20, 0xEF, 0x09, 0x20, 0x2E, 0x0B, 0x20, 0xD0, 0x08, 0x4C, 0xA5, 0x08, 0xAD, 0x9C, 0x70, 0x38, 0xE9, 0x7F, 0x30, 0x0A, 0x6D, 0x9D, 0x70, 0x90, 0x0F, 0xA9, 0xFF, 0x4C, 0xEC, 0x08, 0x6D, 0x9D, 0x70, 0xB0, 0x05, 0xA9, 0x00, 0x4C, 0xEC, 0x08, 0x20, 0xEF, 0x12, 0x60, 0xAD, 0x7A, 0x70, 0xC9, 0x04, 0xD0, 0x09, 0xAD, 0x79, 0x70, 0x8D, 0x40, 0x70, 0x4C, 0x00, 0x09, 0xAD, 0x7A, 0x70, 0xC9, 0x03, 0xD0, 0x0A, 0xAD, 0x79, 0x70, 0x4A, 0x4A, 0x4A, 0xA8, 0x4C, 0x17, 0x09, 0xAE, 0x49, 0x70, 0xBC, 0xE8, 0x33, 0xAD, 0x22, 0x70, 0xC9, 0x0C, 0x30, 0x08, 0xC8, 0xC9, 0x24, 0xD0, 0x03, 0x98, 0x0A, 0xA8, 0xAD, 0x02, 0x70, 0xAE, 0x48, 0x70, 0xF0, 0x0E, 0xAD, 0x03, 0x70, 0xCA, 0xCA, 0xCA, 0xF0, 0x06, 0x4A, 0xE8, 0xF0, 0x02, 0x4A, 0x4A, 0x4A, 0x29, 0x0F, 0xAA, 0xBD, 0x0C, 0x34, 0x8D, 0x26, 0x70, 0xD0, 0x10, 0x18, 0xBD, 0xFC, 0x33, 0x7D, 0xFC, 0x33, 0x88, 0xD0, 0xFA, 0x8D, 0x25, 0x70, 0x4C, 0x6D, 0x09, 0xBD, 0xFC, 0x33, 0x7D, 0xFC, 0x33, 0x88, 0xD0, 0xFA, 0x8D, 0x0C, 0x70, 0xA9, 0xFF, 0x38, 0xED, 0x0C, 0x70, 0x8D, 0x25, 0x70, 0xAD, 0x7A, 0x70, 0xC9, 0x03, 0xF0, 0x0D, 0xAD, 0x49, 0x70, 0xD0, 0x08, 0xA9, 0x00, 0x8D, 0x25, 0x70, 0x8D, 0x26, 0x70, 0xAD, 0x70, 0x70, 0xD0, 0x05, 0xAD, 0x67, 0x70, 0xD0, 0x15, 0xBD, 0x1C, 0x34, 0xAA, 0xA9, 0x07, 0x9D, 0xFF, 0xD7, 0xA9, 0x02, 0x9D, 0x00, 0xD8, 0xE0, 0x01, 0xF0, 0x03, 0x9D, 0xFE, 0xD7, 0x18, 0xAD, 0x25, 0x70, 0x69, 0x04, 0x8D, 0x27, 0x70, 0xAD, 0x26, 0x70, 0x69, 0x00, 0x8D, 0x28, 0x70, 0x60, 0xAD, 0x83, 0x70, 0xF0, 0x13, 0xAD, 0x40, 0x70, 0xD0, 0x08, 0xA9, 0x00, 0x8D, 0x83, 0x70, 0x4C, 0xCA, 0x09, 0xCE, 0x40, 0x70, 0xCE, 0x40, 0x70, 0xAD, 0x25, 0x70, 0x38, 0xED, 0x40, 0x70, 0x8D, 0x25, 0x70, 0xAD, 0x26, 0x70, 0xE9, 0x00, 0x8D, 0x26, 0x70, 0xAD, 0x27, 0x70, 0x38, 0xED, 0x40, 0x70, 0x8D, 0x27, 0x70, 0xAD, 0x28, 0x70, 0xE9, 0x00, 0x8D, 0x28, 0x70, 0x60, 0xA9, 0xE0, 0x8D, 0x02, 0xDC, 0xAD, 0x02, 0xDC, 0x8D, 0x06, 0x70, 0xA9, 0xC0, 0x8D, 0x02, 0xDC, 0xA9, 0x80, 0x8D, 0x00, 0xDC, 0xA0, 0x80, 0xEA, 0x88, 0x10, 0xFC, 0xAE, 0x19, 0xD4, 0x8E, 0x78, 0x70, 0xAC, 0x1A, 0xD4, 0x8C, 0x79, 0x70, 0xAD, 0x00, 0xDC, 0x09, 0x50, 0x8D, 0x09, 0x70, 0xAD, 0x06, 0x70, 0x8D, 0x02, 0xDC, 0xA9, 0xFF, 0x8D, 0x02, 0xDC, 0xAD, 0x29, 0x70, 0xD0, 0x21, 0xE0, 0xA0, 0x90, 0x05, 0xA9, 0x01, 0x8D, 0x76, 0x70, 0xE0, 0x60, 0xB0, 0x05, 0xA9, 0x01, 0x8D, 0x77, 0x70, 0xAD, 0x76, 0x70, 0xF0, 0x0A, 0xAD, 0x77, 0x70, 0xF0, 0x05, 0xA9, 0x01, 0x20, 0x3C, 0x11, 0xAD, 0x29, 0x70, 0xF0, 0x04, 0x8A, 0x8D, 0x9D, 0x70, 0xAD, 0x7A, 0x70, 0xC9, 0x01, 0xD0, 0x15, 0xAD, 0x79, 0x70, 0xC9, 0xF5, 0x90, 0x05, 0xA9, 0xF5, 0x8D, 0x79, 0x70, 0xAD, 0x79, 0x70, 0x20, 0x69, 0x10, 0xAD, 0x79, 0x70, 0x60, 0xA2, 0x08, 0xA9, 0xFF, 0x9D, 0xA0, 0x70, 0xCA, 0x10, 0xFA, 0x60, 0xA9, 0x00, 0x8D, 0x7A, 0x70, 0x8D, 0x5C, 0x70, 0x8D, 0x6C, 0x70, 0x8D, 0x58, 0x70, 0x8D, 0x40, 0x70, 0x8D, 0x70, 0x70, 0x8D, 0x21, 0x70, 0x8D, 0x03, 0x70, 0x8D, 0x02, 0x70, 0x8D, 0x05, 0x70, 0x8D, 0x75, 0x70, 0x8D, 0x76, 0x70, 0x8D, 0x77, 0x70, 0xA9, 0x02, 0x8D, 0x7B, 0x70, 0xA9, 0x04, 0x8D, 0x71, 0x70, 0xA9, 0x00, 0x20, 0x5D, 0x11, 0xA9, 0x00, 0x20, 0x73, 0x11, 0xA9, 0x66, 0x85, 0x22, 0xA9, 0x37, 0x85, 0x23, 0xA9, 0x66, 0x85, 0x24, 0xA9, 0x37, 0x85, 0x25, 0xA9, 0x02, 0x8D, 0x20, 0x70, 0xA9, 0x00, 0x8D, 0x1D, 0x70, 0xA9, 0x03, 0xA0, 0x02, 0x20, 0x2E, 0x11, 0xA9, 0x0F, 0x8D, 0x1C, 0x70, 0xA9, 0x70, 0x8D, 0x04, 0x70, 0xA0, 0x00, 0x20, 0xAA, 0x13, 0xA2, 0x0C, 0xBD, 0x2C, 0x34, 0x8D, 0x16, 0x70, 0x8D, 0x17, 0x70, 0x8D, 0x18, 0x70, 0xBD, 0x74, 0x34, 0x8D, 0x19, 0x70, 0x8D, 0x1A, 0x70, 0x8D, 0x1B, 0x70, 0x60, 0xA9, 0x2D, 0x8D, 0x18, 0x03, 0x8D, 0xFA, 0xFF, 0xA9, 0x0B, 0x8D, 0x19, 0x03, 0x8D, 0xFB, 0xFF, 0xA9, 0x81, 0x8D, 0x0D, 0xDD, 0xA9, 0x01, 0x8D, 0x04, 0xDD, 0xA9, 0x00, 0x8D, 0x05, 0xDD, 0xA9, 0x19, 0x8D, 0x0E, 0xDD, 0x60, 0x40, 0xAD, 0x70, 0x70, 0xD0, 0x2E, 0xAD, 0x20, 0x70, 0xF0, 0x1E, 0xC9, 0x02, 0xF0, 0x25, 0xAD, 0x1F, 0x70, 0xD0, 0x20, 0xAD, 0xA0, 0x70, 0xC9, 0xFF, 0xD0, 0x19, 0xAD, 0xA1, 0x70, 0xC9, 0xFF, 0xD0, 0x12, 0xAD, 0xA2, 0x70, 0xC9, 0xFF, 0xD0, 0x0B, 0xAD, 0x11, 0xD0, 0x29, 0xEF, 0x8D, 0x11, 0xD0, 0x4C, 0x69, 0x0B, 0xAD, 0x11, 0xD0, 0x09, 0x10, 0x8D, 0x11, 0xD0, 0xA9, 0x00, 0x8D, 0x1F, 0x70, 0xAD, 0xA0, 0x70, 0x8D, 0x0C, 0x70, 0x20, 0x8A, 0x0B, 0xAD, 0xA1, 0x70, 0x8D, 0x0C, 0x70, 0x20, 0x8A, 0x0B, 0xAD, 0xA2, 0x70, 0x8D, 0x0C, 0x70, 0x20, 0x8A, 0x0B, 0x60, 0xAD, 0x70, 0x70, 0xF0, 0x01, 0x60, 0xAE, 0x21, 0x70, 0xE8, 0xE0, 0x28, 0xD0, 0x02, 0xA2, 0x00, 0x8E, 0x21, 0x70, 0xA2, 0x05, 0xBD, 0x3D, 0x29, 0x6D, 0x21, 0x70, 0xA8, 0xAD, 0x0C, 0x70, 0xC9, 0xFF, 0xF0, 0x0A, 0xAD, 0x03, 0x70, 0x2D, 0x45, 0x70, 0x18, 0x6D, 0x0C, 0x70, 0x69, 0xBE, 0x8D, 0x8F, 0x70, 0xAD, 0x0C, 0x70, 0xC9, 0xFF, 0xD0, 0x05, 0xA9, 0x7F, 0x4C, 0xCB, 0x0B, 0xAD, 0x8F, 0x70, 0x91, 0x2B, 0x99, 0xC8, 0x04, 0x99, 0x90, 0x05, 0x99, 0x58, 0x06, 0xC0, 0xF8, 0x30, 0x03, 0x99, 0x20, 0x07, 0x69, 0x0C, 0x91, 0x2D, 0x99, 0xC8, 0xD8, 0x99, 0x90, 0xD9, 0x99, 0x58, 0xDA, 0xC0, 0xF8, 0x30, 0x03, 0x99, 0x20, 0xDB, 0xCA, 0x10, 0xAB, 0x60, 0xA9, 0x15, 0x8D, 0x18, 0xD0, 0xA2, 0x31, 0xA0, 0x22, 0x20, 0x0B, 0x0D, 0x20, 0xE9, 0x0F, 0xA2, 0x0C, 0xBD, 0xB2, 0x33, 0xC9, 0x40, 0x30, 0x02, 0xE9, 0x40, 0x9D, 0xB2, 0x07, 0xCA, 0x10, 0xF1, 0xA2, 0x00, 0xA0, 0x00, 0xAD, 0x61, 0x70, 0xF0, 0x02, 0xA2, 0x0C, 0xBD, 0x9A, 0x33, 0xF0, 0x12, 0xC9, 0x40, 0x30, 0x02, 0xE9, 0x40, 0x99, 0xDD, 0x07, 0xA9, 0x0B, 0x99, 0xDD, 0xDB, 0xE8, 0xC8, 0xD0, 0xE9, 0xA9, 0x0B, 0x8D, 0xE2, 0x07, 0x20, 0x07, 0x12, 0xAC, 0x71, 0x70, 0x20, 0xE8, 0x10, 0xAD, 0x45, 0x70, 0xAC, 0x68, 0x70, 0x20, 0x2E, 0x11, 0xAD, 0x49, 0x70, 0x20, 0x5D, 0x11, 0xAD, 0x48, 0x70, 0x20, 0x73, 0x11, 0xAD, 0x29, 0x70, 0x20, 0x3C, 0x11, 0xAD, 0x57, 0x70, 0x8D, 0x9D, 0x70, 0x20, 0x5A, 0x13, 0x20, 0x32, 0x13, 0xAD, 0x69, 0x70, 0x20, 0x6E, 0x12, 0x20, 0x07, 0x12, 0xAD, 0x6A, 0x70, 0x20, 0xC1, 0x11, 0xAC, 0x6C, 0x70, 0x20, 0xD3, 0x10, 0x20, 0x86, 0x12, 0xAD, 0x6B, 0x70, 0x20, 0xD6, 0x12, 0x20, 0xBC, 0x14, 0xAD, 0x7A, 0x70, 0x20, 0x47, 0x10, 0x60, 0xAD, 0x70, 0x70, 0xF0, 0x01, 0x60, 0x18, 0xA9, 0x04, 0x8D, 0x46, 0x70, 0xBD, 0x52, 0x32, 0xC9, 0x40, 0x30, 0x02, 0xE9, 0x40, 0x99, 0x00, 0x04, 0xE8, 0xC8, 0xCE, 0x46, 0x70, 0xD0, 0xED, 0x60, 0xA2, 0x00, 0xA9, 0x20, 0x9D, 0x00, 0x04, 0x9D, 0x00, 0x05, 0x9D, 0x00, 0x06, 0x9D, 0x00, 0x07, 0xCA, 0xD0, 0xF1, 0x60, 0x8E, 0x72, 0x70, 0xAA, 0xB9, 0x46, 0x29, 0x18, 0x6D, 0x72, 0x70, 0x85, 0x31, 0x85, 0x33, 0xB9, 0x60, 0x29, 0x69, 0x00, 0x85, 0x32, 0x18, 0x69, 0xD4, 0x85, 0x34, 0x8E, 0x72, 0x70, 0x8A, 0x29, 0x0F, 0xAA, 0xBD, 0xEC, 0x33, 0xA0, 0x01, 0x91, 0x31, 0xAD, 0x8D, 0x70, 0x91, 0x33, 0xAD, 0x72, 0x70, 0x4A, 0x4A, 0x4A, 0x4A, 0xAA, 0xBD, 0xEC, 0x33, 0xA0, 0x00, 0x91, 0x31, 0xAD, 0x8D, 0x70, 0x91, 0x33, 0x60, 0x84, 0x2F, 0x86, 0x30, 0xA9, 0x01, 0x8D, 0x6D, 0x70, 0xA0, 0x00, 0xB1, 0x2F, 0xC9, 0xFF, 0xF0, 0x5B, 0xAA, 0xBD, 0x60, 0x29, 0x85, 0x32, 0x18, 0x69, 0xD4, 0x85, 0x34, 0xBD, 0x46, 0x29, 0x85, 0x31, 0x85, 0x33, 0xA0, 0x01, 0x8C, 0x6E, 0x70, 0xA0, 0x00, 0x8C, 0x6F, 0x70, 0xAC, 0x6E, 0x70, 0xB1, 0x2F, 0xF0, 0x28, 0xC8, 0x8C, 0x6E, 0x70, 0xC9, 0x80, 0x10, 0x17, 0xC9, 0x40, 0x30, 0x02, 0xE9, 0x40, 0xAC, 0x6F, 0x70, 0x91, 0x31, 0xAD, 0x6D, 0x70, 0x91, 0x33, 0xC8, 0x8C, 0x6F, 0x70, 0x4C, 0x38, 0x0D, 0x38, 0xE9, 0x80, 0x8D, 0x6D, 0x70, 0x4C, 0x38, 0x0D, 0xC8, 0x98, 0x18, 0x65, 0x2F, 0x85, 0x2F, 0xA5, 0x30, 0x69, 0x00, 0x85, 0x30, 0x4C, 0x14, 0x0D, 0x60, 0xAD, 0x86, 0x70, 0xD0, 0x0B, 0xA9, 0x7F, 0x8D, 0x9E, 0x70, 0x8D, 0x9C, 0x70, 0x4C, 0xB0, 0x0D, 0xC9, 0x06, 0xD0, 0x03, 0x4C, 0x9A, 0x0E, 0xC9, 0x01, 0xD0, 0x03, 0x4C, 0x86, 0x0E, 0xC9, 0x02, 0xD0, 0x03, 0x4C, 0x56, 0x0E, 0xC9, 0x03, 0xF0, 0x10, 0xC9, 0x04, 0xF0, 0x67, 0xC9, 0x05, 0xF0, 0x76, 0xC9, 0x07, 0xD0, 0x03, 0x4C, 0x32, 0x0E, 0x60, 0xAD, 0x03, 0x70, 0xAD, 0x87, 0x70, 0x29, 0xF8, 0xF0, 0x0B, 0xAE, 0x87, 0x70, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0x8E, 0x87, 0x70, 0xAD, 0x87, 0x70, 0x8D, 0x9C, 0x70, 0xA9, 0xB4, 0x8D, 0x98, 0x70, 0xAD, 0x1D, 0x70, 0xC9, 0x20, 0xF0, 0x22, 0xC9, 0x21, 0xF0, 0x1E, 0xA2, 0x05, 0xA0, 0x00, 0xBD, 0xA0, 0x70, 0xC9, 0xFF, 0xD0, 0x01, 0xC8, 0xCA, 0x10, 0xF5, 0xCC, 0x99, 0x70, 0xF0, 0x09, 0x8C, 0x99, 0x70, 0xAD, 0x98, 0x70, 0x8D, 0x87, 0x70, 0x60, 0xAC, 0xA0, 0x70, 0xCC, 0x9A, 0x70, 0xF0, 0x09, 0x8C, 0x9A, 0x70, 0xAD, 0x98, 0x70, 0x8D, 0x87, 0x70, 0x60, 0xAD, 0x03, 0x70, 0x29, 0x08, 0xF0, 0x06, 0xA9, 0xE6, 0x8D, 0x9C, 0x70, 0x60, 0xA9, 0x00, 0x8D, 0x9C, 0x70, 0x60, 0xAD, 0x03, 0x70, 0x29, 0x02, 0xF0, 0x06, 0xA9, 0x96, 0x8D, 0x9C, 0x70, 0x60, 0xA9, 0x32, 0x8D, 0x9C, 0x70, 0x60, 0xAD, 0x03, 0x70, 0xAD, 0x87, 0x70, 0x29, 0xE0, 0xF0, 0x0B, 0xAE, 0x87, 0x70, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0x8E, 0x87, 0x70, 0xAD, 0x87, 0x70, 0x20, 0x69, 0x10, 0xA9, 0xB4, 0x8D, 0x98, 0x70, 0x4C, 0xD1, 0x0D, 0x60, 0xAD, 0x03, 0x70, 0x29, 0x01, 0xF0, 0x01, 0x60, 0xAD, 0x87, 0x70, 0xC9, 0xFF, 0xF0, 0x03, 0xEE, 0x87, 0x70, 0xAD, 0x87, 0x70, 0x8D, 0x9C, 0x70, 0xA9, 0x00, 0x8D, 0x98, 0x70, 0xA2, 0x05, 0xBD, 0xA0, 0x70, 0xC9, 0xFF, 0xD0, 0x09, 0xCA, 0x10, 0xF6, 0xAD, 0x98, 0x70, 0x8D, 0x87, 0x70, 0x60, 0xA9, 0x96, 0x8D, 0x8B, 0x70, 0xA9, 0xFE, 0x8D, 0x8A, 0x70, 0x20, 0xBE, 0x0E, 0xAD, 0x87, 0x70, 0x8D, 0x9C, 0x70, 0x60, 0xAD, 0x87, 0x70, 0x30, 0x05, 0xA9, 0xC8, 0x8D, 0x87, 0x70, 0xA9, 0x96, 0x8D, 0x8B, 0x70, 0xA9, 0xFE, 0x8D, 0x8A, 0x70, 0x20, 0xBE, 0x0E, 0xAE, 0x87, 0x70, 0x8E, 0x79, 0x70, 0xAD, 0x87, 0x70, 0x20, 0x69, 0x10, 0x60, 0xAD, 0x03, 0x70, 0x29, 0x07, 0xF0, 0x01, 0x60, 0xAD, 0x89, 0x70, 0xF0, 0x12, 0xAE, 0x87, 0x70, 0xE8, 0x8E, 0x87, 0x70, 0x8E, 0x79, 0x70, 0xAE, 0x87, 0x70, 0xE0, 0xF5, 0xF0, 0x0D, 0x60, 0xAE, 0x87, 0x70, 0xCA, 0x8E, 0x87, 0x70, 0xE0, 0x96, 0xF0, 0x01, 0x60, 0xAD, 0x89, 0x70, 0x18, 0x69, 0x01, 0x29, 0x01, 0x8D, 0x89, 0x70, 0x60, 0xA9, 0x01, 0x8D, 0x75, 0x70, 0xA9, 0x1E, 0x8D, 0x47, 0x70, 0x20, 0xBC, 0x14, 0xA2, 0x19, 0xBD, 0x00, 0x71, 0x9D, 0x20, 0x71, 0xCA, 0x10, 0xF7, 0xAD, 0x29, 0x70, 0x8D, 0x41, 0x71, 0xAD, 0x6B, 0x70, 0x8D, 0x42, 0x71, 0xAD, 0x1D, 0x70, 0x8D, 0x43, 0x71, 0xAD, 0x86, 0x70, 0x8D, 0x43, 0x71, 0xAD, 0x1E, 0x70, 0x8D, 0x44, 0x71, 0xAD, 0x49, 0x70, 0x8D, 0x46, 0x71, 0xAD, 0x48, 0x70, 0x8D, 0x47, 0x71, 0xAD, 0x1C, 0x70, 0x8D, 0x48, 0x71, 0xAD, 0x24, 0x70, 0x8D, 0x49, 0x71, 0xAD, 0x57, 0x70, 0x8D, 0x4A, 0x71, 0x60, 0xAD, 0x75, 0x70, 0xD0, 0x01, 0x60, 0xA9, 0x1F, 0x8D, 0x47, 0x70, 0x20, 0xBC, 0x14, 0xAD, 0x49, 0x71, 0x8D, 0x24, 0x70, 0xAD, 0x48, 0x71, 0x8D, 0x1C, 0x70, 0xAD, 0x41, 0x71, 0x20, 0x3C, 0x11, 0xAD, 0x42, 0x71, 0x20, 0xD6, 0x12, 0xAD, 0x43, 0x71, 0x8D, 0x1D, 0x70, 0x20, 0x5A, 0x13, 0xAD, 0x43, 0x71, 0x8D, 0x86, 0x70, 0x20, 0x32, 0x13, 0xAD, 0x46, 0x71, 0x20, 0x5D, 0x11, 0xAD, 0x47, 0x71, 0x20, 0x73, 0x11, 0xAD, 0x4A, 0x71, 0x8D, 0x57, 0x70, 0xA2, 0x19, 0xBD, 0x20, 0x71, 0x9D, 0x00, 0xD4, 0x9D, 0x20, 0xD4, 0x9D, 0x00, 0x71, 0xCA, 0x10, 0xF1, 0xAD, 0x04, 0x71, 0x8D, 0x30, 0x70, 0xAD, 0x0B, 0x71, 0x8D, 0x37, 0x70, 0xAD, 0x12, 0x71, 0x8D, 0x3E, 0x70, 0x60, 0xAD, 0x9D, 0x70, 0x8D, 0x52, 0x70, 0xA9, 0x00, 0x8D, 0x20, 0xD0, 0x20, 0xB4, 0x0C, 0xA9, 0x28, 0x8D, 0x58, 0x70, 0xAD, 0x70, 0x70, 0x49, 0x01, 0x20, 0x2A, 0x11, 0x20, 0xF5, 0x0B, 0xAD, 0x70, 0x70, 0xF0, 0x0E, 0xA2, 0x2D, 0xA0, 0x36, 0x20, 0x0B, 0x0D, 0xAD, 0x52, 0x70, 0x8D, 0x9D, 0x70, 0x60, 0xA2, 0x00, 0xBD, 0x18, 0x2D, 0xF0, 0x11, 0xC9, 0x40, 0x30, 0x02, 0xE9, 0x40, 0x9D, 0xC0, 0x07, 0xA9, 0x0B, 0x9D, 0xC0, 0xDB, 0xE8, 0xD0, 0xEA, 0x20, 0x07, 0x12, 0xAD, 0x52, 0x70, 0x8D, 0x9D, 0x70, 0x60, 0xA9, 0x00, 0x20, 0x2F, 0x13, 0xA9, 0x00, 0x20, 0x5D, 0x11, 0xA9, 0x00, 0x4C, 0x73, 0x11, 0x8D, 0x61, 0x70, 0x4C, 0xF5, 0x0B, 0xAD, 0x40, 0x70, 0xC9, 0xFC, 0xF0, 0x11, 0xEE, 0x40, 0x70, 0xEE, 0x40, 0x70, 0xEE, 0x40, 0x70, 0xEE, 0x40, 0x70, 0xA9, 0x01, 0x8D, 0x83, 0x70, 0x60, 0x8D, 0x20, 0x70, 0x60, 0x20, 0x3C, 0x11, 0xAD, 0x57, 0x70, 0x8D, 0x9D, 0x70, 0x60, 0x8D, 0x7A, 0x70, 0xC9, 0x00, 0xF0, 0x03, 0x8D, 0x7B, 0x70, 0x0A, 0x0A, 0x18, 0x69, 0x64, 0xAA, 0xA0, 0xC4, 0x4C, 0x94, 0x0C, 0xA2, 0x00, 0x8E, 0x29, 0x70, 0x8D, 0x9D, 0x70, 0xA9, 0x00, 0x4C, 0x3C, 0x11, 0xAA, 0x4A, 0x4A, 0x4A, 0x4A, 0x8D, 0x03, 0xD4, 0x8D, 0x0A, 0xD4, 0x8D, 0x11, 0xD4, 0x8D, 0x23, 0xD4, 0x8D, 0x2A, 0xD4, 0x8D, 0x31, 0xD4, 0x8D, 0x03, 0x71, 0x8D, 0x0A, 0x71, 0x8D, 0x11, 0x71, 0x8A, 0x0A, 0x0A, 0x0A, 0x0A, 0x09, 0x0F, 0x8D, 0x02, 0xD4, 0x8D, 0x09, 0xD4, 0x8D, 0x10, 0xD4, 0x8D, 0x22, 0xD4, 0x8D, 0x29, 0xD4, 0x8D, 0x30, 0xD4, 0x8D, 0x02, 0x71, 0x8D, 0x09, 0x71, 0x8D, 0x10, 0x71, 0x60, 0x8C, 0x6C, 0x70, 0xAC, 0x6C, 0x70, 0xAD, 0x97, 0x70, 0x19, 0xDC, 0x10, 0x39, 0xDF, 0x10, 0x8D, 0x17, 0xD4, 0x8D, 0x17, 0x71, 0xAD, 0x17, 0x71, 0x19, 0xDC, 0x10, 0x39, 0xDF, 0x10, 0x8D, 0x37, 0xD4, 0xB9, 0xE2, 0x10, 0x8D, 0x5C, 0x70, 0xB9, 0xE5, 0x10, 0xAA, 0xA0, 0x4C, 0x4C, 0x94, 0x0C, 0x0F, 0x00, 0x00, 0xFF, 0xF0, 0xF0, 0x00, 0x00, 0x01, 0x04, 0x00, 0x60, 0x8C, 0x71, 0x70, 0x98, 0x38, 0xE9, 0x04, 0x8D, 0xF3, 0x70, 0x98, 0x0A, 0x0A, 0x18, 0x69, 0x14, 0xAA, 0xA0, 0x57, 0x4C, 0x94, 0x0C, 0x8D, 0x67, 0x70, 0xC9, 0x00, 0xF0, 0x11, 0xA9, 0x00, 0x85, 0x2B, 0xA9, 0x04, 0x85, 0x2C, 0xA9, 0x00, 0x85, 0x2D, 0xA9, 0xD8, 0x85, 0x2E, 0x60, 0xA9, 0xC8, 0x85, 0x2B, 0xA9, 0x04, 0x85, 0x2C, 0xA9, 0xC8, 0x85, 0x2D, 0xA9, 0xD8, 0x85, 0x2E, 0x20, 0xF5, 0x0B, 0x60, 0x8D, 0x70, 0x70, 0x60, 0x8D, 0x45, 0x70, 0x8C, 0x68, 0x70, 0x98, 0x18, 0x69, 0x30, 0x8D, 0xBC, 0x04, 0x60, 0x8D, 0x29, 0x70, 0x0A, 0xD0, 0x0C, 0xAE, 0x57, 0x70, 0x8E, 0x16, 0xD4, 0x8E, 0x36, 0xD4, 0x8D, 0x16, 0x71, 0xA0, 0x00, 0x8C, 0x76, 0x70, 0x8C, 0x77, 0x70, 0x0A, 0xAA, 0xA0, 0x9C, 0x4C, 0x94, 0x0C, 0x8D, 0x49, 0x70, 0xAC, 0x70, 0x70, 0xF0, 0x01, 0x60, 0xA0, 0x6C, 0x18, 0x69, 0x30, 0x99, 0x00, 0x04, 0xA9, 0x20, 0xA2, 0x08, 0x60, 0x8D, 0x48, 0x70, 0xAC, 0x70, 0x70, 0xF0, 0x01, 0x60, 0xA0, 0x94, 0x18, 0x69, 0x30, 0x99, 0x00, 0x04, 0xA9, 0x02, 0xA2, 0x08, 0x9D, 0x00, 0xD8, 0xCA, 0x10, 0xFA, 0x60, 0x8D, 0x0D, 0xD4, 0x8D, 0x2D, 0xD4, 0x8D, 0x0D, 0x71, 0x60, 0x8D, 0x14, 0xD4, 0x8D, 0x34, 0xD4, 0x8D, 0x14, 0x71, 0x60, 0x8D, 0x6A, 0x70, 0x8D, 0x06, 0xD4, 0x8D, 0x0D, 0xD4, 0x8D, 0x14, 0xD4, 0x8D, 0x26, 0xD4, 0x8D, 0x2D, 0xD4, 0x8D, 0x34, 0xD4, 0x8D, 0x06, 0x71, 0x8D, 0x0D, 0x71, 0x8D, 0x14, 0x71, 0xAC, 0x70, 0x70, 0xF0, 0x01, 0x60, 0x29, 0x0F, 0xA8, 0xB9, 0xF4, 0x11, 0x18, 0x69, 0x30, 0x8D, 0x8A, 0x04, 0x60, 0xA0, 0x8A, 0xA9, 0xE0, 0xCD, 0x6A, 0x70, 0x30, 0x05, 0xA9, 0x30, 0x4C, 0xF0, 0x11, 0xA9, 0xE9, 0xCD, 0x6A, 0x70, 0x30, 0x05, 0xA9, 0x31, 0x4C, 0xF0, 0x11, 0xA9, 0x32, 0x99, 0x00, 0x04, 0x60, 0x00, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x8D, 0xF7, 0x70, 0xA9, 0x2F, 0x8D, 0xE1, 0x07, 0xAD, 0x50, 0x71, 0xD0, 0x01, 0x60, 0xA9, 0x2F, 0x8D, 0xDC, 0x07, 0x8D, 0xD7, 0x07, 0xAE, 0xF7, 0x70, 0x30, 0x19, 0xA9, 0x20, 0x8D, 0xD8, 0x07, 0xA9, 0x03, 0x8D, 0xD9, 0x07, 0xA9, 0x08, 0x8D, 0xDA, 0x07, 0xA9, 0x31, 0x18, 0x6D, 0xF7, 0x70, 0x8D, 0xDB, 0x07, 0x60, 0xA9, 0x0F, 0x8D, 0xD8, 0x07, 0xA9, 0x0D, 0x8D, 0xD9, 0x07, 0xA9, 0x0E, 0x8D, 0xDA, 0x07, 0xA9, 0x09, 0x8D, 0xDB, 0x07, 0x20, 0x13, 0x13, 0x60, 0x8D, 0x69, 0x70, 0x8D, 0x0C, 0xD4, 0x8D, 0x13, 0xD4, 0x8D, 0x2C, 0xD4, 0x8D, 0x33, 0xD4, 0x8D, 0x05, 0xD4, 0x8D, 0x25, 0xD4, 0x8D, 0x0C, 0x71, 0x8D, 0x13, 0x71, 0x8D, 0x05, 0x71, 0xAC, 0x70, 0x70, 0xF0, 0x01, 0x60, 0x4A, 0x4A, 0x4A, 0x4A, 0xA8, 0xB9, 0xF4, 0x11, 0x18, 0x69, 0x30, 0x8D, 0x62, 0x04, 0x60, 0x8D, 0x1C, 0x70, 0xAD, 0x24, 0x70, 0x29, 0xF0, 0x0D, 0x1C, 0x70, 0x8D, 0x18, 0xD4, 0x8D, 0x38, 0xD4, 0x8D, 0x18, 0x71, 0xAC, 0x70, 0x70, 0xF0, 0x01, 0x60, 0x29, 0x0F, 0xAA, 0xBD, 0xF4, 0x11, 0x18, 0x69, 0x30, 0x8D, 0xA7, 0x04, 0x60, 0xAA, 0xBD, 0xF4, 0x11, 0xAA, 0xA0, 0xA7, 0xA9, 0x07, 0x20, 0x94, 0x0C, 0x60, 0xA0, 0xA7, 0xA9, 0x07, 0xCD, 0x1C, 0x70, 0x30, 0x05, 0xA2, 0x50, 0x4C, 0x94, 0x0C, 0xA9, 0x0B, 0xCD, 0x1C, 0x70, 0x30, 0x05, 0xA2, 0x54, 0x4C, 0x94, 0x0C, 0xA2, 0x58, 0x4C, 0x94, 0x0C, 0x8D, 0x6B, 0x70, 0xAA, 0xBD, 0x28, 0x29, 0x8D, 0x22, 0x70, 0xAC, 0x70, 0x70, 0xF0, 0x01, 0x60, 0x8A, 0x18, 0x69, 0x30, 0xAA, 0x8D, 0x7F, 0x04, 0x60, 0x8D, 0x16, 0xD4, 0x8D, 0x36, 0xD4, 0x8D, 0x16, 0x71, 0x8D, 0x57, 0x70, 0xAC, 0x70, 0x70, 0xF0, 0x01, 0x60, 0xAC, 0x67, 0x70, 0xF0, 0x01, 0x60, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x18, 0x69, 0x30, 0x8D, 0x75, 0x04, 0x60, 0xAD, 0x50, 0x71, 0x0A, 0x0A, 0x0A, 0xAA, 0xA0, 0x00, 0xBD, 0xF6, 0x29, 0xC9, 0x40, 0x30, 0x02, 0xE9, 0x40, 0x99, 0xCF, 0x07, 0xE8, 0xC8, 0xC0, 0x08, 0xD0, 0xEE, 0x60, 0x8D, 0x86, 0x70, 0xAD, 0x70, 0x70, 0xF0, 0x01, 0x60, 0xAD, 0x86, 0x70, 0x0A, 0x0A, 0x0A, 0xAA, 0xA0, 0x00, 0xBD, 0x1E, 0x2A, 0xC9, 0x40, 0x30, 0x02, 0xE9, 0x40, 0x99, 0xAF, 0x04, 0xE8, 0xC8, 0xC0, 0x05, 0xD0, 0xEE, 0x60, 0x06, 0x07, 0x09, 0x8D, 0x1D, 0x70, 0xAC, 0x70, 0x70, 0xF0, 0x01, 0x60, 0xAD, 0x1D, 0x70, 0xAE, 0x1D, 0x70, 0xBD, 0x4A, 0x33, 0xAA, 0xA0, 0x00, 0xBD, 0xCA, 0x32, 0xC9, 0x40, 0x30, 0x02, 0xE9, 0x40, 0x99, 0x2D, 0x04, 0xE8, 0xC8, 0xC0, 0x05, 0xD0, 0xEE, 0xE8, 0xE8, 0xBD, 0xCA, 0x32, 0x8D, 0x84, 0x70, 0xA9, 0x08, 0x8D, 0x80, 0x70, 0xAD, 0x1D, 0x70, 0x29, 0x0F, 0xA8, 0xB9, 0x54, 0x13, 0xA8, 0xB9, 0xC0, 0x33, 0x85, 0x35, 0xB9, 0xCA, 0x33, 0x85, 0x36, 0xB9, 0xD4, 0x33, 0x85, 0x47, 0xB9, 0xDE, 0x33, 0x85, 0x48, 0x60, 0x8C, 0x47, 0x70, 0xB9, 0x38, 0x28, 0x8D, 0x1C, 0x70, 0xB9, 0xFC, 0x27, 0x20, 0x3C, 0x11, 0x20, 0x75, 0x0A, 0xA9, 0x7F, 0x8D, 0x9C, 0x70, 0x8D, 0x9E, 0x70, 0xAC, 0x47, 0x70, 0xB9, 0x1A, 0x28, 0x8D, 0x9D, 0x70, 0xAC, 0x47, 0x70, 0xB9, 0x0B, 0x27, 0x8D, 0x1D, 0x70, 0x20, 0x5A, 0x13, 0xAC, 0x47, 0x70, 0xB9, 0x56, 0x28, 0x8D, 0x02, 0xD4, 0x8D, 0x09, 0xD4, 0x8D, 0x10, 0xD4, 0x8D, 0x22, 0xD4, 0x8D, 0x29, 0xD4, 0x8D, 0x30, 0xD4, 0x8D, 0x02, 0x71, 0x8D, 0x09, 0x71, 0x8D, 0x10, 0x71, 0xAC, 0x47, 0x70, 0xB9, 0x74, 0x28, 0x8D, 0x03, 0xD4, 0x8D, 0x0A, 0xD4, 0x8D, 0x11, 0xD4, 0x8D, 0x23, 0xD4, 0x8D, 0x2A, 0xD4, 0x8D, 0x31, 0xD4, 0x8D, 0x03, 0x71, 0x8D, 0x0A, 0x71, 0x8D, 0x11, 0x71, 0xAC, 0x47, 0x70, 0xB9, 0x92, 0x28, 0x8D, 0x30, 0x70, 0xB9, 0xB0, 0x28, 0x8D, 0x37, 0x70, 0xB9, 0xCE, 0x28, 0x8D, 0x3E, 0x70, 0xAC, 0x47, 0x70, 0xB9, 0x48, 0x27, 0x29, 0x0F, 0x8C, 0x0C, 0x70, 0x20, 0x73, 0x11, 0xAC, 0x0C, 0x70, 0xB9, 0x48, 0x27, 0x29, 0xF0, 0x4A, 0x4A, 0x4A, 0x4A, 0x20, 0x5D, 0x11, 0xAC, 0x0C, 0x70, 0xB9, 0x84, 0x27, 0x20, 0x50, 0x12, 0xAC, 0x47, 0x70, 0xAC, 0x0C, 0x70, 0xB9, 0xA2, 0x27, 0x20, 0xA3, 0x11, 0xAC, 0x0C, 0x70, 0xB9, 0xC0, 0x27, 0x20, 0x8F, 0x11, 0xB9, 0xDE, 0x27, 0x20, 0x99, 0x11, 0xAC, 0x47, 0x70, 0xB9, 0xEC, 0x28, 0xAE, 0x5C, 0x70, 0xF0, 0x02, 0x29, 0xF0, 0x8D, 0x17, 0xD4, 0x8D, 0x37, 0xD4, 0x8D, 0x17, 0x71, 0x29, 0x01, 0xF0, 0x07, 0xA0, 0x4C, 0xA2, 0x04, 0x20, 0x94, 0x0C, 0xAC, 0x47, 0x70, 0xB9, 0x0A, 0x29, 0x29, 0xF0, 0x0D, 0x1C, 0x70, 0x8D, 0x24, 0x70, 0x20, 0x86, 0x12, 0xAC, 0x47, 0x70, 0xB9, 0x66, 0x27, 0x20, 0xD6, 0x12, 0xAC, 0x47, 0x70, 0xB9, 0x2A, 0x27, 0x8D, 0x86, 0x70, 0x20, 0x32, 0x13, 0x20, 0xBC, 0x14, 0x60, 0xAD, 0x70, 0x70, 0xF0, 0x01, 0x60, 0xAD, 0x47, 0x70, 0x29, 0xF0, 0xD0, 0x1F, 0xAC, 0x47, 0x70, 0xC8, 0x98, 0x0A, 0x0A, 0x0A, 0x0A, 0xA8, 0x88, 0xA2, 0x0F, 0xB9, 0x0B, 0x25, 0xC9, 0x40, 0x30, 0x03, 0x38, 0xE9, 0x40, 0x9D, 0x12, 0x04, 0x88, 0xCA, 0x10, 0xEF, 0x60, 0xAC, 0x47, 0x70, 0xC8, 0x98, 0x0A, 0x0A, 0x0A, 0x0A, 0xA8, 0x88, 0xA2, 0x0F, 0xB9, 0x0B, 0x26, 0xC9, 0x40, 0x30, 0x03, 0x38, 0xE9, 0x40, 0x9D, 0x12, 0x04, 0x88, 0xCA, 0x10, 0xEF, 0x60, 0xAD, 0x1D, 0x70, 0xF0, 0x28, 0x29, 0x20, 0xF0, 0x03, 0x4C, 0x54, 0x15, 0xAD, 0x1D, 0x70, 0x29, 0x10, 0xF0, 0x03, 0x4C, 0xC3, 0x19, 0xAD, 0x1D, 0x70, 0x29, 0x40, 0xF0, 0x03, 0x4C, 0x14, 0x16, 0xAD, 0x1D, 0x70, 0x29, 0x08, 0xF0, 0x03, 0x4C, 0x93, 0x16, 0x4C, 0xAF, 0x15, 0xA2, 0x02, 0xBD, 0xA0, 0x70, 0x9D, 0xB0, 0x70, 0xCA, 0x10, 0xF7, 0xAD, 0xA0, 0x70, 0x8D, 0xB3, 0x70, 0xAD, 0xA1, 0x70, 0x8D, 0xB4, 0x70, 0xAD, 0xA2, 0x70, 0x8D, 0xB5, 0x70, 0x4C, 0xB9, 0x18, 0xAD, 0xA0, 0x70, 0x8D, 0x0C, 0x70, 0x8D, 0xB0, 0x70, 0xC9, 0xFF, 0xF0, 0x29, 0xAE, 0x1D, 0x70, 0xE0, 0x21, 0xF0, 0x07, 0xE0, 0x32, 0xF0, 0x03, 0x18, 0x69, 0x0C, 0x8D, 0xB1, 0x70, 0xAD, 0x0C, 0x70, 0xAE, 0x1D, 0x70, 0xE0, 0x21, 0xF0, 0x08, 0x38, 0xE9, 0x0C, 0xB0, 0x03, 0xAD, 0x0C, 0x70, 0x8D, 0xB2, 0x70, 0x4C, 0x90, 0x15, 0x8D, 0xB1, 0x70, 0x8D, 0xB2, 0x70, 0xAD, 0xB0, 0x70, 0x8D, 0xB3, 0x70, 0xAD, 0xB1, 0x70, 0x8D, 0xB4, 0x70, 0xAD, 0xB2, 0x70, 0x8D, 0xB5, 0x70, 0xAD, 0x1D, 0x70, 0x29, 0x10, 0xF0, 0x03, 0x4C, 0xCE, 0x19, 0x4C, 0xB9, 0x18, 0x20, 0x1E, 0x21, 0xA2, 0x02, 0xBD, 0xA0, 0x70, 0x9D, 0xB0, 0x70, 0xCA, 0x10, 0xF7, 0xAD, 0xB0, 0x70, 0xC9, 0xFF, 0xF0, 0x26, 0xAD, 0xB1, 0x70, 0xC9, 0xFF, 0xD0, 0x0C, 0xAD, 0xB0, 0x70, 0x18, 0x69, 0x07, 0x8D, 0xB1, 0x70, 0x4C, 0xEA, 0x15, 0xAD, 0xB2, 0x70, 0xC9, 0xFF, 0xD0, 0x0C, 0xAD, 0xB1, 0x70, 0x18, 0x69, 0x07, 0x8D, 0xB2, 0x70, 0x4C, 0xEA, 0x15, 0xAD, 0xB0, 0x70, 0x8D, 0xB3, 0x70, 0xAD, 0xB1, 0x70, 0x8D, 0xB4, 0x70, 0xAD, 0xB2, 0x70, 0x8D, 0xB5, 0x70, 0xAD, 0x1D, 0x70, 0xC9, 0x02, 0xF0, 0x03, 0x4C, 0xB9, 0x18, 0x4C, 0xCE, 0x19, 0x03, 0x07, 0x0F, 0x07, 0x03, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0xAD, 0x1D, 0x70, 0x29, 0x0F, 0xAA, 0xBD, 0x09, 0x16, 0x8D, 0x0C, 0x70, 0xAE, 0x1D, 0x70, 0xE0, 0x43, 0xF0, 0x35, 0xE0, 0x44, 0xF0, 0x31, 0xAD, 0x03, 0x70, 0x2D, 0x0C, 0x70, 0xD0, 0x03, 0xEE, 0x85, 0x70, 0x20, 0x1E, 0x21, 0xA2, 0x00, 0xA9, 0xFF, 0xDD, 0xA0, 0x70, 0xF0, 0x06, 0xE8, 0xEC, 0x80, 0x70, 0xD0, 0xF5, 0xCA, 0xEC, 0x85, 0x70, 0x10, 0x05, 0xA9, 0x00, 0x8D, 0x85, 0x70, 0xAC, 0x85, 0x70, 0xB9, 0xA0, 0x70, 0x4C, 0x57, 0x15, 0xAD, 0x03, 0x70, 0x2D, 0x0C, 0x70, 0xD0, 0x03, 0xCE, 0x85, 0x70, 0x20, 0x1E, 0x21, 0xA2, 0x00, 0xA9, 0xFF, 0xDD, 0xA0, 0x70, 0xF0, 0x06, 0xE8, 0xEC, 0x80, 0x70, 0x30, 0xF5, 0x8E, 0x0C, 0x70, 0xAD, 0x85, 0x70, 0x10, 0x09, 0xAE, 0x0C, 0x70, 0xF0, 0x01, 0xCA, 0x8E, 0x85, 0x70, 0xAC, 0x85, 0x70, 0xB9, 0xA0, 0x70, 0x4C, 0x57, 0x15, 0xAD, 0xA0, 0x70, 0x8D, 0xB0, 0x70, 0xAD, 0xA1, 0x70, 0x8D, 0xB4, 0x70, 0xAD, 0xA2, 0x70, 0x8D, 0xB2, 0x70, 0xAD, 0xA3, 0x70, 0x8D, 0xB3, 0x70, 0xAD, 0xA4, 0x70, 0x8D, 0xB1, 0x70, 0xAD, 0xA5, 0x70, 0x8D, 0xB5, 0x70, 0x4C, 0xB9, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0A, 0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFC, 0xFD, 0xFE, 0xFF, 0xAD, 0xF3, 0x70, 0x18, 0x6D, 0xF0, 0x70, 0x8D, 0xF4, 0x70, 0xA8, 0xB9, 0xB9, 0x17, 0x18, 0x69, 0x04, 0xA8, 0xB9, 0xC0, 0x33, 0x85, 0x22, 0xB9, 0xCA, 0x33, 0x85, 0x23, 0xB9, 0xD4, 0x33, 0x85, 0x24, 0xB9, 0xDE, 0x33, 0x85, 0x25, 0xAC, 0xF4, 0x70, 0xB9, 0xBA, 0x16, 0x8D, 0xF6, 0x70, 0xA2, 0x05, 0xBD, 0xB0, 0x70, 0xC9, 0xFF, 0xF0, 0x07, 0x18, 0x6D, 0xF6, 0x70, 0x9D, 0xB0, 0x70, 0xCA, 0x10, 0xEF, 0xA2, 0x02, 0x8E, 0x0C, 0x70, 0xBC, 0xB0, 0x70, 0xBD, 0x43, 0x29, 0xAA, 0xC0, 0xFF, 0xD0, 0x04, 0xA9, 0x00, 0xF0, 0x3F, 0xAD, 0x61, 0x70, 0xF0, 0x14, 0x18, 0xB9, 0x2C, 0x34, 0x71, 0x22, 0x8D, 0x43, 0x70, 0xB9, 0x74, 0x34, 0x71, 0x24, 0x8D, 0x44, 0x70, 0x4C, 0x39, 0x19, 0x18, 0xB9, 0xBC, 0x34, 0x71, 0x22, 0x8D, 0x43, 0x70, 0xB9, 0x0F, 0x35, 0x71, 0x24, 0x8D, 0x44, 0x70, 0x18, 0xAD, 0x43, 0x70, 0x6D, 0x25, 0x70, 0x9D, 0x00, 0xD4, 0xAD, 0x44, 0x70, 0x6D, 0x26, 0x70, 0x9D, 0x01, 0xD4, 0xA9, 0x01, 0x1D, 0x30, 0x70, 0x9D, 0x04, 0xD4, 0x9D, 0x04, 0x71, 0xAE, 0x0C, 0x70, 0xCA, 0x30, 0x03, 0x4C, 0xFD, 0x18, 0xA2, 0x02, 0x8E, 0x0C, 0x70, 0xBC, 0xB3, 0x70, 0xBD, 0x43, 0x29, 0xAA, 0xC0, 0xFF, 0xD0, 0x04, 0xA9, 0x00, 0xF0, 0x3F, 0xAD, 0x61, 0x70, 0xF0, 0x14, 0x18, 0xB9, 0x2C, 0x34, 0x71, 0x22, 0x8D, 0x43, 0x70, 0xB9, 0x74, 0x34, 0x71, 0x24, 0x8D, 0x44, 0x70, 0x4C, 0x9E, 0x19, 0x18, 0xB9, 0xBC, 0x34, 0x71, 0x22, 0x8D, 0x43, 0x70, 0xB9, 0x0F, 0x35, 0x71, 0x24, 0x8D, 0x44, 0x70, 0x18, 0xAD, 0x43, 0x70, 0x6D, 0x27, 0x70, 0x9D, 0x20, 0xD4, 0xAD, 0x44, 0x70, 0x6D, 0x28, 0x70, 0x9D, 0x21, 0xD4, 0xA9, 0x01, 0x1D, 0x30, 0x70, 0x9D, 0x24, 0xD4, 0x9D, 0x04, 0x71, 0xAE, 0x0C, 0x70, 0xCA, 0x10, 0xA0, 0x60, 0xA2, 0x02, 0xBD, 0xA0, 0x70, 0x9D, 0xB0, 0x70, 0xCA, 0x10, 0xF7, 0xA2, 0x02, 0xBC, 0xB0, 0x70, 0xC0, 0xFF, 0xD0, 0x03, 0x4C, 0xEA, 0x19, 0xAD, 0x03, 0x70, 0x29, 0x01, 0xF0, 0x03, 0x4C, 0xEA, 0x19, 0x20, 0x42, 0x1A, 0x20, 0x42, 0x1A, 0x18, 0xBD, 0x16, 0x70, 0x71, 0x22, 0x8D, 0x43, 0x70, 0xBD, 0x19, 0x70, 0x71, 0x24, 0x8D, 0x44, 0x70, 0x98, 0xBC, 0x43, 0x29, 0xC9, 0xFF, 0xD0, 0x04, 0xA9, 0x00, 0xF0, 0x28, 0x18, 0xAD, 0x43, 0x70, 0x6D, 0x25, 0x70, 0x99, 0x00, 0xD4, 0xAD, 0x44, 0x70, 0x6D, 0x26, 0x70, 0x99, 0x01, 0xD4, 0x18, 0xAD, 0x43, 0x70, 0x6D, 0x27, 0x70, 0x99, 0x20, 0xD4, 0xAD, 0x44, 0x70, 0x6D, 0x28, 0x70, 0x99, 0x21, 0xD4, 0xA9, 0x01, 0x19, 0x30, 0x70, 0x99, 0x04, 0xD4, 0x99, 0x24, 0xD4, 0x99, 0x04, 0x71, 0xCA, 0x30, 0x03, 0x4C, 0xD0, 0x19, 0x60, 0xAD, 0x61, 0x70, 0xF0, 0x0C, 0xBD, 0x19, 0x70, 0xD9, 0x74, 0x34, 0xF0, 0x10, 0x30, 0x2A, 0x10, 0x3E, 0xBD, 0x19, 0x70, 0xD9, 0x0F, 0x35, 0xF0, 0x04, 0x30, 0x1E, 0x10, 0x32, 0xAD, 0x61, 0x70, 0xF0, 0x0D, 0xBD, 0x16, 0x70, 0xD9, 0x2C, 0x34, 0xF0, 0x69, 0xB0, 0x23, 0x4C, 0x7B, 0x1A, 0xBD, 0x16, 0x70, 0xD9, 0xBC, 0x34, 0xF0, 0x5C, 0xB0, 0x16, 0xBD, 0x16, 0x70, 0x18, 0x71, 0x35, 0x9D, 0x16, 0x70, 0xBD, 0x19, 0x70, 0x71, 0x47, 0x9D, 0x19, 0x70, 0xA9, 0x00, 0x4C, 0xA4, 0x1A, 0xBD, 0x16, 0x70, 0x38, 0xF1, 0x35, 0x9D, 0x16, 0x70, 0xBD, 0x19, 0x70, 0xF1, 0x47, 0x9D, 0x19, 0x70, 0xA9, 0x01, 0xDD, 0x54, 0x70, 0x9D, 0x54, 0x70, 0xF0, 0x29, 0x98, 0xDD, 0x51, 0x70, 0x9D, 0x51, 0x70, 0xD0, 0x20, 0xAD, 0x61, 0x70, 0xF0, 0x0F, 0xB9, 0x2C, 0x34, 0x9D, 0x16, 0x70, 0xB9, 0x74, 0x34, 0x9D, 0x19, 0x70, 0x4C, 0xD5, 0x1A, 0xB9, 0xBC, 0x34, 0x9D, 0x16, 0x70, 0xB9, 0x0F, 0x35, 0x9D, 0x19, 0x70, 0x60, 0xA9, 0x7F, 0x8D, 0x0D, 0xDC, 0xA9, 0x13, 0x85, 0xC2, 0xA9, 0x22, 0x85, 0xC3, 0xA9, 0xBF, 0x8D, 0x00, 0xDC, 0xAD, 0x01, 0xDC, 0x29, 0x10, 0xD0, 0x08, 0xA9, 0x87, 0x85, 0xC2, 0xA9, 0x23, 0x85, 0xC3, 0xA9, 0xFD, 0x8D, 0x00, 0xDC, 0xAD, 0x01, 0xDC, 0x29, 0x80, 0xD0, 0x0B, 0xA9, 0x87, 0x85, 0xC2, 0xA9, 0x23, 0x85, 0xC3, 0x4C, 0x10, 0x1C, 0xA9, 0x7F, 0x8D, 0x00, 0xDC, 0xAD, 0x01, 0xDC, 0x29, 0x20, 0xD0, 0x08, 0xA9, 0x03, 0x85, 0xC2, 0xA9, 0x24, 0x85, 0xC3, 0xA9, 0x7F, 0x8D, 0x00, 0xDC, 0xAD, 0x01, 0xDC, 0x29, 0x80, 0xD0, 0x08, 0xA9, 0x7F, 0x85, 0xC2, 0xA9, 0x24, 0x85, 0xC3, 0xA9, 0x7F, 0x8D, 0x00, 0xDC, 0xAD, 0x01, 0xDC, 0x29, 0x04, 0xD0, 0x08, 0xA9, 0x0B, 0x85, 0xC2, 0xA9, 0x23, 0x85, 0xC3, 0xAD, 0x58, 0x70, 0xF0, 0x06, 0xCE, 0x58, 0x70, 0x4C, 0x55, 0x1B, 0xA9, 0x00, 0x8D, 0x9B, 0x70, 0xAE, 0x80, 0x70, 0xE8, 0xE8, 0xBD, 0xD0, 0x70, 0x9D, 0xE0, 0x70, 0xA9, 0xFF, 0x9D, 0xD0, 0x70, 0xCA, 0x10, 0xF2, 0xAE, 0x80, 0x70, 0xE8, 0xE8, 0xA0, 0x00, 0xB9, 0xA3, 0x21, 0xF0, 0x1C, 0x8D, 0x00, 0xDC, 0xAD, 0x01, 0xDC, 0x39, 0xBC, 0x21, 0xD0, 0x0E, 0x98, 0x18, 0x6D, 0x22, 0x70, 0x9D, 0xD0, 0x70, 0xCA, 0xEE, 0x9B, 0x70, 0x30, 0x03, 0xC8, 0xD0, 0xDF, 0xAE, 0x80, 0x70, 0xE8, 0xE8, 0xBD, 0xD0, 0x70, 0xAC, 0x80, 0x70, 0xC8, 0xC8, 0xD9, 0xE0, 0x70, 0xF0, 0x12, 0x88, 0x10, 0xF8, 0x8D, 0x81, 0x70, 0x8E, 0x82, 0x70, 0x20, 0x98, 0x1E, 0xAD, 0x81, 0x70, 0xAE, 0x82, 0x70, 0xCA, 0x10, 0xDE, 0xAE, 0x80, 0x70, 0xE8, 0xE8, 0xBD, 0xE0, 0x70, 0xAC, 0x80, 0x70, 0xC8, 0xC8, 0xD9, 0xD0, 0x70, 0xF0, 0x12, 0x88, 0x10, 0xF8, 0x8D, 0x81, 0x70, 0x8E, 0x82, 0x70, 0x20, 0xC6, 0x1E, 0xAD, 0x81, 0x70, 0xAE, 0x82, 0x70, 0xCA, 0x10, 0xDE, 0xAE, 0x9B, 0x70, 0xF0, 0x0D, 0xA9, 0x8F, 0x85, 0xC2, 0xA9, 0x22, 0x85, 0xC3, 0xA9, 0x00, 0x8D, 0x58, 0x70, 0xAD, 0x58, 0x70, 0xF0, 0x01, 0x60, 0x8E, 0x66, 0x70, 0xA9, 0x7F, 0x8D, 0x00, 0xDC, 0xAD, 0x01, 0xDC, 0x29, 0x10, 0xD0, 0x06, 0x20, 0x20, 0x10, 0x4C, 0x60, 0x1C, 0xA2, 0x3C, 0xBD, 0xD5, 0x21, 0x8D, 0x00, 0xDC, 0xAD, 0x01, 0xDC, 0x3D, 0xD6, 0x21, 0xD0, 0x3C, 0x8A, 0x0A, 0xA8, 0xB1, 0xC2, 0x8D, 0x62, 0x70, 0xC8, 0xB1, 0xC2, 0x8D, 0x63, 0x70, 0xF0, 0x2C, 0xA9, 0x1C, 0x48, 0xA9, 0x4A, 0x48, 0x8E, 0x64, 0x70, 0xC8, 0xB1, 0xC2, 0x8D, 0x65, 0x70, 0xC8, 0xB1, 0xC2, 0xA8, 0xAD, 0x65, 0x70, 0x6C, 0x62, 0x70, 0xEA, 0xEA, 0xAE, 0x64, 0x70, 0xA5, 0xC2, 0xC9, 0x13, 0xF0, 0x08, 0xA9, 0x28, 0x8D, 0x58, 0x70, 0x4C, 0x60, 0x1C, 0xCA, 0xCA, 0x10, 0xB2, 0x60, 0xAD, 0x50, 0x71, 0xF0, 0x03, 0x20, 0xF8, 0x3A, 0xD0, 0x03, 0x4C, 0xE7, 0x1E, 0x10, 0x68, 0x8D, 0x7D, 0x70, 0xA8, 0x29, 0xF0, 0xC9, 0xF0, 0xF0, 0x0F, 0x20, 0xFF, 0x3A, 0x8D, 0x7E, 0x70, 0xAD, 0x7D, 0x70, 0x20, 0xF0, 0x1C, 0x4C, 0x61, 0x1C, 0x98, 0xC9, 0xF0, 0xD0, 0x0A, 0x20, 0xFF, 0x3A, 0xC9, 0xF7, 0xD0, 0xF9, 0x4C, 0x61, 0x1C, 0xC9, 0xF1, 0xD0, 0x06, 0x20, 0xFF, 0x3A, 0x4C, 0x61, 0x1C, 0xC9, 0xF2, 0xD0, 0x09, 0x20, 0xFF, 0x3A, 0x20, 0xFF, 0x3A, 0x4C, 0x61, 0x1C, 0xC9, 0xF3, 0xD0, 0x09, 0x20, 0xFF, 0x3A, 0x4C, 0x61, 0x1C, 0x4C, 0x61, 0x1C, 0xC9, 0xF8, 0xD0, 0x03, 0x4C, 0x61, 0x1C, 0xC9, 0xFA, 0xD0, 0x03, 0x4C, 0x61, 0x1C, 0xC9, 0xFC, 0xD0, 0x03, 0x4C, 0x61, 0x1C, 0xC9, 0xFF, 0xD0, 0x00, 0x4C, 0x61, 0x1C, 0x8D, 0x7E, 0x70, 0xAD, 0x7D, 0x70, 0x29, 0xF0, 0xC9, 0xF0, 0xD0, 0x03, 0x4C, 0x61, 0x1C, 0xAD, 0x7D, 0x70, 0x20, 0xF0, 0x1C, 0x4C, 0x61, 0x1C, 0xA8, 0xAD, 0xF7, 0x70, 0x30, 0x16, 0x98, 0x29, 0x0F, 0xCD, 0xF7, 0x70, 0xF0, 0x0E, 0x98, 0x09, 0x40, 0xF0, 0x05, 0x98, 0x09, 0x20, 0xF0, 0x03, 0x20, 0xFF, 0x3A, 0x60, 0x98, 0x29, 0xF0, 0xC9, 0x80, 0xD0, 0x03, 0x4C, 0xB4, 0x1E, 0xC9, 0x90, 0xD0, 0x03, 0x4C, 0x7E, 0x1E, 0xC9, 0xE0, 0xF0, 0x3A, 0xC9, 0xB0, 0xD0, 0x03, 0x4C, 0x7B, 0x1D, 0xC9, 0xD0, 0xF0, 0x2B, 0xC9, 0xA0, 0xF0, 0x0F, 0xC9, 0xC0, 0xF0, 0x12, 0x8D, 0xE4, 0x07, 0xA9, 0x02, 0x8D, 0x20, 0xD0, 0x4C, 0xE7, 0x1E, 0xAD, 0x7E, 0x70, 0x20, 0xFF, 0x3A, 0x60, 0xAC, 0x7E, 0x70, 0x10, 0x02, 0xA0, 0x1D, 0xC0, 0x1E, 0x30, 0x02, 0xA0, 0x00, 0x20, 0xAA, 0x13, 0x60, 0xAD, 0x7E, 0x70, 0x60, 0xAD, 0x7E, 0x70, 0x4A, 0x4A, 0x6D, 0x7E, 0x70, 0x38, 0xE9, 0x50, 0x30, 0x09, 0xC9, 0x46, 0x30, 0x0B, 0xA9, 0x46, 0x4C, 0x77, 0x1D, 0xC9, 0xBA, 0x10, 0x02, 0xA9, 0xBA, 0x8D, 0xF0, 0x70, 0x60, 0x20, 0xFF, 0x3A, 0xA8, 0xAD, 0x7E, 0x70, 0x29, 0xEF, 0xD0, 0x0A, 0x98, 0x29, 0xF0, 0x8D, 0x97, 0x70, 0x20, 0xAF, 0x10, 0x60, 0xC9, 0x01, 0xD0, 0x11, 0x98, 0x0A, 0xA8, 0x8D, 0x9D, 0x70, 0xAD, 0x29, 0x70, 0xF0, 0x05, 0xA9, 0x00, 0x20, 0x3C, 0x11, 0x60, 0xC9, 0x02, 0xD0, 0x0E, 0x98, 0x4A, 0x4A, 0x4A, 0x29, 0x0F, 0xAA, 0xBD, 0xFB, 0x24, 0x20, 0x57, 0x13, 0x60, 0xC9, 0x03, 0xD0, 0x0B, 0x98, 0x4A, 0x4A, 0x4A, 0x4A, 0x29, 0x07, 0x20, 0x2F, 0x13, 0x60, 0xC9, 0x04, 0xD0, 0x08, 0x98, 0x0A, 0x29, 0xF0, 0x20, 0x50, 0x12, 0x60, 0xC9, 0x05, 0xD0, 0x0C, 0x98, 0x4A, 0x4A, 0x4A, 0x29, 0x0F, 0x09, 0xF0, 0x20, 0xA3, 0x11, 0x60, 0xC9, 0x06, 0xD0, 0x2D, 0x98, 0x0A, 0x09, 0x10, 0x20, 0x69, 0x10, 0xEE, 0x00, 0x04, 0xAD, 0x86, 0x70, 0xC9, 0x07, 0xF0, 0x04, 0xC9, 0x06, 0xD0, 0x0B, 0xEE, 0x01, 0x04, 0xA9, 0x00, 0x8D, 0x86, 0x70, 0x20, 0x32, 0x13, 0xAD, 0x7A, 0x70, 0xC9, 0x01, 0xD0, 0x05, 0xA9, 0x00, 0x20, 0x47, 0x10, 0x60, 0xC9, 0x07, 0xD0, 0x08, 0x98, 0x4A, 0x4A, 0x4A, 0x20, 0x83, 0x12, 0x60, 0xC9, 0x08, 0xD0, 0x0B, 0x98, 0x4A, 0x4A, 0x4A, 0x4A, 0x29, 0x03, 0x20, 0x5D, 0x11, 0x60, 0xC9, 0x09, 0xD0, 0x0B, 0x98, 0x4A, 0x4A, 0x4A, 0x4A, 0x29, 0x03, 0x20, 0x73, 0x11, 0x60, 0xC9, 0x0D, 0xD0, 0x14, 0x98, 0x4A, 0x4A, 0x4A, 0x29, 0x03, 0xAA, 0xBD, 0x7A, 0x1E, 0x8D, 0x37, 0x70, 0x8D, 0x3E, 0x70, 0x8D, 0x30, 0x70, 0x60, 0xC9, 0x0E, 0xD0, 0x0E, 0x98, 0x4A, 0x4A, 0x4A, 0x29, 0x03, 0xAA, 0xBD, 0x7A, 0x1E, 0x8D, 0x37, 0x70, 0x60, 0xC9, 0x0F, 0xD0, 0x0E, 0x98, 0x4A, 0x4A, 0x4A, 0x29, 0x03, 0xAA, 0xBD, 0x7A, 0x1E, 0x8D, 0x3E, 0x70, 0x60, 0x60, 0x10, 0x20, 0x40, 0x80, 0x8D, 0x0C, 0x70, 0x20, 0xFF, 0x3A, 0x8D, 0x7F, 0x70, 0xD0, 0x09, 0xAD, 0x7E, 0x70, 0x38, 0xE9, 0x0C, 0x4C, 0xC6, 0x1E, 0xAD, 0x7E, 0x70, 0x38, 0xE9, 0x0C, 0xAE, 0x80, 0x70, 0xA8, 0xCA, 0xBD, 0xA0, 0x70, 0xC9, 0xFF, 0xF0, 0x05, 0xCA, 0x10, 0xF6, 0xA2, 0x00, 0x98, 0x9D, 0xA0, 0x70, 0xAD, 0x7F, 0x70, 0xEE, 0x8C, 0x70, 0x60, 0x8D, 0x0C, 0x70, 0x20, 0xFF, 0x3A, 0x8D, 0x7F, 0x70, 0xAD, 0x0C, 0x70, 0xAD, 0x7E, 0x70, 0x38, 0xE9, 0x0C, 0xAE, 0x80, 0x70, 0x8D, 0x0C, 0x70, 0xCA, 0xBD, 0xA0, 0x70, 0xCD, 0x0C, 0x70, 0xF0, 0x06, 0xCA, 0x10, 0xF5, 0x4C, 0xE0, 0x1E, 0xA9, 0xFF, 0x9D, 0xA0, 0x70, 0xAD, 0x7F, 0x70, 0xEE, 0x8B, 0x70, 0x60, 0xAE, 0x84, 0x70, 0xCA, 0xBD, 0xA0, 0x70, 0xC9, 0xFF, 0xF0, 0x06, 0xCA, 0x10, 0xF6, 0x4C, 0x14, 0x1F, 0xAC, 0x84, 0x70, 0xB9, 0xA0, 0x70, 0xC9, 0xFF, 0xD0, 0x07, 0xC8, 0xC0, 0x08, 0xF0, 0xEB, 0xD0, 0xF2, 0x9D, 0xA0, 0x70, 0xA9, 0xFF, 0x99, 0xA0, 0x70, 0x4C, 0xF2, 0x1E, 0x60, 0x20, 0xE5, 0x20, 0xC9, 0xFF, 0xD0, 0xF9, 0xA2, 0xFF, 0xA0, 0x60, 0xCA, 0xD0, 0xFD, 0x88, 0xD0, 0xFA, 0x60, 0xAE, 0x9D, 0x70, 0x8E, 0x54, 0x70, 0x8D, 0x60, 0x70, 0x20, 0xB4, 0x0C, 0x20, 0xF5, 0x0B, 0xA2, 0x2A, 0xA0, 0x66, 0x20, 0x0B, 0x0D, 0x20, 0x6A, 0x20, 0xA2, 0x09, 0xA9, 0x20, 0x9D, 0x00, 0x04, 0xCA, 0x10, 0xFA, 0xA2, 0x5C, 0xA0, 0x00, 0x20, 0x94, 0x0C, 0xA9, 0x24, 0x8D, 0x04, 0x04, 0x20, 0xDA, 0x20, 0xC9, 0x10, 0xD0, 0x03, 0x4C, 0x52, 0x20, 0xAA, 0x0A, 0x0A, 0x0A, 0x0A, 0x8D, 0x5A, 0x70, 0xBD, 0xEC, 0x33, 0x8D, 0x04, 0x04, 0xA9, 0x24, 0x8D, 0x05, 0x04, 0x20, 0xDA, 0x20, 0xC9, 0x10, 0xD0, 0x03, 0x4C, 0x52, 0x20, 0xAA, 0x0D, 0x5A, 0x70, 0x8D, 0x5A, 0x70, 0xBD, 0xEC, 0x33, 0x8D, 0x05, 0x04, 0xA9, 0x3E, 0x8D, 0x06, 0x04, 0xA9, 0x24, 0x8D, 0x07, 0x04, 0x20, 0xDA, 0x20, 0xC9, 0x10, 0xD0, 0x03, 0x4C, 0x52, 0x20, 0xAA, 0x0A, 0x0A, 0x0A, 0x0A, 0x8D, 0x5B, 0x70, 0xBD, 0xEC, 0x33, 0x8D, 0x07, 0x04, 0xA9, 0x24, 0x8D, 0x08, 0x04, 0x20, 0xDA, 0x20, 0xC9, 0x10, 0xD0, 0x03, 0x4C, 0x52, 0x20, 0xAA, 0x0D, 0x5B, 0x70, 0x8D, 0x5B, 0x70, 0xBD, 0xEC, 0x33, 0x8D, 0x08, 0x04, 0xAE, 0x5A, 0x70, 0xE0, 0x20, 0x30, 0x2E, 0xAD, 0x5B, 0x70, 0x9D, 0xE0, 0xD3, 0x9D, 0x00, 0xD4, 0x9D, 0xE0, 0x70, 0x9D, 0xE7, 0xD3, 0x9D, 0x07, 0xD4, 0x9D, 0xE7, 0x70, 0x9D, 0xEE, 0xD3, 0x9D, 0x0E, 0xD4, 0x9D, 0xEE, 0x70, 0xE0, 0x24, 0xD0, 0x09, 0x8D, 0x30, 0x70, 0x8D, 0x37, 0x70, 0x8D, 0x3E, 0x70, 0x4C, 0x38, 0x20, 0xAE, 0x5A, 0x70, 0xAD, 0x5B, 0x70, 0x9D, 0x00, 0xD4, 0x9D, 0x20, 0xD4, 0x9D, 0x00, 0x71, 0xE0, 0x04, 0xD0, 0x03, 0x8D, 0x30, 0x70, 0xE0, 0x0B, 0xD0, 0x03, 0x8D, 0x37, 0x70, 0xE0, 0x12, 0xD0, 0x03, 0x8D, 0x3E, 0x70, 0xE0, 0x16, 0xD0, 0x03, 0x8D, 0x57, 0x70, 0xE0, 0x15, 0xF0, 0x04, 0xE0, 0x16, 0xD0, 0x08, 0xA9, 0x00, 0x8D, 0x29, 0x70, 0x20, 0x56, 0x11, 0xAE, 0x5A, 0x70, 0xAD, 0x5B, 0x70, 0xE0, 0x18, 0xD0, 0x10, 0x8D, 0x0C, 0x70, 0x29, 0xF0, 0x8D, 0x24, 0x70, 0xAD, 0x0C, 0x70, 0x29, 0x0F, 0x8D, 0x1C, 0x70, 0xA5, 0xC5, 0xC9, 0x40, 0xD0, 0xFA, 0x20, 0x86, 0x12, 0xA9, 0x00, 0x20, 0x2A, 0x11, 0x20, 0xF5, 0x0B, 0xAD, 0x54, 0x70, 0x8D, 0x9D, 0x70, 0x60, 0xA0, 0x02, 0x8C, 0x73, 0x70, 0xB9, 0x00, 0x71, 0x8D, 0x74, 0x70, 0x98, 0x0A, 0x18, 0x69, 0x04, 0xA8, 0xAD, 0x74, 0x70, 0xA2, 0x06, 0x20, 0xC8, 0x0C, 0xAC, 0x73, 0x70, 0xB9, 0x07, 0x71, 0x8D, 0x74, 0x70, 0x98, 0x0A, 0x18, 0x69, 0x04, 0xA8, 0xAD, 0x74, 0x70, 0xA2, 0x0A, 0x20, 0xC8, 0x0C, 0xAC, 0x73, 0x70, 0xB9, 0x0E, 0x71, 0x8D, 0x74, 0x70, 0x98, 0x0A, 0x18, 0x69, 0x04, 0xA8, 0xAD, 0x74, 0x70, 0xA2, 0x0E, 0x20, 0xC8, 0x0C, 0xAC, 0x73, 0x70, 0xC8, 0xC0, 0x07, 0xD0, 0xB3, 0xA0, 0x15, 0x8C, 0x73, 0x70, 0xB9, 0x00, 0x71, 0x8D, 0x74, 0x70, 0x98, 0x38, 0xE9, 0x02, 0xA8, 0xAD, 0x74, 0x70, 0xA2, 0x05, 0x20, 0xC8, 0x0C, 0xAC, 0x73, 0x70, 0xC8, 0xC0, 0x19, 0xD0, 0xE2, 0x60, 0x20, 0x15, 0x1F, 0x20, 0xE5, 0x20, 0xC9, 0xFF, 0xF0, 0xF9, 0x60, 0xAD, 0x60, 0x70, 0xF0, 0x1A, 0xA0, 0x00, 0xB9, 0x5B, 0x21, 0xF0, 0x10, 0x8D, 0x00, 0xDC, 0xAD, 0x01, 0xDC, 0x39, 0x7F, 0x21, 0xD0, 0x02, 0x98, 0x60, 0xC8, 0xD0, 0xEB, 0xA9, 0xFF, 0x60, 0xA0, 0x00, 0xB9, 0x6D, 0x21, 0xF0, 0x10, 0x8D, 0x00, 0xDC, 0xAD, 0x01, 0xDC, 0x39, 0x91, 0x21, 0xD0, 0x02, 0x98, 0x60, 0xC8, 0xD0, 0xEB, 0xA9, 0xFF, 0x60, 0xA9, 0x08, 0x8D, 0x22, 0x01, 0xAC, 0x22, 0x01, 0xB9, 0x9F, 0x70, 0x8D, 0x27, 0x01, 0x4C, 0x3A, 0x21, 0x88, 0xF0, 0x11, 0xB9, 0x9F, 0x70, 0xCD, 0x26, 0x01, 0x90, 0xF5, 0x8C, 0x25, 0x01, 0x8D, 0x26, 0x01, 0x4C, 0x2F, 0x21, 0xAC, 0x22, 0x01, 0xAD, 0x26, 0x01, 0x99, 0x9F, 0x70, 0xAC, 0x25, 0x01, 0xAD, 0x27, 0x01, 0x99, 0x9F, 0x70, 0xCE, 0x22, 0x01, 0xD0, 0xC9, 0x60, 0xBF, 0x7F, 0xFD, 0xFB, 0xFB, 0xF7, 0xEF, 0xEF, 0xDF, 0xBF, 0xF7, 0xF7, 0xEF, 0xEF, 0xDF, 0xDF, 0x7F, 0x00, 0xEF, 0x7F, 0x7F, 0xFD, 0xFD, 0xFB, 0xFB, 0xF7, 0xF7, 0xEF, 0xFD, 0xF7, 0xFB, 0xFB, 0xFD, 0xFB, 0x7F, 0x00, 0x08, 0x08, 0x01, 0x01, 0x08, 0x01, 0x01, 0x08, 0x08, 0x01, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x00, 0x08, 0x01, 0x08, 0x01, 0x08, 0x01, 0x08, 0x01, 0x08, 0x01, 0x04, 0x10, 0x10, 0x04, 0x40, 0x20, 0x02, 0x00, 0x7F, 0x7F, 0xFD, 0xFD, 0xFD, 0xFB, 0xFB, 0xFB, 0xFB, 0xF7, 0xF7, 0xF7, 0xEF, 0xEF, 0xEF, 0xEF, 0xDF, 0xDF, 0xDF, 0xBF, 0xBF, 0xBF, 0xBF, 0xFE, 0x00, 0x40, 0x08, 0x02, 0x01, 0x40, 0x02, 0x01, 0x40, 0x08, 0x02, 0x01, 0x40, 0x02, 0x01, 0x40, 0x08, 0x02, 0x40, 0x08, 0x02, 0x01, 0x40, 0x08, 0x01, 0x00, 0x7F, 0x10, 0xFD, 0x04, 0xFD, 0x20, 0xFB, 0x04, 0xFB, 0x20, 0xF7, 0x04, 0xF7, 0x20, 0xEF, 0x04, 0xEF, 0x20, 0xDF, 0x04, 0xDF, 0x20, 0xBF, 0x04, 0xBF, 0x20, 0xFD, 0x10, 0xFB, 0x80, 0xFB, 0x10, 0xF7, 0x80, 0xF7, 0x10, 0xEF, 0x80, 0xEF, 0x10, 0xDF, 0x80, 0xDF, 0x10, 0xBF, 0x80, 0xFE, 0x80, 0xFE, 0x04, 0xFE, 0x10, 0xFE, 0x20, 0xFE, 0x40, 0xFE, 0x08, 0xFE, 0x02, 0x7F, 0x02, 0x20, 0x10, 0x00, 0x00, 0xAA, 0x13, 0x00, 0x0A, 0xAA, 0x13, 0x00, 0x0B, 0xAA, 0x13, 0x00, 0x0C, 0xAA, 0x13, 0x00, 0x0D, 0xAA, 0x13, 0x00, 0x0E, 0xAA, 0x13, 0x00, 0x0F, 0xAA, 0x13, 0x00, 0x10, 0xAA, 0x13, 0x00, 0x11, 0xAA, 0x13, 0x00, 0x12, 0xAA, 0x13, 0x00, 0x13, 0xAA, 0x13, 0x00, 0x15, 0xAA, 0x13, 0x00, 0x14, 0xAA, 0x13, 0x00, 0x00, 0xAA, 0x13, 0x00, 0x01, 0xAA, 0x13, 0x00, 0x02, 0xAA, 0x13, 0x00, 0x03, 0xAA, 0x13, 0x00, 0x04, 0xAA, 0x13, 0x00, 0x05, 0xAA, 0x13, 0x00, 0x06, 0xAA, 0x13, 0x00, 0x07, 0xAA, 0x13, 0x00, 0x08, 0xAA, 0x13, 0x00, 0x09, 0x57, 0x13, 0x00, 0x00, 0x57, 0x13, 0x01, 0x00, 0xD6, 0x12, 0x03, 0x00, 0xD6, 0x12, 0x02, 0x00, 0xD6, 0x12, 0x01, 0x00, 0xD6, 0x12, 0x00, 0x00, 0xB8, 0x0F, 0x00, 0x00, 0x4A, 0x0F, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0x12, 0x03, 0x00, 0xD6, 0x12, 0x02, 0x00, 0xD6, 0x12, 0x01, 0x00, 0xD6, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x11, 0xE0, 0x00, 0xA3, 0x11, 0xE9, 0x00, 0xA3, 0x11, 0xEE, 0x00, 0x57, 0x13, 0x00, 0x00, 0x57, 0x13, 0x01, 0x00, 0x57, 0x13, 0x02, 0x00, 0x57, 0x13, 0x20, 0x00, 0x57, 0x13, 0x40, 0x00, 0x57, 0x13, 0x41, 0x00, 0x57, 0x13, 0x42, 0x00, 0x57, 0x13, 0x43, 0x00, 0x57, 0x13, 0x44, 0x00, 0x2F, 0x13, 0x00, 0x00, 0x2F, 0x13, 0x01, 0x00, 0x2F, 0x13, 0x02, 0x00, 0x2F, 0x13, 0x03, 0x00, 0x2F, 0x13, 0x04, 0x00, 0x2F, 0x13, 0x05, 0x00, 0x2F, 0x13, 0x06, 0x00, 0x2F, 0x13, 0x07, 0x00, 0x2F, 0x13, 0x08, 0x00, 0x57, 0x13, 0x21, 0x00, 0x57, 0x13, 0x31, 0x00, 0x57, 0x13, 0x32, 0x00, 0x83, 0x12, 0x0F, 0x00, 0x83, 0x12, 0x0B, 0x00, 0x83, 0x12, 0x07, 0x00, 0x83, 0x12, 0x00, 0x00, 0x57, 0x13, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x12, 0x00, 0x00, 0x50, 0x12, 0x90, 0x00, 0x50, 0x12, 0xE0, 0x00, 0x2E, 0x11, 0x08, 0x01, 0x2E, 0x11, 0x03, 0x02, 0x2E, 0x11, 0x15, 0x03, 0x39, 0x10, 0x02, 0x00, 0x39, 0x10, 0x01, 0x00, 0x39, 0x10, 0x00, 0x00, 0xFE, 0x10, 0x01, 0x00, 0xFE, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x11, 0x00, 0x00, 0x73, 0x11, 0x01, 0x00, 0x73, 0x11, 0x02, 0x00, 0x73, 0x11, 0x03, 0x00, 0x5D, 0x11, 0x00, 0x00, 0x5D, 0x11, 0x01, 0x00, 0x5D, 0x11, 0x02, 0x00, 0x5D, 0x11, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x10, 0x00, 0x00, 0x3D, 0x10, 0x01, 0x00, 0x57, 0x13, 0x12, 0x00, 0x57, 0x13, 0x11, 0x00, 0x57, 0x13, 0x10, 0x00, 0x57, 0x13, 0x00, 0x00, 0x0B, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5C, 0x10, 0x00, 0x00, 0x5C, 0x10, 0x20, 0x00, 0x5C, 0x10, 0x40, 0x00, 0x5C, 0x10, 0x60, 0x00, 0x5C, 0x10, 0x80, 0x00, 0x5C, 0x10, 0xA0, 0x00, 0x5C, 0x10, 0xC0, 0x00, 0x5C, 0x10, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAC, 0x10, 0x00, 0x00, 0xAC, 0x10, 0x00, 0x01, 0xAC, 0x10, 0x00, 0x02, 0x47, 0x10, 0x00, 0x00, 0x47, 0x10, 0x01, 0x00, 0x47, 0x10, 0x03, 0x00, 0x47, 0x10, 0x04, 0x00, 0x04, 0x12, 0xFF, 0xFF, 0x04, 0x12, 0x00, 0x00, 0x04, 0x12, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x10, 0x01, 0x00, 0x1A, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x10, 0x00, 0x00, 0xE8, 0x10, 0x00, 0x01, 0xE8, 0x10, 0x00, 0x02, 0xE8, 0x10, 0x00, 0x03, 0xE8, 0x10, 0x00, 0x04, 0xE8, 0x10, 0x00, 0x05, 0xE8, 0x10, 0x00, 0x06, 0xE8, 0x10, 0x00, 0x07, 0xE8, 0x10, 0x00, 0x08, 0xE8, 0x10, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0x13, 0x00, 0x16, 0xAA, 0x13, 0x00, 0x17, 0xAA, 0x13, 0x00, 0x18, 0xAA, 0x13, 0x00, 0x19, 0xAA, 0x13, 0x00, 0x1A, 0xAA, 0x13, 0x00, 0x1B, 0xAA, 0x13, 0x00, 0x1C, 0xAA, 0x13, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x1F, 0x00, 0x00, 0xF5, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x10, 0x11, 0x12, 0x20, 0x21, 0x31, 0x32, 0x40, 0x41, 0x42, 0x43, 0x44, 0x08, 0x53, 0x41, 0x57, 0x54, 0x4F, 0x4F, 0x54, 0x48, 0x20, 0x42, 0x41, 0x53, 0x53, 0x20, 0x20, 0x20, 0x47, 0x52, 0x49, 0x54, 0x54, 0x59, 0x20, 0x42, 0x41, 0x53, 0x53, 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x4F, 0x52, 0x54, 0x41, 0x4D, 0x45, 0x4E, 0x54, 0x4F, 0x20, 0x35, 0x54, 0x48, 0x53, 0x20, 0x53, 0x41, 0x57, 0x20, 0x50, 0x4F, 0x52, 0x54, 0x41, 0x4D, 0x45, 0x4E, 0x54, 0x4F, 0x20, 0x20, 0x50, 0x55, 0x4C, 0x53, 0x45, 0x20, 0x35, 0x54, 0x48, 0x53, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x55, 0x4C, 0x53, 0x45, 0x20, 0x48, 0x49, 0x47, 0x48, 0x20, 0x50, 0x4F, 0x52, 0x54, 0x20, 0x54, 0x52, 0x49, 0x4E, 0x47, 0x4C, 0x20, 0x48, 0x49, 0x47, 0x48, 0x20, 0x4C, 0x4F, 0x4E, 0x47, 0x54, 0x52, 0x49, 0x41, 0x4E, 0x47, 0x4C, 0x45, 0x20, 0x44, 0x52, 0x4F, 0x50, 0x20, 0x20, 0x20, 0x53, 0x49, 0x44, 0x20, 0x45, 0x58, 0x50, 0x4C, 0x4F, 0x53, 0x49, 0x4F, 0x4E, 0x20, 0x20, 0x20, 0x4D, 0x55, 0x54, 0x45, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x49, 0x4C, 0x54, 0x45, 0x52, 0x20, 0x42, 0x41, 0x53, 0x53, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x57, 0x45, 0x45, 0x50, 0x20, 0x41, 0x52, 0x50, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x4C, 0x55, 0x43, 0x4B, 0x20, 0x41, 0x52, 0x50, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x4C, 0x4F, 0x57, 0x20, 0x41, 0x52, 0x50, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x49, 0x4C, 0x54, 0x45, 0x52, 0x20, 0x53, 0x54, 0x41, 0x43, 0x4B, 0x20, 0x31, 0x20, 0x20, 0x46, 0x49, 0x4C, 0x54, 0x45, 0x52, 0x20, 0x53, 0x54, 0x41, 0x43, 0x4B, 0x20, 0x32, 0x20, 0x20, 0x50, 0x55, 0x4C, 0x53, 0x41, 0x52, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x56, 0x49, 0x42, 0x52, 0x41, 0x54, 0x4F, 0x20, 0x4C, 0x45, 0x41, 0x44, 0x20, 0x20, 0x20, 0x20, 0x53, 0x4C, 0x4F, 0x57, 0x20, 0x52, 0x49, 0x53, 0x45, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x42, 0x45, 0x4E, 0x44, 0x49, 0x4E, 0x47, 0x20, 0x45, 0x43, 0x48, 0x4F, 0x20, 0x20, 0x20, 0x20, 0x36, 0x20, 0x43, 0x48, 0x41, 0x4E, 0x4E, 0x45, 0x4C, 0x20, 0x53, 0x41, 0x57, 0x20, 0x20, 0x20, 0x41, 0x52, 0x50, 0x20, 0x4C, 0x45, 0x41, 0x44, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4C, 0x41, 0x53, 0x45, 0x52, 0x20, 0x42, 0x41, 0x53, 0x53, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x52, 0x4F, 0x4D, 0x42, 0x4F, 0x4E, 0x45, 0x20, 0x42, 0x4C, 0x41, 0x53, 0x54, 0x20, 0x20, 0x4E, 0x4F, 0x49, 0x53, 0x59, 0x20, 0x53, 0x51, 0x55, 0x41, 0x52, 0x45, 0x20, 0x41, 0x52, 0x50, 0x54, 0x52, 0x49, 0x41, 0x4E, 0x47, 0x4C, 0x45, 0x20, 0x53, 0x59, 0x4E, 0x43, 0x20, 0x20, 0x20, 0x4D, 0x4F, 0x4E, 0x4F, 0x20, 0x53, 0x59, 0x4E, 0x43, 0x20, 0x45, 0x43, 0x48, 0x4F, 0x20, 0x20, 0x43, 0x4C, 0x45, 0x41, 0x4E, 0x20, 0x53, 0x41, 0x57, 0x54, 0x4F, 0x4F, 0x54, 0x48, 0x20, 0x20, 0x43, 0x4C, 0x45, 0x41, 0x4E, 0x20, 0x54, 0x52, 0x49, 0x41, 0x4E, 0x47, 0x4C, 0x45, 0x20, 0x20, 0x43, 0x4C, 0x45, 0x41, 0x4E, 0x20, 0x53, 0x51, 0x55, 0x41, 0x52, 0x45, 0x20, 0x20, 0x20, 0x20, 0x50, 0x41, 0x54, 0x43, 0x48, 0x20, 0x53, 0x41, 0x56, 0x45, 0x44, 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0x55, 0x53, 0x54, 0x4F, 0x4D, 0x20, 0x50, 0x41, 0x54, 0x43, 0x48, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x02, 0x11, 0x01, 0x11, 0x00, 0x20, 0x10, 0x00, 0x00, 0x40, 0x41, 0x42, 0x20, 0x21, 0x00, 0x20, 0x00, 0x12, 0x08, 0x44, 0x31, 0x32, 0x40, 0x32, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x07, 0x06, 0x01, 0x03, 0x02, 0x00, 0x03, 0x01, 0x03, 0x00, 0x02, 0x03, 0x04, 0x01, 0x01, 0x02, 0x00, 0x03, 0x01, 0x03, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x11, 0x02, 0x02, 0x13, 0x13, 0x00, 0x01, 0x02, 0x13, 0x00, 0x00, 0x22, 0x13, 0x11, 0x10, 0x02, 0x00, 0x33, 0x10, 0x11, 0x10, 0x12, 0x13, 0x00, 0x00, 0x13, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x03, 0x03, 0x00, 0x00, 0x01, 0x02, 0x03, 0x01, 0x01, 0x02, 0x03, 0x03, 0x01, 0x03, 0x01, 0x03, 0x00, 0x03, 0x03, 0x01, 0x01, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF5, 0xF0, 0xF0, 0xF8, 0xF0, 0xFE, 0xF6, 0xF0, 0x00, 0xF0, 0xFA, 0xF6, 0xF6, 0xFA, 0xF9, 0xFE, 0xF7, 0xFF, 0xEE, 0xF0, 0xF5, 0xF5, 0x86, 0xF6, 0xF2, 0xF8, 0xF2, 0xF2, 0xF0, 0xF0, 0xF5, 0xF0, 0xF0, 0xF8, 0xF0, 0xFE, 0xF6, 0xF0, 0x00, 0xF0, 0xFA, 0xF6, 0xF6, 0xFA, 0xF9, 0xFE, 0xF7, 0xFF, 0xEE, 0xF0, 0xF5, 0xF5, 0xF6, 0x54, 0xF2, 0xF8, 0xF2, 0xF2, 0xF0, 0xF0, 0xF5, 0xF0, 0xF0, 0xF8, 0xF0, 0xFE, 0xF6, 0xF0, 0x00, 0xF0, 0xFA, 0xF6, 0xF6, 0xFA, 0xF9, 0xFE, 0xF7, 0xFF, 0xEE, 0xF0, 0xF5, 0xF5, 0xF6, 0xF6, 0xF2, 0xF8, 0xF2, 0xF2, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x90, 0xC0, 0xFF, 0x40, 0x50, 0xC0, 0x70, 0x80, 0x00, 0x80, 0xA0, 0xC0, 0xFF, 0xA0, 0x80, 0xC0, 0xC0, 0x80, 0x80, 0xC0, 0xF0, 0xC0, 0xB0, 0xA0, 0x50, 0x50, 0xC0, 0xC0, 0x80, 0x0F, 0x0F, 0x0B, 0x09, 0x09, 0x07, 0x0F, 0x0C, 0x0C, 0x00, 0x0F, 0x0C, 0x0F, 0x0B, 0x09, 0x07, 0x0F, 0x0C, 0x0F, 0x08, 0x0F, 0x0C, 0x0B, 0x09, 0x0F, 0x0F, 0x0C, 0x0F, 0x0F, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x10, 0x10, 0x80, 0x00, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x10, 0x20, 0x20, 0x40, 0x20, 0x20, 0x14, 0x80, 0x40, 0x12, 0x14, 0x20, 0x10, 0x40, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x10, 0x10, 0x80, 0x00, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x10, 0x20, 0x20, 0x40, 0x20, 0x20, 0x14, 0x20, 0x80, 0x12, 0x14, 0x20, 0x10, 0x40, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x10, 0x10, 0x80, 0x00, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x10, 0x20, 0x20, 0x40, 0x20, 0x20, 0x14, 0x10, 0x10, 0x12, 0x14, 0x20, 0x10, 0x40, 0xEF, 0xEF, 0x0F, 0x0F, 0xEF, 0xEF, 0x0F, 0x0F, 0xEF, 0xEF, 0xEF, 0xEF, 0x0F, 0x0F, 0xEF, 0xEF, 0x0F, 0x0F, 0xEF, 0xEF, 0xEF, 0xEF, 0x0F, 0x0F, 0xEF, 0xEF, 0xEF, 0x0F, 0x0F, 0xEF, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x10, 0x10, 0x00, 0x0C, 0x18, 0x24, 0x30, 0x10, 0x30, 0x50, 0x70, 0x90, 0xB0, 0xD0, 0xF0, 0xF0, 0xD0, 0xB0, 0x90, 0x70, 0x50, 0x30, 0x10, 0x00, 0x28, 0x50, 0x78, 0xA0, 0xC8, 0x00, 0x07, 0x0E, 0x00, 0x28, 0x50, 0x78, 0xA0, 0xC8, 0xF0, 0x18, 0x40, 0x68, 0x90, 0xB8, 0xE0, 0x08, 0x30, 0x58, 0x80, 0xA8, 0xD0, 0xF8, 0x20, 0x48, 0x70, 0x98, 0xC0, 0xE8, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x82, 0x4E, 0x4F, 0x54, 0x45, 0x20, 0x4F, 0x4E, 0x53, 0x00, 0x09, 0x82, 0x4E, 0x4F, 0x54, 0x45, 0x20, 0x4F, 0x46, 0x46, 0x53, 0x00, 0x0A, 0x82, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4D, 0x49, 0x44, 0x49, 0x00, 0x0B, 0x82, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x49, 0x4E, 0x00, 0x13, 0x82, 0x42, 0x55, 0x46, 0x46, 0x45, 0x52, 0x53, 0x20, 0x45, 0x54, 0x43, 0x00, 0xFF, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x45, 0x51, 0x55, 0x45, 0x4E, 0x54, 0x4C, 0x50, 0x41, 0x53, 0x53, 0x50, 0x4F, 0x52, 0x54, 0x20, 0x20, 0x20, 0x44, 0x41, 0x54, 0x45, 0x4C, 0x4E, 0x41, 0x4D, 0x45, 0x53, 0x4F, 0x46, 0x54, 0x4E, 0x4F, 0x4E, 0x45, 0x20, 0x20, 0x20, 0x20, 0x46, 0x49, 0x4C, 0x54, 0x31, 0x20, 0x20, 0x20, 0x46, 0x49, 0x4C, 0x54, 0x32, 0x20, 0x20, 0x20, 0x46, 0x49, 0x4C, 0x54, 0x33, 0x20, 0x20, 0x20, 0x46, 0x49, 0x4C, 0x54, 0x34, 0x20, 0x20, 0x20, 0x46, 0x49, 0x4C, 0x54, 0x35, 0x20, 0x20, 0x20, 0x50, 0x55, 0x4C, 0x53, 0x31, 0x20, 0x20, 0x20, 0x50, 0x55, 0x4C, 0x53, 0x32, 0x20, 0x20, 0x20, 0x50, 0x55, 0x4C, 0x53, 0x33, 0x20, 0x20, 0x20, 0x06, 0x82, 0x41, 0x4C, 0x4C, 0x20, 0x4F, 0x53, 0x31, 0x20, 0x4F, 0x53, 0x32, 0x20, 0x4F, 0x53, 0x33, 0x20, 0x20, 0x37, 0x20, 0x20, 0x36, 0x20, 0x20, 0x35, 0x20, 0x20, 0x34, 0x20, 0x20, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x00, 0x07, 0x81, 0x24, 0x32, 0x32, 0x20, 0x24, 0x30, 0x32, 0x20, 0x24, 0x30, 0x39, 0x20, 0x24, 0x31, 0x30, 0x87, 0x20, 0x20, 0x2B, 0x2D, 0x2D, 0x2D, 0x50, 0x55, 0x4C, 0x53, 0x45, 0x2D, 0x57, 0x49, 0x44, 0x54, 0x48, 0x2D, 0x4C, 0x4F, 0x57, 0x2D, 0x2D, 0x2D, 0x2B, 0x00, 0x08, 0x8E, 0x20, 0x56, 0x41, 0x4C, 0x20, 0x24, 0x20, 0x20, 0x20, 0x24, 0x20, 0x20, 0x20, 0x24, 0x00, 0x09, 0x81, 0x24, 0x32, 0x33, 0x20, 0x24, 0x30, 0x33, 0x20, 0x24, 0x30, 0x41, 0x20, 0x24, 0x31, 0x31, 0x87, 0x20, 0x20, 0x2E, 0x20, 0x20, 0x2E, 0x20, 0x20, 0x2E, 0x20, 0x20, 0x2E, 0x20, 0x20, 0x2B, 0x50, 0x55, 0x4C, 0x53, 0x2D, 0x48, 0x49, 0x47, 0x48, 0x2B, 0x00, 0x0A, 0x8E, 0x20, 0x56, 0x41, 0x4C, 0x20, 0x24, 0x20, 0x20, 0x20, 0x24, 0x20, 0x20, 0x20, 0x24, 0x00, 0x0B, 0x81, 0x24, 0x32, 0x34, 0x20, 0x24, 0x30, 0x34, 0x20, 0x24, 0x30, 0x42, 0x20, 0x24, 0x31, 0x32, 0x87, 0x20, 0x20, 0x4E, 0x4F, 0x20, 0x53, 0x51, 0x20, 0x53, 0x41, 0x20, 0x54, 0x52, 0x20, 0x54, 0x45, 0x20, 0x52, 0x49, 0x20, 0x53, 0x59, 0x20, 0x47, 0x54, 0x00, 0x0C, 0x8E, 0x20, 0x56, 0x41, 0x4C, 0x20, 0x24, 0x20, 0x20, 0x20, 0x24, 0x20, 0x20, 0x20, 0x24, 0x00, 0x0D, 0x81, 0x24, 0x32, 0x35, 0x20, 0x24, 0x30, 0x35, 0x20, 0x24, 0x30, 0x43, 0x20, 0x24, 0x31, 0x33, 0x87, 0x20, 0x20, 0x2B, 0x2D, 0x41, 0x54, 0x54, 0x41, 0x43, 0x4B, 0x2D, 0x2D, 0x2B, 0x20, 0x2B, 0x2D, 0x2D, 0x44, 0x45, 0x43, 0x41, 0x59, 0x2D, 0x2D, 0x2B, 0x00, 0x0E, 0x8E, 0x20, 0x56, 0x41, 0x4C, 0x20, 0x24, 0x20, 0x20, 0x20, 0x24, 0x20, 0x20, 0x20, 0x24, 0x00, 0x0F, 0x81, 0x24, 0x32, 0x36, 0x20, 0x24, 0x30, 0x36, 0x20, 0x24, 0x30, 0x44, 0x20, 0x24, 0x31, 0x34, 0x87, 0x20, 0x20, 0x2B, 0x2D, 0x53, 0x55, 0x53, 0x54, 0x41, 0x49, 0x4E, 0x2D, 0x2B, 0x20, 0x2B, 0x2D, 0x52, 0x45, 0x4C, 0x45, 0x41, 0x53, 0x45, 0x2D, 0x2B, 0x00, 0x10, 0x8E, 0x20, 0x56, 0x41, 0x4C, 0x20, 0x24, 0x20, 0x20, 0x20, 0x24, 0x20, 0x20, 0x20, 0x24, 0x00, 0x11, 0x82, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x00, 0x12, 0x82, 0x41, 0x4C, 0x4C, 0x20, 0x56, 0x41, 0x4C, 0x20, 0x20, 0x37, 0x20, 0x20, 0x36, 0x20, 0x20, 0x35, 0x20, 0x20, 0x34, 0x20, 0x20, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x8B, 0x20, 0x20, 0x50, 0x52, 0x45, 0x53, 0x53, 0x00, 0x13, 0x81, 0x24, 0x31, 0x35, 0x20, 0x8E, 0x24, 0x20, 0x20, 0x20, 0x20, 0x87, 0x2E, 0x20, 0x20, 0x2E, 0x20, 0x20, 0x2E, 0x20, 0x20, 0x2E, 0x20, 0x20, 0x2E, 0x20, 0x2B, 0x46, 0x49, 0x4C, 0x54, 0x2D, 0x4C, 0x4F, 0x2B, 0x8B, 0x20, 0x20, 0x27, 0x5F, 0x27, 0x20, 0x54, 0x4F, 0x00, 0x14, 0x81, 0x24, 0x31, 0x36, 0x20, 0x8E, 0x24, 0x20, 0x20, 0x20, 0x20, 0x87, 0x2B, 0x2D, 0x46, 0x49, 0x4C, 0x54, 0x45, 0x52, 0x2D, 0x43, 0x55, 0x54, 0x4F, 0x46, 0x46, 0x2D, 0x48, 0x49, 0x47, 0x48, 0x2D, 0x2D, 0x2B, 0x8B, 0x20, 0x20, 0x43, 0x41, 0x4E, 0x43, 0x45, 0x4C, 0x00, 0x15, 0x81, 0x24, 0x31, 0x37, 0x20, 0x8E, 0x24, 0x20, 0x20, 0x20, 0x20, 0x87, 0x2B, 0x46, 0x49, 0x4C, 0x54, 0x2D, 0x52, 0x45, 0x53, 0x2D, 0x2B, 0x20, 0x46, 0x58, 0x20, 0x46, 0x31, 0x20, 0x46, 0x32, 0x20, 0x46, 0x33, 0x8B, 0x20, 0x20, 0x00, 0x16, 0x81, 0x24, 0x31, 0x38, 0x20, 0x8E, 0x24, 0x20, 0x20, 0x20, 0x20, 0x87, 0x58, 0x58, 0x20, 0x48, 0x50, 0x20, 0x42, 0x50, 0x20, 0x4C, 0x50, 0x20, 0x2B, 0x2D, 0x56, 0x4F, 0x4C, 0x55, 0x4D, 0x45, 0x2D, 0x2D, 0x2B, 0x00, 0x17, 0x82, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x00, 0x18, 0x8B, 0x45, 0x4E, 0x54, 0x45, 0x52, 0x20, 0x32, 0x2D, 0x44, 0x49, 0x47, 0x49, 0x54, 0x20, 0x48, 0x45, 0x58, 0x20, 0x41, 0x44, 0x44, 0x52, 0x45, 0x53, 0x53, 0x20, 0x54, 0x48, 0x45, 0x4E, 0x20, 0x48, 0x45, 0x58, 0x20, 0x56, 0x41, 0x4C, 0x55, 0x45, 0x00, 0xFF, 0x52, 0x45, 0x54, 0x55, 0x52, 0x4E, 0x3D, 0x48, 0x45, 0x4C, 0x50, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x82, 0x43, 0x59, 0x4E, 0x54, 0x48, 0x43, 0x41, 0x52, 0x54, 0x20, 0x2D, 0x81, 0x4B, 0x45, 0x59, 0x20, 0x43, 0x4F, 0x4D, 0x4D, 0x41, 0x4E, 0x44, 0x53, 0x82, 0x2D, 0x8B, 0x20, 0x20, 0x52, 0x45, 0x54, 0x55, 0x52, 0x4E, 0x20, 0x54, 0x4F, 0x20, 0x45, 0x58, 0x49, 0x54, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x00, 0x01, 0x82, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x00, 0x02, 0x83, 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x8F, 0x20, 0x41, 0x4E, 0x44, 0x20, 0x83, 0x4E, 0x55, 0x4D, 0x42, 0x45, 0x52, 0x53, 0x20, 0x52, 0x4F, 0x57, 0x53, 0x8F, 0x20, 0x41, 0x52, 0x45, 0x20, 0x81, 0x50, 0x49, 0x41, 0x4E, 0x4F, 0x20, 0x4B, 0x45, 0x59, 0x53, 0x20, 0x20, 0x00, 0x03, 0x83, 0x41, 0x53, 0x44, 0x46, 0x8F, 0x20, 0x41, 0x4E, 0x44, 0x83, 0x20, 0x5A, 0x58, 0x43, 0x56, 0x20, 0x52, 0x4F, 0x57, 0x53, 0x8F, 0x20, 0x53, 0x45, 0x4C, 0x45, 0x43, 0x54, 0x81, 0x20, 0x53, 0x4F, 0x55, 0x4E, 0x44, 0x20, 0x50, 0x52, 0x45, 0x53, 0x45, 0x54, 0x53, 0x20, 0x00, 0x04, 0x83, 0x53, 0x50, 0x41, 0x43, 0x45, 0x8F, 0x3D, 0x42, 0x45, 0x4E, 0x44, 0x45, 0x52, 0x83, 0x20, 0x20, 0x43, 0x55, 0x52, 0x53, 0x4F, 0x52, 0x2D, 0x4B, 0x45, 0x59, 0x53, 0x8F, 0x3D, 0x46, 0x49, 0x46, 0x54, 0x48, 0x53, 0x2D, 0x4F, 0x4E, 0x2F, 0x4F, 0x46, 0x46, 0x00, 0x05, 0x83, 0x46, 0x55, 0x4E, 0x43, 0x54, 0x49, 0x4F, 0x4E, 0x2D, 0x4B, 0x45, 0x59, 0x53, 0x8F, 0x3D, 0x4F, 0x43, 0x54, 0x41, 0x56, 0x45, 0x83, 0x20, 0x5F, 0x8F, 0x3D, 0x4C, 0x4F, 0x41, 0x44, 0x2D, 0x43, 0x55, 0x53, 0x54, 0x4F, 0x4D, 0x2D, 0x53, 0x4F, 0x55, 0x4E, 0x44, 0x00, 0x06, 0x82, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x00, 0x07, 0x81, 0x50, 0x52, 0x45, 0x53, 0x53, 0x20, 0x43, 0x54, 0x52, 0x4C, 0x20, 0x2B, 0x00, 0x08, 0x8D, 0x41, 0x53, 0x44, 0x8F, 0x3D, 0x52, 0x45, 0x4C, 0x45, 0x41, 0x53, 0x45, 0x2D, 0x54, 0x49, 0x4D, 0x45, 0x20, 0x8D, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A, 0x3B, 0x8F, 0x3D, 0x53, 0x4F, 0x55, 0x4E, 0x44, 0x2D, 0x4D, 0x4F, 0x44, 0x45, 0x00, 0x09, 0x8D, 0x5A, 0x58, 0x43, 0x56, 0x42, 0x4E, 0x4D, 0x8F, 0x3D, 0x4D, 0x4F, 0x44, 0x2D, 0x4D, 0x4F, 0x44, 0x45, 0x20, 0x8D, 0x46, 0x31, 0x2D, 0x46, 0x37, 0x8F, 0x3D, 0x56, 0x4F, 0x4C, 0x20, 0x48, 0x49, 0x2F, 0x4D, 0x45, 0x44, 0x2F, 0x4C, 0x4F, 0x2F, 0x4F, 0x46, 0x46, 0x00, 0x0A, 0x82, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x00, 0x0B, 0x81, 0x50, 0x52, 0x45, 0x53, 0x53, 0x20, 0x53, 0x48, 0x49, 0x46, 0x54, 0x20, 0x2B, 0x00, 0x0C, 0x8A, 0x41, 0x53, 0x44, 0x8F, 0x3D, 0x41, 0x54, 0x54, 0x41, 0x43, 0x4B, 0x20, 0x20, 0x8A, 0x46, 0x47, 0x48, 0x8F, 0x3D, 0x56, 0x49, 0x44, 0x2D, 0x53, 0x54, 0x59, 0x4C, 0x45, 0x8A, 0x20, 0x4A, 0x4B, 0x4C, 0x8F, 0x3D, 0x56, 0x49, 0x44, 0x2D, 0x4F, 0x4E, 0x2F, 0x4F, 0x46, 0x46, 0x00, 0x0D, 0x8A, 0x5A, 0x58, 0x43, 0x56, 0x8F, 0x3D, 0x54, 0x52, 0x45, 0x4D, 0x2D, 0x53, 0x50, 0x44, 0x20, 0x8A, 0x42, 0x4E, 0x4D, 0x2C, 0x8F, 0x3D, 0x54, 0x52, 0x45, 0x4D, 0x2D, 0x4C, 0x45, 0x56, 0x4C, 0x8A, 0x20, 0x3B, 0x3A, 0x8F, 0x3D, 0x56, 0x49, 0x44, 0x2D, 0x53, 0x49, 0x5A, 0x45, 0x00, 0x0E, 0x8A, 0x43, 0x55, 0x52, 0x53, 0x4F, 0x52, 0x2D, 0x4B, 0x45, 0x59, 0x53, 0x8F, 0x3D, 0x50, 0x41, 0x44, 0x44, 0x4C, 0x45, 0x31, 0x2D, 0x4F, 0x4E, 0x2F, 0x4F, 0x46, 0x46, 0x00, 0x0F, 0x8A, 0x46, 0x31, 0x2D, 0x46, 0x37, 0x8F, 0x3D, 0x50, 0x4F, 0x52, 0x54, 0x41, 0x4D, 0x45, 0x4E, 0x54, 0x4F, 0x20, 0x8A, 0x52, 0x45, 0x54, 0x55, 0x52, 0x4E, 0x8F, 0x3D, 0x43, 0x4C, 0x45, 0x41, 0x52, 0x2D, 0x4D, 0x4F, 0x44, 0x55, 0x4C, 0x41, 0x54, 0x49, 0x4F, 0x4E, 0x00, 0x10, 0x82, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x00, 0x11, 0x81, 0x50, 0x52, 0x45, 0x53, 0x53, 0x20, 0x43, 0x4F, 0x4D, 0x4D, 0x4F, 0x44, 0x4F, 0x52, 0x45, 0x2D, 0x4B, 0x45, 0x59, 0x20, 0x2B, 0x00, 0x12, 0x8E, 0x41, 0x53, 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x8F, 0x3D, 0x46, 0x49, 0x58, 0x45, 0x44, 0x2D, 0x43, 0x55, 0x54, 0x4F, 0x46, 0x46, 0x20, 0x20, 0x8E, 0x2C, 0x2E, 0x2F, 0x8F, 0x3D, 0x4F, 0x4D, 0x4E, 0x49, 0x2F, 0x43, 0x48, 0x31, 0x2F, 0x43, 0x48, 0x35, 0x00, 0x13, 0x8E, 0x5A, 0x58, 0x43, 0x8F, 0x3D, 0x46, 0x49, 0x4C, 0x54, 0x2D, 0x4F, 0x4E, 0x2F, 0x4F, 0x46, 0x46, 0x2F, 0x44, 0x49, 0x53, 0x41, 0x42, 0x4C, 0x45, 0x8E, 0x20, 0x56, 0x42, 0x4E, 0x4D, 0x8F, 0x3D, 0x50, 0x41, 0x44, 0x44, 0x4C, 0x45, 0x32, 0x00, 0x14, 0x82, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x00, 0x15, 0x81, 0x50, 0x52, 0x45, 0x53, 0x53, 0x20, 0x52, 0x55, 0x4E, 0x2D, 0x53, 0x54, 0x4F, 0x50, 0x20, 0x2B, 0x00, 0x16, 0x87, 0x41, 0x53, 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A, 0x3B, 0x8F, 0x3D, 0x54, 0x55, 0x4E, 0x49, 0x4E, 0x47, 0x87, 0x20, 0x20, 0x2E, 0x2F, 0x8F, 0x3D, 0x50, 0x41, 0x4C, 0x2F, 0x4E, 0x54, 0x53, 0x43, 0x00, 0x17, 0x87, 0x5A, 0x58, 0x43, 0x56, 0x42, 0x4E, 0x4D, 0x8F, 0x3D, 0x81, 0x4D, 0x4F, 0x52, 0x45, 0x8F, 0x2D, 0x81, 0x50, 0x52, 0x45, 0x53, 0x45, 0x54, 0x53, 0x20, 0x20, 0x87, 0x46, 0x31, 0x8F, 0x3D, 0x53, 0x49, 0x44, 0x2D, 0x45, 0x44, 0x49, 0x54, 0x2D, 0x43, 0x36, 0x34, 0x4B, 0x45, 0x59, 0x53, 0x00, 0x18, 0x87, 0x46, 0x33, 0x8F, 0x3D, 0x53, 0x41, 0x56, 0x45, 0x2D, 0x43, 0x55, 0x53, 0x54, 0x4F, 0x4D, 0x2D, 0x53, 0x4F, 0x55, 0x4E, 0x44, 0x20, 0x20, 0x87, 0x46, 0x37, 0x8F, 0x3D, 0x53, 0x49, 0x44, 0x2D, 0x45, 0x44, 0x49, 0x54, 0x2D, 0x50, 0x49, 0x41, 0x4E, 0x4F, 0x20, 0x00, 0xFF, 0x00, 0x82, 0x43, 0x59, 0x4E, 0x54, 0x48, 0x43, 0x41, 0x52, 0x54, 0x20, 0x20, 0x8F, 0x50, 0x52, 0x45, 0x53, 0x45, 0x54, 0x8C, 0x3D, 0x81, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x8A, 0x4D, 0x4F, 0x44, 0x45, 0x8C, 0x3D, 0x81, 0x58, 0x20, 0x20, 0x20, 0x20, 0x83, 0x20, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x8D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x8F, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x20, 0x8D, 0x46, 0x49, 0x4C, 0x54, 0x52, 0x8C, 0x3D, 0x81, 0x58, 0x20, 0x20, 0x20, 0x00, 0x02, 0x8F, 0x54, 0x55, 0x4E, 0x49, 0x4E, 0x47, 0x8C, 0x3D, 0x81, 0x58, 0x20, 0x20, 0x20, 0x83, 0x41, 0x54, 0x54, 0x41, 0x43, 0x4B, 0x8C, 0x3D, 0x81, 0x58, 0x20, 0x87, 0x54, 0x52, 0x45, 0x4D, 0x4F, 0x4C, 0x4F, 0x8C, 0x3D, 0x81, 0x58, 0x20, 0x8D, 0x43, 0x55, 0x54, 0x4F, 0x46, 0x46, 0x8C, 0x3D, 0x81, 0x58, 0x20, 0x20, 0x00, 0x03, 0x8F, 0x4F, 0x43, 0x54, 0x41, 0x56, 0x45, 0x8C, 0x3D, 0x81, 0x58, 0x20, 0x20, 0x20, 0x83, 0x52, 0x45, 0x4C, 0x45, 0x41, 0x53, 0x8C, 0x3D, 0x81, 0x58, 0x20, 0x87, 0x54, 0x52, 0x4D, 0x2D, 0x53, 0x50, 0x44, 0x8C, 0x3D, 0x81, 0x58, 0x20, 0x8D, 0x50, 0x41, 0x44, 0x44, 0x31, 0x8C, 0x3D, 0x81, 0x58, 0x20, 0x20, 0x20, 0x00, 0x04, 0x8F, 0x56, 0x4F, 0x4C, 0x55, 0x4D, 0x45, 0x8C, 0x3D, 0x81, 0x58, 0x20, 0x20, 0x20, 0x8F, 0x4D, 0x4F, 0x44, 0x8C, 0x3D, 0x81, 0x58, 0x58, 0x58, 0x58, 0x58, 0x20, 0x8F, 0x20, 0x56, 0x49, 0x44, 0x45, 0x4F, 0x8C, 0x3D, 0x81, 0x58, 0x20, 0x8F, 0x50, 0x41, 0x44, 0x44, 0x32, 0x8C, 0x3D, 0x81, 0x58, 0x20, 0x20, 0x20, 0x00, 0x17, 0x82, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0xFF, 0x4F, 0x46, 0x46, 0x20, 0x4F, 0x4E, 0x20, 0x20, 0x53, 0x4C, 0x4F, 0x57, 0x4D, 0x45, 0x44, 0x20, 0x46, 0x41, 0x53, 0x54, 0x2D, 0x34, 0x30, 0x20, 0x2D, 0x33, 0x30, 0x20, 0x2D, 0x32, 0x30, 0x20, 0x2D, 0x31, 0x30, 0x20, 0x30, 0x20, 0x20, 0x20, 0x2B, 0x31, 0x30, 0x20, 0x2B, 0x32, 0x30, 0x20, 0x2B, 0x33, 0x30, 0x20, 0x2B, 0x34, 0x30, 0x20, 0x2B, 0x35, 0x30, 0x20, 0x50, 0x4F, 0x4C, 0x59, 0x4D, 0x4F, 0x4E, 0x4F, 0x46, 0x52, 0x45, 0x51, 0x46, 0x49, 0x4C, 0x54, 0x56, 0x4F, 0x4C, 0x20, 0x4C, 0x4F, 0x57, 0x20, 0x4D, 0x45, 0x44, 0x20, 0x48, 0x49, 0x47, 0x48, 0x53, 0x49, 0x44, 0x3A, 0x44, 0x49, 0x53, 0x20, 0x4F, 0x46, 0x46, 0x20, 0x50, 0x55, 0x4C, 0x53, 0x58, 0x58, 0x58, 0x58, 0x4C, 0x46, 0x4F, 0x20, 0x42, 0x45, 0x4E, 0x44, 0x50, 0x4F, 0x4C, 0x59, 0x20, 0x20, 0x20, 0x03, 0x50, 0x4F, 0x52, 0x54, 0x31, 0x20, 0x20, 0x03, 0x50, 0x4F, 0x52, 0x54, 0x32, 0x20, 0x20, 0x03, 0x50, 0x4F, 0x52, 0x54, 0x33, 0x20, 0x20, 0x03, 0x4D, 0x4F, 0x4E, 0x4F, 0x31, 0x20, 0x20, 0x01, 0x4D, 0x4F, 0x4E, 0x4F, 0x32, 0x20, 0x20, 0x01, 0x4D, 0x4F, 0x4E, 0x50, 0x31, 0x20, 0x20, 0x01, 0x41, 0x52, 0x50, 0x31, 0x20, 0x20, 0x20, 0x07, 0x41, 0x52, 0x50, 0x32, 0x20, 0x20, 0x20, 0x07, 0x41, 0x52, 0x50, 0x33, 0x20, 0x20, 0x20, 0x07, 0x41, 0x52, 0x50, 0x34, 0x20, 0x20, 0x20, 0x07, 0x41, 0x52, 0x50, 0x35, 0x20, 0x20, 0x20, 0x07, 0x36, 0x43, 0x48, 0x41, 0x4E, 0x20, 0x20, 0x06, 0x35, 0x54, 0x48, 0x53, 0x20, 0x20, 0x20, 0x03, 0x35, 0x50, 0x4F, 0x52, 0x54, 0x20, 0x20, 0x03, 0x4D, 0x4F, 0x4E, 0x50, 0x32, 0x20, 0x20, 0x01, 0x00, 0x68, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x28, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x78, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x40, 0x48, 0x50, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x50, 0x41, 0x4C, 0x20, 0x56, 0x32, 0x2E, 0x30, 0x2E, 0x31, 0x00, 0x4E, 0x54, 0x53, 0x43, 0x20, 0x56, 0x32, 0x2E, 0x30, 0x2E, 0x31, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x62, 0xF2, 0x82, 0xCA, 0x66, 0xBA, 0x02, 0x4A, 0xDA, 0x6A, 0x35, 0x35, 0x36, 0x36, 0x37, 0x37, 0x38, 0x38, 0x38, 0x39, 0xAA, 0x3A, 0x1E, 0x12, 0x66, 0x66, 0x72, 0x92, 0x22, 0xB2, 0x35, 0x36, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x39, 0x39, 0x00, 0x02, 0x05, 0x0F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x01, 0x02, 0x03, 0x02, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x06, 0x07, 0x08, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x02, 0x03, 0x04, 0x05, 0x18, 0x38, 0x5A, 0x7D, 0xA3, 0xCB, 0xF6, 0x23, 0x53, 0x86, 0xBB, 0xF4, 0x30, 0x7A, 0xB4, 0xFB, 0x47, 0x97, 0xED, 0x47, 0xA7, 0x0C, 0x77, 0xE9, 0x61, 0xE1, 0x68, 0xF7, 0x8F, 0x2F, 0xDA, 0x8E, 0x4D, 0x18, 0xEE, 0xD2, 0xC3, 0xC3, 0xD1, 0xEF, 0x1F, 0x60, 0xB5, 0x1E, 0x9C, 0x31, 0xDF, 0xA5, 0x87, 0x86, 0xA2, 0xDF, 0x3E, 0xC1, 0x6B, 0x3C, 0x39, 0x63, 0xBE, 0x4B, 0x0F, 0x0C, 0x45, 0xBF, 0x7D, 0x83, 0xD6, 0x79, 0x73, 0xC7, 0x7C, 0x97, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, 0x07, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0x0A, 0x0B, 0x0B, 0x0C, 0x0D, 0x0E, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x15, 0x16, 0x17, 0x19, 0x1A, 0x1C, 0x1D, 0x1F, 0x21, 0x23, 0x25, 0x27, 0x2A, 0x2C, 0x2F, 0x32, 0x35, 0x38, 0x3B, 0x3F, 0x43, 0x47, 0x4B, 0x4F, 0x54, 0x59, 0x5E, 0x64, 0x6A, 0x70, 0x77, 0x7E, 0x2D, 0x4E, 0x71, 0x96, 0xBE, 0xE7, 0x14, 0x42, 0x74, 0xA9, 0xE0, 0x1B, 0x5A, 0x9C, 0xE2, 0x2D, 0x7B, 0xCF, 0x27, 0x85, 0xE8, 0x51, 0xC1, 0x37, 0xB4, 0x38, 0xC4, 0x59, 0xF7, 0x9E, 0x4E, 0x0A, 0xD0, 0xA2, 0x81, 0x6D, 0x67, 0x70, 0x89, 0xB2, 0xED, 0x3B, 0x9D, 0x14, 0xA0, 0x45, 0x03, 0xDB, 0xCF, 0xE1, 0x12, 0x65, 0xDB, 0x76, 0x3A, 0x27, 0x41, 0x8A, 0x05, 0xB5, 0x9D, 0xC1, 0x24, 0xC9, 0xB6, 0xED, 0x73, 0x4E, 0x82, 0x14, 0x0A, 0x6A, 0x3B, 0x82, 0x48, 0x93, 0x6B, 0xDA, 0xE7, 0x9C, 0x04, 0x28, 0x14, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0x0A, 0x0A, 0x0B, 0x0C, 0x0D, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x17, 0x18, 0x1A, 0x1B, 0x1D, 0x1F, 0x20, 0x22, 0x24, 0x27, 0x29, 0x2B, 0x2E, 0x31, 0x34, 0x37, 0x3A, 0x3E, 0x41, 0x45, 0x49, 0x4E, 0x52, 0x57, 0x5C, 0x62, 0x68, 0x6E, 0x75, 0x7C, 0x83, 0x8B, 0x93, 0x9C, 0xA5, 0xAF, 0xB9, 0xC4, 0xD0, 0xDD, 0xEA, 0xF8, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0, 0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE8, 0xE3, 0xE9, 0xE4, 0xE2, 0xE0, 0xDE, 0xDC, 0xDA, 0xD8, 0xD6, 0xD3, 0xD0, 0xCD, 0xCA, 0xC7, 0xC4, 0xC0, 0xBC, 0xB8, 0xB4, 0xAF, 0xAB, 0xA5, 0xA0, 0x9A, 0x94, 0x8E, 0x87, 0x80, 0x78, 0x70, 0x68, 0x5E, 0xA4, 0xFB, 0x40, 0x34, 0x28, 0x1B, 0x0E, 0xFF, 0xF0, 0xE0, 0xCE, 0xBC, 0xA9, 0x95, 0x7F, 0x68, 0x50, 0x36, 0x1B, 0xFE, 0xDF, 0xBF, 0x9C, 0x78, 0x52, 0x29, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFC, 0xF7, 0xF6, 0xF6, 0xF5, 0xF4, 0xF4, 0xF3, 0xF2, 0xF1, 0xF1, 0xEF, 0xEE, 0xEA, 0xEF, 0xEB, 0xEA, 0xE8, 0xE7, 0xE5, 0xE4, 0xE2, 0xE0, 0xDE, 0xDC, 0xDA, 0xD8, 0xD6, 0xD3, 0xD0, 0xCD, 0xCA, 0xC7, 0xC4, 0xC0, 0xBC, 0xB8, 0xB4, 0xAF, 0xAB, 0xA5, 0xA0, 0x9A, 0x94, 0x8E, 0x87, 0xBB, 0x3C, 0x70, 0x67, 0x5E, 0x55, 0x4A, 0x40, 0x34, 0x28, 0x1B, 0x0D, 0xFF, 0xF0, 0xDF, 0xCE, 0xBC, 0xA9, 0x94, 0x7F, 0x68, 0x50, 0x35, 0x1A, 0xFD, 0xDF, 0xBE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFD, 0xFA, 0xFA, 0xF9, 0xF9, 0xF8, 0xF8, 0xF7, 0xF7, 0xF6, 0xF6, 0xF5, 0xF4, 0xF2, 0xF5, 0xF2, 0xF1, 0xF0, 0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE8, 0xE7, 0xE5, 0xE4, 0xE2, 0xE0, 0xDE, 0xDC, 0xDA, 0xD8, 0xD6, 0xD3, 0xD0, 0xCD, 0xCA, 0xC7, 0xC4, 0xC0, 0xBC, 0xB8, 0xB4, 0xAF, 0xD2, 0x7E, 0xA0, 0x9A, 0x94, 0x8E, 0x87, 0x80, 0x78, 0x70, 0x67, 0x5E, 0x55, 0x4B, 0x40, 0x34, 0x28, 0x1B, 0x0E, 0xFF, 0xF0, 0xE0, 0xCE, 0xBC, 0xA9, 0x95, 0x7F, 0xFD, 0xFD, 0xFD, 0xFD, 0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0xFB, 0xFB, 0xFA, 0xF9, 0xFB, 0xF9, 0xF9, 0xF8, 0xF8, 0xF7, 0xF7, 0xF6, 0xF6, 0xF5, 0xF4, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0, 0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE8, 0xE7, 0xE5, 0xE4, 0xE2, 0xE0, 0xDE, 0xDC, 0xDA, 0xD8, 0xE9, 0xBF, 0xD0, 0xCD, 0xCA, 0xC7, 0xC4, 0xC0, 0xBC, 0xB8, 0xB4, 0xAF, 0xAB, 0xA6, 0xA0, 0x9A, 0x94, 0x8E, 0x87, 0x80, 0x78, 0x70, 0x67, 0x5E, 0x55, 0x4B, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x05, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0x0A, 0x0A, 0x0B, 0x0C, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x18, 0x19, 0x1B, 0x1C, 0x1E, 0x20, 0x22, 0x24, 0x26, 0x28, 0x17, 0x41, 0x30, 0x33, 0x36, 0x39, 0x3C, 0x40, 0x44, 0x48, 0x4C, 0x51, 0x55, 0x5A, 0x60, 0x66, 0x6C, 0x72, 0x79, 0x80, 0x88, 0x90, 0x99, 0xA2, 0xAB, 0xB5, 0xC0, 0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0x0A, 0x0A, 0x0B, 0x0C, 0x0E, 0x0B, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x18, 0x19, 0x1B, 0x1C, 0x1E, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2D, 0x30, 0x33, 0x36, 0x39, 0x3C, 0x40, 0x44, 0x48, 0x4C, 0x51, 0x2E, 0x82, 0x60, 0x66, 0x6C, 0x72, 0x79, 0x80, 0x88, 0x90, 0x99, 0xA2, 0xAB, 0xB5, 0xC0, 0xCC, 0xD8, 0xE5, 0xF2, 0x01, 0x10, 0x20, 0x32, 0x44, 0x57, 0x6B, 0x81, 0x09, 0x0A, 0x0A, 0x0B, 0x0C, 0x0C, 0x0D, 0x0E, 0x0F, 0x0F, 0x11, 0x12, 0x16, 0x11, 0x15, 0x16, 0x18, 0x19, 0x1B, 0x1C, 0x1E, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2D, 0x30, 0x33, 0x36, 0x39, 0x3C, 0x40, 0x44, 0x48, 0x4C, 0x51, 0x55, 0x5B, 0x60, 0x66, 0x6C, 0x72, 0x79, 0x45, 0xC4, 0x90, 0x99, 0xA2, 0xAB, 0xB6, 0xC0, 0xCC, 0xD8, 0xE5, 0xF3, 0x01, 0x10, 0x21, 0x32, 0x44, 0x57, 0x6C, 0x81, 0x98, 0xB0, 0xCB, 0xE6, 0x03, 0x21, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x18, 0x1D, 0x17, 0x1C, 0x1E, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2D, 0x30, 0x33, 0x36, 0x39, 0x3C, 0x40, 0x44, 0x48, 0x4C, 0x51, 0x55, 0x5B, 0x60, 0x66, 0x6C, 0x72, 0x79, 0x80, 0x88, 0x90, 0x98, 0xA2, 0x5C, 0x05, 0xC0, 0xCC, 0xD8, 0xE5, 0xF2, 0x01, 0x10, 0x20, 0x32, 0x44, 0x57, 0x6B, 0x81, 0x98, 0xB0, 0xCA, 0xE5, 0x02, 0x21, 0x41, 0x64, 0x88, 0xAE, 0xD7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x10, 0x11, 0x11, 0x13, 0x14, 0x15, 0x16, 0x18, 0x19, 0x1A, 0x1C, 0x1E, 0x25, 0x1D, 0x23, 0x26, 0x28, 0x2B, 0x2D, 0x30, 0x32, 0x35, 0x39, 0x3C, 0x40, 0x43, 0x47, 0x4C, 0x50, 0x55, 0x5A, 0x5F, 0x65, 0x6B, 0x72, 0x78, 0x80, 0x87, 0x8F, 0x98, 0xA0, 0xAA, 0xB4, 0xBF, 0xCA, 0x73, 0x47, 0xF1, 0xFF, 0x0E, 0x1E, 0x2F, 0x41, 0x55, 0x68, 0x7E, 0x95, 0xAD, 0xC6, 0xE2, 0xFE, 0x1C, 0x3D, 0x5F, 0x83, 0xA9, 0xD1, 0xFD, 0x2A, 0x5A, 0x8D, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0xA9, 0x03, 0x60, 0x85, 0x6E, 0xA5, 0x6E, 0xAA, 0xCA, 0x78, 0xBD, 0x55, 0x3B, 0x85, 0x64, 0xBD, 0x59, 0x3B, 0x85, 0x66, 0xBD, 0x5D, 0x3B, 0x85, 0x68, 0xBD, 0x61, 0x3B, 0x85, 0x6A, 0xA9, 0xDE, 0x85, 0x65, 0x85, 0x67, 0x85, 0x69, 0x85, 0x6B, 0x20, 0xEC, 0x3A, 0xA2, 0x00, 0xCA, 0xD0, 0xFD, 0xB1, 0x66, 0x11, 0x66, 0x11, 0x66, 0x8D, 0xA0, 0x04, 0x8D, 0x50, 0x04, 0xA9, 0xB4, 0x1D, 0x65, 0x3B, 0x91, 0x64, 0xA2, 0x00, 0xCA, 0xD0, 0xFD, 0xA0, 0x00, 0xB1, 0x66, 0x11, 0x66, 0x11, 0x66, 0x8D, 0xA1, 0x04, 0x8D, 0x51, 0x04, 0xAD, 0x50, 0x04, 0xD0, 0x08, 0xAD, 0x51, 0x04, 0xF0, 0x03, 0x4C, 0x6B, 0x3A, 0xA6, 0x6E, 0xCA, 0x86, 0x6E, 0xF0, 0x03, 0x4C, 0xFF, 0x39, 0xA9, 0x00, 0x85, 0x6E, 0x20, 0xEC, 0x3A, 0xA5, 0x6E, 0x58, 0x60, 0x78, 0x85, 0x6E, 0xAA, 0xCA, 0xA9, 0xFF, 0x8D, 0x02, 0xDC, 0xA9, 0x00, 0x8D, 0x03, 0xDC, 0xA9, 0x00, 0x85, 0x71, 0x85, 0x6F, 0x85, 0x70, 0xBD, 0x55, 0x3B, 0x85, 0x64, 0xBD, 0x59, 0x3B, 0x85, 0x66, 0xBD, 0x5D, 0x3B, 0x85, 0x68, 0xBD, 0x61, 0x3B, 0x85, 0x6A, 0xA9, 0xDE, 0x85, 0x65, 0x85, 0x67, 0x85, 0x69, 0x85, 0x6B, 0x20, 0xEC, 0x3A, 0xA9, 0x00, 0x85, 0x6C, 0x85, 0x6D, 0xBD, 0x69, 0x3B, 0xD0, 0x0A, 0xA9, 0x15, 0x8D, 0x18, 0x03, 0xA9, 0x3B, 0x8D, 0x19, 0x03, 0xA9, 0x2B, 0x8D, 0x14, 0x03, 0xA9, 0x3B, 0x8D, 0x15, 0x03, 0xA9, 0x94, 0x1D, 0x65, 0x3B, 0x91, 0x64, 0x58, 0x60, 0x78, 0x20, 0xEC, 0x3A, 0xA9, 0x31, 0x8D, 0x14, 0x03, 0xA9, 0xEA, 0x8D, 0x15, 0x03, 0xA9, 0x47, 0x8D, 0x18, 0x03, 0xA9, 0xFE, 0x8D, 0x19, 0x03, 0x58, 0x60, 0xA0, 0x00, 0xA9, 0x03, 0x91, 0x64, 0x60, 0xA6, 0x6C, 0xE4, 0x6D, 0x60, 0xA6, 0x6C, 0xE4, 0x6D, 0xD0, 0x0A, 0x60, 0xA6, 0x6C, 0xE4, 0x6D, 0xD0, 0x03, 0x4C, 0xFF, 0x3A, 0xBD, 0x00, 0x7F, 0xA8, 0xE8, 0x8A, 0x29, 0xFF, 0x85, 0x6C, 0x98, 0x60, 0x60, 0x48, 0x8A, 0x48, 0x98, 0x48, 0xA0, 0x00, 0xB1, 0x66, 0x29, 0x01, 0xF0, 0x03, 0x20, 0x47, 0x3B, 0x68, 0xA8, 0x68, 0xAA, 0x68, 0x40, 0xA6, 0x6E, 0xCA, 0xBD, 0x69, 0x3B, 0xF0, 0x0E, 0xA0, 0x00, 0xB1, 0x66, 0x29, 0x01, 0xF0, 0x06, 0x20, 0x47, 0x3B, 0x4C, 0x25, 0x3B, 0xAD, 0x0D, 0xDC, 0x4C, 0x25, 0x3B, 0xB1, 0x6A, 0xA6, 0x6D, 0x9D, 0x00, 0x7F, 0xE8, 0x8A, 0x29, 0xFF, 0x85, 0x6D, 0x60, 0x00, 0x08, 0x04, 0x00, 0x02, 0x08, 0x06, 0x02, 0x01, 0x09, 0x05, 0x01, 0x03, 0x09, 0x07, 0x03, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00}; +#endif /* _BIN_CYNTHCART_ */ diff --git a/lib/emulator/flash/kernal.h b/lib/emulator/flash/kernal.h new file mode 100644 index 0000000..2b4e671 --- /dev/null +++ b/lib/emulator/flash/kernal.h @@ -0,0 +1,4 @@ +#ifndef _BIN_KERNAL_ +#define _BIN_KERNAL_ +unsigned char __in_flash("usbsid_binary") kernal[] = {0x85, 0x56, 0x20, 0x0F, 0xBC, 0xA5, 0x61, 0xC9, 0x88, 0x90, 0x03, 0x20, 0xD4, 0xBA, 0x20, 0xCC, 0xBC, 0xA5, 0x07, 0x18, 0x69, 0x81, 0xF0, 0xF3, 0x38, 0xE9, 0x01, 0x48, 0xA2, 0x05, 0xB5, 0x69, 0xB4, 0x61, 0x95, 0x61, 0x94, 0x69, 0xCA, 0x10, 0xF5, 0xA5, 0x56, 0x85, 0x70, 0x20, 0x53, 0xB8, 0x20, 0xB4, 0xBF, 0xA9, 0xC4, 0xA0, 0xBF, 0x20, 0x59, 0xE0, 0xA9, 0x00, 0x85, 0x6F, 0x68, 0x20, 0xB9, 0xBA, 0x60, 0x85, 0x71, 0x84, 0x72, 0x20, 0xCA, 0xBB, 0xA9, 0x57, 0x20, 0x28, 0xBA, 0x20, 0x5D, 0xE0, 0xA9, 0x57, 0xA0, 0x00, 0x4C, 0x28, 0xBA, 0x85, 0x71, 0x84, 0x72, 0x20, 0xC7, 0xBB, 0xB1, 0x71, 0x85, 0x67, 0xA4, 0x71, 0xC8, 0x98, 0xD0, 0x02, 0xE6, 0x72, 0x85, 0x71, 0xA4, 0x72, 0x20, 0x28, 0xBA, 0xA5, 0x71, 0xA4, 0x72, 0x18, 0x69, 0x05, 0x90, 0x01, 0xC8, 0x85, 0x71, 0x84, 0x72, 0x20, 0x67, 0xB8, 0xA9, 0x5C, 0xA0, 0x00, 0xC6, 0x67, 0xD0, 0xE4, 0x60, 0x98, 0x35, 0x44, 0x7A, 0x00, 0x68, 0x28, 0xB1, 0x46, 0x00, 0x20, 0x2B, 0xBC, 0x30, 0x37, 0xD0, 0x20, 0x20, 0xF3, 0xFF, 0x86, 0x22, 0x84, 0x23, 0xA0, 0x04, 0xB1, 0x22, 0x85, 0x62, 0xC8, 0xB1, 0x22, 0x85, 0x64, 0xA0, 0x08, 0xB1, 0x22, 0x85, 0x63, 0xC8, 0xB1, 0x22, 0x85, 0x65, 0x4C, 0xE3, 0xE0, 0xA9, 0x8B, 0xA0, 0x00, 0x20, 0xA2, 0xBB, 0xA9, 0x8D, 0xA0, 0xE0, 0x20, 0x28, 0xBA, 0xA9, 0x92, 0xA0, 0xE0, 0x20, 0x67, 0xB8, 0xA6, 0x65, 0xA5, 0x62, 0x85, 0x65, 0x86, 0x62, 0xA6, 0x63, 0xA5, 0x64, 0x85, 0x63, 0x86, 0x64, 0xA9, 0x00, 0x85, 0x66, 0xA5, 0x61, 0x85, 0x70, 0xA9, 0x80, 0x85, 0x61, 0x20, 0xD7, 0xB8, 0xA2, 0x8B, 0xA0, 0x00, 0x4C, 0xD4, 0xBB, 0xC9, 0xF0, 0xD0, 0x07, 0x84, 0x38, 0x86, 0x37, 0x4C, 0x63, 0xA6, 0xAA, 0xD0, 0x02, 0xA2, 0x1E, 0x4C, 0x37, 0xA4, 0x20, 0xD2, 0xFF, 0xB0, 0xE8, 0x60, 0x20, 0xCF, 0xFF, 0xB0, 0xE2, 0x60, 0x20, 0xAD, 0xE4, 0xB0, 0xDC, 0x60, 0x20, 0xC6, 0xFF, 0xB0, 0xD6, 0x60, 0x20, 0xE4, 0xFF, 0xB0, 0xD0, 0x60, 0x20, 0x8A, 0xAD, 0x20, 0xF7, 0xB7, 0xA9, 0xE1, 0x48, 0xA9, 0x46, 0x48, 0xAD, 0x0F, 0x03, 0x48, 0xAD, 0x0C, 0x03, 0xAE, 0x0D, 0x03, 0xAC, 0x0E, 0x03, 0x28, 0x6C, 0x14, 0x00, 0x08, 0x8D, 0x0C, 0x03, 0x8E, 0x0D, 0x03, 0x8C, 0x0E, 0x03, 0x68, 0x8D, 0x0F, 0x03, 0x60, 0x20, 0xD4, 0xE1, 0xA6, 0x2D, 0xA4, 0x2E, 0xA9, 0x2B, 0x20, 0xD8, 0xFF, 0xB0, 0x95, 0x60, 0xA9, 0x01, 0x2C, 0xA9, 0x00, 0x85, 0x0A, 0x20, 0xD4, 0xE1, 0xA5, 0x0A, 0xA6, 0x2B, 0xA4, 0x2C, 0x20, 0xD5, 0xFF, 0xB0, 0x57, 0xA5, 0x0A, 0xF0, 0x17, 0xA2, 0x1C, 0x20, 0xB7, 0xFF, 0x29, 0x10, 0xD0, 0x17, 0xA5, 0x7A, 0xC9, 0x02, 0xF0, 0x07, 0xA9, 0x64, 0xA0, 0xA3, 0x4C, 0x1E, 0xAB, 0x60, 0x20, 0xB7, 0xFF, 0x29, 0xBF, 0xF0, 0x05, 0xA2, 0x1D, 0x4C, 0x37, 0xA4, 0xA5, 0x7B, 0xC9, 0x02, 0xD0, 0x0E, 0x86, 0x2D, 0x84, 0x2E, 0xA9, 0x76, 0xA0, 0xA3, 0x20, 0x1E, 0xAB, 0x4C, 0x2A, 0xA5, 0x20, 0x8E, 0xA6, 0x20, 0x33, 0xA5, 0x4C, 0x77, 0xA6, 0x20, 0x19, 0xE2, 0x20, 0xC0, 0xFF, 0xB0, 0x0B, 0x60, 0x20, 0x19, 0xE2, 0xA5, 0x49, 0x20, 0xC3, 0xFF, 0x90, 0xC3, 0x4C, 0xF9, 0xE0, 0xA9, 0x00, 0x20, 0xBD, 0xFF, 0xA2, 0x01, 0xA0, 0x00, 0x20, 0xBA, 0xFF, 0x20, 0x06, 0xE2, 0x20, 0x57, 0xE2, 0x20, 0x06, 0xE2, 0x20, 0x00, 0xE2, 0xA0, 0x00, 0x86, 0x49, 0x20, 0xBA, 0xFF, 0x20, 0x06, 0xE2, 0x20, 0x00, 0xE2, 0x8A, 0xA8, 0xA6, 0x49, 0x4C, 0xBA, 0xFF, 0x20, 0x0E, 0xE2, 0x4C, 0x9E, 0xB7, 0x20, 0x79, 0x00, 0xD0, 0x02, 0x68, 0x68, 0x60, 0x20, 0xFD, 0xAE, 0x20, 0x79, 0x00, 0xD0, 0xF7, 0x4C, 0x08, 0xAF, 0xA9, 0x00, 0x20, 0xBD, 0xFF, 0x20, 0x11, 0xE2, 0x20, 0x9E, 0xB7, 0x86, 0x49, 0x8A, 0xA2, 0x01, 0xA0, 0x00, 0x20, 0xBA, 0xFF, 0x20, 0x06, 0xE2, 0x20, 0x00, 0xE2, 0x86, 0x4A, 0xA0, 0x00, 0xA5, 0x49, 0xE0, 0x03, 0x90, 0x01, 0x88, 0x20, 0xBA, 0xFF, 0x20, 0x06, 0xE2, 0x20, 0x00, 0xE2, 0x8A, 0xA8, 0xA6, 0x4A, 0xA5, 0x49, 0x20, 0xBA, 0xFF, 0x20, 0x06, 0xE2, 0x20, 0x0E, 0xE2, 0x20, 0x9E, 0xAD, 0x20, 0xA3, 0xB6, 0xA6, 0x22, 0xA4, 0x23, 0x4C, 0xBD, 0xFF, 0xA9, 0xE0, 0xA0, 0xE2, 0x20, 0x67, 0xB8, 0x20, 0x0C, 0xBC, 0xA9, 0xE5, 0xA0, 0xE2, 0xA6, 0x6E, 0x20, 0x07, 0xBB, 0x20, 0x0C, 0xBC, 0x20, 0xCC, 0xBC, 0xA9, 0x00, 0x85, 0x6F, 0x20, 0x53, 0xB8, 0xA9, 0xEA, 0xA0, 0xE2, 0x20, 0x50, 0xB8, 0xA5, 0x66, 0x48, 0x10, 0x0D, 0x20, 0x49, 0xB8, 0xA5, 0x66, 0x30, 0x09, 0xA5, 0x12, 0x49, 0xFF, 0x85, 0x12, 0x20, 0xB4, 0xBF, 0xA9, 0xEA, 0xA0, 0xE2, 0x20, 0x67, 0xB8, 0x68, 0x10, 0x03, 0x20, 0xB4, 0xBF, 0xA9, 0xEF, 0xA0, 0xE2, 0x4C, 0x43, 0xE0, 0x20, 0xCA, 0xBB, 0xA9, 0x00, 0x85, 0x12, 0x20, 0x6B, 0xE2, 0xA2, 0x4E, 0xA0, 0x00, 0x20, 0xF6, 0xE0, 0xA9, 0x57, 0xA0, 0x00, 0x20, 0xA2, 0xBB, 0xA9, 0x00, 0x85, 0x66, 0xA5, 0x12, 0x20, 0xDC, 0xE2, 0xA9, 0x4E, 0xA0, 0x00, 0x4C, 0x0F, 0xBB, 0x48, 0x4C, 0x9D, 0xE2, 0x81, 0x49, 0x0F, 0xDA, 0xA2, 0x83, 0x49, 0x0F, 0xDA, 0xA2, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x05, 0x84, 0xE6, 0x1A, 0x2D, 0x1B, 0x86, 0x28, 0x07, 0xFB, 0xF8, 0x87, 0x99, 0x68, 0x89, 0x01, 0x87, 0x23, 0x35, 0xDF, 0xE1, 0x86, 0xA5, 0x5D, 0xE7, 0x28, 0x83, 0x49, 0x0F, 0xDA, 0xA2, 0xA5, 0x66, 0x48, 0x10, 0x03, 0x20, 0xB4, 0xBF, 0xA5, 0x61, 0x48, 0xC9, 0x81, 0x90, 0x07, 0xA9, 0xBC, 0xA0, 0xB9, 0x20, 0x0F, 0xBB, 0xA9, 0x3E, 0xA0, 0xE3, 0x20, 0x43, 0xE0, 0x68, 0xC9, 0x81, 0x90, 0x07, 0xA9, 0xE0, 0xA0, 0xE2, 0x20, 0x50, 0xB8, 0x68, 0x10, 0x03, 0x4C, 0xB4, 0xBF, 0x60, 0x0B, 0x76, 0xB3, 0x83, 0xBD, 0xD3, 0x79, 0x1E, 0xF4, 0xA6, 0xF5, 0x7B, 0x83, 0xFC, 0xB0, 0x10, 0x7C, 0x0C, 0x1F, 0x67, 0xCA, 0x7C, 0xDE, 0x53, 0xCB, 0xC1, 0x7D, 0x14, 0x64, 0x70, 0x4C, 0x7D, 0xB7, 0xEA, 0x51, 0x7A, 0x7D, 0x63, 0x30, 0x88, 0x7E, 0x7E, 0x92, 0x44, 0x99, 0x3A, 0x7E, 0x4C, 0xCC, 0x91, 0xC7, 0x7F, 0xAA, 0xAA, 0xAA, 0x13, 0x81, 0x00, 0x00, 0x00, 0x00, 0x20, 0xCC, 0xFF, 0xA9, 0x00, 0x85, 0x13, 0x20, 0x7A, 0xA6, 0x58, 0xA2, 0x80, 0x6C, 0x00, 0x03, 0x8A, 0x30, 0x03, 0x4C, 0x3A, 0xA4, 0x4C, 0x74, 0xA4, 0x20, 0x53, 0xE4, 0x20, 0xBF, 0xE3, 0x20, 0x22, 0xE4, 0xA2, 0xFB, 0x9A, 0xD0, 0xE4, 0xE6, 0x7A, 0xD0, 0x02, 0xE6, 0x7B, 0xAD, 0x60, 0xEA, 0xC9, 0x3A, 0xB0, 0x0A, 0xC9, 0x20, 0xF0, 0xEF, 0x38, 0xE9, 0x30, 0x38, 0xE9, 0xD0, 0x60, 0x80, 0x4F, 0xC7, 0x52, 0x58, 0xA9, 0x4C, 0x85, 0x54, 0x8D, 0x10, 0x03, 0xA9, 0x48, 0xA0, 0xB2, 0x8D, 0x11, 0x03, 0x8C, 0x12, 0x03, 0xA9, 0x91, 0xA0, 0xB3, 0x85, 0x05, 0x84, 0x06, 0xA9, 0xAA, 0xA0, 0xB1, 0x85, 0x03, 0x84, 0x04, 0xA2, 0x1C, 0xBD, 0xA2, 0xE3, 0x95, 0x73, 0xCA, 0x10, 0xF8, 0xA9, 0x03, 0x85, 0x53, 0xA9, 0x00, 0x85, 0x68, 0x85, 0x13, 0x85, 0x18, 0xA2, 0x01, 0x8E, 0xFD, 0x01, 0x8E, 0xFC, 0x01, 0xA2, 0x19, 0x86, 0x16, 0x38, 0x20, 0x9C, 0xFF, 0x86, 0x2B, 0x84, 0x2C, 0x38, 0x20, 0x99, 0xFF, 0x86, 0x37, 0x84, 0x38, 0x86, 0x33, 0x84, 0x34, 0xA0, 0x00, 0x98, 0x91, 0x2B, 0xE6, 0x2B, 0xD0, 0x02, 0xE6, 0x2C, 0x60, 0xA5, 0x2B, 0xA4, 0x2C, 0x20, 0x08, 0xA4, 0xA9, 0x73, 0xA0, 0xE4, 0x20, 0x1E, 0xAB, 0xA5, 0x37, 0x38, 0xE5, 0x2B, 0xAA, 0xA5, 0x38, 0xE5, 0x2C, 0x20, 0xCD, 0xBD, 0xA9, 0x60, 0xA0, 0xE4, 0x20, 0x1E, 0xAB, 0x4C, 0x44, 0xA6, 0x8B, 0xE3, 0x83, 0xA4, 0x7C, 0xA5, 0x1A, 0xA7, 0xE4, 0xA7, 0x86, 0xAE, 0xA2, 0x0B, 0xBD, 0x47, 0xE4, 0x9D, 0x00, 0x03, 0xCA, 0x10, 0xF7, 0x60, 0x00, 0x20, 0x42, 0x41, 0x53, 0x49, 0x43, 0x20, 0x42, 0x59, 0x54, 0x45, 0x53, 0x20, 0x46, 0x52, 0x45, 0x45, 0x0D, 0x00, 0x93, 0x0D, 0x20, 0x20, 0x20, 0x20, 0x2A, 0x2A, 0x2A, 0x2A, 0x20, 0x43, 0x4F, 0x4D, 0x4D, 0x4F, 0x44, 0x4F, 0x52, 0x45, 0x20, 0x36, 0x34, 0x20, 0x42, 0x41, 0x53, 0x49, 0x43, 0x20, 0x56, 0x32, 0x20, 0x2A, 0x2A, 0x2A, 0x2A, 0x0D, 0x0D, 0x20, 0x36, 0x34, 0x4B, 0x20, 0x52, 0x41, 0x4D, 0x20, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4D, 0x20, 0x20, 0x00, 0x81, 0x48, 0x20, 0xC9, 0xFF, 0xAA, 0x68, 0x90, 0x01, 0x8A, 0x60, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x85, 0xA9, 0xA9, 0x01, 0x85, 0xAB, 0x60, 0xAD, 0x86, 0x02, 0x91, 0xF3, 0x60, 0x69, 0x02, 0xA4, 0x91, 0xC8, 0xD0, 0x04, 0xC5, 0xA1, 0xD0, 0xF7, 0x60, 0x19, 0x26, 0x44, 0x19, 0x1A, 0x11, 0xE8, 0x0D, 0x70, 0x0C, 0x06, 0x06, 0xD1, 0x02, 0x37, 0x01, 0xAE, 0x00, 0x69, 0x00, 0xA2, 0x00, 0xA0, 0xDC, 0x60, 0xA2, 0x28, 0xA0, 0x19, 0x60, 0xB0, 0x07, 0x86, 0xD6, 0x84, 0xD3, 0x20, 0x6C, 0xE5, 0xA6, 0xD6, 0xA4, 0xD3, 0x60, 0x20, 0xA0, 0xE5, 0xA9, 0x00, 0x8D, 0x91, 0x02, 0x85, 0xCF, 0xA9, 0x48, 0x8D, 0x8F, 0x02, 0xA9, 0xEB, 0x8D, 0x90, 0x02, 0xA9, 0x0A, 0x8D, 0x89, 0x02, 0x8D, 0x8C, 0x02, 0xA9, 0x0E, 0x8D, 0x86, 0x02, 0xA9, 0x04, 0x8D, 0x8B, 0x02, 0xA9, 0x0C, 0x85, 0xCD, 0x85, 0xCC, 0xAD, 0x88, 0x02, 0x09, 0x80, 0xA8, 0xA9, 0x00, 0xAA, 0x94, 0xD9, 0x18, 0x69, 0x28, 0x90, 0x01, 0xC8, 0xE8, 0xE0, 0x1A, 0xD0, 0xF3, 0xA9, 0xFF, 0x95, 0xD9, 0xA2, 0x18, 0x20, 0xFF, 0xE9, 0xCA, 0x10, 0xFA, 0xA0, 0x00, 0x84, 0xD3, 0x84, 0xD6, 0xA6, 0xD6, 0xA5, 0xD3, 0xB4, 0xD9, 0x30, 0x08, 0x18, 0x69, 0x28, 0x85, 0xD3, 0xCA, 0x10, 0xF4, 0x20, 0xF0, 0xE9, 0xA9, 0x27, 0xE8, 0xB4, 0xD9, 0x30, 0x06, 0x18, 0x69, 0x28, 0xE8, 0x10, 0xF6, 0x85, 0xD5, 0x4C, 0x24, 0xEA, 0xE4, 0xC9, 0xF0, 0x03, 0x4C, 0xED, 0xE6, 0x60, 0xEA, 0x20, 0xA0, 0xE5, 0x4C, 0x66, 0xE5, 0xA9, 0x03, 0x85, 0x9A, 0xA9, 0x00, 0x85, 0x99, 0xA2, 0x2F, 0xBD, 0xB8, 0xEC, 0x9D, 0xFF, 0xCF, 0xCA, 0xD0, 0xF7, 0x60, 0xAC, 0x77, 0x02, 0xA2, 0x00, 0xBD, 0x78, 0x02, 0x9D, 0x77, 0x02, 0xE8, 0xE4, 0xC6, 0xD0, 0xF5, 0xC6, 0xC6, 0x98, 0x58, 0x18, 0x60, 0x20, 0x16, 0xE7, 0xA5, 0xC6, 0x85, 0xCC, 0x8D, 0x92, 0x02, 0xF0, 0xF7, 0x78, 0xA5, 0xCF, 0xF0, 0x0C, 0xA5, 0xCE, 0xAE, 0x87, 0x02, 0xA0, 0x00, 0x84, 0xCF, 0x20, 0x13, 0xEA, 0x20, 0xB4, 0xE5, 0xC9, 0x83, 0xD0, 0x10, 0xA2, 0x09, 0x78, 0x86, 0xC6, 0xBD, 0xE6, 0xEC, 0x9D, 0x76, 0x02, 0xCA, 0xD0, 0xF7, 0xF0, 0xCF, 0xC9, 0x0D, 0xD0, 0xC8, 0xA4, 0xD5, 0x84, 0xD0, 0xB1, 0xD1, 0xC9, 0x20, 0xD0, 0x03, 0x88, 0xD0, 0xF7, 0xC8, 0x84, 0xC8, 0xA0, 0x00, 0x8C, 0x92, 0x02, 0x84, 0xD3, 0x84, 0xD4, 0xA5, 0xC9, 0x30, 0x1B, 0xA6, 0xD6, 0x20, 0x91, 0xE5, 0xE4, 0xC9, 0xD0, 0x12, 0xA5, 0xCA, 0x85, 0xD3, 0xC5, 0xC8, 0x90, 0x0A, 0xB0, 0x2B, 0x98, 0x48, 0x8A, 0x48, 0xA5, 0xD0, 0xF0, 0x93, 0xA4, 0xD3, 0xB1, 0xD1, 0x85, 0xD7, 0x29, 0x3F, 0x06, 0xD7, 0x24, 0xD7, 0x10, 0x02, 0x09, 0x80, 0x90, 0x04, 0xA6, 0xD4, 0xD0, 0x04, 0x70, 0x02, 0x09, 0x40, 0xE6, 0xD3, 0x20, 0x84, 0xE6, 0xC4, 0xC8, 0xD0, 0x17, 0xA9, 0x00, 0x85, 0xD0, 0xA9, 0x0D, 0xA6, 0x99, 0xE0, 0x03, 0xF0, 0x06, 0xA6, 0x9A, 0xE0, 0x03, 0xF0, 0x03, 0x20, 0x16, 0xE7, 0xA9, 0x0D, 0x85, 0xD7, 0x68, 0xAA, 0x68, 0xA8, 0xA5, 0xD7, 0xC9, 0xDE, 0xD0, 0x02, 0xA9, 0xFF, 0x18, 0x60, 0xC9, 0x22, 0xD0, 0x08, 0xA5, 0xD4, 0x49, 0x01, 0x85, 0xD4, 0xA9, 0x22, 0x60, 0x09, 0x40, 0xA6, 0xC7, 0xF0, 0x02, 0x09, 0x80, 0xA6, 0xD8, 0xF0, 0x02, 0xC6, 0xD8, 0xAE, 0x86, 0x02, 0x20, 0x13, 0xEA, 0x20, 0xB6, 0xE6, 0x68, 0xA8, 0xA5, 0xD8, 0xF0, 0x02, 0x46, 0xD4, 0x68, 0xAA, 0x68, 0x18, 0x58, 0x60, 0x20, 0xB3, 0xE8, 0xE6, 0xD3, 0xA5, 0xD5, 0xC5, 0xD3, 0xB0, 0x3F, 0xC9, 0x4F, 0xF0, 0x32, 0xAD, 0x92, 0x02, 0xF0, 0x03, 0x4C, 0x67, 0xE9, 0xA6, 0xD6, 0xE0, 0x19, 0x90, 0x07, 0x20, 0xEA, 0xE8, 0xC6, 0xD6, 0xA6, 0xD6, 0x16, 0xD9, 0x56, 0xD9, 0xE8, 0xB5, 0xD9, 0x09, 0x80, 0x95, 0xD9, 0xCA, 0xA5, 0xD5, 0x18, 0x69, 0x28, 0x85, 0xD5, 0xB5, 0xD9, 0x30, 0x03, 0xCA, 0xD0, 0xF9, 0x4C, 0xF0, 0xE9, 0xC6, 0xD6, 0x20, 0x7C, 0xE8, 0xA9, 0x00, 0x85, 0xD3, 0x60, 0xA6, 0xD6, 0xD0, 0x06, 0x86, 0xD3, 0x68, 0x68, 0xD0, 0x9D, 0xCA, 0x86, 0xD6, 0x20, 0x6C, 0xE5, 0xA4, 0xD5, 0x84, 0xD3, 0x60, 0x48, 0x85, 0xD7, 0x8A, 0x48, 0x98, 0x48, 0xA9, 0x00, 0x85, 0xD0, 0xA4, 0xD3, 0xA5, 0xD7, 0x10, 0x03, 0x4C, 0xD4, 0xE7, 0xC9, 0x0D, 0xD0, 0x03, 0x4C, 0x91, 0xE8, 0xC9, 0x20, 0x90, 0x10, 0xC9, 0x60, 0x90, 0x04, 0x29, 0xDF, 0xD0, 0x02, 0x29, 0x3F, 0x20, 0x84, 0xE6, 0x4C, 0x93, 0xE6, 0xA6, 0xD8, 0xF0, 0x03, 0x4C, 0x97, 0xE6, 0xC9, 0x14, 0xD0, 0x2E, 0x98, 0xD0, 0x06, 0x20, 0x01, 0xE7, 0x4C, 0x73, 0xE7, 0x20, 0xA1, 0xE8, 0x88, 0x84, 0xD3, 0x20, 0x24, 0xEA, 0xC8, 0xB1, 0xD1, 0x88, 0x91, 0xD1, 0xC8, 0xB1, 0xF3, 0x88, 0x91, 0xF3, 0xC8, 0xC4, 0xD5, 0xD0, 0xEF, 0xA9, 0x20, 0x91, 0xD1, 0xAD, 0x86, 0x02, 0x91, 0xF3, 0x10, 0x4D, 0xA6, 0xD4, 0xF0, 0x03, 0x4C, 0x97, 0xE6, 0xC9, 0x12, 0xD0, 0x02, 0x85, 0xC7, 0xC9, 0x13, 0xD0, 0x03, 0x20, 0x66, 0xE5, 0xC9, 0x1D, 0xD0, 0x17, 0xC8, 0x20, 0xB3, 0xE8, 0x84, 0xD3, 0x88, 0xC4, 0xD5, 0x90, 0x09, 0xC6, 0xD6, 0x20, 0x7C, 0xE8, 0xA0, 0x00, 0x84, 0xD3, 0x4C, 0xA8, 0xE6, 0xC9, 0x11, 0xD0, 0x1D, 0x18, 0x98, 0x69, 0x28, 0xA8, 0xE6, 0xD6, 0xC5, 0xD5, 0x90, 0xEC, 0xF0, 0xEA, 0xC6, 0xD6, 0xE9, 0x28, 0x90, 0x04, 0x85, 0xD3, 0xD0, 0xF8, 0x20, 0x7C, 0xE8, 0x4C, 0xA8, 0xE6, 0x20, 0xCB, 0xE8, 0x4C, 0x44, 0xEC, 0x29, 0x7F, 0xC9, 0x7F, 0xD0, 0x02, 0xA9, 0x5E, 0xC9, 0x20, 0x90, 0x03, 0x4C, 0x91, 0xE6, 0xC9, 0x0D, 0xD0, 0x03, 0x4C, 0x91, 0xE8, 0xA6, 0xD4, 0xD0, 0x3F, 0xC9, 0x14, 0xD0, 0x37, 0xA4, 0xD5, 0xB1, 0xD1, 0xC9, 0x20, 0xD0, 0x04, 0xC4, 0xD3, 0xD0, 0x07, 0xC0, 0x4F, 0xF0, 0x24, 0x20, 0x65, 0xE9, 0xA4, 0xD5, 0x20, 0x24, 0xEA, 0x88, 0xB1, 0xD1, 0xC8, 0x91, 0xD1, 0x88, 0xB1, 0xF3, 0xC8, 0x91, 0xF3, 0x88, 0xC4, 0xD3, 0xD0, 0xEF, 0xA9, 0x20, 0x91, 0xD1, 0xAD, 0x86, 0x02, 0x91, 0xF3, 0xE6, 0xD8, 0x4C, 0xA8, 0xE6, 0xA6, 0xD8, 0xF0, 0x05, 0x09, 0x40, 0x4C, 0x97, 0xE6, 0xC9, 0x11, 0xD0, 0x16, 0xA6, 0xD6, 0xF0, 0x37, 0xC6, 0xD6, 0xA5, 0xD3, 0x38, 0xE9, 0x28, 0x90, 0x04, 0x85, 0xD3, 0x10, 0x2A, 0x20, 0x6C, 0xE5, 0xD0, 0x25, 0xC9, 0x12, 0xD0, 0x04, 0xA9, 0x00, 0x85, 0xC7, 0xC9, 0x1D, 0xD0, 0x12, 0x98, 0xF0, 0x09, 0x20, 0xA1, 0xE8, 0x88, 0x84, 0xD3, 0x4C, 0xA8, 0xE6, 0x20, 0x01, 0xE7, 0x4C, 0xA8, 0xE6, 0xC9, 0x13, 0xD0, 0x06, 0x20, 0x44, 0xE5, 0x4C, 0xA8, 0xE6, 0x09, 0x80, 0x20, 0xCB, 0xE8, 0x4C, 0x4F, 0xEC, 0x46, 0xC9, 0xA6, 0xD6, 0xE8, 0xE0, 0x19, 0xD0, 0x03, 0x20, 0xEA, 0xE8, 0xB5, 0xD9, 0x10, 0xF4, 0x86, 0xD6, 0x4C, 0x6C, 0xE5, 0xA2, 0x00, 0x86, 0xD8, 0x86, 0xC7, 0x86, 0xD4, 0x86, 0xD3, 0x20, 0x7C, 0xE8, 0x4C, 0xA8, 0xE6, 0xA2, 0x02, 0xA9, 0x00, 0xC5, 0xD3, 0xF0, 0x07, 0x18, 0x69, 0x28, 0xCA, 0xD0, 0xF6, 0x60, 0xC6, 0xD6, 0x60, 0xA2, 0x02, 0xA9, 0x27, 0xC5, 0xD3, 0xF0, 0x07, 0x18, 0x69, 0x28, 0xCA, 0xD0, 0xF6, 0x60, 0xA6, 0xD6, 0xE0, 0x19, 0xF0, 0x02, 0xE6, 0xD6, 0x60, 0xA2, 0x0F, 0xDD, 0xDA, 0xE8, 0xF0, 0x04, 0xCA, 0x10, 0xF8, 0x60, 0x8E, 0x86, 0x02, 0x60, 0x90, 0x05, 0x1C, 0x9F, 0x9C, 0x1E, 0x1F, 0x9E, 0x81, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0xA5, 0xAC, 0x48, 0xA5, 0xAD, 0x48, 0xA5, 0xAE, 0x48, 0xA5, 0xAF, 0x48, 0xA2, 0xFF, 0xC6, 0xD6, 0xC6, 0xC9, 0xCE, 0xA5, 0x02, 0xE8, 0x20, 0xF0, 0xE9, 0xE0, 0x18, 0xB0, 0x0C, 0xBD, 0xF1, 0xEC, 0x85, 0xAC, 0xB5, 0xDA, 0x20, 0xC8, 0xE9, 0x30, 0xEC, 0x20, 0xFF, 0xE9, 0xA2, 0x00, 0xB5, 0xD9, 0x29, 0x7F, 0xB4, 0xDA, 0x10, 0x02, 0x09, 0x80, 0x95, 0xD9, 0xE8, 0xE0, 0x18, 0xD0, 0xEF, 0xA5, 0xF1, 0x09, 0x80, 0x85, 0xF1, 0xA5, 0xD9, 0x10, 0xC3, 0xE6, 0xD6, 0xEE, 0xA5, 0x02, 0xA9, 0x7F, 0x8D, 0x00, 0xDC, 0xAD, 0x01, 0xDC, 0xC9, 0xFB, 0x08, 0xA9, 0x7F, 0x8D, 0x00, 0xDC, 0x28, 0xD0, 0x0B, 0xA0, 0x00, 0xEA, 0xCA, 0xD0, 0xFC, 0x88, 0xD0, 0xF9, 0x84, 0xC6, 0xA6, 0xD6, 0x68, 0x85, 0xAF, 0x68, 0x85, 0xAE, 0x68, 0x85, 0xAD, 0x68, 0x85, 0xAC, 0x60, 0xA6, 0xD6, 0xE8, 0xB5, 0xD9, 0x10, 0xFB, 0x8E, 0xA5, 0x02, 0xE0, 0x18, 0xF0, 0x0E, 0x90, 0x0C, 0x20, 0xEA, 0xE8, 0xAE, 0xA5, 0x02, 0xCA, 0xC6, 0xD6, 0x4C, 0xDA, 0xE6, 0xA5, 0xAC, 0x48, 0xA5, 0xAD, 0x48, 0xA5, 0xAE, 0x48, 0xA5, 0xAF, 0x48, 0xA2, 0x19, 0xCA, 0x20, 0xF0, 0xE9, 0xEC, 0xA5, 0x02, 0x90, 0x0E, 0xF0, 0x0C, 0xBD, 0xEF, 0xEC, 0x85, 0xAC, 0xB5, 0xD8, 0x20, 0xC8, 0xE9, 0x30, 0xE9, 0x20, 0xFF, 0xE9, 0xA2, 0x17, 0xEC, 0xA5, 0x02, 0x90, 0x0F, 0xB5, 0xDA, 0x29, 0x7F, 0xB4, 0xD9, 0x10, 0x02, 0x09, 0x80, 0x95, 0xDA, 0xCA, 0xD0, 0xEC, 0xAE, 0xA5, 0x02, 0x20, 0xDA, 0xE6, 0x4C, 0x58, 0xE9, 0x29, 0x03, 0x0D, 0x88, 0x02, 0x85, 0xAD, 0x20, 0xE0, 0xE9, 0xA0, 0x27, 0xB1, 0xAC, 0x91, 0xD1, 0xB1, 0xAE, 0x91, 0xF3, 0x88, 0x10, 0xF5, 0x60, 0x20, 0x24, 0xEA, 0xA5, 0xAC, 0x85, 0xAE, 0xA5, 0xAD, 0x29, 0x03, 0x09, 0xD8, 0x85, 0xAF, 0x60, 0xBD, 0xF0, 0xEC, 0x85, 0xD1, 0xB5, 0xD9, 0x29, 0x03, 0x0D, 0x88, 0x02, 0x85, 0xD2, 0x60, 0xA0, 0x27, 0x20, 0xF0, 0xE9, 0x20, 0x24, 0xEA, 0x20, 0xDA, 0xE4, 0xA9, 0x20, 0x91, 0xD1, 0x88, 0x10, 0xF6, 0x60, 0xEA, 0xA8, 0xA9, 0x02, 0x85, 0xCD, 0x20, 0x24, 0xEA, 0x98, 0xA4, 0xD3, 0x91, 0xD1, 0x8A, 0x91, 0xF3, 0x60, 0xA5, 0xD1, 0x85, 0xF3, 0xA5, 0xD2, 0x29, 0x03, 0x09, 0xD8, 0x85, 0xF4, 0x60, 0x20, 0xEA, 0xFF, 0xA5, 0xCC, 0xD0, 0x29, 0xC6, 0xCD, 0xD0, 0x25, 0xA9, 0x14, 0x85, 0xCD, 0xA4, 0xD3, 0x46, 0xCF, 0xAE, 0x87, 0x02, 0xB1, 0xD1, 0xB0, 0x11, 0xE6, 0xCF, 0x85, 0xCE, 0x20, 0x24, 0xEA, 0xB1, 0xF3, 0x8D, 0x87, 0x02, 0xAE, 0x86, 0x02, 0xA5, 0xCE, 0x49, 0x80, 0x20, 0x1C, 0xEA, 0xA5, 0x01, 0x29, 0x10, 0xF0, 0x0A, 0xA0, 0x00, 0x84, 0xC0, 0xA5, 0x01, 0x09, 0x20, 0xD0, 0x08, 0xA5, 0xC0, 0xD0, 0x06, 0xA5, 0x01, 0x29, 0x1F, 0x85, 0x01, 0x20, 0x87, 0xEA, 0xAD, 0x0D, 0xDC, 0x68, 0xA8, 0x68, 0xAA, 0x68, 0x40, 0xA9, 0x00, 0x8D, 0x8D, 0x02, 0xA0, 0x40, 0x84, 0xCB, 0x8D, 0x00, 0xDC, 0xAE, 0x01, 0xDC, 0xE0, 0xFF, 0xF0, 0x61, 0xA8, 0xA9, 0x81, 0x85, 0xF5, 0xA9, 0xEB, 0x85, 0xF6, 0xA9, 0xFE, 0x8D, 0x00, 0xDC, 0xA2, 0x08, 0x48, 0xAD, 0x01, 0xDC, 0xCD, 0x01, 0xDC, 0xD0, 0xF8, 0x4A, 0xB0, 0x16, 0x48, 0xB1, 0xF5, 0xC9, 0x05, 0xB0, 0x0C, 0xC9, 0x03, 0xF0, 0x08, 0x0D, 0x8D, 0x02, 0x8D, 0x8D, 0x02, 0x10, 0x02, 0x84, 0xCB, 0x68, 0xC8, 0xC0, 0x41, 0xB0, 0x0B, 0xCA, 0xD0, 0xDF, 0x38, 0x68, 0x2A, 0x8D, 0x00, 0xDC, 0xD0, 0xCC, 0x68, 0x6C, 0x8F, 0x02, 0xA4, 0xCB, 0xB1, 0xF5, 0xAA, 0xC4, 0xC5, 0xF0, 0x07, 0xA0, 0x10, 0x8C, 0x8C, 0x02, 0xD0, 0x36, 0x29, 0x7F, 0x2C, 0x8A, 0x02, 0x30, 0x16, 0x70, 0x49, 0xC9, 0x7F, 0xF0, 0x29, 0xC9, 0x14, 0xF0, 0x0C, 0xC9, 0x20, 0xF0, 0x08, 0xC9, 0x1D, 0xF0, 0x04, 0xC9, 0x11, 0xD0, 0x35, 0xAC, 0x8C, 0x02, 0xF0, 0x05, 0xCE, 0x8C, 0x02, 0xD0, 0x2B, 0xCE, 0x8B, 0x02, 0xD0, 0x26, 0xA0, 0x04, 0x8C, 0x8B, 0x02, 0xA4, 0xC6, 0x88, 0x10, 0x1C, 0xA4, 0xCB, 0x84, 0xC5, 0xAC, 0x8D, 0x02, 0x8C, 0x8E, 0x02, 0xE0, 0xFF, 0xF0, 0x0E, 0x8A, 0xA6, 0xC6, 0xEC, 0x89, 0x02, 0xB0, 0x06, 0x9D, 0x77, 0x02, 0xE8, 0x86, 0xC6, 0xA9, 0x7F, 0x8D, 0x00, 0xDC, 0x60, 0xAD, 0x8D, 0x02, 0xC9, 0x03, 0xD0, 0x15, 0xCD, 0x8E, 0x02, 0xF0, 0xEE, 0xAD, 0x91, 0x02, 0x30, 0x1D, 0xAD, 0x18, 0xD0, 0x49, 0x02, 0x8D, 0x18, 0xD0, 0x4C, 0x76, 0xEB, 0x0A, 0xC9, 0x08, 0x90, 0x02, 0xA9, 0x06, 0xAA, 0xBD, 0x79, 0xEB, 0x85, 0xF5, 0xBD, 0x7A, 0xEB, 0x85, 0xF6, 0x4C, 0xE0, 0xEA, 0x81, 0xEB, 0xC2, 0xEB, 0x03, 0xEC, 0x78, 0xEC, 0x14, 0x0D, 0x1D, 0x88, 0x85, 0x86, 0x87, 0x11, 0x33, 0x57, 0x41, 0x34, 0x5A, 0x53, 0x45, 0x01, 0x35, 0x52, 0x44, 0x36, 0x43, 0x46, 0x54, 0x58, 0x37, 0x59, 0x47, 0x38, 0x42, 0x48, 0x55, 0x56, 0x39, 0x49, 0x4A, 0x30, 0x4D, 0x4B, 0x4F, 0x4E, 0x2B, 0x50, 0x4C, 0x2D, 0x2E, 0x3A, 0x40, 0x2C, 0x5C, 0x2A, 0x3B, 0x13, 0x01, 0x3D, 0x5E, 0x2F, 0x31, 0x5F, 0x04, 0x32, 0x20, 0x02, 0x51, 0x03, 0xFF, 0x94, 0x8D, 0x9D, 0x8C, 0x89, 0x8A, 0x8B, 0x91, 0x23, 0xD7, 0xC1, 0x24, 0xDA, 0xD3, 0xC5, 0x01, 0x25, 0xD2, 0xC4, 0x26, 0xC3, 0xC6, 0xD4, 0xD8, 0x27, 0xD9, 0xC7, 0x28, 0xC2, 0xC8, 0xD5, 0xD6, 0x29, 0xC9, 0xCA, 0x30, 0xCD, 0xCB, 0xCF, 0xCE, 0xDB, 0xD0, 0xCC, 0xDD, 0x3E, 0x5B, 0xBA, 0x3C, 0xA9, 0xC0, 0x5D, 0x93, 0x01, 0x3D, 0xDE, 0x3F, 0x21, 0x5F, 0x04, 0x22, 0xA0, 0x02, 0xD1, 0x83, 0xFF, 0x94, 0x8D, 0x9D, 0x8C, 0x89, 0x8A, 0x8B, 0x91, 0x96, 0xB3, 0xB0, 0x97, 0xAD, 0xAE, 0xB1, 0x01, 0x98, 0xB2, 0xAC, 0x99, 0xBC, 0xBB, 0xA3, 0xBD, 0x9A, 0xB7, 0xA5, 0x9B, 0xBF, 0xB4, 0xB8, 0xBE, 0x29, 0xA2, 0xB5, 0x30, 0xA7, 0xA1, 0xB9, 0xAA, 0xA6, 0xAF, 0xB6, 0xDC, 0x3E, 0x5B, 0xA4, 0x3C, 0xA8, 0xDF, 0x5D, 0x93, 0x01, 0x3D, 0xDE, 0x3F, 0x81, 0x5F, 0x04, 0x95, 0xA0, 0x02, 0xAB, 0x83, 0xFF, 0xC9, 0x0E, 0xD0, 0x07, 0xAD, 0x18, 0xD0, 0x09, 0x02, 0xD0, 0x09, 0xC9, 0x8E, 0xD0, 0x0B, 0xAD, 0x18, 0xD0, 0x29, 0xFD, 0x8D, 0x18, 0xD0, 0x4C, 0xA8, 0xE6, 0xC9, 0x08, 0xD0, 0x07, 0xA9, 0x80, 0x0D, 0x91, 0x02, 0x30, 0x09, 0xC9, 0x09, 0xD0, 0xEE, 0xA9, 0x7F, 0x2D, 0x91, 0x02, 0x8D, 0x91, 0x02, 0x4C, 0xA8, 0xE6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1C, 0x17, 0x01, 0x9F, 0x1A, 0x13, 0x05, 0xFF, 0x9C, 0x12, 0x04, 0x1E, 0x03, 0x06, 0x14, 0x18, 0x1F, 0x19, 0x07, 0x9E, 0x02, 0x08, 0x15, 0x16, 0x12, 0x09, 0x0A, 0x92, 0x0D, 0x0B, 0x0F, 0x0E, 0xFF, 0x10, 0x0C, 0xFF, 0xFF, 0x1B, 0x00, 0xFF, 0x1C, 0xFF, 0x1D, 0xFF, 0xFF, 0x1F, 0x1E, 0xFF, 0x90, 0x06, 0xFF, 0x05, 0xFF, 0xFF, 0x11, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x37, 0x00, 0x00, 0x00, 0x08, 0x00, 0x14, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x06, 0x01, 0x02, 0x03, 0x04, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x4C, 0x4F, 0x41, 0x44, 0x0D, 0x52, 0x55, 0x4E, 0x0D, 0x00, 0x28, 0x50, 0x78, 0xA0, 0xC8, 0xF0, 0x18, 0x40, 0x68, 0x90, 0xB8, 0xE0, 0x08, 0x30, 0x58, 0x80, 0xA8, 0xD0, 0xF8, 0x20, 0x48, 0x70, 0x98, 0xC0, 0x09, 0x40, 0x2C, 0x09, 0x20, 0x20, 0xA4, 0xF0, 0x48, 0x24, 0x94, 0x10, 0x0A, 0x38, 0x66, 0xA3, 0x20, 0x40, 0xED, 0x46, 0x94, 0x46, 0xA3, 0x68, 0x85, 0x95, 0x78, 0x20, 0x97, 0xEE, 0xC9, 0x3F, 0xD0, 0x03, 0x20, 0x85, 0xEE, 0xAD, 0x00, 0xDD, 0x09, 0x08, 0x8D, 0x00, 0xDD, 0x78, 0x20, 0x8E, 0xEE, 0x20, 0x97, 0xEE, 0x20, 0xB3, 0xEE, 0x78, 0x20, 0x97, 0xEE, 0x20, 0xA9, 0xEE, 0xB0, 0x64, 0x20, 0x85, 0xEE, 0x24, 0xA3, 0x10, 0x0A, 0x20, 0xA9, 0xEE, 0x90, 0xFB, 0x20, 0xA9, 0xEE, 0xB0, 0xFB, 0x20, 0xA9, 0xEE, 0x90, 0xFB, 0x20, 0x8E, 0xEE, 0xA9, 0x08, 0x85, 0xA5, 0xAD, 0x00, 0xDD, 0xCD, 0x00, 0xDD, 0xD0, 0xF8, 0x0A, 0x90, 0x3F, 0x66, 0x95, 0xB0, 0x05, 0x20, 0xA0, 0xEE, 0xD0, 0x03, 0x20, 0x97, 0xEE, 0x20, 0x85, 0xEE, 0xEA, 0xEA, 0xEA, 0xEA, 0xAD, 0x00, 0xDD, 0x29, 0xDF, 0x09, 0x10, 0x8D, 0x00, 0xDD, 0xC6, 0xA5, 0xD0, 0xD4, 0xA9, 0x04, 0x8D, 0x07, 0xDC, 0xA9, 0x19, 0x8D, 0x0F, 0xDC, 0xAD, 0x0D, 0xDC, 0xAD, 0x0D, 0xDC, 0x29, 0x02, 0xD0, 0x0A, 0x20, 0xA9, 0xEE, 0xB0, 0xF4, 0x58, 0x60, 0xA9, 0x80, 0x2C, 0xA9, 0x03, 0x20, 0x1C, 0xFE, 0x58, 0x18, 0x90, 0x4A, 0x85, 0x95, 0x20, 0x36, 0xED, 0xAD, 0x00, 0xDD, 0x29, 0xF7, 0x8D, 0x00, 0xDD, 0x60, 0x85, 0x95, 0x20, 0x36, 0xED, 0x78, 0x20, 0xA0, 0xEE, 0x20, 0xBE, 0xED, 0x20, 0x85, 0xEE, 0x20, 0xA9, 0xEE, 0x30, 0xFB, 0x58, 0x60, 0x24, 0x94, 0x30, 0x05, 0x38, 0x66, 0x94, 0xD0, 0x05, 0x48, 0x20, 0x40, 0xED, 0x68, 0x85, 0x95, 0x18, 0x60, 0x78, 0x20, 0x8E, 0xEE, 0xAD, 0x00, 0xDD, 0x09, 0x08, 0x8D, 0x00, 0xDD, 0xA9, 0x5F, 0x2C, 0xA9, 0x3F, 0x20, 0x11, 0xED, 0x20, 0xBE, 0xED, 0x8A, 0xA2, 0x0A, 0xCA, 0xD0, 0xFD, 0xAA, 0x20, 0x85, 0xEE, 0x4C, 0x97, 0xEE, 0x78, 0xA9, 0x00, 0x85, 0xA5, 0x20, 0x85, 0xEE, 0x20, 0xA9, 0xEE, 0x10, 0xFB, 0xA9, 0x01, 0x8D, 0x07, 0xDC, 0xA9, 0x19, 0x8D, 0x0F, 0xDC, 0x20, 0x97, 0xEE, 0xAD, 0x0D, 0xDC, 0xAD, 0x0D, 0xDC, 0x29, 0x02, 0xD0, 0x07, 0x20, 0xA9, 0xEE, 0x30, 0xF4, 0x10, 0x18, 0xA5, 0xA5, 0xF0, 0x05, 0xA9, 0x02, 0x4C, 0xB2, 0xED, 0x20, 0xA0, 0xEE, 0x20, 0x85, 0xEE, 0xA9, 0x40, 0x20, 0x1C, 0xFE, 0xE6, 0xA5, 0xD0, 0xCA, 0xA9, 0x08, 0x85, 0xA5, 0xAD, 0x00, 0xDD, 0xCD, 0x00, 0xDD, 0xD0, 0xF8, 0x0A, 0x10, 0xF5, 0x66, 0xA4, 0xAD, 0x00, 0xDD, 0xCD, 0x00, 0xDD, 0xD0, 0xF8, 0x0A, 0x30, 0xF5, 0xC6, 0xA5, 0xD0, 0xE4, 0x20, 0xA0, 0xEE, 0x24, 0x90, 0x50, 0x03, 0x20, 0x06, 0xEE, 0xA5, 0xA4, 0x58, 0x18, 0x60, 0xAD, 0x00, 0xDD, 0x29, 0xEF, 0x8D, 0x00, 0xDD, 0x60, 0xAD, 0x00, 0xDD, 0x09, 0x10, 0x8D, 0x00, 0xDD, 0x60, 0xAD, 0x00, 0xDD, 0x29, 0xDF, 0x8D, 0x00, 0xDD, 0x60, 0xAD, 0x00, 0xDD, 0x09, 0x20, 0x8D, 0x00, 0xDD, 0x60, 0xAD, 0x00, 0xDD, 0xCD, 0x00, 0xDD, 0xD0, 0xF8, 0x0A, 0x60, 0x8A, 0xA2, 0xB8, 0xCA, 0xD0, 0xFD, 0xAA, 0x60, 0xA5, 0xB4, 0xF0, 0x47, 0x30, 0x3F, 0x46, 0xB6, 0xA2, 0x00, 0x90, 0x01, 0xCA, 0x8A, 0x45, 0xBD, 0x85, 0xBD, 0xC6, 0xB4, 0xF0, 0x06, 0x8A, 0x29, 0x04, 0x85, 0xB5, 0x60, 0xA9, 0x20, 0x2C, 0x94, 0x02, 0xF0, 0x14, 0x30, 0x1C, 0x70, 0x14, 0xA5, 0xBD, 0xD0, 0x01, 0xCA, 0xC6, 0xB4, 0xAD, 0x93, 0x02, 0x10, 0xE3, 0xC6, 0xB4, 0xD0, 0xDF, 0xE6, 0xB4, 0xD0, 0xF0, 0xA5, 0xBD, 0xF0, 0xED, 0xD0, 0xEA, 0x70, 0xE9, 0x50, 0xE6, 0xE6, 0xB4, 0xA2, 0xFF, 0xD0, 0xCB, 0xAD, 0x94, 0x02, 0x4A, 0x90, 0x07, 0x2C, 0x01, 0xDD, 0x10, 0x1D, 0x50, 0x1E, 0xA9, 0x00, 0x85, 0xBD, 0x85, 0xB5, 0xAE, 0x98, 0x02, 0x86, 0xB4, 0xAC, 0x9D, 0x02, 0xCC, 0x9E, 0x02, 0xF0, 0x13, 0xB1, 0xF9, 0x85, 0xB6, 0xEE, 0x9D, 0x02, 0x60, 0xA9, 0x40, 0x2C, 0xA9, 0x10, 0x0D, 0x97, 0x02, 0x8D, 0x97, 0x02, 0xA9, 0x01, 0x8D, 0x0D, 0xDD, 0x4D, 0xA1, 0x02, 0x09, 0x80, 0x8D, 0xA1, 0x02, 0x8D, 0x0D, 0xDD, 0x60, 0xA2, 0x09, 0xA9, 0x20, 0x2C, 0x93, 0x02, 0xF0, 0x01, 0xCA, 0x50, 0x02, 0xCA, 0xCA, 0x60, 0xA6, 0xA9, 0xD0, 0x33, 0xC6, 0xA8, 0xF0, 0x36, 0x30, 0x0D, 0xA5, 0xA7, 0x45, 0xAB, 0x85, 0xAB, 0x46, 0xA7, 0x66, 0xAA, 0x60, 0xC6, 0xA8, 0xA5, 0xA7, 0xF0, 0x67, 0xAD, 0x93, 0x02, 0x0A, 0xA9, 0x01, 0x65, 0xA8, 0xD0, 0xEF, 0xA9, 0x90, 0x8D, 0x0D, 0xDD, 0x0D, 0xA1, 0x02, 0x8D, 0xA1, 0x02, 0x85, 0xA9, 0xA9, 0x02, 0x4C, 0x3B, 0xEF, 0xA5, 0xA7, 0xD0, 0xEA, 0x4C, 0xD3, 0xE4, 0xAC, 0x9B, 0x02, 0xC8, 0xCC, 0x9C, 0x02, 0xF0, 0x2A, 0x8C, 0x9B, 0x02, 0x88, 0xA5, 0xAA, 0xAE, 0x98, 0x02, 0xE0, 0x09, 0xF0, 0x04, 0x4A, 0xE8, 0xD0, 0xF8, 0x91, 0xF7, 0xA9, 0x20, 0x2C, 0x94, 0x02, 0xF0, 0xB4, 0x30, 0xB1, 0xA5, 0xA7, 0x45, 0xAB, 0xF0, 0x03, 0x70, 0xA9, 0x2C, 0x50, 0xA6, 0xA9, 0x01, 0x2C, 0xA9, 0x04, 0x2C, 0xA9, 0x80, 0x2C, 0xA9, 0x02, 0x0D, 0x97, 0x02, 0x8D, 0x97, 0x02, 0x4C, 0x7E, 0xEF, 0xA5, 0xAA, 0xD0, 0xF1, 0xF0, 0xEC, 0x85, 0x9A, 0xAD, 0x94, 0x02, 0x4A, 0x90, 0x29, 0xA9, 0x02, 0x2C, 0x01, 0xDD, 0x10, 0x1D, 0xD0, 0x20, 0xAD, 0xA1, 0x02, 0x29, 0x02, 0xD0, 0xF9, 0x2C, 0x01, 0xDD, 0x70, 0xFB, 0xAD, 0x01, 0xDD, 0x09, 0x02, 0x8D, 0x01, 0xDD, 0x2C, 0x01, 0xDD, 0x70, 0x07, 0x30, 0xF9, 0xA9, 0x40, 0x8D, 0x97, 0x02, 0x18, 0x60, 0x20, 0x28, 0xF0, 0xAC, 0x9E, 0x02, 0xC8, 0xCC, 0x9D, 0x02, 0xF0, 0xF4, 0x8C, 0x9E, 0x02, 0x88, 0xA5, 0x9E, 0x91, 0xF9, 0xAD, 0xA1, 0x02, 0x4A, 0xB0, 0x1E, 0xA9, 0x10, 0x8D, 0x0E, 0xDD, 0xAD, 0x99, 0x02, 0x8D, 0x04, 0xDD, 0xAD, 0x9A, 0x02, 0x8D, 0x05, 0xDD, 0xA9, 0x81, 0x20, 0x3B, 0xEF, 0x20, 0x06, 0xEF, 0xA9, 0x11, 0x8D, 0x0E, 0xDD, 0x60, 0x85, 0x99, 0xAD, 0x94, 0x02, 0x4A, 0x90, 0x28, 0x29, 0x08, 0xF0, 0x24, 0xA9, 0x02, 0x2C, 0x01, 0xDD, 0x10, 0xAD, 0xF0, 0x22, 0xAD, 0xA1, 0x02, 0x4A, 0xB0, 0xFA, 0xAD, 0x01, 0xDD, 0x29, 0xFD, 0x8D, 0x01, 0xDD, 0xAD, 0x01, 0xDD, 0x29, 0x04, 0xF0, 0xF9, 0xA9, 0x90, 0x18, 0x4C, 0x3B, 0xEF, 0xAD, 0xA1, 0x02, 0x29, 0x12, 0xF0, 0xF3, 0x18, 0x60, 0xAD, 0x97, 0x02, 0xAC, 0x9C, 0x02, 0xCC, 0x9B, 0x02, 0xF0, 0x0B, 0x29, 0xF7, 0x8D, 0x97, 0x02, 0xB1, 0xF7, 0xEE, 0x9C, 0x02, 0x60, 0x09, 0x08, 0x8D, 0x97, 0x02, 0xA9, 0x00, 0x60, 0x48, 0xAD, 0xA1, 0x02, 0xF0, 0x11, 0xAD, 0xA1, 0x02, 0x29, 0x03, 0xD0, 0xF9, 0xA9, 0x10, 0x8D, 0x0D, 0xDD, 0xA9, 0x00, 0x8D, 0xA1, 0x02, 0x68, 0x60, 0x0D, 0x49, 0x2F, 0x4F, 0x20, 0x45, 0x52, 0x52, 0x4F, 0x52, 0x20, 0xA3, 0x0D, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48, 0x49, 0x4E, 0x47, 0xA0, 0x46, 0x4F, 0x52, 0xA0, 0x0D, 0x50, 0x52, 0x45, 0x53, 0x53, 0x20, 0x50, 0x4C, 0x41, 0x59, 0x20, 0x4F, 0x4E, 0x20, 0x54, 0x41, 0x50, 0xC5, 0x50, 0x52, 0x45, 0x53, 0x53, 0x20, 0x52, 0x45, 0x43, 0x4F, 0x52, 0x44, 0x20, 0x26, 0x20, 0x50, 0x4C, 0x41, 0x59, 0x20, 0x4F, 0x4E, 0x20, 0x54, 0x41, 0x50, 0xC5, 0x0D, 0x4C, 0x4F, 0x41, 0x44, 0x49, 0x4E, 0xC7, 0x0D, 0x53, 0x41, 0x56, 0x49, 0x4E, 0x47, 0xA0, 0x0D, 0x56, 0x45, 0x52, 0x49, 0x46, 0x59, 0x49, 0x4E, 0xC7, 0x0D, 0x46, 0x4F, 0x55, 0x4E, 0x44, 0xA0, 0x0D, 0x4F, 0x4B, 0x8D, 0x24, 0x9D, 0x10, 0x0D, 0xB9, 0xBD, 0xF0, 0x08, 0x29, 0x7F, 0x20, 0xD2, 0xFF, 0xC8, 0x28, 0x10, 0xF3, 0x18, 0x60, 0xA5, 0x99, 0xD0, 0x08, 0xA5, 0xC6, 0xF0, 0x0F, 0x78, 0x4C, 0xB4, 0xE5, 0xC9, 0x02, 0xD0, 0x18, 0x84, 0x97, 0x20, 0x86, 0xF0, 0xA4, 0x97, 0x18, 0x60, 0xA5, 0x99, 0xD0, 0x0B, 0xA5, 0xD3, 0x85, 0xCA, 0xA5, 0xD6, 0x85, 0xC9, 0x4C, 0x32, 0xE6, 0xC9, 0x03, 0xD0, 0x09, 0x85, 0xD0, 0xA5, 0xD5, 0x85, 0xC8, 0x4C, 0x32, 0xE6, 0xB0, 0x38, 0xC9, 0x02, 0xF0, 0x3F, 0x86, 0x97, 0x20, 0x99, 0xF1, 0xB0, 0x16, 0x48, 0x20, 0x99, 0xF1, 0xB0, 0x0D, 0xD0, 0x05, 0xA9, 0x40, 0x20, 0x1C, 0xFE, 0xC6, 0xA6, 0xA6, 0x97, 0x68, 0x60, 0xAA, 0x68, 0x8A, 0xA6, 0x97, 0x60, 0x20, 0x0D, 0xF8, 0xD0, 0x0B, 0x20, 0x41, 0xF8, 0xB0, 0x11, 0xA9, 0x00, 0x85, 0xA6, 0xF0, 0xF0, 0xB1, 0xB2, 0x18, 0x60, 0xA5, 0x90, 0xF0, 0x04, 0xA9, 0x0D, 0x18, 0x60, 0x4C, 0x13, 0xEE, 0x20, 0x4E, 0xF1, 0xB0, 0xF7, 0xC9, 0x00, 0xD0, 0xF2, 0xAD, 0x97, 0x02, 0x29, 0x60, 0xD0, 0xE9, 0xF0, 0xEE, 0x48, 0xA5, 0x9A, 0xC9, 0x03, 0xD0, 0x04, 0x68, 0x4C, 0x16, 0xE7, 0x90, 0x04, 0x68, 0x4C, 0xDD, 0xED, 0x4A, 0x68, 0x85, 0x9E, 0x8A, 0x48, 0x98, 0x48, 0x90, 0x23, 0x20, 0x0D, 0xF8, 0xD0, 0x0E, 0x20, 0x64, 0xF8, 0xB0, 0x0E, 0xA9, 0x02, 0xA0, 0x00, 0x91, 0xB2, 0xC8, 0x84, 0xA6, 0xA5, 0x9E, 0x91, 0xB2, 0x18, 0x68, 0xA8, 0x68, 0xAA, 0xA5, 0x9E, 0x90, 0x02, 0xA9, 0x00, 0x60, 0x20, 0x17, 0xF0, 0x4C, 0xFC, 0xF1, 0x20, 0x0F, 0xF3, 0xF0, 0x03, 0x4C, 0x01, 0xF7, 0x20, 0x1F, 0xF3, 0xA5, 0xBA, 0xF0, 0x16, 0xC9, 0x03, 0xF0, 0x12, 0xB0, 0x14, 0xC9, 0x02, 0xD0, 0x03, 0x4C, 0x4D, 0xF0, 0xA6, 0xB9, 0xE0, 0x60, 0xF0, 0x03, 0x4C, 0x0A, 0xF7, 0x85, 0x99, 0x18, 0x60, 0xAA, 0x20, 0x09, 0xED, 0xA5, 0xB9, 0x10, 0x06, 0x20, 0xCC, 0xED, 0x4C, 0x48, 0xF2, 0x20, 0xC7, 0xED, 0x8A, 0x24, 0x90, 0x10, 0xE6, 0x4C, 0x07, 0xF7, 0x20, 0x0F, 0xF3, 0xF0, 0x03, 0x4C, 0x01, 0xF7, 0x20, 0x1F, 0xF3, 0xA5, 0xBA, 0xD0, 0x03, 0x4C, 0x0D, 0xF7, 0xC9, 0x03, 0xF0, 0x0F, 0xB0, 0x11, 0xC9, 0x02, 0xD0, 0x03, 0x4C, 0xE1, 0xEF, 0xA6, 0xB9, 0xE0, 0x60, 0xF0, 0xEA, 0x85, 0x9A, 0x18, 0x60, 0xAA, 0x20, 0x0C, 0xED, 0xA5, 0xB9, 0x10, 0x05, 0x20, 0xBE, 0xED, 0xD0, 0x03, 0x20, 0xB9, 0xED, 0x8A, 0x24, 0x90, 0x10, 0xE7, 0x4C, 0x07, 0xF7, 0x20, 0x14, 0xF3, 0xF0, 0x02, 0x18, 0x60, 0x20, 0x1F, 0xF3, 0x8A, 0x48, 0xA5, 0xBA, 0xF0, 0x50, 0xC9, 0x03, 0xF0, 0x4C, 0xB0, 0x47, 0xC9, 0x02, 0xD0, 0x1D, 0x68, 0x20, 0xF2, 0xF2, 0x20, 0x83, 0xF4, 0x20, 0x27, 0xFE, 0xA5, 0xF8, 0xF0, 0x01, 0xC8, 0xA5, 0xFA, 0xF0, 0x01, 0xC8, 0xA9, 0x00, 0x85, 0xF8, 0x85, 0xFA, 0x4C, 0x7D, 0xF4, 0xA5, 0xB9, 0x29, 0x0F, 0xF0, 0x23, 0x20, 0xD0, 0xF7, 0xA9, 0x00, 0x38, 0x20, 0xDD, 0xF1, 0x20, 0x64, 0xF8, 0x90, 0x04, 0x68, 0xA9, 0x00, 0x60, 0xA5, 0xB9, 0xC9, 0x62, 0xD0, 0x0B, 0xA9, 0x05, 0x20, 0x6A, 0xF7, 0x4C, 0xF1, 0xF2, 0x20, 0x42, 0xF6, 0x68, 0xAA, 0xC6, 0x98, 0xE4, 0x98, 0xF0, 0x14, 0xA4, 0x98, 0xB9, 0x59, 0x02, 0x9D, 0x59, 0x02, 0xB9, 0x63, 0x02, 0x9D, 0x63, 0x02, 0xB9, 0x6D, 0x02, 0x9D, 0x6D, 0x02, 0x18, 0x60, 0xA9, 0x00, 0x85, 0x90, 0x8A, 0xA6, 0x98, 0xCA, 0x30, 0x15, 0xDD, 0x59, 0x02, 0xD0, 0xF8, 0x60, 0xBD, 0x59, 0x02, 0x85, 0xB8, 0xBD, 0x63, 0x02, 0x85, 0xBA, 0xBD, 0x6D, 0x02, 0x85, 0xB9, 0x60, 0xA9, 0x00, 0x85, 0x98, 0xA2, 0x03, 0xE4, 0x9A, 0xB0, 0x03, 0x20, 0xFE, 0xED, 0xE4, 0x99, 0xB0, 0x03, 0x20, 0xEF, 0xED, 0x86, 0x9A, 0xA9, 0x00, 0x85, 0x99, 0x60, 0xA6, 0xB8, 0xD0, 0x03, 0x4C, 0x0A, 0xF7, 0x20, 0x0F, 0xF3, 0xD0, 0x03, 0x4C, 0xFE, 0xF6, 0xA6, 0x98, 0xE0, 0x0A, 0x90, 0x03, 0x4C, 0xFB, 0xF6, 0xE6, 0x98, 0xA5, 0xB8, 0x9D, 0x59, 0x02, 0xA5, 0xB9, 0x09, 0x60, 0x85, 0xB9, 0x9D, 0x6D, 0x02, 0xA5, 0xBA, 0x9D, 0x63, 0x02, 0xF0, 0x5A, 0xC9, 0x03, 0xF0, 0x56, 0x90, 0x05, 0x20, 0xD5, 0xF3, 0x90, 0x4F, 0xC9, 0x02, 0xD0, 0x03, 0x4C, 0x09, 0xF4, 0x20, 0xD0, 0xF7, 0xB0, 0x03, 0x4C, 0x13, 0xF7, 0xA5, 0xB9, 0x29, 0x0F, 0xD0, 0x1F, 0x20, 0x17, 0xF8, 0xB0, 0x36, 0x20, 0xAF, 0xF5, 0xA5, 0xB7, 0xF0, 0x0A, 0x20, 0xEA, 0xF7, 0x90, 0x18, 0xF0, 0x28, 0x4C, 0x04, 0xF7, 0x20, 0x2C, 0xF7, 0xF0, 0x20, 0x90, 0x0C, 0xB0, 0xF4, 0x20, 0x38, 0xF8, 0xB0, 0x17, 0xA9, 0x04, 0x20, 0x6A, 0xF7, 0xA9, 0xBF, 0xA4, 0xB9, 0xC0, 0x60, 0xF0, 0x07, 0xA0, 0x00, 0xA9, 0x02, 0x91, 0xB2, 0x98, 0x85, 0xA6, 0x18, 0x60, 0xA5, 0xB9, 0x30, 0xFA, 0xA4, 0xB7, 0xF0, 0xF6, 0xA9, 0x00, 0x85, 0x90, 0xA5, 0xBA, 0x20, 0x0C, 0xED, 0xA5, 0xB9, 0x09, 0xF0, 0x20, 0xB9, 0xED, 0xA5, 0x90, 0x10, 0x05, 0x68, 0x68, 0x4C, 0x07, 0xF7, 0xA5, 0xB7, 0xF0, 0x0C, 0xA0, 0x00, 0xB1, 0xBB, 0x20, 0xDD, 0xED, 0xC8, 0xC4, 0xB7, 0xD0, 0xF6, 0x4C, 0x54, 0xF6, 0x20, 0x83, 0xF4, 0x8C, 0x97, 0x02, 0xC4, 0xB7, 0xF0, 0x0A, 0xB1, 0xBB, 0x99, 0x93, 0x02, 0xC8, 0xC0, 0x04, 0xD0, 0xF2, 0x20, 0x4A, 0xEF, 0x8E, 0x98, 0x02, 0xAD, 0x93, 0x02, 0x29, 0x0F, 0xF0, 0x1C, 0x0A, 0xAA, 0xAD, 0xA6, 0x02, 0xD0, 0x09, 0xBC, 0xC1, 0xFE, 0xBD, 0xC0, 0xFE, 0x4C, 0x40, 0xF4, 0xBC, 0xEB, 0xE4, 0xBD, 0xEA, 0xE4, 0x8C, 0x96, 0x02, 0x8D, 0x95, 0x02, 0xAD, 0x95, 0x02, 0x0A, 0x20, 0x2E, 0xFF, 0xAD, 0x94, 0x02, 0x4A, 0x90, 0x09, 0xAD, 0x01, 0xDD, 0x0A, 0xB0, 0x03, 0x20, 0x0D, 0xF0, 0xAD, 0x9B, 0x02, 0x8D, 0x9C, 0x02, 0xAD, 0x9E, 0x02, 0x8D, 0x9D, 0x02, 0x20, 0x27, 0xFE, 0xA5, 0xF8, 0xD0, 0x05, 0x88, 0x84, 0xF8, 0x86, 0xF7, 0xA5, 0xFA, 0xD0, 0x05, 0x88, 0x84, 0xFA, 0x86, 0xF9, 0x38, 0xA9, 0xF0, 0x4C, 0x2D, 0xFE, 0xA9, 0x7F, 0x8D, 0x0D, 0xDD, 0xA9, 0x06, 0x8D, 0x03, 0xDD, 0x8D, 0x01, 0xDD, 0xA9, 0x04, 0x0D, 0x00, 0xDD, 0x8D, 0x00, 0xDD, 0xA0, 0x00, 0x8C, 0xA1, 0x02, 0x60, 0x86, 0xC3, 0x84, 0xC4, 0x6C, 0x30, 0x03, 0x85, 0x93, 0xA9, 0x00, 0x85, 0x90, 0xA5, 0xBA, 0xD0, 0x03, 0x4C, 0x13, 0xF7, 0xC9, 0x03, 0xF0, 0xF9, 0x90, 0x7B, 0xA4, 0xB7, 0xD0, 0x03, 0x4C, 0x10, 0xF7, 0xA6, 0xB9, 0x20, 0xAF, 0xF5, 0xA9, 0x60, 0x85, 0xB9, 0x20, 0xD5, 0xF3, 0xA5, 0xBA, 0x20, 0x09, 0xED, 0xA5, 0xB9, 0x20, 0xC7, 0xED, 0x20, 0x13, 0xEE, 0x85, 0xAE, 0xA5, 0x90, 0x4A, 0x4A, 0xB0, 0x50, 0x20, 0x13, 0xEE, 0x85, 0xAF, 0x8A, 0xD0, 0x08, 0xA5, 0xC3, 0x85, 0xAE, 0xA5, 0xC4, 0x85, 0xAF, 0x20, 0xD2, 0xF5, 0xA9, 0xFD, 0x25, 0x90, 0x85, 0x90, 0x20, 0xE1, 0xFF, 0xD0, 0x03, 0x4C, 0x33, 0xF6, 0x20, 0x13, 0xEE, 0xAA, 0xA5, 0x90, 0x4A, 0x4A, 0xB0, 0xE8, 0x8A, 0xA4, 0x93, 0xF0, 0x0C, 0xA0, 0x00, 0xD1, 0xAE, 0xF0, 0x08, 0xA9, 0x10, 0x20, 0x1C, 0xFE, 0x2C, 0x91, 0xAE, 0xE6, 0xAE, 0xD0, 0x02, 0xE6, 0xAF, 0x24, 0x90, 0x50, 0xCB, 0x20, 0xEF, 0xED, 0x20, 0x42, 0xF6, 0x90, 0x79, 0x4C, 0x04, 0xF7, 0x4A, 0xB0, 0x03, 0x4C, 0x13, 0xF7, 0x20, 0xD0, 0xF7, 0xB0, 0x03, 0x4C, 0x13, 0xF7, 0x20, 0x17, 0xF8, 0xB0, 0x68, 0x20, 0xAF, 0xF5, 0xA5, 0xB7, 0xF0, 0x09, 0x20, 0xEA, 0xF7, 0x90, 0x0B, 0xF0, 0x5A, 0xB0, 0xDA, 0x20, 0x2C, 0xF7, 0xF0, 0x53, 0xB0, 0xD3, 0xA5, 0x90, 0x29, 0x10, 0x38, 0xD0, 0x4A, 0xE0, 0x01, 0xF0, 0x11, 0xE0, 0x03, 0xD0, 0xDD, 0xA0, 0x01, 0xB1, 0xB2, 0x85, 0xC3, 0xC8, 0xB1, 0xB2, 0x85, 0xC4, 0xB0, 0x04, 0xA5, 0xB9, 0xD0, 0xEF, 0xA0, 0x03, 0xB1, 0xB2, 0xA0, 0x01, 0xF1, 0xB2, 0xAA, 0xA0, 0x04, 0xB1, 0xB2, 0xA0, 0x02, 0xF1, 0xB2, 0xA8, 0x18, 0x8A, 0x65, 0xC3, 0x85, 0xAE, 0x98, 0x65, 0xC4, 0x85, 0xAF, 0xA5, 0xC3, 0x85, 0xC1, 0xA5, 0xC4, 0x85, 0xC2, 0x20, 0xD2, 0xF5, 0x20, 0x4A, 0xF8, 0x24, 0x18, 0xA6, 0xAE, 0xA4, 0xAF, 0x60, 0xA5, 0x9D, 0x10, 0x1E, 0xA0, 0x0C, 0x20, 0x2F, 0xF1, 0xA5, 0xB7, 0xF0, 0x15, 0xA0, 0x17, 0x20, 0x2F, 0xF1, 0xA4, 0xB7, 0xF0, 0x0C, 0xA0, 0x00, 0xB1, 0xBB, 0x20, 0xD2, 0xFF, 0xC8, 0xC4, 0xB7, 0xD0, 0xF6, 0x60, 0xA0, 0x49, 0xA5, 0x93, 0xF0, 0x02, 0xA0, 0x59, 0x4C, 0x2B, 0xF1, 0x86, 0xAE, 0x84, 0xAF, 0xAA, 0xB5, 0x00, 0x85, 0xC1, 0xB5, 0x01, 0x85, 0xC2, 0x6C, 0x32, 0x03, 0xA5, 0xBA, 0xD0, 0x03, 0x4C, 0x13, 0xF7, 0xC9, 0x03, 0xF0, 0xF9, 0x90, 0x5F, 0xA9, 0x61, 0x85, 0xB9, 0xA4, 0xB7, 0xD0, 0x03, 0x4C, 0x10, 0xF7, 0x20, 0xD5, 0xF3, 0x20, 0x8F, 0xF6, 0xA5, 0xBA, 0x20, 0x0C, 0xED, 0xA5, 0xB9, 0x20, 0xB9, 0xED, 0xA0, 0x00, 0x20, 0x8E, 0xFB, 0xA5, 0xAC, 0x20, 0xDD, 0xED, 0xA5, 0xAD, 0x20, 0xDD, 0xED, 0x20, 0xD1, 0xFC, 0xB0, 0x16, 0xB1, 0xAC, 0x20, 0xDD, 0xED, 0x20, 0xE1, 0xFF, 0xD0, 0x07, 0x20, 0x42, 0xF6, 0xA9, 0x00, 0x38, 0x60, 0x20, 0xDB, 0xFC, 0xD0, 0xE5, 0x20, 0xFE, 0xED, 0x24, 0xB9, 0x30, 0x11, 0xA5, 0xBA, 0x20, 0x0C, 0xED, 0xA5, 0xB9, 0x29, 0xEF, 0x09, 0xE0, 0x20, 0xB9, 0xED, 0x20, 0xFE, 0xED, 0x18, 0x60, 0x4A, 0xB0, 0x03, 0x4C, 0x13, 0xF7, 0x20, 0xD0, 0xF7, 0x90, 0x8D, 0x20, 0x38, 0xF8, 0xB0, 0x25, 0x20, 0x8F, 0xF6, 0xA2, 0x03, 0xA5, 0xB9, 0x29, 0x01, 0xD0, 0x02, 0xA2, 0x01, 0x8A, 0x20, 0x6A, 0xF7, 0xB0, 0x12, 0x20, 0x67, 0xF8, 0xB0, 0x0D, 0xA5, 0xB9, 0x29, 0x02, 0xF0, 0x06, 0xA9, 0x05, 0x20, 0x6A, 0xF7, 0x24, 0x18, 0x60, 0xA5, 0x9D, 0x10, 0xFB, 0xA0, 0x51, 0x20, 0x2F, 0xF1, 0x4C, 0xC1, 0xF5, 0xA2, 0x00, 0xE6, 0xA2, 0xD0, 0x06, 0xE6, 0xA1, 0xD0, 0x02, 0xE6, 0xA0, 0x38, 0xA5, 0xA2, 0xE9, 0x01, 0xA5, 0xA1, 0xE9, 0x1A, 0xA5, 0xA0, 0xE9, 0x4F, 0x90, 0x06, 0x86, 0xA0, 0x86, 0xA1, 0x86, 0xA2, 0xAD, 0x01, 0xDC, 0xCD, 0x01, 0xDC, 0xD0, 0xF8, 0xAA, 0x30, 0x13, 0xA2, 0xBD, 0x8E, 0x00, 0xDC, 0xAE, 0x01, 0xDC, 0xEC, 0x01, 0xDC, 0xD0, 0xF8, 0x8D, 0x00, 0xDC, 0xE8, 0xD0, 0x02, 0x85, 0x91, 0x60, 0x78, 0xA5, 0xA2, 0xA6, 0xA1, 0xA4, 0xA0, 0x78, 0x85, 0xA2, 0x86, 0xA1, 0x84, 0xA0, 0x58, 0x60, 0xA5, 0x91, 0xC9, 0x7F, 0xD0, 0x07, 0x08, 0x20, 0xCC, 0xFF, 0x85, 0xC6, 0x28, 0x60, 0xA9, 0x01, 0x2C, 0xA9, 0x02, 0x2C, 0xA9, 0x03, 0x2C, 0xA9, 0x04, 0x2C, 0xA9, 0x05, 0x2C, 0xA9, 0x06, 0x2C, 0xA9, 0x07, 0x2C, 0xA9, 0x08, 0x2C, 0xA9, 0x09, 0x48, 0x20, 0xCC, 0xFF, 0xA0, 0x00, 0x24, 0x9D, 0x50, 0x0A, 0x20, 0x2F, 0xF1, 0x68, 0x48, 0x09, 0x30, 0x20, 0xD2, 0xFF, 0x68, 0x38, 0x60, 0xA5, 0x93, 0x48, 0x20, 0x41, 0xF8, 0x68, 0x85, 0x93, 0xB0, 0x32, 0xA0, 0x00, 0xB1, 0xB2, 0xC9, 0x05, 0xF0, 0x2A, 0xC9, 0x01, 0xF0, 0x08, 0xC9, 0x03, 0xF0, 0x04, 0xC9, 0x04, 0xD0, 0xE1, 0xAA, 0x24, 0x9D, 0x10, 0x17, 0xA0, 0x63, 0x20, 0x2F, 0xF1, 0xA0, 0x05, 0xB1, 0xB2, 0x20, 0xD2, 0xFF, 0xC8, 0xC0, 0x15, 0xD0, 0xF6, 0xA5, 0xA1, 0x20, 0xE0, 0xE4, 0xEA, 0x18, 0x88, 0x60, 0x85, 0x9E, 0x20, 0xD0, 0xF7, 0x90, 0x5E, 0xA5, 0xC2, 0x48, 0xA5, 0xC1, 0x48, 0xA5, 0xAF, 0x48, 0xA5, 0xAE, 0x48, 0xA0, 0xBF, 0xA9, 0x20, 0x91, 0xB2, 0x88, 0xD0, 0xFB, 0xA5, 0x9E, 0x91, 0xB2, 0xC8, 0xA5, 0xC1, 0x91, 0xB2, 0xC8, 0xA5, 0xC2, 0x91, 0xB2, 0xC8, 0xA5, 0xAE, 0x91, 0xB2, 0xC8, 0xA5, 0xAF, 0x91, 0xB2, 0xC8, 0x84, 0x9F, 0xA0, 0x00, 0x84, 0x9E, 0xA4, 0x9E, 0xC4, 0xB7, 0xF0, 0x0C, 0xB1, 0xBB, 0xA4, 0x9F, 0x91, 0xB2, 0xE6, 0x9E, 0xE6, 0x9F, 0xD0, 0xEE, 0x20, 0xD7, 0xF7, 0xA9, 0x69, 0x85, 0xAB, 0x20, 0x6B, 0xF8, 0xA8, 0x68, 0x85, 0xAE, 0x68, 0x85, 0xAF, 0x68, 0x85, 0xC1, 0x68, 0x85, 0xC2, 0x98, 0x60, 0xA6, 0xB2, 0xA4, 0xB3, 0xC0, 0x02, 0x60, 0x20, 0xD0, 0xF7, 0x8A, 0x85, 0xC1, 0x18, 0x69, 0xC0, 0x85, 0xAE, 0x98, 0x85, 0xC2, 0x69, 0x00, 0x85, 0xAF, 0x60, 0x20, 0x2C, 0xF7, 0xB0, 0x1D, 0xA0, 0x05, 0x84, 0x9F, 0xA0, 0x00, 0x84, 0x9E, 0xC4, 0xB7, 0xF0, 0x10, 0xB1, 0xBB, 0xA4, 0x9F, 0xD1, 0xB2, 0xD0, 0xE7, 0xE6, 0x9E, 0xE6, 0x9F, 0xA4, 0x9E, 0xD0, 0xEC, 0x18, 0x60, 0x20, 0xD0, 0xF7, 0xE6, 0xA6, 0xA4, 0xA6, 0xC0, 0xC0, 0x60, 0x20, 0x2E, 0xF8, 0xF0, 0x1A, 0xA0, 0x1B, 0x20, 0x2F, 0xF1, 0x20, 0xD0, 0xF8, 0x20, 0x2E, 0xF8, 0xD0, 0xF8, 0xA0, 0x6A, 0x4C, 0x2F, 0xF1, 0xA9, 0x10, 0x24, 0x01, 0xD0, 0x02, 0x24, 0x01, 0x18, 0x60, 0x20, 0x2E, 0xF8, 0xF0, 0xF9, 0xA0, 0x2E, 0xD0, 0xDD, 0xA9, 0x00, 0x85, 0x90, 0x85, 0x93, 0x20, 0xD7, 0xF7, 0x20, 0x17, 0xF8, 0xB0, 0x1F, 0x78, 0xA9, 0x00, 0x85, 0xAA, 0x85, 0xB4, 0x85, 0xB0, 0x85, 0x9E, 0x85, 0x9F, 0x85, 0x9C, 0xA9, 0x90, 0xA2, 0x0E, 0xD0, 0x11, 0x20, 0xD7, 0xF7, 0xA9, 0x14, 0x85, 0xAB, 0x20, 0x38, 0xF8, 0xB0, 0x6C, 0x78, 0xA9, 0x82, 0xA2, 0x08, 0xA0, 0x7F, 0x8C, 0x0D, 0xDC, 0x8D, 0x0D, 0xDC, 0xAD, 0x0E, 0xDC, 0x09, 0x19, 0x8D, 0x0F, 0xDC, 0x29, 0x91, 0x8D, 0xA2, 0x02, 0x20, 0xA4, 0xF0, 0xAD, 0x11, 0xD0, 0x29, 0xEF, 0x8D, 0x11, 0xD0, 0xAD, 0x14, 0x03, 0x8D, 0x9F, 0x02, 0xAD, 0x15, 0x03, 0x8D, 0xA0, 0x02, 0x20, 0xBD, 0xFC, 0xA9, 0x02, 0x85, 0xBE, 0x20, 0x97, 0xFB, 0xA5, 0x01, 0x29, 0x1F, 0x85, 0x01, 0x85, 0xC0, 0xA2, 0xFF, 0xA0, 0xFF, 0x88, 0xD0, 0xFD, 0xCA, 0xD0, 0xF8, 0x58, 0xAD, 0xA0, 0x02, 0xCD, 0x15, 0x03, 0x18, 0xF0, 0x15, 0x20, 0xD0, 0xF8, 0x20, 0xBC, 0xF6, 0x4C, 0xBE, 0xF8, 0x20, 0xE1, 0xFF, 0x18, 0xD0, 0x0B, 0x20, 0x93, 0xFC, 0x38, 0x68, 0x68, 0xA9, 0x00, 0x8D, 0xA0, 0x02, 0x60, 0x86, 0xB1, 0xA5, 0xB0, 0x0A, 0x0A, 0x18, 0x65, 0xB0, 0x18, 0x65, 0xB1, 0x85, 0xB1, 0xA9, 0x00, 0x24, 0xB0, 0x30, 0x01, 0x2A, 0x06, 0xB1, 0x2A, 0x06, 0xB1, 0x2A, 0xAA, 0xAD, 0x06, 0xDC, 0xC9, 0x16, 0x90, 0xF9, 0x65, 0xB1, 0x8D, 0x04, 0xDC, 0x8A, 0x6D, 0x07, 0xDC, 0x8D, 0x05, 0xDC, 0xAD, 0xA2, 0x02, 0x8D, 0x0E, 0xDC, 0x8D, 0xA4, 0x02, 0xAD, 0x0D, 0xDC, 0x29, 0x10, 0xF0, 0x09, 0xA9, 0xF9, 0x48, 0xA9, 0x2A, 0x48, 0x4C, 0x43, 0xFF, 0x58, 0x60, 0xAE, 0x07, 0xDC, 0xA0, 0xFF, 0x98, 0xED, 0x06, 0xDC, 0xEC, 0x07, 0xDC, 0xD0, 0xF2, 0x86, 0xB1, 0xAA, 0x8C, 0x06, 0xDC, 0x8C, 0x07, 0xDC, 0xA9, 0x19, 0x8D, 0x0F, 0xDC, 0xAD, 0x0D, 0xDC, 0x8D, 0xA3, 0x02, 0x98, 0xE5, 0xB1, 0x86, 0xB1, 0x4A, 0x66, 0xB1, 0x4A, 0x66, 0xB1, 0xA5, 0xB0, 0x18, 0x69, 0x3C, 0xC5, 0xB1, 0xB0, 0x4A, 0xA6, 0x9C, 0xF0, 0x03, 0x4C, 0x60, 0xFA, 0xA6, 0xA3, 0x30, 0x1B, 0xA2, 0x00, 0x69, 0x30, 0x65, 0xB0, 0xC5, 0xB1, 0xB0, 0x1C, 0xE8, 0x69, 0x26, 0x65, 0xB0, 0xC5, 0xB1, 0xB0, 0x17, 0x69, 0x2C, 0x65, 0xB0, 0xC5, 0xB1, 0x90, 0x03, 0x4C, 0x10, 0xFA, 0xA5, 0xB4, 0xF0, 0x1D, 0x85, 0xA8, 0xD0, 0x19, 0xE6, 0xA9, 0xB0, 0x02, 0xC6, 0xA9, 0x38, 0xE9, 0x13, 0xE5, 0xB1, 0x65, 0x92, 0x85, 0x92, 0xA5, 0xA4, 0x49, 0x01, 0x85, 0xA4, 0xF0, 0x2B, 0x86, 0xD7, 0xA5, 0xB4, 0xF0, 0x22, 0xAD, 0xA3, 0x02, 0x29, 0x01, 0xD0, 0x05, 0xAD, 0xA4, 0x02, 0xD0, 0x16, 0xA9, 0x00, 0x85, 0xA4, 0x8D, 0xA4, 0x02, 0xA5, 0xA3, 0x10, 0x30, 0x30, 0xBF, 0xA2, 0xA6, 0x20, 0xE2, 0xF8, 0xA5, 0x9B, 0xD0, 0xB9, 0x4C, 0xBC, 0xFE, 0xA5, 0x92, 0xF0, 0x07, 0x30, 0x03, 0xC6, 0xB0, 0x2C, 0xE6, 0xB0, 0xA9, 0x00, 0x85, 0x92, 0xE4, 0xD7, 0xD0, 0x0F, 0x8A, 0xD0, 0xA0, 0xA5, 0xA9, 0x30, 0xBD, 0xC9, 0x10, 0x90, 0xB9, 0x85, 0x96, 0xB0, 0xB5, 0x8A, 0x45, 0x9B, 0x85, 0x9B, 0xA5, 0xB4, 0xF0, 0xD2, 0xC6, 0xA3, 0x30, 0xC5, 0x46, 0xD7, 0x66, 0xBF, 0xA2, 0xDA, 0x20, 0xE2, 0xF8, 0x4C, 0xBC, 0xFE, 0xA5, 0x96, 0xF0, 0x04, 0xA5, 0xB4, 0xF0, 0x07, 0xA5, 0xA3, 0x30, 0x03, 0x4C, 0x97, 0xF9, 0x46, 0xB1, 0xA9, 0x93, 0x38, 0xE5, 0xB1, 0x65, 0xB0, 0x0A, 0xAA, 0x20, 0xE2, 0xF8, 0xE6, 0x9C, 0xA5, 0xB4, 0xD0, 0x11, 0xA5, 0x96, 0xF0, 0x26, 0x85, 0xA8, 0xA9, 0x00, 0x85, 0x96, 0xA9, 0x81, 0x8D, 0x0D, 0xDC, 0x85, 0xB4, 0xA5, 0x96, 0x85, 0xB5, 0xF0, 0x09, 0xA9, 0x00, 0x85, 0xB4, 0xA9, 0x01, 0x8D, 0x0D, 0xDC, 0xA5, 0xBF, 0x85, 0xBD, 0xA5, 0xA8, 0x05, 0xA9, 0x85, 0xB6, 0x4C, 0xBC, 0xFE, 0x20, 0x97, 0xFB, 0x85, 0x9C, 0xA2, 0xDA, 0x20, 0xE2, 0xF8, 0xA5, 0xBE, 0xF0, 0x02, 0x85, 0xA7, 0xA9, 0x0F, 0x24, 0xAA, 0x10, 0x17, 0xA5, 0xB5, 0xD0, 0x0C, 0xA6, 0xBE, 0xCA, 0xD0, 0x0B, 0xA9, 0x08, 0x20, 0x1C, 0xFE, 0xD0, 0x04, 0xA9, 0x00, 0x85, 0xAA, 0x4C, 0xBC, 0xFE, 0x70, 0x31, 0xD0, 0x18, 0xA5, 0xB5, 0xD0, 0xF5, 0xA5, 0xB6, 0xD0, 0xF1, 0xA5, 0xA7, 0x4A, 0xA5, 0xBD, 0x30, 0x03, 0x90, 0x18, 0x18, 0xB0, 0x15, 0x29, 0x0F, 0x85, 0xAA, 0xC6, 0xAA, 0xD0, 0xDD, 0xA9, 0x40, 0x85, 0xAA, 0x20, 0x8E, 0xFB, 0xA9, 0x00, 0x85, 0xAB, 0xF0, 0xD0, 0xA9, 0x80, 0x85, 0xAA, 0xD0, 0xCA, 0xA5, 0xB5, 0xF0, 0x0A, 0xA9, 0x04, 0x20, 0x1C, 0xFE, 0xA9, 0x00, 0x4C, 0x4A, 0xFB, 0x20, 0xD1, 0xFC, 0x90, 0x03, 0x4C, 0x48, 0xFB, 0xA6, 0xA7, 0xCA, 0xF0, 0x2D, 0xA5, 0x93, 0xF0, 0x0C, 0xA0, 0x00, 0xA5, 0xBD, 0xD1, 0xAC, 0xF0, 0x04, 0xA9, 0x01, 0x85, 0xB6, 0xA5, 0xB6, 0xF0, 0x4B, 0xA2, 0x3D, 0xE4, 0x9E, 0x90, 0x3E, 0xA6, 0x9E, 0xA5, 0xAD, 0x9D, 0x01, 0x01, 0xA5, 0xAC, 0x9D, 0x00, 0x01, 0xE8, 0xE8, 0x86, 0x9E, 0x4C, 0x3A, 0xFB, 0xA6, 0x9F, 0xE4, 0x9E, 0xF0, 0x35, 0xA5, 0xAC, 0xDD, 0x00, 0x01, 0xD0, 0x2E, 0xA5, 0xAD, 0xDD, 0x01, 0x01, 0xD0, 0x27, 0xE6, 0x9F, 0xE6, 0x9F, 0xA5, 0x93, 0xF0, 0x0B, 0xA5, 0xBD, 0xA0, 0x00, 0xD1, 0xAC, 0xF0, 0x17, 0xC8, 0x84, 0xB6, 0xA5, 0xB6, 0xF0, 0x07, 0xA9, 0x10, 0x20, 0x1C, 0xFE, 0xD0, 0x09, 0xA5, 0x93, 0xD0, 0x05, 0xA8, 0xA5, 0xBD, 0x91, 0xAC, 0x20, 0xDB, 0xFC, 0xD0, 0x43, 0xA9, 0x80, 0x85, 0xAA, 0x78, 0xA2, 0x01, 0x8E, 0x0D, 0xDC, 0xAE, 0x0D, 0xDC, 0xA6, 0xBE, 0xCA, 0x30, 0x02, 0x86, 0xBE, 0xC6, 0xA7, 0xF0, 0x08, 0xA5, 0x9E, 0xD0, 0x27, 0x85, 0xBE, 0xF0, 0x23, 0x20, 0x93, 0xFC, 0x20, 0x8E, 0xFB, 0xA0, 0x00, 0x84, 0xAB, 0xB1, 0xAC, 0x45, 0xAB, 0x85, 0xAB, 0x20, 0xDB, 0xFC, 0x20, 0xD1, 0xFC, 0x90, 0xF2, 0xA5, 0xAB, 0x45, 0xBD, 0xF0, 0x05, 0xA9, 0x20, 0x20, 0x1C, 0xFE, 0x4C, 0xBC, 0xFE, 0xA5, 0xC2, 0x85, 0xAD, 0xA5, 0xC1, 0x85, 0xAC, 0x60, 0xA9, 0x08, 0x85, 0xA3, 0xA9, 0x00, 0x85, 0xA4, 0x85, 0xA8, 0x85, 0x9B, 0x85, 0xA9, 0x60, 0xA5, 0xBD, 0x4A, 0xA9, 0x60, 0x90, 0x02, 0xA9, 0xB0, 0xA2, 0x00, 0x8D, 0x06, 0xDC, 0x8E, 0x07, 0xDC, 0xAD, 0x0D, 0xDC, 0xA9, 0x19, 0x8D, 0x0F, 0xDC, 0xA5, 0x01, 0x49, 0x08, 0x85, 0x01, 0x29, 0x08, 0x60, 0x38, 0x66, 0xB6, 0x30, 0x3C, 0xA5, 0xA8, 0xD0, 0x12, 0xA9, 0x10, 0xA2, 0x01, 0x20, 0xB1, 0xFB, 0xD0, 0x2F, 0xE6, 0xA8, 0xA5, 0xB6, 0x10, 0x29, 0x4C, 0x57, 0xFC, 0xA5, 0xA9, 0xD0, 0x09, 0x20, 0xAD, 0xFB, 0xD0, 0x1D, 0xE6, 0xA9, 0xD0, 0x19, 0x20, 0xA6, 0xFB, 0xD0, 0x14, 0xA5, 0xA4, 0x49, 0x01, 0x85, 0xA4, 0xF0, 0x0F, 0xA5, 0xBD, 0x49, 0x01, 0x85, 0xBD, 0x29, 0x01, 0x45, 0x9B, 0x85, 0x9B, 0x4C, 0xBC, 0xFE, 0x46, 0xBD, 0xC6, 0xA3, 0xA5, 0xA3, 0xF0, 0x3A, 0x10, 0xF3, 0x20, 0x97, 0xFB, 0x58, 0xA5, 0xA5, 0xF0, 0x12, 0xA2, 0x00, 0x86, 0xD7, 0xC6, 0xA5, 0xA6, 0xBE, 0xE0, 0x02, 0xD0, 0x02, 0x09, 0x80, 0x85, 0xBD, 0xD0, 0xD9, 0x20, 0xD1, 0xFC, 0x90, 0x0A, 0xD0, 0x91, 0xE6, 0xAD, 0xA5, 0xD7, 0x85, 0xBD, 0xB0, 0xCA, 0xA0, 0x00, 0xB1, 0xAC, 0x85, 0xBD, 0x45, 0xD7, 0x85, 0xD7, 0x20, 0xDB, 0xFC, 0xD0, 0xBB, 0xA5, 0x9B, 0x49, 0x01, 0x85, 0xBD, 0x4C, 0xBC, 0xFE, 0xC6, 0xBE, 0xD0, 0x03, 0x20, 0xCA, 0xFC, 0xA9, 0x50, 0x85, 0xA7, 0xA2, 0x08, 0x78, 0x20, 0xBD, 0xFC, 0xD0, 0xEA, 0xA9, 0x78, 0x20, 0xAF, 0xFB, 0xD0, 0xE3, 0xC6, 0xA7, 0xD0, 0xDF, 0x20, 0x97, 0xFB, 0xC6, 0xAB, 0x10, 0xD8, 0xA2, 0x0A, 0x20, 0xBD, 0xFC, 0x58, 0xE6, 0xAB, 0xA5, 0xBE, 0xF0, 0x30, 0x20, 0x8E, 0xFB, 0xA2, 0x09, 0x86, 0xA5, 0x86, 0xB6, 0xD0, 0x83, 0x08, 0x78, 0xAD, 0x11, 0xD0, 0x09, 0x10, 0x8D, 0x11, 0xD0, 0x20, 0xCA, 0xFC, 0xA9, 0x7F, 0x8D, 0x0D, 0xDC, 0x20, 0xDD, 0xFD, 0xAD, 0xA0, 0x02, 0xF0, 0x09, 0x8D, 0x15, 0x03, 0xAD, 0x9F, 0x02, 0x8D, 0x14, 0x03, 0x28, 0x60, 0x20, 0x93, 0xFC, 0xF0, 0x97, 0xBD, 0x93, 0xFD, 0x8D, 0x14, 0x03, 0xBD, 0x94, 0xFD, 0x8D, 0x15, 0x03, 0x60, 0xA5, 0x01, 0x09, 0x20, 0x85, 0x01, 0x60, 0x38, 0xA5, 0xAC, 0xE5, 0xAE, 0xA5, 0xAD, 0xE5, 0xAF, 0x60, 0xE6, 0xAC, 0xD0, 0x02, 0xE6, 0xAD, 0x60, 0xA2, 0xFF, 0x78, 0x9A, 0xD8, 0x20, 0x02, 0xFD, 0xD0, 0x03, 0x6C, 0x00, 0x80, 0x8E, 0x16, 0xD0, 0x20, 0xA3, 0xFD, 0x20, 0x50, 0xFD, 0x20, 0x15, 0xFD, 0x20, 0x5B, 0xFF, 0x58, 0x6C, 0x00, 0xA0, 0xA2, 0x05, 0xBD, 0x0F, 0xFD, 0xDD, 0x03, 0x80, 0xD0, 0x03, 0xCA, 0xD0, 0xF5, 0x60, 0xC3, 0xC2, 0xCD, 0x38, 0x30, 0xA2, 0x30, 0xA0, 0xFD, 0x18, 0x86, 0xC3, 0x84, 0xC4, 0xA0, 0x1F, 0xB9, 0x14, 0x03, 0xB0, 0x02, 0xB1, 0xC3, 0x91, 0xC3, 0x99, 0x14, 0x03, 0x88, 0x10, 0xF1, 0x60, 0x31, 0xEA, 0x66, 0xFE, 0x47, 0xFE, 0x4A, 0xF3, 0x91, 0xF2, 0x0E, 0xF2, 0x50, 0xF2, 0x33, 0xF3, 0x57, 0xF1, 0xCA, 0xF1, 0xED, 0xF6, 0x3E, 0xF1, 0x2F, 0xF3, 0x66, 0xFE, 0xA5, 0xF4, 0xED, 0xF5, 0xA9, 0x00, 0xA8, 0x99, 0x02, 0x00, 0x99, 0x00, 0x02, 0x99, 0x00, 0x03, 0xC8, 0xD0, 0xF4, 0xA2, 0x3C, 0xA0, 0x03, 0x86, 0xB2, 0x84, 0xB3, 0xA8, 0xA9, 0x03, 0x85, 0xC2, 0xE6, 0xC2, 0xB1, 0xC1, 0xAA, 0xA9, 0x55, 0x91, 0xC1, 0xD1, 0xC1, 0xD0, 0x0F, 0x2A, 0x91, 0xC1, 0xD1, 0xC1, 0xD0, 0x08, 0x8A, 0x91, 0xC1, 0xC8, 0xD0, 0xE8, 0xF0, 0xE4, 0x98, 0xAA, 0xA4, 0xC2, 0x18, 0x20, 0x2D, 0xFE, 0xA9, 0x08, 0x8D, 0x82, 0x02, 0xA9, 0x04, 0x8D, 0x88, 0x02, 0x60, 0x6A, 0xFC, 0xCD, 0xFB, 0x31, 0xEA, 0x2C, 0xF9, 0xA9, 0x7F, 0x8D, 0x0D, 0xDC, 0x8D, 0x0D, 0xDD, 0x8D, 0x00, 0xDC, 0xA9, 0x08, 0x8D, 0x0E, 0xDC, 0x8D, 0x0E, 0xDD, 0x8D, 0x0F, 0xDC, 0x8D, 0x0F, 0xDD, 0xA2, 0x00, 0x8E, 0x03, 0xDC, 0x8E, 0x03, 0xDD, 0x8E, 0x18, 0xD4, 0xCA, 0x8E, 0x02, 0xDC, 0xA9, 0x07, 0x8D, 0x00, 0xDD, 0xA9, 0x3F, 0x8D, 0x02, 0xDD, 0xA9, 0xE7, 0x85, 0x01, 0xA9, 0x2F, 0x85, 0x00, 0xAD, 0xA6, 0x02, 0xF0, 0x0A, 0xA9, 0x25, 0x8D, 0x04, 0xDC, 0xA9, 0x40, 0x4C, 0xF3, 0xFD, 0xA9, 0x95, 0x8D, 0x04, 0xDC, 0xA9, 0x42, 0x8D, 0x05, 0xDC, 0x4C, 0x6E, 0xFF, 0x85, 0xB7, 0x86, 0xBB, 0x84, 0xBC, 0x60, 0x85, 0xB8, 0x86, 0xBA, 0x84, 0xB9, 0x60, 0xA5, 0xBA, 0xC9, 0x02, 0xD0, 0x0D, 0xAD, 0x97, 0x02, 0x48, 0xA9, 0x00, 0x8D, 0x97, 0x02, 0x68, 0x60, 0x85, 0x9D, 0xA5, 0x90, 0x05, 0x90, 0x85, 0x90, 0x60, 0x8D, 0x85, 0x02, 0x60, 0x90, 0x06, 0xAE, 0x83, 0x02, 0xAC, 0x84, 0x02, 0x8E, 0x83, 0x02, 0x8C, 0x84, 0x02, 0x60, 0x90, 0x06, 0xAE, 0x81, 0x02, 0xAC, 0x82, 0x02, 0x8E, 0x81, 0x02, 0x8C, 0x82, 0x02, 0x60, 0x78, 0x6C, 0x18, 0x03, 0x48, 0x8A, 0x48, 0x98, 0x48, 0xA9, 0x7F, 0x8D, 0x0D, 0xDD, 0xAC, 0x0D, 0xDD, 0x30, 0x1C, 0x20, 0x02, 0xFD, 0xD0, 0x03, 0x6C, 0x02, 0x80, 0x20, 0xBC, 0xF6, 0x20, 0xE1, 0xFF, 0xD0, 0x0C, 0x20, 0x15, 0xFD, 0x20, 0xA3, 0xFD, 0x20, 0x18, 0xE5, 0x6C, 0x02, 0xA0, 0x98, 0x2D, 0xA1, 0x02, 0xAA, 0x29, 0x01, 0xF0, 0x28, 0xAD, 0x00, 0xDD, 0x29, 0xFB, 0x05, 0xB5, 0x8D, 0x00, 0xDD, 0xAD, 0xA1, 0x02, 0x8D, 0x0D, 0xDD, 0x8A, 0x29, 0x12, 0xF0, 0x0D, 0x29, 0x02, 0xF0, 0x06, 0x20, 0xD6, 0xFE, 0x4C, 0x9D, 0xFE, 0x20, 0x07, 0xFF, 0x20, 0xBB, 0xEE, 0x4C, 0xB6, 0xFE, 0x8A, 0x29, 0x02, 0xF0, 0x06, 0x20, 0xD6, 0xFE, 0x4C, 0xB6, 0xFE, 0x8A, 0x29, 0x10, 0xF0, 0x03, 0x20, 0x07, 0xFF, 0xAD, 0xA1, 0x02, 0x8D, 0x0D, 0xDD, 0x68, 0xA8, 0x68, 0xAA, 0x68, 0x40, 0xC1, 0x27, 0x3E, 0x1A, 0xC5, 0x11, 0x74, 0x0E, 0xED, 0x0C, 0x45, 0x06, 0xF0, 0x02, 0x46, 0x01, 0xB8, 0x00, 0x71, 0x00, 0xAD, 0x01, 0xDD, 0x29, 0x01, 0x85, 0xA7, 0xAD, 0x06, 0xDD, 0xE9, 0x1C, 0x6D, 0x99, 0x02, 0x8D, 0x06, 0xDD, 0xAD, 0x07, 0xDD, 0x6D, 0x9A, 0x02, 0x8D, 0x07, 0xDD, 0xA9, 0x11, 0x8D, 0x0F, 0xDD, 0xAD, 0xA1, 0x02, 0x8D, 0x0D, 0xDD, 0xA9, 0xFF, 0x8D, 0x06, 0xDD, 0x8D, 0x07, 0xDD, 0x4C, 0x59, 0xEF, 0xAD, 0x95, 0x02, 0x8D, 0x06, 0xDD, 0xAD, 0x96, 0x02, 0x8D, 0x07, 0xDD, 0xA9, 0x11, 0x8D, 0x0F, 0xDD, 0xA9, 0x12, 0x4D, 0xA1, 0x02, 0x8D, 0xA1, 0x02, 0xA9, 0xFF, 0x8D, 0x06, 0xDD, 0x8D, 0x07, 0xDD, 0xAE, 0x98, 0x02, 0x86, 0xA8, 0x60, 0xAA, 0xAD, 0x96, 0x02, 0x2A, 0xA8, 0x8A, 0x69, 0xC8, 0x8D, 0x99, 0x02, 0x98, 0x69, 0x00, 0x8D, 0x9A, 0x02, 0x60, 0xEA, 0xEA, 0x08, 0x68, 0x29, 0xEF, 0x48, 0x48, 0x8A, 0x48, 0x98, 0x48, 0xBA, 0xBD, 0x04, 0x01, 0x29, 0x10, 0xF0, 0x03, 0x6C, 0x16, 0x03, 0x6C, 0x14, 0x03, 0x20, 0x18, 0xE5, 0xAD, 0x12, 0xD0, 0xD0, 0xFB, 0xAD, 0x19, 0xD0, 0x29, 0x01, 0x8D, 0xA6, 0x02, 0x4C, 0xDD, 0xFD, 0xA9, 0x81, 0x8D, 0x0D, 0xDC, 0xAD, 0x0E, 0xDC, 0x29, 0x80, 0x09, 0x11, 0x8D, 0x0E, 0xDC, 0x4C, 0x8E, 0xEE, 0x03, 0x4C, 0x5B, 0xFF, 0x4C, 0xA3, 0xFD, 0x4C, 0x50, 0xFD, 0x4C, 0x15, 0xFD, 0x4C, 0x1A, 0xFD, 0x4C, 0x18, 0xFE, 0x4C, 0xB9, 0xED, 0x4C, 0xC7, 0xED, 0x4C, 0x25, 0xFE, 0x4C, 0x34, 0xFE, 0x4C, 0x87, 0xEA, 0x4C, 0x21, 0xFE, 0x4C, 0x13, 0xEE, 0x4C, 0xDD, 0xED, 0x4C, 0xEF, 0xED, 0x4C, 0xFE, 0xED, 0x4C, 0x0C, 0xED, 0x4C, 0x09, 0xED, 0x4C, 0x07, 0xFE, 0x4C, 0x00, 0xFE, 0x4C, 0xF9, 0xFD, 0x6C, 0x1A, 0x03, 0x6C, 0x1C, 0x03, 0x6C, 0x1E, 0x03, 0x6C, 0x20, 0x03, 0x6C, 0x22, 0x03, 0x6C, 0x24, 0x03, 0x6C, 0x26, 0x03, 0x4C, 0x9E, 0xF4, 0x4C, 0xDD, 0xF5, 0x4C, 0xE4, 0xF6, 0x4C, 0xDD, 0xF6, 0x6C, 0x28, 0x03, 0x6C, 0x2A, 0x03, 0x6C, 0x2C, 0x03, 0x4C, 0x9B, 0xF6, 0x4C, 0x05, 0xE5, 0x4C, 0x0A, 0xE5, 0x4C, 0x00, 0xE5, 0x52, 0x52, 0x42, 0x59, 0x43, 0xFE, 0xE2, 0xFC, 0x48, 0xFF}; +#endif /* _BIN_KERNAL_ */ diff --git a/lib/emulator/interface.cpp b/lib/emulator/interface.cpp new file mode 100644 index 0000000..0b0954a --- /dev/null +++ b/lib/emulator/interface.cpp @@ -0,0 +1,554 @@ +/* + * USBSID-Pico is a RPi Pico/PicoW (RP2040) & Pico2/Pico2W (RP2350) based board + * for interfacing one or two MOS SID chips and/or hardware SID emulators over + * (WEB)USB with your computer, phone or ASID supporting player + * + * interface.cpp + * This file is part of USBSID-Pico (https://github.com/LouDnl/USBSID-Pico) + * File author: LouD + * + * Any licensing conditions from the above named source automatically + * apply to this code + * + * Copyright (c) 2024-2025 LouD + * + * 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, version 2. + * + * 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 . + * + */ + +#include +#include +#include + +#include +#include +#include + +#ifdef ONBOARD_SIDPLAYER +#include +static const char *chiptype_s[4] = {"Unknown", "MOS6581", "MOS8580", "MOS6581 and MOS8580"}; +static const char *clockspeed_s[5] = {"Unknown", "PAL", "NTSC", "PAL and NTSC", "DREAN"}; +#endif + +#ifdef ANALYSE_STACKUSAGE +extern "C" { +#include "tool_heapusage.c" +extern void heapbefore(void); +extern void heapafter(void); +extern void getFreeStack(void); +} +#else +extern void heapbefore(void){}; +extern void heapafter(void){}; +extern void getFreeStack(void){}; +#endif + +extern "C" { + #include "logging.h" +} + +#ifdef ONBOARD_EMULATOR +/* constants */ +static const uint16_t kBasicPrgStart = 0x0801; +static const uint16_t kBasicTxtTab = 0x002b; +static const uint16_t kBasicVarTab = 0x002d; +static const uint16_t kBasicAryTab = 0x002f; +static const uint16_t kBasicStrEnd = 0x0031; + +/* Static variables */ +static bool nosdl_ = true; +static bool isbinary_ = false; +static bool havecart_ = false; +static bool midi_ = false; +/* Static logging variables */ +static bool logmemrw = false; /* log _all_ memory reads and writes */ +static bool logcia1rw = false; /* log cia1 memory reads and writes */ +static bool logcia2rw = false; /* log cia2 memory reads and writes */ +static bool logiorw = false; /* log io memory reads and writes */ +static bool logplarw = false; /* log pla memory reads and writes */ +static bool logcrtrw = false; /* log cart memory reads and writes */ +static bool logsidrw = false; /* log sid memory reads and writes */ +static bool bankswlog = false; /* log bank switching */ +/* Static IO/Memory variables */ +static uint16_t load_addr, init_addr; /* Zero as signal it hasn't been changed */ +static uint16_t aptr; /* pointer for counting addresses */ +#endif + +#ifdef ONBOARD_SIDPLAYER +static uint16_t pl_loadaddr; +static uint16_t pl_initaddr; +static uint16_t pl_playaddr; +static uint16_t pl_datalength; +static uint8_t *pl_databuffer; +static uint16_t pl_dataoffset; +static uint32_t pl_sidspeed; +static int pl_songs; +static int pl_song_number; +static int pl_sidflags; +static int pl_curr_sidspeed; +static int pl_chiptype; +static int pl_clockspeed; +static int pl_sidversion; +static int pl_clock_speed; +static int pl_raster_lines; +static int pl_rasterrow_cycles; +static int pl_frame_cycles; +static int pl_refresh_rate; +#endif + +/* Machine */ +#ifdef ONBOARD_EMULATOR +C64 *c64 = nullptr; +#endif +#ifdef ONBOARD_SIDPLAYER +SidFile * sidfile_ = nullptr; +#endif + +using namespace std; + + +#ifdef ONBOARD_EMULATOR +/** + * @brief read short from little endian as big endian + */ +static uint16_t read_short_le(uint8_t * ptr, uint8_t pos) +{ + char b; + uint16_t v = 0; + v |= (ptr[pos]); + v |= (ptr[(pos+1)] << 8); + return v; +} + + /** + * @brief read short from big endian as big endian + */ +static uint16_t read_short_be(uint8_t * ptr, uint8_t pos) +{ + char b; + uint16_t v = 0; + v |= (ptr[(pos)] << 8); + v |= (ptr[pos+1]); + return v; +} + +/** + * @brief enable specific machine logging + */ +extern "C" void logging_enable(int logid) +{ + switch(logid) { + case 0: logmemrw = true; break; + case 1: logcia1rw = true; break; + case 2: logcia2rw = true; break; + case 3: logiorw = true; break; + case 4: logplarw = true; break; + case 5: logcrtrw = true; break; + case 6: logsidrw = true; break; + default: break; + } + return; +} + +/** + * @brief disable specific machine logging + */ +extern "C" void logging_disable(int logid) +{ + switch(logid) { + case 0: logmemrw = false; break; + case 1: logcia1rw = false; break; + case 2: logcia2rw = false; break; + case 3: logiorw = false; break; + case 4: logplarw = false; break; + case 5: logcrtrw = false; break; + case 6: logsidrw = false; break; + default: break; + } + return; +} + +/** + * @brief disables all logging on emulator stop + */ +static void disable_all_logging(void) +{ + logmemrw = false; + logcia1rw = false; + logcia2rw = false; + logiorw = false; + logplarw = false; + logcrtrw = false; + logsidrw = false; + bankswlog = false; + return; +} + +/** + * @brief set c64 logging + */ +extern "C" void _set_logging(void) +{ + if(logmemrw) {c64->mem_->setlogrw(0);} else {c64->mem_->unsetlogrw(0);}; + if(logcia1rw){c64->mem_->setlogrw(1);} else {c64->mem_->unsetlogrw(1);}; + if(logcia2rw){c64->mem_->setlogrw(2);} else {c64->mem_->unsetlogrw(2);}; + if(logiorw) {c64->mem_->setlogrw(3);} else {c64->mem_->unsetlogrw(3);}; + if(logplarw) {c64->mem_->setlogrw(4);} else {c64->mem_->unsetlogrw(4);}; + if(logcrtrw) {c64->mem_->setlogrw(5);} else {c64->mem_->unsetlogrw(5);}; + if(logsidrw) {c64->mem_->setlogrw(6);} else {c64->mem_->unsetlogrw(6);}; +} + +/** + * @brief Start Emudore with cynthcart loaded + * will run continuously if set to true + */ +extern "C" void start_emudore_cynthcart( + uint8_t * basic_, uint8_t * chargen_, + uint8_t * kernal_, uint8_t * binary_, + bool run_continuously +) +{ + if (c64 != nullptr) { + D("Emudore already running!\n"); + return; + } + (void) heapbefore(); + midi_ = true; + c64 = new C64( + nosdl_,isbinary_,havecart_,bankswlog,midi_, + basic_,chargen_,kernal_,binary_ + ); + (void) heapafter(); + + _set_logging(); /* Set c64 logging */ + + unsigned short binsize = 13166; + + load_addr = aptr = read_short_le(binary_,0); + size_t pos = 2; /* pos starts at 2 after reading the load address at 0 and 1 */ + (void) heapbefore(); + while(pos <= binsize) { + // D("ADDR: $%04x POS: %d VAL: %02X\n",aptr,pos,binary_[pos]); + c64->mem_->write_byte_no_io(aptr++,binary_[pos++]); + } + + /* basic-tokenized prg */ + if(load_addr == kBasicPrgStart) + { + /* make BASIC happy */ + c64->mem_->write_word_no_io(kBasicTxtTab,load_addr); + c64->mem_->write_word_no_io(kBasicVarTab,aptr); + c64->mem_->write_word_no_io(kBasicAryTab,aptr); + c64->mem_->write_word_no_io(kBasicStrEnd,aptr); + if (init_addr == 0x0) { + init_addr = ((c64->mem_->read_byte_no_io(load_addr)|c64->mem_->read_byte_no_io(load_addr+0x1)<<8)+0x2); + D("1. load_addr %04X calculated init_addr %04X\n", load_addr, init_addr); + c64->cpu_->pc(init_addr); + } else { + D("2. load_addr %04X calculated init_addr %04X\n", load_addr, init_addr); + c64->cpu_->pc(init_addr); /* Example: Cynthcart start/init address is 0x80D */ + } + } + else { + init_addr = ((c64->mem_->read_byte_no_io(load_addr)|c64->mem_->read_byte_no_io(load_addr+0x1)<<8)+0x2); + D("3. load_addr %04X calculated init_addr %04X\n", load_addr, init_addr); + c64->cpu_->pc(init_addr); + } + + (void) heapafter(); + if (run_continuously) {c64->start();}; + return; +} + +extern "C" unsigned int run_emulation_cycle(void) +{ + return c64->emulate(); +} + +extern "C" unsigned int run_specified_cycle( + bool cpu, bool cia1, bool cia2, + bool vic, bool io, bool cart) +{ + return c64->emulate_specified(cpu,cia1,cia2,vic,io,cart); +} + +/** + * @brief stop Emudore and free up memory + */ +extern "C" bool stop_emudore(void) +{ + D("Stopping emudore\n"); + (void) heapbefore(); + if (c64 != nullptr) { + if (c64->is_looping()) { + D("Disabling emudore loop\n"); + c64->disable_looping(); + } + D("Stopping c64\n"); + delete c64; + disable_all_logging(); + c64 = nullptr; + (void) heapafter(); + return true; + } + (void) heapafter(); + return false; +} + +extern "C" bool is_looping(void) +{ + if (c64 != nullptr) + return c64->is_looping(); + else return false; +} + +extern "C" bool disable_looping(void) +{ + if (c64 != nullptr) + return c64->disable_looping(); + else return false; +} + +#ifdef ONBOARD_SIDPLAYER +static void print_sid_info() +{ + cout << "\n< Sid Info >" << endl; + cout << "---------------------------------------------" << endl; + cout << "SID Title : " << sidfile_->GetModuleName() << endl; + cout << "Author Name : " << sidfile_->GetAuthorName() << endl; + cout << "Release & (C) : " << sidfile_->GetCopyrightInfo() << endl; + cout << "---------------------------------------------" << endl; + cout << "SID Type : " << sidfile_->GetSidType() << endl; + cout << "SID Format version : " << dec << pl_sidversion << endl; + cout << "---------------------------------------------" << endl; + // cout << "SID Flags : 0x" << hex << sidflags << " 0b" << bitset<8>{sidflags} << endl; + cout << "Chip Type : " << chiptype_s[pl_chiptype] << endl; + if (pl_sidversion == 3 || pl_sidversion == 4) + cout << "Chip Type 2 : " << chiptype_s[sidfile_->GetChipType(2)] << endl; + if (pl_sidversion == 4) + cout << "Chip Type 3 : " << chiptype_s[sidfile_->GetChipType(3)] << endl; + cout << "Clock Type : " << hex << clockspeed_s[pl_clockspeed] << endl; + cout << "Clock Speed : " << dec << pl_clock_speed << endl; + cout << "Raster Lines : " << dec << pl_raster_lines << endl; + cout << "Rasterrow Cycles : " << dec << pl_rasterrow_cycles << endl; + cout << "Frame Cycles : " << dec << pl_frame_cycles << endl; + cout << "Refresh Rate : " << dec << pl_refresh_rate << endl; + if (pl_sidversion == 3 || pl_sidversion == 4 || pl_sidversion == 78) { + cout << "---------------------------------------------" << endl; + cout << "SID 2 $addr : $d" << hex << sidfile_->GetSIDaddr(2) << "0" << endl; + if (pl_sidversion == 4 || pl_sidversion == 78) + cout << "SID 3 $addr : $d" << hex << sidfile_->GetSIDaddr(3) << "0" << endl; + if (pl_sidversion == 78) + cout << "SID 4 $addr : $d" << hex << sidfile_->GetSIDaddr(4) << "0" << endl; + } + cout << "---------------------------------------------" << endl; + cout << "Data Offset : $" << setfill('0') << setw(4) << hex << sidfile_->GetDataOffset() << endl; + cout << "Image length : $" << hex << sidfile_->GetInitAddress() << " - $" << hex << (sidfile_->GetInitAddress() - 1) + sidfile_->GetDataLength() << endl; + cout << "Load Address : $" << hex << sidfile_->GetLoadAddress() << endl; + cout << "Init Address : $" << hex << sidfile_->GetInitAddress() << endl; + cout << "Play Address : $" << hex << sidfile_->GetPlayAddress() << endl; + cout << "---------------------------------------------" << endl; + cout << "Song Speed(s) : $" << hex << pl_curr_sidspeed << " $0x" << hex << pl_sidspeed << endl;//" 0b" << bitset<32>{pl_sidspeed} << endl; + cout << "Timer : " << (pl_curr_sidspeed == 1 ? "CIA1" : "Clock") << endl; + cout << "Selected Sub-Song : " << dec << pl_song_number + 1 << " / " << dec << sidfile_->GetNumOfSongs() << endl; +} + +/** + * @brief start emudore PRG tune player + */ +extern "C" void start_emudore_prgtuneplayer( + uint8_t * basic_, uint8_t * chargen_, + uint8_t * kernal_, uint8_t * binary_, + size_t binsize_, bool run_continuously) +{ + if (c64 != nullptr) { + D("Emudore already running!\n"); + return; + } + (void) heapbefore(); + midi_ = true; + c64 = new C64( + nosdl_,isbinary_,havecart_,bankswlog,midi_, + basic_,chargen_,kernal_,binary_ + ); + (void) heapafter(); + + _set_logging(); /* Set c64 logging */ + + unsigned short binsize = 13166; + + load_addr = aptr = read_short_le(binary_,0); + size_t pos = 2; /* pos starts at 2 after reading the load address at 0 and 1 */ + (void) heapbefore(); + while(pos <= binsize) { + // D("ADDR: $%04x POS: %d VAL: %02X\n",aptr,pos,binary_[pos]); + c64->mem_->write_byte_no_io(aptr++,binary_[pos++]); + } + + /* basic-tokenized prg */ + if(load_addr == kBasicPrgStart) + { + /* make BASIC happy */ + c64->mem_->write_word_no_io(kBasicTxtTab,load_addr); + c64->mem_->write_word_no_io(kBasicVarTab,aptr); + c64->mem_->write_word_no_io(kBasicAryTab,aptr); + c64->mem_->write_word_no_io(kBasicStrEnd,aptr); + if (init_addr == 0x0) { + init_addr = ((c64->mem_->read_byte_no_io(load_addr)|c64->mem_->read_byte_no_io(load_addr+0x1)<<8)+0x2); + D("1. load_addr %04X calculated init_addr %04X\n", load_addr, init_addr); + c64->cpu_->pc(init_addr); + } else { + D("2. load_addr %04X calculated init_addr %04X\n", load_addr, init_addr); + c64->cpu_->pc(init_addr); /* Example: Cynthcart start/init address is 0x80D */ + } + } + else { + init_addr = ((c64->mem_->read_byte_no_io(load_addr)|c64->mem_->read_byte_no_io(load_addr+0x1)<<8)+0x2); + D("3. load_addr %04X calculated init_addr %04X\n", load_addr, init_addr); + c64->cpu_->pc(init_addr); + } + + (void) heapafter(); + if (run_continuously) {c64->start();}; + return; +} + +/** + * @brief start emudore SID tune player + */ +extern "C" void start_emudore_sidtuneplayer( + uint8_t * basic_, uint8_t * chargen_, + uint8_t * kernal_, uint8_t * binary_, + size_t binsize_, bool run_continuously) +{ + (void) getFreeStack(); + (void) heapbefore(); + + sidfile_ = new SidFile(); + if(sidfile_->ParsePtr(binary_,binsize_)) { + DBG("[EMU] Error parsing sidfile!\n"); + delete sidfile_; + return; + } + pl_songs = sidfile_->GetNumOfSongs(); + pl_song_number = sidfile_->GetFirstSong(); /* TODO: FIX N FINISH ;) */ + pl_sidflags = sidfile_->GetSidFlags(); + pl_sidspeed = sidfile_->GetSongSpeed(pl_song_number); // + 1); + pl_curr_sidspeed = pl_sidspeed & (1 << pl_song_number); // ? 1 : 0; // 1 ~ 60Hz, 2 ~ 50Hz + pl_chiptype = sidfile_->GetChipType(1); + pl_clockspeed = sidfile_->GetClockSpeed(); + pl_sidversion = sidfile_->GetSidVersion(); + pl_clock_speed = clockSpeed[pl_clockspeed]; + pl_raster_lines = scanLines[pl_clockspeed]; + pl_rasterrow_cycles = scanlinesCycles[pl_clockspeed]; + pl_frame_cycles = pl_raster_lines * pl_rasterrow_cycles; + pl_refresh_rate = refreshRate[pl_clockspeed]; + pl_loadaddr = sidfile_->GetLoadAddress(); + pl_datalength = sidfile_->GetDataLength(); + /* pl_databuffer = sidfile_->GetDataPtr(); */ + pl_dataoffset = (sidfile_->GetDataOffset() + 2); + // pl_databuffer = binary_+pl_dataoffset; + pl_playaddr = sidfile_->GetPlayAddress(); + pl_initaddr = sidfile_->GetInitAddress(); + + (void) heapafter(); + (void) getFreeStack(); + print_sid_info(); + delete sidfile_; + if (c64 != nullptr) { + D("Emudore already running!\n"); + return; + } + (void) heapbefore(); + midi_ = false; /* No need when playing tunes */ + c64 = new C64( + nosdl_,isbinary_,havecart_,bankswlog,midi_, + basic_,chargen_,kernal_,nullptr + ); + (void) heapafter(); + + // logging_enable(0); /* Memory RW */ + _set_logging(); /* Set c64 logging */ + // c64->mem_->setlogrw(6); /* Enable SID logging */ + + // unsigned short binsize = 0x109f; + + // load_addr = aptr = read_short_le(binary_,0); + // load_addr = aptr = pl_loadaddr; // $109f + // 0x007c + // size_t pos = (0x7C+2); /* pos starts at 2 after reading the load address at 0 and 1 */ + (void) heapbefore(); + // while(pos <= binsize) { + // D("ADDR: $%04x POS: %d VAL: %02X\n",aptr,pos,binary_[pos]); + // c64->mem_->write_byte(aptr++,binary_[pos++]); + // } + /* Load SID data into memory */ + // for (unsigned int i = 0; i < binsize; i++) { + // c64->mem_->write_byte((load_addr+i),binary_[(0x7C+2)+i]); + for (unsigned int i = 0; i < pl_datalength; i++) { + // c64->mem_->write_byte((pl_loadaddr+i),pl_databuffer[i]); + c64->mem_->write_byte_no_io((pl_loadaddr+i),binary_[pl_dataoffset+i]); + // printf("MEM @ $%04x:$%02X FILE @ $%04x:$%02X\n", + // pl_loadaddr+i, c64->mem_->read_byte_no_io((pl_loadaddr+i)), + // pl_dataoffset+i, binary_[pl_dataoffset+i]); + } + printf("load: $%04X play: $%04X init: $%04X\n", + pl_loadaddr, pl_playaddr, pl_initaddr); + { /* Init SID player */ + // install reset vector for microplayer (0x0202) + // c64->mem_->write_byte_no_io(0x0007, 0x78); // 0x78 SEI disable interrupts + c64->mem_->write_byte_no_io(0xFFFC, 0x02); /* addr lo */ + c64->mem_->write_byte_no_io(0xFFFD, 0x02); /* addr hi */ + + // install IRQ vector for play routine launcher (0x020C) + c64->mem_->write_byte_no_io(0xFFFE, 0x0C); /* addr lo */ + c64->mem_->write_byte_no_io(0xFFFF, 0x02); /* addr hi */ + + // clear kernel and basic rom from ram + // c64->mem_->write_byte_no_io(0x0001, 0x35); + c64->pla_->runtime_bank_switching(0x1C); /* Mode 28 */ + + // install the micro player, 6502 assembly code + c64->mem_->write_byte_no_io(0x0202, 0xA9); // 0xA9 LDA imm load A with the song number + c64->mem_->write_byte_no_io(0x0203, 0); // 0xNN #NN song number + + c64->mem_->write_byte_no_io(0x0204, 0x20); // 0x20 JSR abs jump sub to INIT routine + c64->mem_->write_byte_no_io(0x0205, pl_initaddr & 0xFF); // $xxNN init address lo + c64->mem_->write_byte_no_io(0x0206, (pl_initaddr >> 8) & 0xFF); // $NNxx init address hi + + c64->mem_->write_byte_no_io(0x0207, 0x58); // 0x58 CLI enable interrupts + c64->mem_->write_byte_no_io(0x0208, 0xEA); // 0xEA NOP impl + c64->mem_->write_byte_no_io(0x0209, 0x4C); // JMP jump to 0x0208 + c64->mem_->write_byte_no_io(0x020A, 0x08); // 0xxxNN address lo + c64->mem_->write_byte_no_io(0x020B, 0x02); // 0xNNxx address hi + + c64->mem_->write_byte_no_io(0x020C, 0xEA); // 0xEA NOP // 0xA9 LDA imm // A = 1 + c64->mem_->write_byte_no_io(0x020D, 0xEA); // 0xEA NOP // 0x01 #NN + c64->mem_->write_byte_no_io(0x020E, 0xEA); // 0xEA NOP // 0x78 SEI disable interrupt + c64->mem_->write_byte_no_io(0x020F, 0x20); // 0x20 JSR jump sub to play routine + c64->mem_->write_byte_no_io(0x0210, pl_playaddr & 0xFF); // $xxNN play address lo + c64->mem_->write_byte_no_io(0x0211, (pl_playaddr >> 8) & 0xFF); // $NNxx play address hi + c64->mem_->write_byte_no_io(0x0212, 0xEA); // 0xEA NOP // 0x58 CLI enable interrupt + c64->mem_->write_byte_no_io(0x0213, 0x40); // 0x40 RTI return from interrupt + } + // c64->emulate(); + // delete sidfile_; + c64->sid_->sid_flush(); + c64->sid_->set_playing(true); + c64->cpu_->pc(c64->mem_->read_word(Memory::kAddrResetVector)); + (void) heapafter(); + if (run_continuously) {c64->start();}; + return; +} +#endif /* ONBOARD_SIDPLAYER */ +#endif /* ONBOARD_EMULATOR */ diff --git a/lib/emulator/interface.h b/lib/emulator/interface.h new file mode 100644 index 0000000..ed434e9 --- /dev/null +++ b/lib/emulator/interface.h @@ -0,0 +1,76 @@ +/* + * USBSID-Pico is a RPi Pico/PicoW (RP2040) & Pico2/Pico2W (RP2350) based board + * for interfacing one or two MOS SID chips and/or hardware SID emulators over + * (WEB)USB with your computer, phone or ASID supporting player + * + * interface.h + * This file is part of USBSID-Pico (https://github.com/LouDnl/USBSID-Pico) + * File author: LouD + * + * Any licensing conditions from the above named source automatically + * apply to this code + * + * Copyright (c) 2024-2025 LouD + * + * 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, version 2. + * + * 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 . + * + */ + +#ifndef _USBSID_INTERFACE_H_ +#define _USBSID_INTERFACE_H_ + +#include /* C type include */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef ONBOARD_EMULATOR +void start_emudore_cynthcart( + uint8_t * basic_, uint8_t * chargen_, + uint8_t * kernal_, uint8_t * binary_, + bool run_continuously +); +bool stop_emudore(void); + +unsigned int run_emulation_cycle(void); +unsigned int run_specified_cycle( + bool cpu, bool cia1, bool cia2, + bool vic, bool io, bool cart); + +bool is_looping(void); +bool disable_looping(void); + +void logging_enable(int logid); +void logging_disable(int logid); + +#ifdef ONBOARD_SIDPLAYER +void start_emudore_sidtuneplayer( + uint8_t * basic_, uint8_t * chargen_, + uint8_t * kernal_, uint8_t * binary_, + size_t binsize_, bool run_continuously +); +void start_emudore_prgtuneplayer( + uint8_t * basic_, uint8_t * chargen_, + uint8_t * kernal_, uint8_t * binary_, + size_t binsize_, bool run_continuously +); +#endif /* ONBOARD_SIDPLAYER */ +#endif /* ONBOARD_EMULATOR */ + +#ifdef __cplusplus +} +#endif + + +#endif /* _USBSID_INTERFACE_H_ */ diff --git a/src/config.c b/src/config.c index 02abe96..178cd00 100644 --- a/src/config.c +++ b/src/config.c @@ -41,7 +41,7 @@ extern void init_sidclock(void); extern void deinit_sidclock(void); extern void cdc_write(uint8_t * itf, uint32_t n); extern void webserial_write(uint8_t * itf, uint32_t n); -extern char dtype; +extern char rtype; extern uint8_t *cdc_itf; extern uint8_t *wusb_itf; extern uint8_t *write_buffer_p; @@ -50,18 +50,9 @@ extern double sid_hz, sid_mhz, sid_us; extern uint8_t sid_memory[]; extern queue_t sidtest_queue; extern bool auto_config; - -/* SID */ -extern bool detect_fmopl(uint8_t base_address); -extern uint8_t detect_sid_type(Socket * socket, SIDChip * sidchip); -extern uint8_t detect_clone_type(Socket * cfg_ptr); -extern void auto_detect_routine(bool auto_config, bool with_delay); -extern void sid_test(int sidno, char test, char wf); -extern bool running_tests; - -/* SID clone config */ -extern void read_fpgasid_configuration(uint8_t base_address); -extern void read_skpico_configuration(uint8_t base_address); +#ifdef ONBOARD_EMULATOR +extern bool offload_ledrunner; +#endif /* GPIO */ extern uint8_t __no_inline_not_in_flash_func(cycled_read_operation)(uint8_t address, uint16_t cycles); @@ -76,20 +67,59 @@ extern void sync_pios(bool at_boot); extern void enable_sid(bool unmute); extern void disable_sid(void); extern void mute_sid(void); +extern void unmute_sid(void); extern void reset_sid_registers(void); extern void toggle_audio_switch(void); extern void set_audio_switch(bool state); +/* MCU */ +extern void mcu_reset(void); /* Midi */ extern void midi_bus_operation(uint8_t a, uint8_t b); -/* MCU */ -extern void mcu_reset(void); +/* SID detection */ +extern bool detect_fmopl(uint8_t base_address); +extern uint8_t detect_sid_type(Socket * socket, SIDChip * sidchip); +extern uint8_t detect_clone_type(Socket * cfg_ptr); +extern void auto_detect_routine(bool auto_config, bool with_delay); + +/* SID tests */ +extern void sid_test(int sidno, char test, char wf); +extern bool running_tests; -/* Config bus */ +/* SID clone config */ +extern void read_fpgasid_configuration(uint8_t base_address); +extern void read_skpico_configuration(uint8_t base_address); + +/* SID player */ +#ifdef ONBOARD_EMULATOR +extern bool stop_emulator(void); +extern void run_emulator(void); +extern void set_logging(int logid); +extern void unset_logging(int logid); +bool emulator_running, starting_emulator, stopping_emulator; + +#ifdef ONBOARD_SIDPLAYER +extern int load_sidtune(uint8_t * sidfile, int sidfilesize, char subt); +extern int load_sidtune_fromflash(int sidflashid, char tuneno); +extern void reset_sidplayer(void); +extern void next_subtune(void); +extern void previous_subtune(void); +extern uint16_t playtime(void); +extern bool sidplayer_init, sidplayer_playing; + +/* SID player locals */ +uint8_t __not_in_flash("usbsid_sidfile") sidfile[0xFFFF]; /* Temporary buffer to store incoming data */ +static int sidfile_size; +static int sidbytes_received; +static bool receiving_sidfile; +bool sidplayer_start; +#endif /* ONBOARD_SIDPLAYER */ +#endif /* ONBOARD_EMULATOR */ + +/* Config BUS */ extern void apply_bus_config(bool quiet); -extern void apply_bus_config_OLD(void); // TODO: REMOVE ME!! extern void apply_fmopl_config(bool quiet); /* Config socket */ @@ -108,7 +138,6 @@ extern void print_pico_features(void); extern void print_config_settings(void); extern void print_socket_config(void); extern void print_bus_config(void); -void (*config_print[5])(void) = { print_cfg_addr, print_pico_features, print_config_settings, print_socket_config, print_bus_config }; extern char *sidtypes[5]; extern char *chiptypes[2]; extern char *clonetypes[6]; @@ -117,6 +146,8 @@ extern char *enabled[2]; extern char *true_false[2]; extern char *single_dual[2]; extern char *mono_stereo[2]; +/* Config logging locals */ +void (*config_print[5])(void) = { print_cfg_addr, print_pico_features, print_config_settings, print_socket_config, print_bus_config }; /* Pre declarations */ void apply_config(bool at_boot, bool print_cfg); @@ -248,7 +279,7 @@ void __no_inline_not_in_flash_func(load_config)(Config* config) memcpy(&temp_config, (void *)(XIP_BASE + (FLASH_CONFIG_OFFSET + (FLASH_PAGE_SIZE * savelocationid))), sizeof(Config)); stdio_flush(); CFG("[CONFIG] LOAD CONFIG FROM SAVE POSITION %d (SAVED CONFIG ID: %d)\n", savelocationid, temp_config.config_saveid); - if ((temp_config.config_saveid >= 0) && (temp_config.config_saveid <= 0xF) /* Max 16 saves */ + if (/* (temp_config.config_saveid >= 0) && */(temp_config.config_saveid <= 0xF) /* Max 16 saves */ && temp_config.config_saveid == savelocationid) { /* Found previously saved config */ savelocationid++; /* Increase id and try again */ goto AGAIN; @@ -325,7 +356,7 @@ void __no_inline_not_in_flash_func(save_config)(Config* config) void write_back_data(size_t buffersize) { - switch (dtype) { + switch (rtype) { case 'C': cdc_write(cdc_itf, buffersize); break; @@ -350,7 +381,9 @@ void handle_config_request(uint8_t * buffer, uint32_t size) * Byte 1 ~ config type * Byte 2 ... 61 the config */ - CFG("[CONFIG BUFFER] %x %x %x %x %x\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]); + if (buffer[0] < 0xD0) { /* Don't log incoming buffer to avoid spam above this region */ + CFG("[CONFIG BUFFER] %x %x %x %x %x\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]); + } switch (buffer[0]) { case RESET_USBSID: CFG("[CMD] RESET_USBSID\n"); @@ -396,7 +429,7 @@ void handle_config_request(uint8_t * buffer, uint32_t size) CFG("[CMD] RELOAD_CONFIG\n"); load_config(&usbsid_config); apply_config(false, true); - for (int i = 0; i < count_of(clockrates); i++) { + for (uint i = 0; i < count_of(clockrates); i++) { if (clockrates[i] == usbsid_config.clock_rate) { apply_clockrate(i, true); } @@ -749,7 +782,7 @@ void handle_config_request(uint8_t * buffer, uint32_t size) memset(write_buffer_p, 0 ,64); /* Empty the write buffer pointer */ read_config(&usbsid_config); /* Read the config into the config buffer */ memcpy(write_buffer_p, config_array, 64); /* Copy the first 64 bytes from the buffer into the write buffer */ - switch (dtype) { + switch (rtype) { case 'C': cdc_write(cdc_itf, 64); break; @@ -765,7 +798,7 @@ void handle_config_request(uint8_t * buffer, uint32_t size) memset(write_buffer_p, 0 ,64); /* Empty the write buffer pointer */ read_config(&usbsid_config); /* Read the config into the config buffer */ memcpy(write_buffer_p, config_array, 64); /* Copy the first 64 bytes from the buffer into the write buffer */ - switch (dtype) { + switch (rtype) { case 'C': cdc_write(cdc_itf, 64); break; @@ -828,7 +861,7 @@ void handle_config_request(uint8_t * buffer, uint32_t size) read_firmware_version(); memset(write_buffer_p, 0, MAX_BUFFER_SIZE); memcpy(write_buffer_p, p_version_array, MAX_BUFFER_SIZE); - switch (dtype) { + switch (rtype) { case 'C': cdc_write(cdc_itf, MAX_BUFFER_SIZE); break; @@ -844,7 +877,7 @@ void handle_config_request(uint8_t * buffer, uint32_t size) read_pcb_version(); memset(write_buffer_p, 0, MAX_BUFFER_SIZE); memcpy(write_buffer_p, p_version_array, MAX_BUFFER_SIZE); - switch (dtype) { + switch (rtype) { case 'C': cdc_write(cdc_itf, MAX_BUFFER_SIZE); break; @@ -899,6 +932,32 @@ void handle_config_request(uint8_t * buffer, uint32_t size) // print_cfg(sid_memory, (numsids * 0x20)); case TEST_FN2: uint8_t st = 0xFF; + #ifdef ONBOARD_EMULATOR + if (buffer[1] == 0) { + CFG("START EMULATOR\n"); + emulator_running = false; + offload_ledrunner = true; + starting_emulator = true; + } + if (buffer[1] == 1) { + CFG("STOP EMULATOR\n"); + #ifdef ONBOARD_SIDPLAYER + sidplayer_playing = false; + #endif + stopping_emulator = true; + stop_emulator(); + } + if (buffer[1] == 2) { + set_logging((int)buffer[2]); + } + #endif + #if defined(ONBOARD_EMULATOR) && defined(ONBOARD_SIDPLAYER) + if (buffer[1] == 3) { + CFG("START SID PLAYER\n"); + offload_ledrunner = true; + sidplayer_start = true; + } + #endif if (buffer[1] == 4) { st = cycled_read_operation(buffer[2], buffer[3]); CFG("[TEST FOUND] %02X\n", st); @@ -946,6 +1005,97 @@ void handle_config_request(uint8_t * buffer, uint32_t size) } CFG("\n"); break; + #if defined(ONBOARD_EMULATOR) && defined(ONBOARD_SIDPLAYER) + case UPLOAD_SID_START: + CFG("[UPLOAD_SID_START]\n"); + receiving_sidfile = true; + sidbytes_received = 0; + break; + case UPLOAD_SID_DATA: + if (sidbytes_received == 0) CFG("[UPLOAD_SID_DATA]\n"); + if (receiving_sidfile) { + for (int i = 1; i < 63; i++) { /* Max buffer size minus command byte (config init byte is already gone) */ + sidfile[sidbytes_received] = buffer[i]; + sidbytes_received++; + } + } + break; + case UPLOAD_SID_END: + CFG("[UPLOAD_SID_END]\n"); + DBG("Received %u bytes\n", sidbytes_received); + receiving_sidfile = false; + /* ISSUE: These are never the same size */ + /* sidfile_size = sidbytes_received; */ + sidbytes_received = 0; + break; + case UPLOAD_SID_SIZE: + CFG("[UPLOAD_SID_SIZE]\n"); + sidfile_size = (buffer[1]<<8|buffer[2]); + DBG("Received SID file size: %u\n", sidfile_size); + break; + case SID_PLAYER_LOAD: + CFG("[SID_PLAYER_LOAD] %d\n", buffer[1]); + CFG("[CONFIG BUFFER SIZE] %d\n", count_of(buffer)); + char tuneno = buffer[2]; /* Should be 0 if not supplied */ + CFG("[SUBTUNE] %d\n", tuneno); + sidplayer_init = false; + switch (buffer[1]) { + case 0: /* From buffer */ + if (load_sidtune(sidfile, sidfile_size, tuneno)) { + sidplayer_init = true; + } + break; + case 1: /* Supremacy */ + if (load_sidtune_fromflash(1, tuneno)) { + sidplayer_init = true; + } + break; + case 2: /* Afterburner */ + if (load_sidtune_fromflash(2, tuneno)) { + sidplayer_init = true; + } + break; + case 3: /* Edge of Disgrace */ + if (load_sidtune_fromflash(3, tuneno)) { + sidplayer_init = true; + } + break; + default: + sidplayer_init = false; + break; + } + break; + case SID_PLAYER_START: + CFG("[SID_PLAYER_START] %d\n", sidplayer_init); + unmute_sid(); /* Must unmute before play start or some tunes will be silent */ + if (sidplayer_init) sidplayer_playing = true; + sidplayer_init = false; + break; + case SID_PLAYER_STOP: + CFG("[SID_PLAYER_STOP]\n"); + sidplayer_playing = false; + reset_sidplayer(); + if (usbsid_config.socketOne.clonetype != 2 + && usbsid_config.socketTwo.clonetype != 2) { + reset_sid(); /* Breaking for tunes on SKPico */ + } else { + mute_sid(); + } + break; + case SID_PLAYER_PAUSE: + sidplayer_playing = !sidplayer_playing; + break; + case SID_PLAYER_NEXT: + sidplayer_playing = false; + next_subtune(); + sidplayer_playing = true; + break; + case SID_PLAYER_PREV: + sidplayer_playing = false; + previous_subtune(); + sidplayer_playing = true; + break; + #endif default: break; } @@ -1063,7 +1213,7 @@ void detect_default_config(void) int return_clockrate(void) { - for (int i = 0; i < count_of(clockrates); i++) { + for (uint i = 0; i < count_of(clockrates); i++) { if (clockrates[i] == usbsid_config.clock_rate) { return i; } diff --git a/src/config.h b/src/config.h index e9f1fb1..5f6ea2e 100644 --- a/src/config.h +++ b/src/config.h @@ -346,6 +346,21 @@ enum TEST_FN = 0x99, /* TODO: Remove before v1 release */ TEST_FN2 = 0x9A, /* TODO: Remove before v1 release */ TEST_FN3 = 0x9B, /* TODO: Remove before v1 release */ +#ifdef ONBOARD_EMULATOR + /* Internal SID player */ + UPLOAD_SID_START = 0xD0, /* Start command for USBSID to go into receiving mode */ + UPLOAD_SID_DATA = 0xD1, /* Init byte for each packet containing data */ + UPLOAD_SID_END = 0xD2, /* End command for USBSID to exit receiving mode */ + UPLOAD_SID_SIZE = 0xD3, /* Packet containing the actual file size */ + + /* Internal SID player */ + SID_PLAYER_LOAD = 0xE0, /* Load SID file into SID player memory and initialize internal SID player */ + SID_PLAYER_START = 0xE1, /* Start SID file play */ + SID_PLAYER_STOP = 0xE2, /* Stop SID file play */ + SID_PLAYER_PAUSE = 0xE3, /* Pause/Unpause SID file play */ + SID_PLAYER_NEXT = 0xE4, /* Next SID subtune play */ + SID_PLAYER_PREV = 0xE5, /* Previous SID subtune play */ +#endif }; /* Config write command byte */ diff --git a/src/globals.h b/src/globals.h index a33b630..a971987 100644 --- a/src/globals.h +++ b/src/globals.h @@ -123,6 +123,12 @@ enum WEBUSB_TOGGLEAU = 0x3B, }; +/* USBSID Uart */ +enum { + BAUD_RATE = 115200, + FFIN_FAST_BAUD_RATE = 921600, +}; + #ifdef __cplusplus } diff --git a/src/gpio.c b/src/gpio.c index 0088102..38bc2ef 100644 --- a/src/gpio.c +++ b/src/gpio.c @@ -22,7 +22,7 @@ * along with this program. If not, see . * */ - +/* TODO: Split PIO, DMA, GPIO and calling functions into separate files/namespaces */ #include "globals.h" #include "config.h" #include "gpio.h" @@ -181,7 +181,7 @@ void setup_piobus(void) busclock_frequency = (float)pico_hz / (usbsid_config.clock_rate * 32) / 2; /* Clock frequency is 8 times the SID clock */ CFG("[BUS CLK INIT] START\n"); - CFG("[PI CLK]@%dMHz [DIV]@%.2f [BUS CLK]@%.2f [CFG SID CLK]%d\n", + CFG("[PI CLK]@%luMHz [DIV]@%.2f [BUS CLK]@%.2f [CFG SID CLK]%d\n", (pico_hz / 1000 / 1000), busclock_frequency, ((float)pico_hz / busclock_frequency / 2), @@ -321,12 +321,12 @@ void restart_bus_clocks(void) pio_sm_set_clkdiv(bus_pio, sm_control, busclock_frequency); pio_sm_set_clkdiv(bus_pio, sm_data, busclock_frequency); - CFG("[PI CLK]@%dMHz [DIV]@%.2f [BUS CLK]@%.2f [CFG SID CLK]%d\n", + CFG("[PI CLK]@%luMHz [DIV]@%.2f [BUS CLK]@%.2f [CFG SID CLK]%d\n", (pico_hz / 1000 / 1000), busclock_frequency, ((float)pico_hz / busclock_frequency / 2), (int)usbsid_config.clock_rate); - CFG("[PI CLK]@%dMHz [DIV]@%.2f [SID CLK]@%.2f [CFG SID CLK]%d\n", + CFG("[PI CLK]@%luMHz [DIV]@%.2f [SID CLK]@%.2f [CFG SID CLK]%d\n", (pico_hz / 1000 / 1000), sidclock_frequency, ((float)pico_hz / sidclock_frequency / 2), @@ -418,7 +418,7 @@ void init_sidclock(void) sidclock_frequency = (float)pico_hz / usbsid_config.clock_rate / 2; CFG("[SID CLK INIT] START\n"); - CFG("[PI CLK]@%dMHz [DIV]@%.2f [SID CLK]@%.2f [CFG SID CLK]%d\n", + CFG("[PI CLK]@%luMHz [DIV]@%.2f [SID CLK]@%.2f [CFG SID CLK]%d\n", (pico_hz / 1000 / 1000), sidclock_frequency, ((float)pico_hz / sidclock_frequency / 2), @@ -494,37 +494,6 @@ static int __not_in_flash_func(set_bus_bits)(uint8_t address, uint8_t data) // address, data, data_word, PRINTF_BYTE_TO_BINARY_INT32(data_word), control_word, PRINTF_BYTE_TO_BINARY_INT16(control_word)); return 1; } -// static int __not_in_flash_func(set_bus_bits)(uint8_t address, uint8_t data) -// { -// /* CFG("[BUS BITS]$%02X:%02X ", address, data); */ -// switch (address) { -// case 0x00 ... 0x1F: -// if (cfg.one == 0b110 || cfg.one == 0b111) return 0; -// data_word = (address & cfg.one_mask) << 8 | data; -// control_word |= cfg.one; -// break; -// case 0x20 ... 0x3F: -// if (cfg.two == 0b110 || cfg.two == 0b111) return 0; -// data_word = (address & cfg.two_mask) << 8 | data; -// control_word |= cfg.two; -// break; -// case 0x40 ... 0x5F: -// if (cfg.three == 0b110 || cfg.three == 0b111) return 0; -// /* Workaround for addresses in this range, mask doesn't work properly */ -// address &= cfg.three_mask; -// data_word = (cfg.three_mask == 0x3f ? (address + 0x20) : address) << 8 | data; -// control_word |= cfg.three; -// break; -// case 0x60 ... 0x7F: -// if (cfg.four == 0b110 || cfg.four == 0b111) return 0; -// data_word = (address & cfg.four_mask) << 8 | data; -// control_word |= cfg.four; -// break; -// } -// /* CFG("$%04x 0b"PRINTF_BINARY_PATTERN_INT32" $%04x 0b"PRINTF_BINARY_PATTERN_INT16"\n", -// data_word, PRINTF_BYTE_TO_BINARY_INT32(data_word), control_word, PRINTF_BYTE_TO_BINARY_INT16(control_word)); */ -// return 1; -// } uint8_t __no_inline_not_in_flash_func(bus_operation)(uint8_t command, uint8_t address, uint8_t data) { /* WARNING: DEPRECATED AND NO LONGER WORKS */ @@ -626,6 +595,27 @@ uint8_t __no_inline_not_in_flash_func(cycled_read_operation)(uint8_t address, ui return (read_data & 0xFF); } +void __no_inline_not_in_flash_func(write_operation)(uint8_t address, uint8_t data) +{ + sid_memory[(address & 0x7F)] = data; + vu = (vu == 0 ? 100 : vu); /* NOTICE: Testfix for core1 setting dtype to 0 */ + control_word = 0b111000; + dir_mask = 0b1111111111111111; /* Always OUT never IN */ + if (set_bus_bits(address, data) != 1) { + return; + } + data_word = (dir_mask << 16) | data_word; + + pio_sm_exec(bus_pio, sm_control, pio_encode_irq_set(false, PIO_IRQ0)); /* Preset the statemachine IRQ to not wait for a 1 */ + pio_sm_exec(bus_pio, sm_data, pio_encode_irq_set(false, PIO_IRQ1)); /* Preset the statemachine IRQ to not wait for a 1 */ + pio_sm_exec(bus_pio, sm_data, pio_encode_wait_pin(true, PHI)); + pio_sm_exec(bus_pio, sm_control, pio_encode_wait_pin(true, PHI)); + pio_sm_put_blocking(bus_pio, sm_control, control_word); + pio_sm_put_blocking(bus_pio, sm_data, data_word); + + return; +} + void __no_inline_not_in_flash_func(cycled_write_operation)(uint8_t address, uint8_t data, uint16_t cycles) { delay_word = cycles; @@ -662,6 +652,56 @@ void __no_inline_not_in_flash_func(cycled_write_operation)(uint8_t address, uint return; } +void __no_inline_not_in_flash_func(cycled_write_operation_nondma)(uint8_t address, uint8_t data, uint16_t cycles) +{ + delay_word = cycles; + sid_memory[(address & 0x7F)] = data; + vu = (vu == 0 ? 100 : vu); /* NOTICE: Testfix for core1 setting dtype to 0 */ + control_word = 0b111000; + dir_mask = 0b1111111111111111; /* Always OUT never IN */ + if (set_bus_bits(address, data) != 1) { + return; + } + data_word = (dir_mask << 16) | data_word; + + pio_sm_put_blocking(bus_pio, sm_control, control_word); + pio_sm_put_blocking(bus_pio, sm_data, data_word); + pio_sm_put_blocking(bus_pio, sm_delay, delay_word); + + GPIODBG("[WC]$%04x 0b"PRINTF_BINARY_PATTERN_INT32" $%04x 0b"PRINTF_BINARY_PATTERN_INT16" $%02X:%02X(%u %u)\n", + data_word, PRINTF_BYTE_TO_BINARY_INT32(data_word), control_word, PRINTF_BYTE_TO_BINARY_INT16(control_word), + address, data, cycles, delay_word); + return; +} + +uint16_t __no_inline_not_in_flash_func(cycled_delayed_write_operation)(uint8_t address, uint8_t data, uint16_t cycles) +{ /* This is a blocking function! */ + sid_memory[(address & 0x7F)] = data; + vu = (vu == 0 ? 100 : vu); /* NOTICE: Testfix for core1 setting dtype to 0 */ + control_word = 0b111000; + dir_mask = 0b1111111111111111; /* Always OUT never IN */ + if (set_bus_bits(address, data) != 1) { + return 0; + } + data_word = (dir_mask << 16) | data_word; + + dma_channel_set_read_addr(dma_tx_control, &control_word, false); + dma_channel_set_read_addr(dma_tx_data, &data_word, false); + + cycled_delay_operation(cycles); /* Replaces the delay DMA */ + pio_sm_exec(bus_pio, sm_control, pio_encode_irq_set(false, PIO_IRQ0)); /* Preset the statemachine IRQ to not wait for a 1 */ + pio_sm_exec(bus_pio, sm_data, pio_encode_irq_set(false, PIO_IRQ1)); /* Preset the statemachine IRQ to not wait for a 1 */ + pio_sm_exec(bus_pio, sm_data, pio_encode_wait_pin(true, PHI)); + pio_sm_exec(bus_pio, sm_control, pio_encode_wait_pin(true, PHI)); + dma_hw->multi_channel_trigger = ( + 1u << dma_tx_control /* Control lines RW, CS1 & CS2 DMA transfer */ + | 1u << dma_tx_data /* Data & Address DMA transfer */ + ); + dma_channel_wait_for_finish_blocking(dma_tx_control); + + return cycles; +} + void unmute_sid(void) { DBG("[UNMUTE]\n"); @@ -755,7 +795,7 @@ void reset_sid(void) void clear_sid_registers(int sidno) { /* NOTICE: CAUSES ISSUES IF USED RIGHT BEFORE PLAYING */ - for (int reg = 0; reg < count_of(sid_registers) - 4; reg++) { + for (uint reg = 0; reg < count_of(sid_registers) - 4; reg++) { cycled_write_operation(((sidno * 0x20) | sid_registers[reg]), 0x0, 0); } return; @@ -802,5 +842,7 @@ void set_audio_switch(bool state) (int)usbsid_config.stereo_en, mono_stereo[(int)usbsid_config.stereo_en], state, mono_stereo[state]); return; } + #else + (void)state; #endif } diff --git a/src/gpio.h b/src/gpio.h index 8625d60..ad85fbd 100644 --- a/src/gpio.h +++ b/src/gpio.h @@ -72,13 +72,19 @@ * PIO1 * SM0: RGB LED control * SM1: LED PWM control + * SM2: Uart RX */ -/* Uart */ -#define BAUD_RATE 115200 +/* Uart 0 */ #define TX 16 /* uart 0 tx */ #define RX 17 /* uart 0 rx */ +/* PIO Uart */ +#ifdef USE_PIO_UART +#define PIOUART_TX 26 +#define PIOUART_RX 27 +#endif + /* Data bus ~ output/input */ #define D0 0 #define D1 1 @@ -125,8 +131,10 @@ #ifndef HAS_AUDIOSWITCH #define NIL1 15 #endif +#ifndef USE_PIO_UART #define NIL2 26 #define NIL3 27 +#endif #define NIL4 28 /* Masks */ diff --git a/src/macros.h b/src/macros.h index c214ab1..5813752 100644 --- a/src/macros.h +++ b/src/macros.h @@ -63,31 +63,31 @@ #endif /* Helper macro for finding the highest value of two */ -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) #endif /* Helper macro for finding the lowest value of two */ -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif /* Helper macro that creates a random value */ -#ifndef randval -#define randval(min,max) (min + rand() / (RAND_MAX / (max - min + 1) + 1)) +#ifndef RANDVAL +#define RANDVAL(min,max) (min + rand() / (RAND_MAX / (max - min + 1) + 1)) #endif /* Helper macro for mapping a value from a range to another range */ -#ifndef map -#define map(x,in_min,in_max,out_min,out_max) ((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min) +#ifndef MAP +#define MAP(x,in_min,in_max,out_min,out_max) ((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min) #endif #if defined(USE_RGB) -#ifndef ugrb_u32 /* RGB ->> GRB */ -#define ugrb_u32(r,g,b) ((uint32_t)(r) << 8) | ((uint32_t)(g) << 16) | (uint32_t)(b) +#ifndef UGRB_U32 /* RGB ->> GRB */ +#define UGRB_U32(r,g,b) ((uint32_t)(r) << 8) | ((uint32_t)(g) << 16) | (uint32_t)(b) #endif -#ifndef rgbb -#define rgbb(inp,br) (uint8_t)abs((inp / 255) * br) +#ifndef RGBB +#define RGBB(inp,br) (uint8_t)fabsl((inp / 255) * br) #endif #endif diff --git a/src/midi.c b/src/midi.c index 62d41ce..1b01b87 100644 --- a/src/midi.c +++ b/src/midi.c @@ -31,895 +31,133 @@ * */ +#include "pico/multicore.h" +#include "pico/util/queue.h" + #include "midi.h" #include "globals.h" #include "config.h" #include "sid.h" #include "logging.h" -#include "midi_patch_cynthcart.h" +#include "midi_ccdefaults.h" +const midi_ccvalues midi_ccvalues_defaults = MIDI_DEFAULT_CCVALUES_INIT; -/* GPIO externals */ +/* GPIO */ extern uint8_t __no_inline_not_in_flash_func(cycled_write_operation)(uint8_t address, uint8_t data, uint16_t cycles); +extern void reset_sid(void); + +/* Midi handler */ +extern void midi_processor_init(void); +extern void process_midi(uint8_t *buffer, int size); -/* ASID externals */ +/* ASID */ extern void process_sysex(uint8_t *buffer, int size); -/* Config externals */ -// extern Config usbsid_config; -// extern int cfg.numsids; -extern RuntimeCFG cfg; +#ifdef ONBOARD_EMULATOR +/* Cynthcart ~ Emudore */ +#include "pico/util/queue.h" /* Intercore queue */ +extern bool emulator_running, + starting_emulator, + stopping_emulator, + offload_ledrunner; +extern bool stop_emulator(void); +queue_t cynthcart_queue; +#endif -/* Init vars */ -uint8_t addr, val; -clock_rates clock_rate = CLOCK_DEFAULT; -hertz_values hertz = HZ_50; -int midi_bytes = 3; -int st[12] = { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3 }; /* SID table */ -int vt[12] = { 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2 }; /* Voice table */ -int voices[12] = {0}; -int voice = 0; -int curr_midi_channel; /* For use in config.c */ -// int freevoice = 0; /* Initialize the midi handlers */ void midi_init(void) { - /* Clear buffers once */ - memset(midimachine.streambuffer, 0, sizeof midimachine.streambuffer); - memset(midimachine.usbstreambuffer, 0, sizeof midimachine.usbstreambuffer); - memset(midimachine.channelkey_states, 0, sizeof midimachine.channelkey_states); - memset(midimachine.bank1channelgate, true, sizeof midimachine.bank1channelgate); + CFG("[MIDI INIT] START\n"); - /* Initial state and index */ + /* Set initial stream state and index */ midimachine.bus = FREE; midimachine.state = IDLE; midimachine.index = 0; - curr_midi_channel = 0; - - /* NOTE: Midi state is not loaded from config on init, needs LOAD_MIDI_STATE command once */ -} + midimachine.midi_bytes = 3; + /* Clear stream buffers once */ + memset(midimachine.streambuffer, 0, sizeof midimachine.streambuffer); + memset(midimachine.usbstreambuffer, 0, sizeof midimachine.usbstreambuffer); -/* Write helper functions */ - -void midi_bus_operation(uint8_t a, uint8_t b) -{ - cycled_write_operation(a, b, 10); /* 10 cycles constant */ -} - -void write(int channel, int sidno, int reg) -{ /* General */ - addr = (0x20 * sidno); - midi_bus_operation((addr | reg), midimachine.channel_states[channel][sidno][reg]); -} - -void write_triple(int channel, int sidno, int reg) -{ - for (int i = 0; i < 3; i++) { - write(channel, sidno, ((i * 7) + reg)); - } -} + /* Start the processor of midi buffers */ + midi_processor_init(); -void write_voice(int channel, int sidno, int voice) -{ /* Voice specific */ - addr = (0x20 * sidno); - midi_bus_operation((addr | (0x05 + voice)), midimachine.channel_states[channel][sidno][ATTDEC + voice]); /* Attack / Decay */ - midi_bus_operation((addr | (0x06 + voice)), midimachine.channel_states[channel][sidno][SUSREL + voice]); /* Sustain / Release */ - midi_bus_operation((addr | (0x02 + voice)), midimachine.channel_states[channel][sidno][PWMLO + voice]); /* PW LO */ - midi_bus_operation((addr | (0x03 + voice)), midimachine.channel_states[channel][sidno][PWMHI + voice]); /* PW HI */ + CFG("[MIDI INIT] FINISHED\n"); } -void write_note(int channel, int sidno, int voice) +#ifdef ONBOARD_EMULATOR +static inline void emulator_queue_init(void) { - addr = (0x20 * sidno); - midi_bus_operation((addr | (0x00 + voice)), midimachine.channel_states[channel][sidno][NOTELO + voice]); - midi_bus_operation((addr | (0x01 + voice)), midimachine.channel_states[channel][sidno][NOTEHI + voice]); + /* emudore */ + queue_init(&cynthcart_queue, sizeof(cynthcart_queue_entry_t), 16); /* 16 entries */ } - -void write_gate(int channel, int sidno, int voice) +static inline void emulator_queue_deinit(void) { - addr = (0x20 * sidno) | (CONTR + voice); - midi_bus_operation(addr, midimachine.channel_states[channel][sidno][CONTR + voice]); + /* emudore */ + queue_free(&cynthcart_queue); + reset_sid(); } - -/* Bank helper functions */ - -void bank_null(int channel, int sidno, int program) +static inline void handle_emulater_data(void) { - /* SID Voices */ - midimachine.channel_states[channel][sidno][PWMLO] = patchPWL[program]; - midimachine.channel_states[channel][sidno][PWMLO + 7] = patchPWL[program]; - midimachine.channel_states[channel][sidno][PWMLO + 14] = patchPWL[program]; - midimachine.channel_states[channel][sidno][PWMHI] = patchPWH[program]; - midimachine.channel_states[channel][sidno][PWMHI + 7] = patchPWH[program]; - midimachine.channel_states[channel][sidno][PWMHI + 14] = patchPWH[program]; - midimachine.channel_states[channel][sidno][CONTR] = patchWave1[program]; - midimachine.channel_states[channel][sidno][CONTR + 7] = patchWave2[program]; - midimachine.channel_states[channel][sidno][CONTR + 14] = patchWave3[program]; - midimachine.channel_states[channel][sidno][ATTDEC] = patchAD[program]; - midimachine.channel_states[channel][sidno][SUSREL] = patchSR1[program]; - midimachine.channel_states[channel][sidno][ATTDEC + 7] = patchAD[program]; - midimachine.channel_states[channel][sidno][SUSREL + 7] = patchSR2[program]; - midimachine.channel_states[channel][sidno][ATTDEC + 14] = patchAD[program]; - midimachine.channel_states[channel][sidno][SUSREL + 14] = patchSR3[program]; - /* SID General */ - midimachine.channel_states[channel][sidno][FC_LO] = newPatchFiltCut[program]; - midimachine.channel_states[channel][sidno][FC_HI] = 0; - midimachine.channel_states[channel][sidno][RESFLT] = patchFilt[program]; - midimachine.channel_states[channel][sidno][MODVOL] = patchVolMode[program] | patchVol[program]; - for (int sidno = 0; sidno < 4; sidno++) { - addr = (sidno * 0x20); - midi_bus_operation((addr | PWMLO), midimachine.channel_states[channel][sidno][PWMLO]); /* PW LO */ - midi_bus_operation((addr | (PWMLO + 7)), midimachine.channel_states[channel][sidno][PWMLO + 7]); /* PW LO */ - midi_bus_operation((addr | (PWMLO + 14)), midimachine.channel_states[channel][sidno][PWMLO + 14]); /* PW LO */ - midi_bus_operation((addr | PWMHI), midimachine.channel_states[channel][sidno][PWMHI]); /* PW HI */ - midi_bus_operation((addr | (PWMHI + 7)), midimachine.channel_states[channel][sidno][PWMHI + 7]); /* PW HI */ - midi_bus_operation((addr | (PWMHI + 14)), midimachine.channel_states[channel][sidno][PWMHI + 14]); /* PW HI */ - midi_bus_operation((addr | CONTR), midimachine.channel_states[channel][sidno][CONTR]); /* Waveform */ - midi_bus_operation((addr | (CONTR + 7)), midimachine.channel_states[channel][sidno][CONTR + 7]); /* Waveform */ - midi_bus_operation((addr | (CONTR + 14)), midimachine.channel_states[channel][sidno][CONTR + 14]); /* Waveform */ - midi_bus_operation((addr | ATTDEC), midimachine.channel_states[channel][sidno][ATTDEC]); /* Attack & Decay */ - midi_bus_operation((addr | SUSREL), midimachine.channel_states[channel][sidno][SUSREL]); /* Sustain & Release */ - midi_bus_operation((addr | (ATTDEC + 7)), midimachine.channel_states[channel][sidno][ATTDEC + 7]); /* Attack & Decay */ - midi_bus_operation((addr | (SUSREL + 7)), midimachine.channel_states[channel][sidno][SUSREL + 7]); /* Sustain & Release */ - midi_bus_operation((addr | (ATTDEC + 14)), midimachine.channel_states[channel][sidno][ATTDEC + 14]); /* Attack & Decay */ - midi_bus_operation((addr | (SUSREL + 14)), midimachine.channel_states[channel][sidno][SUSREL + 14]); /* Sustain & Release */ - - midi_bus_operation((addr | FC_LO), midimachine.channel_states[channel][sidno][FC_LO]); /* Filtercut LO */ - midi_bus_operation((addr | FC_HI), midimachine.channel_states[channel][sidno][FC_HI]); /* Filtercut HI */ - // midi_bus_operation((addr | RESFLT), midimachine.channel_states[channel][sidno][RESFLT]); /* Filer */ // BUG: Causes the sound to be SILENT!? - midi_bus_operation((addr | MODVOL), midimachine.channel_states[channel][sidno][MODVOL]); /* Mode & Volume */ + for (size_t e = 0; e < midimachine.index; e++) { + /* Create queue entry */ + cynthcart_queue_entry_t cq_entry; + /* Add byte to queue */ + cq_entry.data = midimachine.streambuffer[e]; + /* Add to queue (blocking wait if queue is full) */ + queue_add_blocking(&cynthcart_queue, &cq_entry); } + return; } -void bank_zero_sidsetter_dualregister(int channel, int val, int hi, int lo, int himask, int lomask, int hishift) -{ /* For provided hi and lo registers of each active SID */ - for (int sid = 0; sid < cfg.numsids; sid++) { - /* Dual Hi */ - midimachine.channel_states[channel][sid][hi] = ((val & himask) >> hishift); - write(channel, sid, hi); /* HI REG */ - /* Dual Lo */ - midimachine.channel_states[channel][sid][lo] = (val & lomask); - write(channel, sid, lo); /* LO REG */ - } -} - -void bank_one_sidsetter_dualregister(int channel, int sidno, int val, int hi, int lo, int himask, int lomask, int hishift) -{ /* For provided hi and lo registers of provided SID */ - /* Dual Hi */ - midimachine.channel_states[channel][sidno][hi] = ((val & himask) >> hishift); - write(channel, sidno, hi); - /* Dual Lo */ - midimachine.channel_states[channel][sidno][lo] = (val & lomask); - write(channel, sidno, lo); -} - -void bank_zero_voicesetter_dualregister(int channel, int val, int hi, int lo, int himask, int lomask, int hishift) -{ /* For provided hi and lo registers of each voice of each active SID */ - for (int sid = 0; sid < cfg.numsids; sid ++) { - for (int i = 0; i < 3; i++) { - /* Dual Hi */ - midimachine.channel_states[channel][sid][(i * 7) + hi] = ((val & himask) >> hishift); - /* Dual Lo */ - midimachine.channel_states[channel][sid][(i * 7) + lo] = (val & lomask); - } - write_triple(channel, sid, hi); /* HI REG */ - write_triple(channel, sid, lo); /* LO REG */ - } -} - -void bank_one_voicesetter_dualregister(int channel, int sidno, int voiceno, int val, int hi, int lo, int himask, int lomask, int hishift) -{ /* For provided hi and lo registers of provided voice of provided SID */ - /* Dual Hi */ - midimachine.channel_states[channel][sidno][(voiceno * 7) + hi] = ((val & himask) >> hishift); - write(channel, sidno, ((voiceno * 7) + hi)); - /* Dual Lo */ - midimachine.channel_states[channel][sidno][(voiceno * 7) + lo] = (val & lomask); - write(channel, sidno, ((voiceno * 7) + lo)); -} - -void bank_zero_sidsetter_singleregister(int channel, int val, int reg, int mask) -{ /* For provided register of each voice of each active SID with provided mask */ - for (int sid = 0; sid < cfg.numsids; sid ++) { - uint8_t keep_state; - keep_state = midimachine.channel_states[channel][sid][reg]; - keep_state &= mask; - val = keep_state | val; - midimachine.channel_states[channel][sid][reg] = val; - write(channel, sid, reg); - } -} - -void bank_one_sidsetter_singleregister(int channel, int sidno, int val, int reg, int mask) -{ /* For provided register of provided voice of provided SID with provided mask */ - uint8_t keep_state; - keep_state = midimachine.channel_states[channel][sidno][reg]; - keep_state &= mask; - val = keep_state | val; - midimachine.channel_states[channel][sidno][reg] = val; - write(channel, sidno, reg); -} - -void bank_one_voicesetter_singleregister(int channel, int sidno, int voiceno, int val, int reg, int mask) -{ /* For provided register of provided voice of provided SID with provided mask */ - uint8_t keep_state; - keep_state = midimachine.channel_states[channel][sidno][((voiceno * 7) + reg)]; - keep_state &= mask; - val = keep_state | val; - midimachine.channel_states[channel][sidno][((voiceno * 7) + reg)] = val; - write(channel, sidno, ((voiceno * 7) + reg)); -} - -void bank_zero_voicetoggle(int channel, int val, int reg, uint8_t toggle) -{ /* For provided register of each voice of each active SID for provided toggle bit */ - for (int sid = 0; sid < cfg.numsids; sid++) { - for (int i = 0; i < 3; i++) { - uint8_t keep_state; - keep_state = midimachine.channel_states[channel][sid][(i * 7) + reg]; - val = val == 1 ? keep_state |= toggle : keep_state & ~(toggle); - midimachine.channel_states[channel][sid][(i * 7) + reg] = val; - } - write_triple(channel, sid, reg); - } -} - -void bank_one_voicetoggle(int channel, int sidno, int voiceno, int val, int reg, uint8_t toggle) -{ /* For provided register of provided voice of provided SID for provided toggle bit */ - uint8_t keep_state; - keep_state = midimachine.channel_states[channel][sidno][(voiceno * 7) + reg]; - val = val == 1 ? keep_state |= toggle : keep_state & ~(toggle); - midimachine.channel_states[channel][sidno][(voiceno * 7) + reg] = val; - write(channel, sidno, (voiceno * 7) + reg); +static inline void emulator_enable(void) +{ + emulator_queue_init(); + emulator_running = false; + offload_ledrunner = true; + starting_emulator = true; + return; } -// void bank_zero_sidsetter_single(int channel, int val, int reg, int mask) -// { -// for (int sid = 0; sid < cfg.numsids; sid++) { -// midimachine.channel_states[channel][sid][reg] = val; -// write(channel, sid, reg); -// } -// } - -// void bank_one_sidsetter_single(int channel, int sidno, int voiceno, int val, int reg, int mask) -// { -// midimachine.channel_states[channel][sidno][reg] = val; -// write(channel, sidno, reg); -// } - -// void bank_zero_voicesetter_single(int channel, int val, int hi, int lo, int himask, int lomask, int hishift) -// { -// // for (int sid = 0; sid < cfg.numsids; sid ++) { /* For each active SID */ -// // for (int i = 0; i < 3; i++) { /* For each voice per SID */ -// // /* Dual Hi */ -// // midimachine.channel_states[channel][sid][(i * 7) + hi] = ((val & himask) >> hishift); -// // /* Dual Lo */ -// // midimachine.channel_states[channel][sid][(i * 7) + lo] = (val & lomask); -// // } -// // write_triple(channel, sid, hi); /* HI REG */ -// // write_triple(channel, sid, lo); /* LO REG */ -// // } -// } - -// void bank_one_voicesetter_single(int channel, int sidno, int voiceno, int val, int hi, int lo, int himask, int lomask, int hishift) -// { -// // /* Dual Hi */ -// // midimachine.channel_states[channel][sidno][(voiceno * 7) + hi] = ((val & himask) >> hishift); -// // write(channel, sidno, ((voiceno * 7) + hi)); -// // /* Dual Lo */ -// // midimachine.channel_states[channel][sidno][(voiceno * 7) + lo] = (val & lomask); -// // write(channel, sidno, ((voiceno * 7) + lo)); -// } - -// void bank_zero_voicesetter_toggle_single_withkeep(int channel, int val, int reg, uint8_t toggle) -// { -// // (void)mask; -// for (int sid = 0; sid < cfg.numsids; sid ++) { /* For each active SID */ -// for (int i = 0; i < 3; i++) { /* For each voice per SID */ -// // midimachine.channel_states[channel][sid][reg * i] = -// // ((midimachine.channel_states[channel][sid][reg] & R_NIBBLE) ^ toggle); -// uint8_t keep_state; -// keep_state = midimachine.channel_states[channel][sid][(i * 7) + reg]; -// /* val = val == 1 ? keep_state |= toggle : keep_state ^ toggle; */ -// val = val == 1 ? keep_state |= toggle : keep_state & ~(toggle); -// midimachine.channel_states[channel][sid][(i * 7) + reg] = val; -// // write(channel, sid, (reg * i)); -// } -// write_triple(channel, sid, reg); -// } -// } - -// // void bank_one_toggle_single(int channel, int sidno, int voiceno, int val, int reg, uint8_t toggle) -// void bank_one_voicesetter_toggle_single_withkeep(int channel, int sidno, int voiceno, int val, int reg, uint8_t toggle) -// { -// uint8_t keep_state; -// keep_state = midimachine.channel_states[channel][sidno][reg]; -// val = val == 1 ? keep_state |= toggle : keep_state & ~(toggle); -// midimachine.channel_states[channel][sidno][reg] = val; -// write(channel, sidno, reg); -// } - -/* Bank noteon ~ noteoff functions */ - -void bank_null_off(int channel, int sidno) +static inline void emulator_disable(void) { - // sidno = midimachine.channelkey_states[channel][sidno][N_KEYS]; - if (midimachine.channelkey_states[channel][sidno][N_KEYS] != 0) midimachine.channelkey_states[channel][sidno][N_KEYS]--; - addr |= (midimachine.channelkey_states[channel][sidno][N_KEYS] * 0x20); - if (midimachine.channelkey_states[channel][sidno][N_KEYS] < 0) midimachine.channelkey_states[channel][sidno][N_KEYS] = 0; - /* Control ~ Gate bit off */ - midimachine.channel_states[channel][sidno][CONTR] = (midimachine.channel_states[channel][sidno][CONTR] & 0xFE); - midimachine.channel_states[channel][sidno][CONTR + 7] = (midimachine.channel_states[channel][sidno][CONTR + 7] & 0xFE); - midimachine.channel_states[channel][sidno][CONTR + 14] = (midimachine.channel_states[channel][sidno][CONTR + 17] & 0xFE); - write_triple(channel, sidno, CONTR); + emulator_running = false; + stopping_emulator = true; + stop_emulator(); + offload_ledrunner = false; + emulator_queue_deinit(); + return; } -void bank_null_on(int channel, int sidno, uint8_t Flo, uint8_t Fhi) +static inline void emulator_reset(void) { - // sidno = midimachine.channelkey_states[channel][sidno][N_KEYS]; - int val1, val2, val3; - if (midimachine.channelkey_states[channel][sidno][N_KEYS] < 0) midimachine.channelkey_states[channel][sidno][N_KEYS] = 0; - addr |= midimachine.channelkey_states[channel][sidno][N_KEYS] <= 4 ? (midimachine.channelkey_states[channel][sidno][N_KEYS] * 0x20) : 0x0; - /* Control ~ Gate bit on */ - val1 = midimachine.channel_states[channel][sidno][CONTR] & 0xFE; - val1 |= 0x1; - val2 = midimachine.channel_states[channel][sidno][CONTR + 7] & 0xFE; - val2 |= 0x1; - val3 = midimachine.channel_states[channel][sidno][CONTR + 14] & 0xFE; - val3 |= 0x1; - midimachine.channel_states[channel][sidno][CONTR] = val1; - midimachine.channel_states[channel][sidno][CONTR + 7] = val2; - midimachine.channel_states[channel][sidno][CONTR + 14] = val3; - write_triple(channel, sidno, CONTR); - /* Note Lo & Hi */ - midimachine.channel_states[channel][sidno][NOTELO] = Flo; - midimachine.channel_states[channel][sidno][NOTELO + 7] = Flo; - midimachine.channel_states[channel][sidno][NOTELO + 14] = Flo; - midimachine.channel_states[channel][sidno][NOTEHI] = Fhi; - midimachine.channel_states[channel][sidno][NOTEHI + 7] = Fhi; - midimachine.channel_states[channel][sidno][NOTEHI + 14] = Fhi; - write_triple(channel, sidno, NOTELO); - write_triple(channel, sidno, NOTEHI); - midimachine.channelkey_states[channel][sidno][N_KEYS]++; + DBG("[MIDI] Emulator reset not implemented yet!\n"); + return; } -void bank_zero_off(int channel, int sidno, uint8_t note) +static inline void handle_emulator_cc(void) { - // if (midimachine.channelkey_states[channel][sidno][N_KEYS] < 0) midimachine.channelkey_states[channel][sidno][N_KEYS] = 0; - // midimachine.channelkey_states[channel][sidno][V1_ACTIVE] == 1 && midimachine.channelkey_notestates[channel][sidno][note_index] == 1 - // ? voice = 0, midimachine.channelkey_states[channel][sidno][V1_ACTIVE] = 0, midimachine.channelkey_notestates[channel][sidno][note_index] = 0 - // : midimachine.channelkey_states[channel][sidno][V2_ACTIVE] == 1 && midimachine.channelkey_notestates[channel][sidno][note_index] == 2 - // ? voice = 1, midimachine.channelkey_states[channel][sidno][V2_ACTIVE] = 0, midimachine.channelkey_notestates[channel][sidno][note_index] = 0 - // : midimachine.channelkey_states[channel][sidno][V3_ACTIVE] == 1 && midimachine.channelkey_notestates[channel][sidno][note_index] == 3 - // ? voice = 2, midimachine.channelkey_states[channel][sidno][V3_ACTIVE] = 0, midimachine.channelkey_notestates[channel][sidno][note_index] = 0 - // : 0; /* ISSUE: EVERY NOTE AFTER 3 KEYS GOES TO VOICE 1 */ - - // if (midimachine.channelkey_states[channel][sidno][N_KEYS] < 0) midimachine.channelkey_states[channel][sidno][N_KEYS] = 0; - - for (int i = 0; i < ((cfg.numsids * 3) - 1); i++) { - // if (voices[i] == buffer[1]) { - if (voices[i] == note) { - voice = i; - voices[i] = 0; - // freevoice = voice; + if (midimachine.streambuffer[1] == midi_ccvalues_defaults.CC_CEN) { /* control emulator enable 0x55 (85) */ + if (!emulator_running) { + emulator_enable(); } - } - sidno = abs(voice / 3); - midimachine.channel_states[channel][sidno][CONTR + (vt[voice] * 7)] = (midimachine.channel_states[channel][sidno][CONTR + (vt[voice] * 7)] & 0xFE); - if (midimachine.channelkey_states[channel][sidno][N_KEYS] != 0) midimachine.channelkey_states[channel][sidno][N_KEYS]--; - write_gate(channel, sidno, (vt[voice] * 7)); - voices[voice] = 0; - for (int i = 0; i < ((cfg.numsids * 3) - 1); i++) { - if (voices[i] == 0) { - voice = i; - break; + } else + if (midimachine.streambuffer[1] == midi_ccvalues_defaults.CC_CDI) { /* control emulator disable 0x56 (86) */ + if (emulator_running) { + emulator_disable(); } - } - // voice = voice == 2 ? voice : voice--; - if (voice != 0) voice--; -} - -void bank_zero_on(int channel, int sidno, uint8_t note, uint8_t Flo, uint8_t Fhi) -{ - // midimachine.channelkey_states[channel][sidno][V1_ACTIVE] == 0 && midimachine.channelkey_notestates[channel][sidno][note_index] != 1 - // ? voice = 0, midimachine.channelkey_states[channel][sidno][V1_ACTIVE] = 1, midimachine.channelkey_notestates[channel][sidno][note_index] = 1 - // : midimachine.channelkey_states[channel][sidno][V2_ACTIVE] == 0 && midimachine.channelkey_notestates[channel][sidno][note_index] != 2 - // ? voice = 1, midimachine.channelkey_states[channel][sidno][V2_ACTIVE] = 1, midimachine.channelkey_notestates[channel][sidno][note_index] = 2 - // : midimachine.channelkey_states[channel][sidno][V3_ACTIVE] == 0 && midimachine.channelkey_notestates[channel][sidno][note_index] != 3 - // ? voice = 2, midimachine.channelkey_states[channel][sidno][V3_ACTIVE] = 1, midimachine.channelkey_notestates[channel][sidno][note_index] = 3 - // : 0; - // for (int i = 0; i < 3; i++) { - // if (voices[i] == 0) voice = i; - // break; - // } - // voices[voice] = buffer[1]; - voices[voice] = note; - sidno = abs(voice / 3); - midimachine.channelkey_states[channel][sidno][N_KEYS]++; - /* write(channel, sid, MODVOL); */ - /* write_voice(channel, sid, (voice * 7)); */ - /* Note Lo & Hi */ - midimachine.channel_states[channel][sidno][NOTELO + (vt[voice] * 7)] = Flo; - midimachine.channel_states[channel][sidno][NOTEHI + (vt[voice] * 7)] = Fhi; - write_note(channel, sidno, (vt[voice] * 7)); - /* Control ~ Gate bit on */ - val = midimachine.channel_states[channel][sidno][CONTR + (vt[voice] * 7)] & 0xFE; - val |= 0x1; - midimachine.channel_states[channel][sidno][CONTR + (vt[voice] * 7)] = val; - write_gate(channel, sidno, (vt[voice] * 7)); - // prevvoice = voice; - // if (voice < 3) voice++; - if (voice < ((cfg.numsids * 3) - 1)) voice++; - if (voice > ((cfg.numsids * 3) - 1)) voice = 0; -} - -void bank_one_off(int channel, int sidno, int voiceno, uint8_t note) -{ - if (midimachine.bank1channelgate[channel]) { - midimachine.channel_states[channel][sidno][CONTR + (voiceno * 7)] = (midimachine.channel_states[channel][sidno][CONTR + (voiceno * 7)] & 0xFE); - write_gate(channel, sidno, (voiceno * 7)); - } - voices[voiceno] = 0; -} - -void bank_one_on(int channel, int sidno, int voiceno, uint8_t note, uint8_t Flo, uint8_t Fhi) -{ - // printf("%d %d %d\n", channel, sidno, voiceno); - /* Keepstate */ - voices[voice] = note; - /* Note Lo & Hi */ - midimachine.channel_states[channel][sidno][NOTELO + (voiceno * 7)] = Flo; - midimachine.channel_states[channel][sidno][NOTEHI + (voiceno * 7)] = Fhi; - write_note(channel, sidno, (voiceno * 7)); - /* Control ~ Gate bit on */ - if (midimachine.bank1channelgate[channel]) { - int val; - val = midimachine.channel_states[channel][sidno][CONTR + (voiceno * 7)] & 0xFE; - val |= 0x1; - midimachine.channel_states[channel][sidno][CONTR + (voiceno * 7)] = val; - write_gate(channel, sidno, (voiceno * 7)); - } -} - -/* Helpers */ - -long map_to_onoff(long in) -{ - return map(in, ZERO, MIDI_CC_MAX, ZERO, ONE); -} - - -/* Midi processing */ - -void process_midi(uint8_t *buffer, int size) -{ - uint8_t note_index = buffer[1]; - uint16_t frequency = musical_scale_values[note_index]; - uint8_t Flo, Fhi; - Flo = (frequency & VOICE_FREQLO); - Fhi = ((frequency >> 8) >= VOICE_FREQHI ? VOICE_FREQHI : (frequency >> 8)); - - int /* in, */ out, volume, channel, voiceno, sidno, bank, program; - curr_midi_channel = channel = (buffer[0] & R_NIBBLE); /* 1 -> 16 ~ 0x0 -> 0xF */ - bank = midimachine.channelbank[channel]; /* Set Bank */ - program = midimachine.channelprogram[channel]; /* Set Program */ - voiceno = vt[(int)channel]; /* Sets the sid voice according the the channel we're on, max voices is 12 with 4x SID */ // TODO: Limit at max voices - sidno = (bank == 1) ? st[(int)channel] : 0; /* Sets the SID number according to the voice we're on */ - volume = midimachine.channel_states[channel][sidno][MODVOL] & R_NIBBLE; - // addr = 0x0; /* Set starting address */ - /* TODO: NEEDED? */ - midimachine.channelkey_states[channel][sidno][N_KEYS] = midimachine.channelkey_states[channel][sidno][N_KEYS] < 0 - ? midimachine.channelkey_states[channel][sidno][N_KEYS] = 0 - : midimachine.channelkey_states[channel][sidno][N_KEYS]; - int voicecount = 0; - for (int i = 0; i < ((cfg.numsids * 3) - 1); i++) { - if (voices[i] == 0) { - voicecount += 1; ; + } else + if (midimachine.streambuffer[1] == midi_ccvalues_defaults.CC_CRE) { /* control emulator reset 0x57 (87) */ + if (emulator_running) { + emulator_reset(); } } - if (voicecount == ((cfg.numsids * 3) - 1) && midimachine.channelkey_states[channel][sidno][N_KEYS] != 0) midimachine.channelkey_states[channel][sidno][N_KEYS] = 0; -// TODO: -// Add clock sync -// Any other missing links -// TODO: -// Reorder the items below into preset CC's and custom CC's - /* Start Status byte handling */ - // printf("%d %d %d %d %d %d %d\n", bank, channel, curr_midi_channel, voiceno, sidno, (bank == 1), st[voiceno]); - switch (buffer[0]) { - case 0x80 ... 0x8F: /* Channel 0~16 Note Off */ - bank = midimachine.channelbank[channel]; - switch (bank) { - case 0: /* Bank 0 */ - bank_zero_off(channel, sidno, buffer[1]); - break; - case 1: /* Bank 1 */ - bank_one_off(channel, sidno, voiceno, buffer[1]); - break; - case 9: /* Bank 9 */ - bank_null_off(channel, sidno); - default: - break; - } - break; - case 0x90 ... 0x9F: /* Channel 0~16 Note On */ - bank = midimachine.channelbank[channel]; - switch (bank) { - case 0: /* Bank 0 */ - bank_zero_on(channel, sidno, buffer[1], Flo, Fhi); - break; - case 1: /* Bank 1 */ - bank_one_on(channel, sidno, voiceno, buffer[1], Flo, Fhi); - break; - case 9: /* Bank 9 */ - bank_null_on(channel, sidno, Flo, Fhi); - default: - break; - } - break; - case 0xA0 ... 0xAF: /* Channel 0~16 Polyphonic Key Pressure (Aftertouch) */ - break; - case 0xB0 ... 0xBF: /* Channel 0~16 Control/Mode Change */ - switch (bank) { /* QUESTION: Should this be/stay bank independent!? */ - case 0: /* Bank 0 ~ Polyfonic stacking */ - case 1: /* Bank 1 ~ Single voices */ - case 9: /* Bank 9 ~ Cynthcart */ - switch (buffer[1]) { /* MSB or LSB for Control/Mode Change */ - /* Bank ~ Patch select */ - case CC_BMSB: /* Bank Select MSB */ - /* Ignore ~ We have no more banks, only 1 bank with 16 programs */ - break; - case CC_BLSB: /* Bank Select LSB */ - bank = midimachine.channelbank[channel] = buffer[2]; /* Set Bank */ - break; - /* Per SID settings */ - case CC_VOL: /* Set Master Volume */ - volume = map(buffer[2], 0, MIDI_CC_MAX, 0, 15); - if (bank == 0) bank_zero_sidsetter_singleregister(channel, volume, MODVOL, L_NIBBLE); - if (bank == 1) bank_one_sidsetter_singleregister(channel, sidno, volume, MODVOL, L_NIBBLE); - break; - case CC_FFC: /* Filter Frequency Cutoff */ - out = map(buffer[2], 0, MIDI_CC_MAX, 0, 2047); - if (bank == 0) bank_zero_sidsetter_dualregister(channel, out, FC_HI, FC_LO, F_MASK_HI, F_MASK_LO, SHIFT_3); /* writes all available sids */ - if (bank == 1) bank_one_sidsetter_dualregister(channel, sidno, out, FC_HI, FC_LO, F_MASK_HI, F_MASK_LO, SHIFT_3); /* writes a single sid */ - // for (int sid = 0; sid < cfg.numsids; sid ++) { - // val = (out & 0x7); - // midimachine.channel_states[channel][sid][FC_LO] = val; - // val = (out & 0x7F8) >> 3; - // midimachine.channel_states[channel][sid][FC_HI] = val; - // write(channel, sid, FC_LO); - // write(channel, sid, FC_HI); - // } - break; - case CC_RES: /* Filter resonance */ - out = map(buffer[2], 0, MIDI_CC_MAX, 0, 15); - if (bank == 0) bank_zero_sidsetter_singleregister(channel, (out << 4), RESFLT, R_NIBBLE); - if (bank == 1) bank_one_sidsetter_singleregister(channel, sidno, (out << 4), RESFLT, R_NIBBLE); - // mask = R_NIBBLE; /* Inverted */ - // for (int sid = 0; sid < cfg.numsids; sid ++) { - // midimachine.channel_states[channel][sid][RESFLT] = (out << 4) | (midimachine.channel_states[channel][sid][RESFLT] & mask); - // write(channel, sid, RESFLT); - // } - break; - case CC_3OFF: /* Voice 3 disconnect */ - out = map_to_onoff(buffer[2]); - if (bank == 0) bank_zero_voicetoggle(channel, out, MODVOL, BIT_7); - if (bank == 1) bank_one_voicetoggle(channel, sidno, voiceno, out, MODVOL, BIT_7); - // for (int sid = 0; sid < cfg.numsids; sid ++) { - // keep_state = midimachine.channel_states[channel][sid][MODVOL]; - // val = out == 1 ? keep_state |= 0x80 : keep_state ^ 0x80; - // midimachine.channel_states[channel][sid][MODVOL] = val; - // write(channel, sid, MODVOL); - // } - /* write(channel, sidno, MODVOL); */ - break; - case CC_FLT1: /* Filter channel 1 */ - out = map_to_onoff(buffer[2]); - if (bank == 0) bank_zero_voicetoggle(channel, out, RESFLT, BIT_0); - if (bank == 1) bank_one_voicetoggle(channel, sidno, voiceno, out, RESFLT, BIT_0); - break; - case CC_FLT2: /* Filter channel 2 */ - out = map_to_onoff(buffer[2]); - if (bank == 0) bank_zero_voicetoggle(channel, out, RESFLT, BIT_1); - if (bank == 1) bank_one_voicetoggle(channel, sidno, voiceno, out, RESFLT, BIT_1); - break; - case CC_FLT3: /* Filter channel 3 */ - out = map_to_onoff(buffer[2]); - if (bank == 0) bank_zero_voicetoggle(channel, out, RESFLT, BIT_2); - if (bank == 1) bank_one_voicetoggle(channel, sidno, voiceno, out, RESFLT, BIT_2); - break; - case CC_FLTE: /* Filter external */ - out = map_to_onoff(buffer[2]); - // uint8_t fltchannel = buffer[1] == CC_FLT1 ? BIT_0 - // : buffer[1] == CC_FLT2 ? BIT_1 - // : buffer[1] == CC_FLT3 ? BIT_2 - // : buffer[1] == CC_FLTE ? BIT_3 - // : 0; // <<- fallback - if (bank == 0) bank_zero_voicetoggle(channel, out, RESFLT, BIT_3); - if (bank == 1) bank_one_voicetoggle(channel, sidno, voiceno, out, RESFLT, BIT_3); - // for (int sid = 0; sid < cfg.numsids; sid++) { - // fltres_state = midimachine.channel_states[channel][sid][RESFLT]; - // val = out == 1 ? fltres_state |= fltchannel : fltres_state ^ fltchannel; - // midimachine.channel_states[channel][sid][RESFLT] = val; - // write(channel, sid, RESFLT); - // } - /* write(channel, sidno, RESFLT); */ - break; - case CC_HPF: /* High pass */ - out = map_to_onoff(buffer[2]); - if (bank == 0) bank_zero_voicetoggle(channel, out, MODVOL, BIT_6); - if (bank == 1) bank_one_voicetoggle(channel, sidno, voiceno, out, MODVOL, BIT_6); - // for (int sid = 0; sid < cfg.numsids; sid ++) { - // keep_state = midimachine.channel_states[channel][sid][MODVOL]; - // val = out == 1 ? keep_state |= 0x40 : keep_state ^ 0x40; - // midimachine.channel_states[channel][sid][MODVOL] = val; - // write(channel, sid, MODVOL); - // } - /* write(channel, sidno, MODVOL); */ - break; - case CC_BPF: /* Band pass */ - out = map_to_onoff(buffer[2]); - if (bank == 0) bank_zero_voicetoggle(channel, out, MODVOL, BIT_5); - if (bank == 1) bank_one_voicetoggle(channel, sidno, voiceno, out, MODVOL, BIT_5); - // for (int sid = 0; sid < cfg.numsids; sid ++) { - // keep_state = midimachine.channel_states[channel][sid][MODVOL]; - // val = out == 1 ? keep_state |= 0x20 : keep_state ^ 0x20; - // midimachine.channel_states[channel][sid][MODVOL] = val; - // write(channel, sid, MODVOL); - // } - /* write(channel, sidno, MODVOL); */ - break; - case CC_LPF: /* Low pass */ - out = map_to_onoff(buffer[2]); - if (bank == 0) bank_zero_voicetoggle(channel, out, MODVOL, BIT_4); - if (bank == 1) bank_one_voicetoggle(channel, sidno, voiceno, out, MODVOL, BIT_4); - // for (int sid = 0; sid < cfg.numsids; sid ++) { - // keep_state = midimachine.channel_states[channel][sid][MODVOL]; - // val = out == 1 ? keep_state |= 0x10 : keep_state ^ 0x10; - // midimachine.channel_states[channel][sid][MODVOL] = val; - // write(channel, sid, MODVOL); - // } - /* write(channel, sidno, MODVOL); */ - break; - /* Per voice settings */ - case CC_PWM: /* Pulse Width Modulation (Modulation wheel) */ - out = map(buffer[2], 0, MIDI_CC_MAX, 0, TRIPLE_NIBBLE); - /* Pulse width Hi & Lo*/ - if (bank == 0) bank_zero_voicesetter_dualregister(channel, out, PWMHI, PWMLO, NIBBLE_3, BYTE, SHIFT_8); /* writes all 3 voices of a sid */ - if (bank == 1) bank_one_voicesetter_dualregister(channel, sidno, voiceno, out, PWMHI, PWMLO, NIBBLE_3, BYTE, SHIFT_8); /* writes a single voice */ - break; - case CC_NOTE: /* Note frequency */ // NOTE: NOT AVAILABLE FOR BANK ZERO FOR NOW - uint8_t b1_note_index = buffer[2]; - uint16_t b1_frequency = musical_scale_values[b1_note_index]; - uint8_t b1_Flo, b1_Fhi; - b1_Flo = (b1_frequency & VOICE_FREQLO); - b1_Fhi = ((b1_frequency >> 8) >= VOICE_FREQHI ? VOICE_FREQHI : (b1_frequency >> 8)); - /* Keepstate */ - voices[voice] = buffer[2]; - /* Note Lo & Hi */ - midimachine.channel_states[channel][sidno][NOTELO + (voiceno * 7)] = b1_Flo; - midimachine.channel_states[channel][sidno][NOTEHI + (voiceno * 7)] = b1_Fhi; - write_note(channel, sidno, (voiceno * 7)); - break; - case CC_NOIS: /* Noise waveform */ - out = map_to_onoff(buffer[2]); - if (bank == 0) bank_zero_voicetoggle(channel, out, CONTR, BIT_7); - if (bank == 1) bank_one_voicetoggle(channel, sidno, voiceno, out, CONTR, BIT_7); - break; - case CC_PULS: /* Pulse waveform */ - out = map_to_onoff(buffer[2]); - if (bank == 0) bank_zero_voicetoggle(channel, out, CONTR, BIT_6); - if (bank == 1) bank_one_voicetoggle(channel, sidno, voiceno, out, CONTR, BIT_6); - break; - case CC_SAWT: /* Sawtooth waveform */ - out = map_to_onoff(buffer[2]); - if (bank == 0) bank_zero_voicetoggle(channel, out, CONTR, BIT_5); - if (bank == 1) bank_one_voicetoggle(channel, sidno, voiceno, out, CONTR, BIT_5); - break; - case CC_TRIA: /* Triangle waveform */ - out = map_to_onoff(buffer[2]); - if (bank == 0) bank_zero_voicetoggle(channel, out, CONTR, BIT_4); - if (bank == 1) bank_one_voicetoggle(channel, sidno, voiceno, out, CONTR, BIT_4); - break; - case CC_TEST: /* Test bit */ - out = map_to_onoff(buffer[2]); - if (bank == 0) bank_zero_voicetoggle(channel, out, CONTR, BIT_3); - if (bank == 1) bank_one_voicetoggle(channel, sidno, voiceno, out, CONTR, BIT_3); - break; - case CC_RMOD: /* Ring modulator bit */ - out = map_to_onoff(buffer[2]); - if (bank == 0) bank_zero_voicetoggle(channel, out, CONTR, BIT_2); - if (bank == 1) bank_one_voicetoggle(channel, sidno, voiceno, out, CONTR, BIT_2); - // for (int sid = 0; sid < cfg.numsids; sid ++) { - // midimachine.channel_states[channel][sid][CONTR] = ((midimachine.channel_states[channel][sid][CONTR] & R_NIBBLE) ^ 0x4); - // midimachine.channel_states[channel][sid][CONTR + 7] = ((midimachine.channel_states[channel][sid][CONTR + 7] & R_NIBBLE) ^ 0x4); - // midimachine.channel_states[channel][sid][CONTR + 14] = ((midimachine.channel_states[channel][sid][CONTR + 14] & R_NIBBLE) ^ 0x4); - // write_triple(channel, sid, CONTR); - // } - /* write_triple(channel, sidno, CONTR); */ - break; - case CC_SYNC: /* Sync bit */ - out = map_to_onoff(buffer[2]); - if (bank == 0) bank_zero_voicetoggle(channel, out, CONTR, BIT_1); - if (bank == 1) bank_one_voicetoggle(channel, sidno, voiceno, out, CONTR, BIT_1); - // for (int sid = 0; sid < cfg.numsids; sid ++) { - // midimachine.channel_states[channel][sid][CONTR] = ((midimachine.channel_states[channel][sid][CONTR] & R_NIBBLE) ^ 0x2); - // midimachine.channel_states[channel][sid][CONTR + 7] = ((midimachine.channel_states[channel][sid][CONTR + 7] & R_NIBBLE) ^ 0x2); - // midimachine.channel_states[channel][sid][CONTR + 14] = ((midimachine.channel_states[channel][sid][CONTR + 14] & R_NIBBLE) ^ 0x2); - // write_triple(channel, sid, CONTR); - // } - /* write_triple(channel, sidno, CONTR); */ - break; - case CC_GATE: /* Gate bit */ - out = map_to_onoff(buffer[2]); - if (bank == 0) bank_zero_voicetoggle(channel, out, CONTR, BIT_0); - if (bank == 1) bank_one_voicetoggle(channel, sidno, voiceno, out, CONTR, BIT_0); - break; - case CC_GTEN: /* Custom setting for handling gate on and gate off in noteon and noteoff */ - out = map_to_onoff(buffer[2]); - midimachine.bank1channelgate[channel] = (bool)out; - break; - case CC_ATT: /* Attack */ // NOTE: NOT AVAILABLE FOR BANK ZERO FOR NOW - out = map(buffer[2], 0, MIDI_CC_MAX, 0, 15); - bank_one_voicesetter_singleregister(channel, sidno, voiceno, (out << 4), ATTDEC, R_NIBBLE); - // mask = R_NIBBLE; /* Inverted */ - // for (int sid = 0; sid < cfg.numsids; sid ++) { - // for (int i = 0; i < 3; i++) { - // midimachine.channel_states[channel][sid][(i * 7) + ATTDEC] = (out << 4) | (midimachine.channel_states[channel][sid][(i * 7) + ATTDEC] & mask); - // } - // write_triple(channel, sid, ATTDEC); - // } - /* write_triple(channel, sidno, ATTDEC); */ - break; - case CC_DEL: /* Decay */ // NOTE: NOT AVAILABLE FOR BANK ZERO FOR NOW - out = map(buffer[2], 0, MIDI_CC_MAX, 0, 15); - bank_one_voicesetter_singleregister(channel, sidno, voiceno, out, ATTDEC, L_NIBBLE); - // out = map(in, 0, 127, 0, 15); - // mask = L_NIBBLE; /* Inverted */ - // for (int sid = 0; sid < cfg.numsids; sid ++) { - // for (int i = 0; i < 3; i++) { - // midimachine.channel_states[channel][sid][(i * 7) + ATTDEC] = (midimachine.channel_states[channel][sid][(i * 7) + ATTDEC] & mask) | out; - // } - // write_triple(channel, sid, ATTDEC); - // } - /* write_triple(channel, sidno, ATTDEC); */ - break; - case CC_SUS: /* Sustain */ // NOTE: NOT AVAILABLE FOR BANK ZERO FOR NOW - out = map(buffer[2], 0, MIDI_CC_MAX, 0, 15); - bank_one_voicesetter_singleregister(channel, sidno, voiceno, (out << 4), SUSREL, R_NIBBLE); - // mask = R_NIBBLE; /* Inverted */ - // for (int sid = 0; sid < cfg.numsids; sid ++) { - // for (int i = 0; i < 3; i++) { - // midimachine.channel_states[channel][sid][(i * 7) + SUSREL] = (out << 4) | (midimachine.channel_states[channel][sid][(i * 7) + SUSREL] & mask); - // } - // write_triple(channel, sid, SUSREL); - // } - /* write_triple(channel, sidno, SUSREL); */ - break; - case CC_REL: /* Release */ // NOTE: NOT AVAILABLE FOR BANK ZERO FOR NOW - out = map(buffer[2], 0, MIDI_CC_MAX, 0, 15); - bank_one_voicesetter_singleregister(channel, sidno, voiceno, out, SUSREL, L_NIBBLE); - // mask = L_NIBBLE; /* Inverted */ - // for (int sid = 0; sid < cfg.numsids; sid ++) { - // for (int i = 0; i < 3; i++) { - // midimachine.channel_states[channel][sid][(i * 7) + SUSREL] = (midimachine.channel_states[channel][sid][(i * 7) + SUSREL] & mask) | out; - // } - // write_triple(channel, sid, SUSREL); - // } - /* write_triple(channel, sidno, SUSREL); */ - break; - default: - break; - } - break; - // case 9: /* Bank 9 ~ Cynthcart */ - default: - break; - } - break; - case 0xC0 ... 0xCF: /* Channel 0~16 Program change */ - program = midimachine.channelprogram[channel] = buffer[1]; /* Set Program */ - // bank = midimachine.channelbank[channel]; - switch (bank) { - case 0: /* Bank 0 ~ Polyfonic stacking */ - switch (program) { - case 0: /* Noise */ - for (int sid = 0; sid < cfg.numsids; sid ++) { - for (int i = 0; i < 3; i++) { - midimachine.channel_states[channel][sid][(i * 7) + CONTR] = ((midimachine.channel_states[channel][sid][(i * 7) + CONTR] & R_NIBBLE) | 0x80); - } - write_triple(channel, sid, CONTR); - } - break; - case 1: /* Pulse */ - for (int sid = 0; sid < cfg.numsids; sid ++) { - for (int i = 0; i < 3; i++) { - midimachine.channel_states[channel][sid][(i * 7) + CONTR] = ((midimachine.channel_states[channel][sid][(i * 7) + CONTR] & R_NIBBLE) | 0x40); - } - write_triple(channel, sid, CONTR); - } - break; - case 2: /* Sawtooth */ - for (int sid = 0; sid < cfg.numsids; sid ++) { - for (int i = 0; i < 3; i++) { - midimachine.channel_states[channel][sid][(i * 7) + CONTR] = ((midimachine.channel_states[channel][sid][(i * 7) + CONTR] & R_NIBBLE) | 0x20); - } - write_triple(channel, sid, CONTR); - } - break; - case 3: /* Triangle */ - for (int sid = 0; sid < cfg.numsids; sid ++) { - for (int i = 0; i < 3; i++) { - midimachine.channel_states[channel][sid][(i * 7) + CONTR] = ((midimachine.channel_states[channel][sid][(i * 7) + CONTR] & R_NIBBLE) | 0x10); - } - write_triple(channel, sid, CONTR); - } - break; - }; - break; - case 1: /* Bank 1 ~ Single voices */ - switch (program) { - case 0: /* Noise */ - midimachine.channel_states[channel][sidno][(voiceno * 7) + CONTR] = ((midimachine.channel_states[channel][sidno][(voiceno * 7) + CONTR] & R_NIBBLE) | 0x80); - write(channel, sidno, CONTR); - break; - case 1: /* Pulse */ - midimachine.channel_states[channel][sidno][(voiceno * 7) + CONTR] = ((midimachine.channel_states[channel][sidno][(voiceno * 7) + CONTR] & R_NIBBLE) | 0x40); - write(channel, sidno, CONTR); - break; - case 2: /* Sawtooth */ - midimachine.channel_states[channel][sidno][(voiceno * 7) + CONTR] = ((midimachine.channel_states[channel][sidno][(voiceno * 7) + CONTR] & R_NIBBLE) | 0x20); - write(channel, sidno, CONTR); - break; - case 3: /* Triangle */ - midimachine.channel_states[channel][sidno][(voiceno * 7) + CONTR] = ((midimachine.channel_states[channel][sidno][(voiceno * 7) + CONTR] & R_NIBBLE) | 0x10); - write(channel, sidno, CONTR); - break; - } - break; - case 9: /* Patches */ - for (int n = 1; n <= cfg.numsids; n++) { - bank_null(channel, (n - 1), program); - } - default: - break; - }; - break; - case 0xD0 ... 0xDF: /* Channel 0~16 Pressure (After-touch) */ - break; - case 0xE0 ... 0xEF: /* Channel 0~16 Pitch Bend Change */ - break; - default: - break; - }; - if (midimachine.channelkey_states[channel][sidno][N_KEYS] == 0) voice = 0; - - MVDBG("[N]%d[V%d]%02x%02x%02x[1][$%04x][$%04x][$%02x][$%02x][$%02x][2][$%04x][$%04x][$%02x][$%02x][$%02x][3][$%04x][$%04x][$%02x][$%02x][$%02x][R][$%02x%01x][$%02x][$%02x]\r\n", - midimachine.channelkey_states[channel][sidno][N_KEYS], // N - voice,voices[0],voices[1],voices[2], //V - (midimachine.channel_states[channel][sidno][NOTEHI] << 8 | midimachine.channel_states[channel][sidno][NOTELO]), // 0&1 - (midimachine.channel_states[channel][sidno][PWMHI] << 8 | midimachine.channel_states[channel][sidno][PWMLO]), // 2&3 - midimachine.channel_states[channel][sidno][CONTR], // 4 - midimachine.channel_states[channel][sidno][ATTDEC], // 5 - midimachine.channel_states[channel][sidno][SUSREL], // 6 - - (midimachine.channel_states[channel][sidno][NOTEHI + 7] << 8 | midimachine.channel_states[channel][sidno][NOTELO + 7]), // 0&1 - (midimachine.channel_states[channel][sidno][PWMHI + 7] << 8 | midimachine.channel_states[channel][sidno][PWMLO + 7]), // 2&3 - midimachine.channel_states[channel][sidno][CONTR + 7], // 4 - midimachine.channel_states[channel][sidno][ATTDEC + 7], // 5 - midimachine.channel_states[channel][sidno][SUSREL + 7], // 6 - - (midimachine.channel_states[channel][sidno][NOTEHI + 14] << 8 | midimachine.channel_states[channel][sidno][NOTELO + 14]), // 0&1 - (midimachine.channel_states[channel][sidno][PWMHI + 14] << 8 | midimachine.channel_states[channel][sidno][PWMLO + 14]), // 2&3 - midimachine.channel_states[channel][sidno][CONTR + 14], // 4 - midimachine.channel_states[channel][sidno][ATTDEC + 14], // 5 - midimachine.channel_states[channel][sidno][SUSREL + 14], // 6 - - midimachine.channel_states[channel][sidno][FC_HI], // 15 - midimachine.channel_states[channel][sidno][FC_LO], // 16 - midimachine.channel_states[channel][sidno][RESFLT], // 17 - midimachine.channel_states[channel][sidno][MODVOL]); // 18 + return; } +#endif /* Processes a 1 byte incoming midi buffer * Figures out if we're receiving midi or sysex */ @@ -934,7 +172,7 @@ void midi_buffer_task(uint8_t buffer) /* System Exclusive */ case 0xF0: /* System Exclusive Start */ if (midimachine.bus != CLAIMED && midimachine.type == NONE) { - dtype = asid; /* Set data type to ASID */ + dtype = sysex; /* Set data type to SysEx */ midimachine.state = RECEIVING; midimachine.type = SYSEX; midimachine.bus = CLAIMED; @@ -945,7 +183,7 @@ void midi_buffer_task(uint8_t buffer) break; case 0xF7: /* System Exclusive End of SysEx (EOX) */ if (midimachine.bus == CLAIMED && midimachine.type == SYSEX) { - dtype = asid; /* Set data type to ASID */ + dtype = sysex; /* Set data type to ASID */ midimachine.streambuffer[midimachine.index] = buffer; midimachine.index++; process_sysex(midimachine.streambuffer, midimachine.index); @@ -973,7 +211,7 @@ void midi_buffer_task(uint8_t buffer) case 0xC0 ... 0xCF: /* Channel 0~16 Program (Patch) change */ case 0xD0 ... 0xDF: /* Channel 0~16 Pressure (After-touch) */ dtype = midi; /* Set data type to midi */ - midi_bytes = 2; + midimachine.midi_bytes = 2; if (midimachine.bus != CLAIMED && midimachine.type == NONE) { if (midimachine.index == 0) MIDBG("[M][B%d]$%02x#%03d", midimachine.index, buffer, buffer); midimachine.type = MIDI; @@ -991,7 +229,7 @@ void midi_buffer_task(uint8_t buffer) case 0xB0 ... 0xBF: /* Channel 0~16 Control/Mode Change */ case 0xE0 ... 0xEF: /* Channel 0~16 Pitch Bend Change */ dtype = midi; /* Set data type to midi */ - midi_bytes = 3; + midimachine.midi_bytes = 3; if (midimachine.bus != CLAIMED && midimachine.type == NONE) { if (midimachine.index == 0) MIDBG("[M][B%d]$%02x#%03d", midimachine.index, buffer, buffer); midimachine.type = MIDI; @@ -1013,10 +251,26 @@ void midi_buffer_task(uint8_t buffer) /* Handle midi 2 & 3 byte buffer */ if (midimachine.type == MIDI) { /* if (midimachine.streambuffer[0] >= 0x80 || midimachine.streambuffer[0] <= 0xEF) { */ - if (midimachine.index == midi_bytes) { + if (midimachine.index == midimachine.midi_bytes) { MIDBG("\n"); dtype = midi; /* Set data type to midi */ - process_midi(midimachine.streambuffer, midimachine.index); + + /* Do something fancy now */ + #ifdef ONBOARD_EMULATOR + if (((midimachine.streambuffer[0] & 0xF0) == 0xB0) /* Control mode change */ + && (midimachine.streambuffer[1] >= midi_ccvalues_defaults.CC_CEN) + && (midimachine.streambuffer[1] <= midi_ccvalues_defaults.CC_CRE)) { + handle_emulator_cc(); + } else + if (emulator_running) { /* Cynthcart, yeah baby yeah! */ + handle_emulater_data(); + } else { /* Boring midi ;-) */ + #endif + process_midi(midimachine.streambuffer, midimachine.index); + #ifdef ONBOARD_EMULATOR + } + #endif + midimachine.index = 0; midimachine.state = IDLE; midimachine.bus = FREE; @@ -1037,7 +291,7 @@ void midi_buffer_task(uint8_t buffer) void process_stream(uint8_t *buffer, size_t size) { /* ISSUE: Processing the stream byte by byte makes it more prone to latency */ - int n = 0; + size_t n = 0; while (1) { midi_buffer_task(buffer[n++]); if (n == size) return; diff --git a/src/midi.h b/src/midi.h index c7fde88..891ebad 100644 --- a/src/midi.h +++ b/src/midi.h @@ -44,23 +44,25 @@ #include #include #include -#include /* Pico libs */ #include "pico/stdlib.h" +/* Midi bus states */ typedef enum { CLAIMED, FREE } bus_state; +/* Midi sysex state */ typedef enum { IDLE, RECEIVING, WAITING_FOR_END } sysex_state; +/* Midi receiving type */ typedef enum { NONE, MIDI, @@ -68,121 +70,28 @@ typedef enum { ASID } midi_type; -extern int midi_bytes; - +/* Base midi communication struct */ typedef struct { /* comms */ bus_state bus; sysex_state state; midi_type type; - uint8_t index; - uint8_t usbstreambuffer[64]; /* Normal speed max buffer for TinyUSB */ - uint8_t streambuffer[64]; /* Normal speed max buffer for TinyUSB */ - uint8_t channel_states[16][4][32]; /* Stores channel states of each SID ~ 4 sids max */ - uint8_t channelkey_states[16][4][4]; /* Stores channelkey states of each SID ~ 4 sids max */ - uint8_t channelkey_notestates[16][4][128]; /* Stores channelkey states of each SID ~ 4 sids max */ - uint8_t channelbank[16]; /* [Channel][Bank(0)] relation */ - uint8_t channelprogram[16]; /* [Channel][Patch/Program(1)] relation */ - bool bank1channelgate[16]; /* Auto gate on/off per channel on noteon and noteoff */ - uint8_t sidaddress; int fmopl; - + int midi_bytes; + uint8_t index; + uint8_t usbstreambuffer[64]; /* Normal speed max buffer size for TinyUSB */ + uint8_t streambuffer[64]; /* Normal speed max buffer size for TinyUSB */ } midi_machine; +/* Is init in usbsid.c */ extern midi_machine midimachine; -extern int curr_midi_channel; - -enum { - N_KEYS = 0, /* n keys pressed */ - V1_ACTIVE = 1, - V2_ACTIVE = 2, - V3_ACTIVE = 3, -}; - -/* Processes the received Midi stream */ -// void process_stream(uint8_t* buffer); // 20240723 ~ disabled, unused - -/* Custom values from CMakeLists import */ -// TODO: Create import file to use - -#ifndef CC_VALUES /* Customizable CC Bytes */ -#define CC_VALUES /* Fallback for backwards compatibility */ - -/* Default Control Change Byte values */ -#ifndef CC_PWM -#define CC_PWM 0x01 /* 1 ~ Pulse Width Modulation (Modulation wheel) */ -#endif /* CC_PWM */ -#ifndef CC_NOTE -#define CC_NOTE 0x14 /* 20 ~ Note frequency */ -#endif /* CC_NOTE */ -#ifndef CC_NOIS -#define CC_NOIS 0x15 /* 21 ~ Noise waveform */ -#endif /* CC_NOIS */ -#ifndef CC_PULS -#define CC_PULS 0x16 /* 22 ~ Pulse waveform */ -#endif /* CC_PULS */ -#ifndef CC_SAWT -#define CC_SAWT 0x17 /* 23 ~ Sawtooth waveform */ -#endif /* CC_SAWT */ -#ifndef CC_TRIA -#define CC_TRIA 0x18 /* 24 ~ Triangle waveform */ -#endif /* CC_TRIA */ -#ifndef CC_TEST -#define CC_TEST 0x19 /* 25 ~ Test bit */ -#endif /* CC_TEST */ -#ifndef CC_RMOD -#define CC_RMOD 0x1A /* 26 ~ Ring modulator bit */ -#endif /* CC_RMOD */ -#ifndef CC_SYNC -#define CC_SYNC 0x1B /* 27 ~ Sync bit */ -#endif /* CC_SYNC */ -#ifndef CC_GATE -#define CC_GATE 0x1C /* 28 ~ Gate bit */ -#endif /* CC_GATE */ -#ifndef CC_GTEN -#define CC_GTEN 0x1D /* 29 ~ Gate auto enabled on noteon note off */ -#endif /* CC_GTEN */ -#ifndef CC_FFC -#define CC_FFC 0x6E /* 110 ~ Filter Frequency Cutoff */ -#endif /* CC_FFC */ -#ifndef CC_RES -#define CC_RES 0x6F /* 111 ~ Filter resonance */ -#endif /* CC_RES */ -#ifndef CC_3OFF -#define CC_3OFF 0x70 /* 112 ~ Voice 3 disconnect */ -#endif /* CC_3OFF */ -#ifndef CC_FLT1 -#define CC_FLT1 0x71 /* 113 ~ Filter channel 1 */ -#endif /* CC_FLT1 */ -#ifndef CC_FLT2 -#define CC_FLT2 0x72 /* 114 ~ Filter channel 2 */ -#endif /* CC_FLT2 */ -#ifndef CC_FLT3 -#define CC_FLT3 0x73 /* 115 ~ Filter channel 3 */ -#endif /* CC_FLT3 */ -#ifndef CC_FLTE -#define CC_FLTE 0x74 /* 116 ~ Filter external */ -#endif /* CC_FLTE */ -#ifndef CC_HPF -#define CC_HPF 0x75 /* 117 ~ High pass */ -#endif /* CC_HPF */ -#ifndef CC_BPF -#define CC_BPF 0x76 /* 118 ~ Band pass */ -#endif /* CC_BPF */ -#ifndef CC_LPF -#define CC_LPF 0x77 /* 119 ~ Low pass */ -#endif /* CC_LPF */ - -#endif /* CC_VALUES */ - -/* Fixed CC Bytes */ -#define CC_BMSB 0x00 /* 0 ~ Bank Select MSB */ -#define CC_BLSB 0x20 /* 32 ~ Bank Select LSB */ -#define CC_VOL 0x07 /* 7 ~ Set Master Volume */ -#define CC_ATT 0x49 /* 73 ~ Attack */ -#define CC_DEL 0x4B /* 75 ~ Decay */ -#define CC_SUS 0x40 /* 64 ~ Sustain */ -#define CC_REL 0x48 /* 72 ~ Release */ + +/* Cynthcart~Emudore queue */ +typedef struct { + uint8_t data; +} cynthcart_queue_entry_t; + + #ifdef __cplusplus } diff --git a/src/midi_ccdefaults.h b/src/midi_ccdefaults.h new file mode 100644 index 0000000..206eed9 --- /dev/null +++ b/src/midi_ccdefaults.h @@ -0,0 +1,133 @@ +/* + * USBSID-Pico is a RPi Pico/PicoW (RP2040) & Pico2/Pico2W (RP2350) based board + * for interfacing one or two MOS SID chips and/or hardware SID emulators over + * (WEB)USB with your computer, phone or ASID supporting player + * + * midi_ccdefaults.h + * This file is part of USBSID-Pico (https://github.com/LouDnl/USBSID-Pico) + * File author: LouD + * + * Any licensing conditions from either of the above named sources automatically + * apply to this code + * + * Copyright (c) 2024-2025 LouD + * + * 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, version 2. + * + * 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 . + * + */ + +#ifndef _USBSID_MIDI_CCDEFAULTS_H_ +#define _USBSID_MIDI_CCDEFAULTS_H_ +#pragma once + +#ifdef __cplusplus + extern "C" { +#endif + + +typedef struct midi_ccvalues { + /* Modifyable values ~ Voice related */ + uint8_t CC_NOTE; /* Note frequency */ + uint8_t CC_PWM; /* Pulse Width Modulation (Modulation wheel) */ + uint8_t CC_NOIS; /* Noise waveform */ + uint8_t CC_PULS; /* Pulse waveform */ + uint8_t CC_SAWT; /* Sawtooth waveform */ + uint8_t CC_TRIA; /* Triangle waveform */ + uint8_t CC_TEST; /* Test bit */ + uint8_t CC_RMOD; /* Ring modulator bit */ + uint8_t CC_SYNC; /* Sync bit */ + uint8_t CC_GATE; /* Gate bit */ + uint8_t CC_GTEN; /* Gate auto enabled on noteon note off */ + /* Modifyable values ~ Chip related */ + uint8_t CC_FFC; /* Filter Frequency Cutoff */ + uint8_t CC_RES; /* Filter resonance */ + uint8_t CC_3OFF; /* Voice 3 disconnect */ + uint8_t CC_FLT1; /* Filter voice 1 */ + uint8_t CC_FLT2; /* Filter voice 2 */ + uint8_t CC_FLT3; /* Filter voice 3 */ + uint8_t CC_FLTE; /* Filter external */ + uint8_t CC_HPF; /* High pass */ + uint8_t CC_BPF; /* Band pass */ + uint8_t CC_LPF; /* Low pass */ + /* Fixed values ~ Midi related */ + uint8_t CC_BMSB; /* Bank Select MSB */ + uint8_t CC_BLSB; /* Bank Select LSB */ + uint8_t CC_MOD; /* Modulation wheel */ + uint8_t CC_MODL; /* Modulation wheel LSB */ + uint8_t CC_AOFF; /* All notes off */ + /* Fixed values ~ Chip related */ + uint8_t CC_VOL; /* Channel Volume */ + /* Fixed values ~ Voice related */ + uint8_t CC_ATT; /* Attack */ + uint8_t CC_DEL; /* Decay */ + uint8_t CC_SUS; /* Sustain */ + uint8_t CC_REL; /* Release */ + /* Fixed undefined CC values ~ Cynthcart related */ + uint8_t CC_CEN; /* Enable Cynthcart */ + uint8_t CC_CDI; /* Disable Cynthcart */ + uint8_t CC_CRE; /* Restart Cynthcart */ +} midi_ccvalues; + +/* Default Control Change Byte values */ +#define MIDI_DEFAULT_CCVALUES_INIT { \ + /* Modifyable values ~ Voice related */ \ + .CC_NOTE = 0x14, /* 20 ~ Note frequency */ \ + .CC_PWM = 0x15, /* 21 ~ Pulse Width Modulation (Modulation wheel) */ \ + .CC_NOIS = 0x16, /* 22 ~ Noise waveform */ \ + .CC_PULS = 0x17, /* 23 ~ Pulse waveform */ \ + .CC_SAWT = 0x18, /* 24 ~ Sawtooth waveform */ \ + .CC_TRIA = 0x19, /* 25 ~ Triangle waveform */ \ + .CC_TEST = 0x1A, /* 26 ~ Test bit */ \ + .CC_RMOD = 0x1B, /* 27 ~ Ring modulator bit */ \ + .CC_SYNC = 0x1C, /* 28 ~ Sync bit */ \ + .CC_GATE = 0x1D, /* 29 ~ Gate bit */ \ + .CC_GTEN = 0x1E, /* 30 ~ Gate auto enabled on noteon note off */ \ + /* Modifyable values ~ Chip related */ \ + .CC_FFC = 0x6E, /* 110 ~ Filter Frequency Cutoff */ \ + .CC_RES = 0x6F, /* 111 ~ Filter resonance */ \ + .CC_3OFF = 0x70, /* 112 ~ Voice 3 disconnect */ \ + .CC_FLT1 = 0x71, /* 113 ~ Filter voice 1 */ \ + .CC_FLT2 = 0x72, /* 114 ~ Filter voice 2 */ \ + .CC_FLT3 = 0x73, /* 115 ~ Filter voice 3 */ \ + .CC_FLTE = 0x74, /* 116 ~ Filter external */ \ + .CC_HPF = 0x75, /* 117 ~ High pass */ \ + .CC_BPF = 0x76, /* 118 ~ Band pass */ \ + .CC_LPF = 0x77, /* 119 ~ Low pass */ \ + /* Fixed values ~ Midi related */ \ + .CC_BMSB = 0x00, /* 0 ~ Bank Select MSB */ \ + .CC_BLSB = 0x20, /* 32 ~ Bank Select LSB */ \ + .CC_MOD = 0x01, /* 1 ~ Modulation wheel */ \ + .CC_MODL = 0x21, /* 33 ~ Modulation wheel LSB */ \ + .CC_AOFF = 0x78, /* 123 ~ All notes off */ \ + /* Fixed values ~ Chip related */ \ + .CC_VOL = 0x07, /* 7 ~ Channel Volume */ \ + /* Fixed values ~ Voice related */ \ + .CC_ATT = 0x49, /* 73 ~ Attack */ \ + .CC_DEL = 0x4B, /* 75 ~ Decay */ \ + .CC_SUS = 0x40, /* 64 ~ Sustain */ \ + .CC_REL = 0x48, /* 72 ~ Release */ \ + /* Fixed (undefined) CC values ~ Cynthcart related */ \ + .CC_CEN = 0x55, /* 85 ~ Enable Cynthcart */ \ + .CC_CDI = 0x56, /* 86 ~ Disable Cynthcart */ \ + .CC_CRE = 0x57, /* 87 ~ Reset Cynthcart */ \ +} \ + +/* static const midi_ccvalues midi_ccvalues_defaults = MIDI_DEFAULT_CCVALUES_INIT; */ +/* const midi_ccvalues midi_ccvalues_defaults = MIDI_DEFAULT_CCVALUES_INIT; */ + + +#ifdef __cplusplus + } +#endif + +#endif /* _USBSID_MIDI_CCDEFAULTS_H_ */ diff --git a/src/midi_defaults.h b/src/midi_defaults.h new file mode 100644 index 0000000..bb86fc2 --- /dev/null +++ b/src/midi_defaults.h @@ -0,0 +1,139 @@ +/* + * USBSID-Pico is a RPi Pico/PicoW (RP2040) & Pico2/Pico2W (RP2350) based board + * for interfacing one or two MOS SID chips and/or hardware SID emulators over + * (WEB)USB with your computer, phone or ASID supporting player + * + * midi_defaults.h + * This file is part of USBSID-Pico (https://github.com/LouDnl/USBSID-Pico) + * File author: LouD + * + * Any licensing conditions from either of the above named sources automatically + * apply to this code + * + * Copyright (c) 2024-2025 LouD + * + * 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, version 2. + * + * 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 . + * + */ + +#ifndef _USBSID_MIDI_DEFAULTS_H_ +#define _USBSID_MIDI_DEFAULTS_H_ +#pragma once + +#include "sid.h" + +#ifdef __cplusplus + extern "C" { +#endif + + +#define NOTEHI(n) ((musical_scale_values[(n - ((n >= 0x81) ? 0x80 : 0))] & 0xFF00) >> 8) +#define NOTELO(n) (musical_scale_values[(n - ((n >= 0x81) ? 0x80 : 0))] & 0xFF) + +#define INSTRUMENT_TYPE "Goattracker2" +#define MAX_TABLE_ENTRIES 16 /* TODO: DECIDE ON MAX VALUE */ +#define NOISE 0b10000000 +#define PULSEWAVE 0b01000000 +#define SAWTOOTH 0b00100000 +#define TRIANGLE 0b00010000 +#define GATE_ON(w) ((w) | (0b1)) +#define GATE_OFF(w) ((w) ^ (0b1)) + + +struct WaveTable_s { + /* 0b0000xxxx Left nibble: noise, pulsewave, sawtooth, triangle */ + /* 0bxxxx0000 Right nibble: test, ringmod, sync, gate */ + uint8_t reg; + /* 0x00 -> 0x80 = note addition */ + /* 0x81 -> 0xE0 = fixed notes from notetable */ + uint8_t pitch_offset; + /* Last entry, end */ + bool end : 1; + /* Jump to entry in pitch_offset */ + bool jump : 1; +} WaveTable_d = {0} ; +struct PulseTable_s { + uint8_t pw_lo; /* 0b11111111 */ + uint8_t pw_hi; /* 0bxxxx1111 */ + uint8_t time; /* TODO */ + uint8_t speed; /* TODO */ + bool pw_ts : 1; /* false pwm, true time speed */ + /* Last entry, end */ + bool end : 1; + /* Jump to entry */ + bool jump : 1; +} PulseTable_d = {0}; +struct FilterTable_s { + uint8_t cutoff_lo; /* 0bxxxxx111 */ + uint8_t cutoff_hi; /* 0b11111111 */ + /* */ + uint8_t resonance; /* 0b1111xxxx */ + uint8_t voices; /* 0bxxxxx321 */ + uint8_t filter; /* 0bx111xxxx */ + /* Last entry, end */ + bool end : 1; + /* Jump to entry */ + bool jump : 1; +} FilterTable_d = {0}; +struct SpeedTable_s { /* Vibrato */ + uint8_t speed; + uint8_t width; + uint8_t delay; +} SpeedTable_d = {0}; + +typedef struct WaveTable_s WaveTable; +typedef struct PulseTable_s PulseTable; +typedef struct FilterTable_s FilterTable; +typedef struct SpeedTable_s SpeedTable; + +struct Instrument_s { + uint8_t attack; + uint8_t decay; + uint8_t sustain; + uint8_t release; + WaveTable wt[MAX_TABLE_ENTRIES]; + PulseTable pt[MAX_TABLE_ENTRIES]; + FilterTable ft[MAX_TABLE_ENTRIES]; + SpeedTable speedtable; + bool has_wt : 1; + bool has_pt : 1; + bool has_ft : 1; + bool has_st : 1; + bool polyphonic : 1; +} Instrument_d = {0}; +typedef struct Instrument_s Instrument; + +struct Bank_s { + Instrument ins[MAX_TABLE_ENTRIES]; +} Bank_d = {0}; +typedef struct Bank_s Bank; + +/* Stores the current Runtime values */ +typedef struct Channel { + // Instrument * instr; + uint8_t bankno; + uint8_t insno; + /* Any other settings */ +} Channel; +typedef struct RuntimeMidi { + Channel channel[MAX_TABLE_ENTRIES]; /* Current channel */ +} RuntimeMidi; + +Bank banks[MAX_TABLE_ENTRIES]; /* No of banks */ + + +#ifdef __cplusplus + } +#endif + +#endif /* _USBSID_MIDI_DEFAULTS_H_ */ diff --git a/src/midi_handler.c b/src/midi_handler.c new file mode 100644 index 0000000..59c1144 --- /dev/null +++ b/src/midi_handler.c @@ -0,0 +1,191 @@ +/* + * USBSID-Pico is a RPi Pico/PicoW (RP2040) & Pico2/Pico2W (RP2350) based board + * for interfacing one or two MOS SID chips and/or hardware SID emulators over + * (WEB)USB with your computer, phone or ASID supporting player + * + * midi_handler.c + * This file is part of USBSID-Pico (https://github.com/LouDnl/USBSID-Pico) + * File author: LouD + * + * The contents of this file are based upon and heavily inspired by the sourcecode from + * TherapSID by Twisted Electrons: https://github.com/twistedelectrons/TherapSID + * TeensyROM by Sensorium Embedded: https://github.com/SensoriumEmbedded/TeensyROM + * SID Factory II by Chordian: https://github.com/Chordian/sidfactory2 + * + * Any licensing conditions from either of the above named sources automatically + * apply to this code + * + * Copyright (c) 2024-2025 LouD + * + * 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, version 2. + * + * 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 . + * + */ + + +#include "pico/multicore.h" +#include "pico/util/queue.h" + +#include + +#include "globals.h" +#include "config.h" +#include "logging.h" +#include "sid.h" +#include "midi.h" +#include "midi_defaults.h" +#include "midi_ccdefaults.h" +#include "midi_patches.h" + + +/* Config */ +extern RuntimeCFG cfg; + +/* GPIO */ +extern uint8_t __no_inline_not_in_flash_func(bus_operation)(uint8_t command, uint8_t address, uint8_t data); +extern uint8_t __no_inline_not_in_flash_func(cycled_write_operation)(uint8_t address, uint8_t data, uint16_t cycles); +extern uint16_t __no_inline_not_in_flash_func(cycled_delay_operation)(uint16_t cycles); + +/* Initialize variables */ +extern const midi_ccvalues midi_ccvalues_defaults; /* midi.c */ +midi_ccvalues CC; +RuntimeMidi RM; + +Bank * bank; +Instrument * instr; /* Points to current channel instrument pointer */ +Channel * channel; +uint8_t channo, insno; /* channel and instrument/program */ +uint16_t bankno; /* msb 7F | lsb 7F */ + + +static void select_program(uint8_t p) +{ + insno = p; + channel->insno = insno; + instr = &bank->ins[channel->insno]; + return; +} + +static void select_bank(uint8_t m, uint8_t l) +{ + bankno = (m << 8 | l); + channel->bankno = bankno; + bank = &banks[channel->bankno]; + return; +} + +static void select_channel(uint8_t c) +{ + channo = c; + channel = &RM.channel[channo]; + return; +} + +void midi_programs_init(void) +{ + bankno = channo = insno = 0; + default_banks(); + + RM.channel[channo].bankno = bankno; + RM.channel[channo].insno = insno; + + bank = &banks[RM.channel[channo].bankno]; /* Starting bank */ + instr = &bank->ins[RM.channel[channo].insno]; +} + +void midi_processor_init(void) +{ + CFG("[START MIDI HANLDER INIT]\n"); + + /* NOTE: Temporary - always init defaults */ + memcpy(&CC, &midi_ccvalues_defaults, sizeof(midi_ccvalues)); + + midi_programs_init(); + + CFG("[END MIDI HANLDER INIT]\n"); + +} + +/* Helper functions */ + +void midi_bus_operation(uint8_t a, uint8_t b) +{ + cycled_write_operation(a, b, 6); /* 6 cycles constant for LDA 2 and STA 4 */ + return; +} + +void process_midi(uint8_t *buffer, int size) +{ + /* TODO: is still fixed to single channel */ + /* TODO: is still fixed to single instrument(program) */ + /* TODO: add non fixed intrument bank */ + /* TODO: ignoring PulseTable jump and pw_ts */ + /* TODO: ignoring FilterTable + filters */ + /* TODO: ignoring SpeedTable */ + /* TODO: Add piano like instrument */ + /* TODO: Add polyphonic instrument */ + static int keys_pressed; + int voices = (cfg.numsids * 3); + uint8_t voice_address = 0x0, base_address = 0x0; + if ((buffer[0] & 0xF0) == 0x90) { + keys_pressed++; + // base_address = ((keys_pressed % 3 == 0) ? (base_address + ( - 1)))op + /* uint8_t voice_address = ((keys_pressed - 1) * 0x20); */ + uint8_t voice_address = ((keys_pressed - 1) * 0x7); /* TODO: MOVE TO NEXT SID */ + int writes = 0; + midi_bus_operation((base_address | MODVOL), 0xE); /* TODO: TEMPORARY VOLUME :) */ + writes++; + midi_bus_operation((voice_address + 0x05), ((instr->attack << 4) | instr->decay)); + writes++; + midi_bus_operation((voice_address + 0x06), ((instr->sustain << 4) | instr->release)); + writes++; + bool pulsetable = true, wavetable = true; + int i = 0; +AGAIN: + if (instr->has_pt && pulsetable) { + midi_bus_operation((voice_address + 0x02), (instr->pt[i].pw_hi & 0xF)); + writes++; + midi_bus_operation((voice_address + 0x03), instr->pt[i].pw_lo); + writes++; + } + if (instr->has_wt && wavetable) { + /* ASSUMING THIS IS AN ABSOLUTE NOTE VALUE!! PITCH_OFFSET => 0x81 */ + if (instr->wt[i].pitch_offset > 0x80) { /* Absolute note values */ + midi_bus_operation((voice_address + 0x00), NOTEHI(instr->wt[i].pitch_offset)); + writes++; + midi_bus_operation((voice_address + 0x01), NOTELO(instr->wt[i].pitch_offset)); + writes++; + } else { /* Additions to input note */ + /* uint8_t note_index = buffer[1]; */ + uint16_t frequency = musical_scale_values[buffer[1]]; + midi_bus_operation((voice_address + 0x00), (NOTEHI(frequency) + NOTEHI(instr->wt[i].pitch_offset))); + writes++; + midi_bus_operation((voice_address + 0x01), (NOTELO(frequency) + NOTELO(instr->wt[i].pitch_offset))); + writes++; + } + midi_bus_operation((voice_address + 0x04), instr->wt[i].reg); + writes++; + } + if (instr->pt[i].end == true) pulsetable = false; + if (instr->wt[i].end == true) wavetable = false; + // DBG("%d:%d%d%d%d\n", i, pulsetable, instr->pt[i].end, wavetable, instr->wt[i].end); + i++; + if (pulsetable || wavetable) { + cycled_delay_operation((uint16_t)(R_PAL - (writes * 6))); /* One table entry each per frame ;) */ + writes = 0; + goto AGAIN; + } + } + if (((buffer[0] & 0xF0) == 0x80) && (keys_pressed > 0)) keys_pressed--; + // DBG("[K]%d\n", keys_pressed); + return; +} diff --git a/src/midi_patch_cynthcart.h b/src/midi_patch_cynthcart.h deleted file mode 100644 index 3b9460a..0000000 --- a/src/midi_patch_cynthcart.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * USBSID-Pico is a RPi Pico/PicoW (RP2040) & Pico2/Pico2W (RP2350) based board - * for interfacing one or two MOS SID chips and/or hardware SID emulators over - * (WEB)USB with your computer, phone or ASID supporting player - * - * midipatches.h - * This file is part of USBSID-Pico (https://github.com/LouDnl/USBSID-Pico) - * File author: LouD - * - * The contents of this file are based upon and heavily inspired by the sourcecode from - * Cynthcart by PaulSlocum: https://github.com/PaulSlocum/cynthcart - * - * Any licensing conditions from either of the above named sources automatically - * apply to this code - * - * Copyright (c) 2024-2025 LouD - * - * 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, version 2. - * - * 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 . - * - */ - -/* Bank 9 */ -/* Hard coded patches */ -// static char patchNAMES[30][20] = { -// "SAWTOOTH BASS", // 0 -// "GRITTY BASS", // 1 -// "PORTAMENTO 5THS", // 2 -// "SAW PORTAMENTO", // 3 -// "PULSE 5THS", // 4 -// "PULSE HIGH PORT", // 5 -// "TRINGL HIGH LONG", // 6 -// "TRIANGLE DROP", // 7 -// "SID EXPLOSION", // 8 -// "MUTE", // 9 -// "FILTER BASS", // 10 -// "SWEEP ARP", // 11 -// "PLUCK ARP", // 12 -// "SLOW ARP", // 13 -// "FILTER STACK 1", // 14 -// "FILTER STACK 2", // 15 -// "PULSAR", // 16 -// "VIBRATO LEAD", // 17 -// "SLOW RISE", // 18 -// "BENDING ECHO", // 19 -// "6 CHANNEL SAW", // 20 -// "ARP LEAD", // 21 -// "LASER BASS", // 22 -// "TROMBONE BLAST", // 23 -// "NOISY SQUARE ARP", // 24 -// "TRIANGLE SYNC", // 25 -// "MONO SYNC ECHO", // 26 -// "CLEAN SAWTOOTH", // 27 -// "CLEAN TRIANGLE", // 28 -// "CLEAN SQUARE", // 29 -// }; -// static uint8_t patchFX[30] = { /* ?? */ -// 0, 5, 0, 0, 7, 6, 1, 3, 2, 0, -// 3, 1, 3, 0, 2, 3, 4, 1, 1, 2, -// 0, 3, 1, 3, 3, 0, 3, 0, 0, 0, -// }; -// static uint8_t patchLFO[30] = { /* ?? */ // (TREMOLO) -// 0x11, 0x02, 0x02, 0x13, 0x13, 0x00, 0x01, 0x02, 0x13, 0x00, -// 0x00, 0x22, 0x13, 0x11, 0x10, 0x02, 0x00, 0x33, 0x10, 0x11, -// 0x10, 0x12, 0x13, 0x00, 0x00, 0x13, 0x13, 0x00, 0x00, 0x00, -// }; -// static uint8_t patchOctave[30] = { /* Starting octave */ -// 0, 0, 1, 1, 1, 2, 3, 3, 0, 0, -// 1, 2, 3, 1, 1, 2, 3, 3, 1, 3, -// 1, 3, 0, 3, 3, 1, 1, 1, 3, 1, -// }; -static uint8_t patchAD[30] = { /* 0x05, 0x0C, 0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xA0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; -static uint8_t patchSR1[30] = { /* 0x06 */ - 0xF0, 0xF5, 0xF0, 0xF0, 0xF8, 0xF0, 0xFE, 0xF6, 0xF0, 0, - 0xF0, 0xFA, 0xF6, 0xF6, 0xFA, 0xF9, 0xFE, 0xF7, 0xFF, 0xEE, - 0xF0, 0xF5, 0xF5, 0x86, 0xF6, 0xF2, 0xF8, 0xF2, 0xF2, 0xF0, -}; -static uint8_t patchSR2[30] = { /* 0x0D */ - 0xF0, 0xF5, 0xF0, 0xF0, 0xF8, 0xF0, 0xFE, 0xF6, 0xF0, 0, - 0xF0, 0xFA, 0xF6, 0xF6, 0xFA, 0xF9, 0xFE, 0xF7, 0xFF, 0xEE, - 0xF0, 0xF5, 0xF5, 0xF6, 0x54, 0xF2, 0xF8, 0xF2, 0xF2, 0xF0, -}; -static uint8_t patchSR3[30] = { /* 0x14 */ - 0xF0, 0xF5, 0xF0, 0xF0, 0xF8, 0xF0, 0xFE, 0xF6, 0xF0, 0, - 0xF0, 0xFA, 0xF6, 0xF6, 0xFA, 0xF9, 0xFE, 0xF7, 0xFF, 0xEE, - 0xF0, 0xF5, 0xF5, 0xF6, 0xF6, 0xF2, 0xF8, 0xF2, 0xF2, 0xF0, -}; -// static uint8_t patchPaddle[30] = { /* 0x15 FC HI ~ Paddle input */ -// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -// }; -static uint8_t newPatchFiltCut[30] = { /* 0x16 FC LO cut off */ - 0xB0, 0x90, 0xC0, 0xFF, 0x40, 0x50, 0xC0, 0x70, 0x80, 0, - 0x80, 0xA0, 0xC0, 0xFF, 0xA0, 0x80, 0xC0, 0xC0, 0x80, 0x80, - 0xC0, 0xF0, 0xC0, 0xb0, 0xA0, 0x50, 0x50, 0xC0, 0xC0, 0x80, -}; -static uint8_t patchVol[30] = { /* 0x18 Volume */ - 0xf, 0xF, 0xb, 0x9, 0x9, 0x7, 0xF, 0xC, 0xc, 0, - 0xf, 0xc, 0xF, 0xb, 0x9, 0x7, 0xF, 0xc, 0xF, 0x8, - 0xf, 0xC, 0xb, 0x9, 0xF, 0xF, 0xC, 0xF, 0xF, 0xc, -}; -static uint8_t patchPWL[30] = { /* 0x02, 0x09, 0x10 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; -static uint8_t patchPWH[30] = { /* 0x03, 0x0A, 0x11 */ - 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, -}; -static uint8_t patchWave1[30] = { /* 0x04 Wave type */ - 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x10, 0x10, 0x80, 0, - 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x10, 0x20, 0x20, 0x40, - 0x20, 0x20, 0x14, 0x80, 0x40, 0x12, 0x14, 0x20, 0x10, 0x40, -}; -static uint8_t patchWave2[30] = { /* 0x0B Wave type */ - 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x10, 0x10, 0x80, 0, - 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x10, 0x20, 0x20, 0x40, - 0x20, 0x20, 0x14, 0x20, 0x80, 0x12, 0x14, 0x20, 0x10, 0x40, -}; -static uint8_t patchWave3[30] = { /* 0x12 Wave type*/ - 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x10, 0x10, 0x80, 0, - 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x10, 0x20, 0x20, 0x40, - 0x20, 0x20, 0x14, 0x10, 0x10, 0x12, 0x14, 0x20, 0x10, 0x40, -}; -static uint8_t patchFilt[30] = { /* 0x17 Res/Filt */ - 0xEF, 0xEF, 0x0F, 0x0F, 0xEF, 0xEF, 0x0F, 0x0F, 0xEF, 0xEF, - 0xEF, 0xEF, 0x0F, 0x0F, 0xEF, 0xEF, 0x0F, 0x0F, 0xEF, 0xEF, - 0xEF, 0xEF, 0x0F, 0x0F, 0xEF, 0xEF, 0xEF, 0x0F, 0x0F, 0xEF, -}; -static uint8_t patchVolMode[30] = { /* 0x18 Mode */ - 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x10, 0x10, -}; -// static uint8_t octaveTable[5] = { /* ?? */ -// 0,12,24,36,48 -// }; -// static uint8_t pwLFO[16] = { -// 0b00010000, 0b00110000, 0b01010000, 0b01110000, -// 0b10010000, 0b10110000, 0b11010000, 0b11110000, -// 0b11110000, 0b11010000, 0b10110000, 0b10010000, -// 0b01110000, 0b01010000, 0b00110000, 0b00010000, -// }; -// static uint8_t patOffset[6] = { -// 0,40,80,120,160,200 -// }; -// static uint8_t voiceOffset[3] = { -// 0x0,0x7,0xE -// }; diff --git a/src/midi_patches.h b/src/midi_patches.h new file mode 100644 index 0000000..b3898b2 --- /dev/null +++ b/src/midi_patches.h @@ -0,0 +1,84 @@ + +/* + * USBSID-Pico is a RPi Pico/PicoW (RP2040) & Pico2/Pico2W (RP2350) based board interfacing one or two + * MOS SID chips and/or hardware SID emulators over (WEB)USB with your computer, + * phone or ASID supporting player + * + * midi_patches.h + * This file is part of USBSID-Pico (https://github.com/LouDnl/USBSID-Pico) + * File author: LouD + * + * Copyright (c) 2024-2025 LouD + * + * 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, version 2. + * + * 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 . + * + */ + +#ifndef _USBSID_MIDI_PATCHES_H_ +#define _USBSID_MIDI_PATCHES_H_ +#pragma once + +#include "midi_defaults.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/* TODO: + * - Add bank / patch switching + * - Move fixed instruments to bank 1 + * - Add custom value insturments to bank 0 + */ + +/* Bank 0 ~ Patch 0 */ +Instrument snare = { + .attack = 0x0, + .decay = 0x0, + .sustain = 0xF, + .release = 0x9, + .has_pt = true, + .has_wt = true, + .wt[0].reg = GATE_ON(NOISE), + .wt[0].pitch_offset = 0xC8, + .wt[1].reg = GATE_ON(PULSEWAVE), + .wt[1].pitch_offset = 0xAC, + .wt[2].reg = GATE_ON(PULSEWAVE), + .wt[2].pitch_offset = 0xA4, + .wt[3].reg = NOISE, + .wt[3].pitch_offset = 0xC4, + .wt[4].reg = NOISE, + .wt[4].pitch_offset = 0xC0, + .wt[4].end = true, + .pt[0].pw_ts = false, + .pt[0].pw_lo = 0x0, + .pt[0].pw_hi = 0x80, + .pt[0].end = true, +}; + + +/* Bank 0 */ +static void default_patches(void) +{ + banks[0].ins[0] = snare; +} + +void default_banks(void) +{ + default_patches(); /* Bank 0 */ +} + +#ifdef __cplusplus + } +#endif + +#endif /* _USBSID_MIDI_PATCHES_H_ */ diff --git a/src/pio/bus_control.pio b/src/pio/bus_control.pio index 1ca4ccb..e1d28b8 100644 --- a/src/pio/bus_control.pio +++ b/src/pio/bus_control.pio @@ -109,6 +109,7 @@ delay: .wrap ; Buffer raster cycle counter program ~ PIO1 SM0 +; If used, triggers an IRQ after each n raster cycles provided .program raster_buffer .wrap_target pull noblock ; Pull data from FIFO, if empty re-use previous data stored in X diff --git a/src/pio/uart_rx.pio b/src/pio/uart_rx.pio new file mode 100644 index 0000000..0e2c314 --- /dev/null +++ b/src/pio/uart_rx.pio @@ -0,0 +1,48 @@ +; +; USBSID-Pico is a RPi Pico/PicoW (RP2040) & Pico2/Pico2W (RP2350) based board +; for interfacing one or two MOS SID chips and/or hardware SID emulators over +; (WEB)USB with your computer, phone or ASID supporting player +; +; uart_rx.pio +; This file is part of USBSID-Pico (https://github.com/LouDnl/USBSID-Pico) +; File author: LouD +; +; The contents of this file are based upon and heavily inspired by the sourcecode +; from the original file: pico-examples/pio/uart_rx/uart_rx.pio +; Licensing conditions from the above named source automatically apply to this +; Copyright (c) 2021 Raspberry Pi (Trading) Ltd. +; SPDX-License-Identifier: BSD-3-Clause +; +; 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, version 2. +; +; 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 . +; + +.program uart_rx + +; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and +; break conditions more gracefully. +; IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX. + +start: + wait 0 pin 0 ; Stall until start bit is asserted + set x, 7 [10] ; Preload bit counter, then delay until halfway through +bitloop: ; the first data bit (12 cycles incl wait, set). + in pins, 1 ; Shift data bit into ISR + jmp x-- bitloop [6] ; Loop 8 times, each loop iteration is 8 cycles + jmp pin good_stop ; Check stop bit (should be high) + + irq 4 rel ; Either a framing error or a break. Set a sticky flag, + wait 1 pin 0 ; and wait for line to return to idle state. + jmp start ; Don't push data if we didn't see good framing. + +good_stop: ; No delay before returning to start; a little slack is + push ; important in case the TX clock is slightly too fast. diff --git a/src/sid_cloneconfig.c b/src/sid_cloneconfig.c index 6a84e57..9582544 100644 --- a/src/sid_cloneconfig.c +++ b/src/sid_cloneconfig.c @@ -82,7 +82,7 @@ void print_fpgasid_sidconfig(int slot, int sidno, uint8_t * configarray) void read_fpgasid_configuration(uint8_t base_address) { - if (((base_address >= 0x0 && base_address < 0x40) && (usbsid_config.socketOne.clonetype != 4)) + if (((/* base_address >= 0x0 && */base_address < 0x40) && (usbsid_config.socketOne.clonetype != 4)) || ((base_address >= 0x40 && base_address < 0x80) && (usbsid_config.socketTwo.clonetype != 4))) { CFG("[SID] ERROR INCORRECT ADDRESS (0x%02x) AND CLONETYPE (%d %d)\n", base_address, usbsid_config.socketOne.clonetype, usbsid_config.socketTwo.clonetype); diff --git a/src/sid_detection.c b/src/sid_detection.c index 07077fe..ed2ef8b 100644 --- a/src/sid_detection.c +++ b/src/sid_detection.c @@ -140,7 +140,7 @@ uint8_t detect_sid_unsafe(uint8_t start_addr) { /* https://codebase64.org/doku.php?id=base:detecting_sid_type */ CFG("[SID] DETECT SID UNSAFE\n"); /* clear sid registers */ - for (int reg = 0; reg < count_of(sid_registers) - 4; reg++) { + for (uint reg = 0; reg < count_of(sid_registers) - 4; reg++) { /* STA $D400,x ~ 5 cycles */ /* DEX ~ 2 cycles*/ /* BPL ~ 2 cycles */ diff --git a/src/tusb_config.h b/src/tusb_config.h index d3a8e2b..bfb47a8 100644 --- a/src/tusb_config.h +++ b/src/tusb_config.h @@ -127,6 +127,7 @@ // Vendor FIFO size of TX and RX // If not configured vendor endpoints will not be buffered +// If configured, make sure to define USE_VENDOR_BUFFER 1 in globals.h #define CFG_TUD_VENDOR_RX_BUFSIZE 0 /* Set to 0 to disable buffering (the fifo is not used) */ #define CFG_TUD_VENDOR_TX_BUFSIZE 0 /* Set to 0 to disable buffering (the fifo is not used) */ diff --git a/src/uart.c b/src/uart.c new file mode 100644 index 0000000..6094d41 --- /dev/null +++ b/src/uart.c @@ -0,0 +1,240 @@ +/* + * USBSID-Pico is a RPi Pico/PicoW (RP2040) & Pico2/Pico2W (RP2350) based board + * for interfacing one or two MOS SID chips and/or hardware SID emulators over + * (WEB)USB with your computer, phone or ASID supporting player + * + * uart.c + * This file is part of USBSID-Pico (https://github.com/LouDnl/USBSID-Pico) + * File author: LouD + * + * The contents of this file are based upon and heavily inspired by the sourcecode + * from the original file: pico-examples/pio/uart_rx/uart_rx.c + * Licensing conditions from the above named source automatically apply to this + * Copyright (c) 2021 Raspberry Pi (Trading) Ltd. + * SPDX-License-Identifier: BSD-3-Clause + * + * 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, version 2. + * + * 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 . + * + */ + +#ifdef USE_PIO_UART + +#include "globals.h" +#include "uart.h" +#include "gpio.h" +#include "logging.h" + + +/* USBSID */ +extern uint8_t __not_in_flash("usbsid_buffer") uart_buffer[64]; + +/* GPIO */ +extern uint16_t __no_inline_not_in_flash_func(cycled_delay_operation)(uint16_t cycles); +extern uint8_t __no_inline_not_in_flash_func(cycled_read_operation)(uint8_t address, uint16_t cycles); +extern void __no_inline_not_in_flash_func(cycled_write_operation)(uint8_t address, uint8_t data, uint16_t cycles); +extern uint16_t __no_inline_not_in_flash_func(cycled_delayed_write_operation)(uint8_t address, uint8_t data, uint16_t cycles); +extern void reset_sid(void); + +/* USBSID */ +extern int usbdata; +extern char ntype, dtype, uart; +extern bool offload_ledrunner; + +/* Locals */ +static PIO uart_pio = pio1; +static uint sm_uartrx; +static int8_t pioirq_uartrx; +static queue_t fifo_uartrx; +static uint offset_uartrx; + +static size_t bytes_per_rxpacket = 8; /* Initial size = init packet */ +static size_t bytes_rxed = 0; /* Counter for incoming bytes */ + +/* Pre declarations */ +static void async_worker_func(async_context_t *async_context, async_when_pending_worker_t *worker); +/* An async context is notified by the irq to "do some work" */ +static async_context_threadsafe_background_t async_context; +static async_when_pending_worker_t worker = { .do_work = async_worker_func }; + + +static inline void uart_rx_program_init(uint pin, uint baud) +{ + pio_sm_set_consecutive_pindirs(uart_pio, sm_uartrx, pin, 1, false); + pio_gpio_init(uart_pio, pin); + gpio_pull_up(pin); + + pio_sm_config uartrx_config = uart_rx_program_get_default_config(offset_uartrx); + sm_config_set_in_pins(&uartrx_config, pin); /* for WAIT, IN */ + sm_config_set_jmp_pin(&uartrx_config, pin); /* for JMP */ + /* Shift to right, autopush disabled */ + sm_config_set_in_shift(&uartrx_config, true, false, 32); + /* Deeper FIFO as we're not doing any TX */ + sm_config_set_fifo_join(&uartrx_config, PIO_FIFO_JOIN_RX); + /* SM transmits 1 bit per 8 execution cycles. */ + float div = (float)clock_get_hz(clk_sys) / (8 * baud); + sm_config_set_clkdiv(&uartrx_config, div); + /* Initialize and enable statemachine */ + pio_sm_init(uart_pio, sm_uartrx, offset_uartrx, &uartrx_config); + pio_sm_set_enabled(uart_pio, sm_uartrx, true); + return; +} + +static inline char uart_rx_program_getc(void) +{ + /* 8-bit read from the uppermost byte of the FIFO, as data is left-justified */ + io_rw_8 *rxfifo_shift = (io_rw_8*)&uart_pio->rxf[sm_uartrx] + 3; + while (pio_sm_is_rx_fifo_empty(uart_pio, sm_uartrx)) + tight_loop_contents(); + return (char)*rxfifo_shift; +} + +static void pio_irq_func(void) +{ + while(!pio_sm_is_rx_fifo_empty(uart_pio, sm_uartrx)) { + char rxdata = uart_rx_program_getc(); + if (!queue_try_add(&fifo_uartrx, &rxdata)) { + panic("fifo_uartrx full"); + } + } + /* Tell the async worker that there are some characters waiting for us */ + async_context_set_work_pending(&async_context.core, &worker); + return; +} + +static void async_worker_func(__unused async_context_t *async_context, __unused async_when_pending_worker_t *worker) +{ /* TODO: Finish */ + usbdata = 1; + dtype = uart; + if (offload_ledrunner == false) bytes_rxed = 0; + offload_ledrunner = true; + while(!queue_is_empty(&fifo_uartrx)) { + if (!queue_try_remove(&fifo_uartrx, &uart_buffer[bytes_rxed])) { + panic("fifo_uartrx empty"); + } else { + // DBG("[%d/%d] %02X $%02X:%02X\n",i,bytes_per_rxpacket,uart_buffer[0],uart_buffer[1],uart_buffer[2]); + if ((uart_buffer[0] == 0xFF && uart_buffer[1] == 0xFF) + || (uart_buffer[1] == 0xFF && uart_buffer[2] == 0xFF) + || (uart_buffer[2] == 0xFF && uart_buffer[3] == 0xFF)) { + DBG("[UART CONFIG] RESET\n"); + memset(uart_buffer, 0, 8); + bytes_per_rxpacket = 8; + bytes_rxed = 0; + usbdata = 0; + dtype = ntype; + offload_ledrunner = false; + /* reset_sid(); */ + return; + } + if ((bytes_per_rxpacket == 2) && (bytes_rxed == (bytes_per_rxpacket - 1))) { + cycled_write_operation(uart_buffer[0], uart_buffer[1], 6); + memset(uart_buffer, 0, 2); + bytes_rxed = 0; + } else if ((bytes_per_rxpacket == 4) && (bytes_rxed == (bytes_per_rxpacket - 1))) { + cycled_write_operation(uart_buffer[0], uart_buffer[1], (uart_buffer[2] << 8 | uart_buffer[3])); + memset(uart_buffer, 0, 4); + bytes_rxed = 0; + } else if ((bytes_per_rxpacket == 8) && (bytes_rxed == (bytes_per_rxpacket - 1))) { + /* ISSUE: At the moment a restart is required to reset back to packet size 8 */ + if (uart_buffer[0] == 0xFF + && uart_buffer[1] == 0xEE + && uart_buffer[2] == 0xDD + && uart_buffer[5] == 0xDD + && uart_buffer[6] == 0xEE + && uart_buffer[7] == 0xFF) { /* Receiving initiator packet */ + bytes_per_rxpacket = (size_t)(uart_buffer[3] << 8 | uart_buffer[4]); + DBG("[UART CONFIG] BYTES PER PACKET SET TO %d\n", bytes_per_rxpacket); + memset(uart_buffer, 0, 8); + bytes_rxed = 0; + } + } else if (bytes_rxed <= (bytes_per_rxpacket - 1)) { + bytes_rxed++; + } + } + } + return; +} + +static void init_async(void) +{ + /* Setup an async context and worker to perform work when needed */ + if (!async_context_threadsafe_background_init_with_defaults(&async_context)) { + panic("failed to setup context"); + } + async_context_add_when_pending_worker(&async_context.core, &worker); + return; +} + +void init_uart(void) +{ + /* create a queue so the irq can save the data somewhere */ + queue_init(&fifo_uartrx, 1, UART_FIFO_SIZE); + + /* Setup an async context and worker to perform work when needed */ + init_async(); + + /* This will find a free pio and state machine for our program and load it for us */ + /* We use pio_claim_free_sm_and_add_program_for_gpio_range (for_gpio_range variant) */ + /* so we will get a PIO instance suitable for addressing gpios >= 32 if needed and supported by the hardware */ + bool success = pio_claim_free_sm_and_add_program_for_gpio_range(&uart_rx_program, &uart_pio, &sm_uartrx, &offset_uartrx, PIOUART_RX, 1, true); + hard_assert(success); + + /* Init uart rx program */ + uart_rx_program_init(PIOUART_RX, FFIN_FAST_BAUD_RATE); + + /* Find a free irq */ + pioirq_uartrx = pio_get_irq_num(uart_pio, 0); + if (irq_get_exclusive_handler(pioirq_uartrx)) { + pioirq_uartrx++; + if (irq_get_exclusive_handler(pioirq_uartrx)) { + panic("All IRQs are in use"); + } + } + + /* Enable interrupt */ + irq_add_shared_handler(pioirq_uartrx, pio_irq_func, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY); /* Add a shared IRQ handler */ + irq_set_enabled(pioirq_uartrx, true); /* Enable the IRQ */ + const uint irq_index = pioirq_uartrx - pio_get_irq_num(uart_pio, 0); /* Get index of the IRQ */ + pio_set_irqn_source_enabled(uart_pio, irq_index, pio_get_rx_fifo_not_empty_interrupt_source(sm_uartrx), true); /* Set uart_pio to tell us when the FIFO is NOT empty */ + + return; +} + +void deinit_uart(void) +{ + // /* Echo characters received from PIO to the console */ + // while (counter < MAX_COUNTER || work_done) { + // // Note that we could just sleep here as we're using "threadsafe_background" that uses a low priority interrupt + // // But if we changed to use a "polling" context that wouldn't work. The following works for both types of context. + // // When using "threadsafe_background" the poll does nothing. This loop is just preventing main from exiting! + // work_done = false; + // async_context_poll(&async_context.core); + // async_context_wait_for_work_ms(&async_context.core, 2000); + // } + + /* Disable interrupt */ + const uint irq_index = pioirq_uartrx - pio_get_irq_num(uart_pio, 0); /* Get index of the IRQ */ + pio_set_irqn_source_enabled(uart_pio, irq_index, pio_get_rx_fifo_not_empty_interrupt_source(sm_uartrx), false); + irq_set_enabled(pioirq_uartrx, false); + irq_remove_handler(pioirq_uartrx, pio_irq_func); + + /* This will free resources and unload our program */ + pio_remove_program_and_unclaim_sm(&uart_rx_program, uart_pio, sm_uartrx, offset_uartrx); + + async_context_remove_when_pending_worker(&async_context.core, &worker); + async_context_deinit(&async_context.core); + queue_free(&fifo_uartrx); + + return; +} + +#endif /* USE_PIO_UART */ diff --git a/src/uart.h b/src/uart.h new file mode 100644 index 0000000..9d71682 --- /dev/null +++ b/src/uart.h @@ -0,0 +1,67 @@ +/* + * USBSID-Pico is a RPi Pico/PicoW (RP2040) & Pico2/Pico2W (RP2350) based board + * for interfacing one or two MOS SID chips and/or hardware SID emulators over + * (WEB)USB with your computer, phone or ASID supporting player + * + * uart.h + * This file is part of USBSID-Pico (https://github.com/LouDnl/USBSID-Pico) + * File author: LouD + * + * Copyright (c) 2024-2025 LouD + * + * 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, version 2. + * + * 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 . + * + */ + +#ifndef _USBSID_UART_H_ +#define _USBSID_UART_H_ +#pragma once + +#ifdef __cplusplus + extern "C" { +#endif + +#ifdef USE_PIO_UART + + +/* Default includes */ +#include +#include +#include + +/* Pico libs */ +#include "pico/stdlib.h" +#include "pico/multicore.h" +#include "pico/util/queue.h" +#include "pico/async_context_threadsafe_background.h" + +/* Pico hardware api's */ +#include "hardware/clocks.h" +#include "hardware/pio.h" +#include "hardware/uart.h" + +/* PIO */ +#include "uart_rx.pio.h" + + +/* What am I doing here? */ +#define UART_FIFO_SIZE 65535 /* TODO: Verify size */ + + +#endif /* USE_PIO_UART */ + +#ifdef __cplusplus + } +#endif + +#endif /* _USBSID_UART_H_ */ diff --git a/src/usbsid.c b/src/usbsid.c index 063f4e6..e5dc2f2 100644 --- a/src/usbsid.c +++ b/src/usbsid.c @@ -41,14 +41,20 @@ uint8_t __not_in_flash("usbsid_buffer") sid_buffer[MAX_BUFFER_SIZE] __aligned(2 uint8_t __not_in_flash("usbsid_buffer") read_buffer[MAX_BUFFER_SIZE] __aligned(2 * MAX_BUFFER_SIZE); uint8_t __not_in_flash("usbsid_buffer") config_buffer[MAX_BUFFER_SIZE] __aligned(2 * MAX_BUFFER_SIZE); uint8_t __not_in_flash("usbsid_buffer") sid_memory[(0x20 * 4)] __aligned(2 * (0x20 * 4)); +uint8_t __not_in_flash("usbsid_buffer") uart_buffer[64] __aligned(2 * 64); + int usb_connected = 0, usbdata = 0; uint32_t cdcread = 0, cdcwrite = 0, webread = 0, webwrite = 0; uint8_t *cdc_itf = 0, *wusb_itf = 0; -char ntype = '0', dtype = '0', cdc = 'C', asid = 'A', midi = 'M', sysex = 'S', wusb = 'W'; +/* nonetype, datatype, returntype */ +char ntype = '0', dtype = '0', rtype = '0'; +char cdc = 'C', asid = 'A', midi = 'M', sysex = 'S', wusb = 'W', uart = 'U'; bool web_serial_connected = false; + double cpu_mhz = 0, cpu_us = 0, sid_hz = 0, sid_mhz = 0, sid_us = 0; int paused_state = 0, reset_state = 0; bool auto_config = false; +bool offload_ledrunner = false; /* Init var pointers for external use */ uint8_t (*write_buffer_p)[MAX_BUFFER_SIZE] = &write_buffer; @@ -83,6 +89,11 @@ extern uint16_t __no_inline_not_in_flash_func(cycled_delay_operation)(uint16_t c extern uint8_t __no_inline_not_in_flash_func(cycled_read_operation)(uint8_t address, uint16_t cycles); extern void __no_inline_not_in_flash_func(cycled_write_operation)(uint8_t address, uint8_t data, uint16_t cycles); +/* Uart */ +#ifdef USE_PIO_UART +extern void init_uart(void); +#endif + /* Vu */ extern uint16_t vu; extern void init_vu(void); @@ -98,6 +109,17 @@ extern bool running_tests; /* SID detection */ extern void auto_detect_routine(bool auto_config, bool with_delay); +/* SID player */ +#ifdef ONBOARD_EMULATOR +extern bool emulator_running, starting_emulator, stopping_emulator; +extern void start_emulator(void); +#ifdef ONBOARD_SIDPLAYER +extern bool sidplayer_init, sidplayer_playing, sidplayer_start; +extern unsigned int run_emulator(void); +extern void start_sidplayer(void); +#endif +#endif + /* Midi */ extern void midi_init(void); extern void process_stream(uint8_t *buffer, size_t size); @@ -253,7 +275,7 @@ void __no_inline_not_in_flash_func(process_buffer)(uint8_t * itf, uint32_t * n) if (command == READ) { /* READING CAN ONLY HANDLE ONE AT A TIME, PERIOD. */ IODBG("[I %d] [%c] $%02X:%02X\n", n_bytes, dtype, sid_buffer[1], sid_buffer[2]); write_buffer[0] = cycled_read_operation(sid_buffer[1], 0); /* write the address to the SID and read the data back */ - switch (dtype) { /* write the result to the USB client */ + switch (rtype) { /* write the result to the USB client */ case 'C': cdc_write(itf, BYTES_TO_SEND); break; @@ -261,7 +283,7 @@ void __no_inline_not_in_flash_func(process_buffer)(uint8_t * itf, uint32_t * n) webserial_write(itf, BYTES_TO_SEND); break; default: - IODBG("[WRITE ERROR]%c\n", dtype); + IODBG("[WRITE ERROR]%c\n", rtype); break; }; vu = (vu == 0 ? 100 : vu); /* NOTICE: Testfix for core1 setting dtype to 0 */ @@ -272,7 +294,7 @@ void __no_inline_not_in_flash_func(process_buffer)(uint8_t * itf, uint32_t * n) case CYCLED_READ: IODBG("[I %d] [%c] $%02X %u\n", n_bytes, dtype, sid_buffer[1], (sid_buffer[2] << 8 | sid_buffer[3])); write_buffer[0] = cycled_read_operation(sid_buffer[1], (sid_buffer[2] << 8 | sid_buffer[3])); - switch (dtype) { /* write the result to the USB client */ + switch (rtype) { /* write the result to the USB client */ case 'C': cdc_write(itf, BYTES_TO_SEND); break; @@ -280,7 +302,7 @@ void __no_inline_not_in_flash_func(process_buffer)(uint8_t * itf, uint32_t * n) webserial_write(itf, BYTES_TO_SEND); break; default: - IODBG("[WRITE ERROR]%c\n", dtype); + IODBG("[WRITE ERROR]%c\n", rtype); break; }; vu = (vu == 0 ? 100 : vu); /* NOTICE: Testfix for core1 setting dtype to 0 */ @@ -323,7 +345,9 @@ void __no_inline_not_in_flash_func(process_buffer)(uint8_t * itf, uint32_t * n) clear_bus_all(); break; case CONFIG: - DBG("[CONFIG]\n"); + if (sid_buffer[1] < 0xD0) { /* Don't log incoming buffer to avoid spam above this region */ + DBG("[CONFIG]\n"); + } /* Copy incoming buffer ignoring the command byte */ memcpy(config_buffer, (sid_buffer + 1), (int)*n - 1); handle_config_request(config_buffer, *n - 1); @@ -356,7 +380,7 @@ void tud_mount_cb(void) void tud_umount_cb(void) { - usb_connected = 0, usbdata = 0, dtype = ntype; + usb_connected = 0, usbdata = 0, dtype = rtype = ntype; DBG("[%s]\n", __func__); disable_sid(); /* NOTICE: Testing if this is causing the random lockups */ } @@ -365,7 +389,7 @@ void tud_suspend_cb(bool remote_wakeup_en) { /* (void) remote_wakeup_en; */ DBG("[%s] remote_wakeup_en:%d\n", __func__, remote_wakeup_en); - usb_connected = 0, usbdata = 0, dtype = ntype; + usb_connected = 0, usbdata = 0, dtype = rtype = ntype; } void tud_resume_cb(void) @@ -417,7 +441,7 @@ void cdc_task(void) if (tud_cdc_n_connected(CDC_ITF)) { if (tud_cdc_n_available(CDC_ITF) > 0) { cdc_itf = CDC_ITF; - usbdata = 1, dtype = cdc; + usbdata = 1, dtype = cdc, rtype = cdc; cdcread = tud_cdc_n_read(CDC_ITF, &read_buffer, MAX_BUFFER_SIZE); /* Read data from client */ tud_cdc_n_read_flush(CDC_ITF); memcpy(sid_buffer, read_buffer, cdcread); @@ -435,7 +459,7 @@ void tud_cdc_rx_cb(uint8_t itf) #ifdef USE_CDC_CALLBACK if (itf == CDC_ITF) { cdc_itf = &itf; - usbdata = 1, dtype = cdc; + usbdata = 1, dtype = cdc, rtype = cdc; cdcread = tud_cdc_n_read(*cdc_itf, &read_buffer, MAX_BUFFER_SIZE); /* Read data from client */ tud_cdc_n_read_flush(*cdc_itf); memcpy(sid_buffer, read_buffer, cdcread); @@ -501,7 +525,7 @@ void vendor_task(void) /* If the fifo buffer is disabled, this function has no use */ if (web_serial_connected) { wusb_itf = WUSB_ITF; - usbdata = 1, dtype = wusb; + usbdata = 1, dtype = wusb, rtype = wusb; webread = tud_vendor_n_read(WUSB_ITF, &read_buffer, MAX_BUFFER_SIZE); tud_vendor_n_read_flush(*wusb_itf); memcpy(sid_buffer, read_buffer, webread); @@ -521,7 +545,7 @@ void tud_vendor_rx_cb(uint8_t itf, uint8_t const* buffer, uint16_t bufsize) /* vendor class has no connect check, thus use this */ if (web_serial_connected && itf == WUSB_ITF) { wusb_itf = &itf; /* Since there's only 1 vendor interface, we know it's 0 */ - usbdata = 1, dtype = wusb; + usbdata = 1, dtype = wusb, rtype = wusb; webread = bufsize; memcpy(sid_buffer, buffer, bufsize); /* No need to flush since we have no fifo */ @@ -676,6 +700,11 @@ void core1_main(void) queue_init(&logging_queue, sizeof(writelogging_queue_entry_t), 16); /* 16 entries deep */ #endif + /* Initialize PIO Uart */ + #ifdef USE_PIO_UART + init_uart(); + #endif + /* Release semaphore when core 1 is started */ sem_release(&core1_init); @@ -691,6 +720,35 @@ void core1_main(void) } } + #ifdef ONBOARD_EMULATOR + /* BUG: If not running directly after boot + * or after stopped and then started again + * the sound is distorted */ + if (!emulator_running && starting_emulator) { + starting_emulator = false; + emulator_running = true; + start_emulator(); + } + #endif + + #if defined(ONBOARD_EMULATOR) && defined(ONBOARD_SIDPLAYER) + if (sidplayer_start) { + sidplayer_start = false; + start_sidplayer(); + sidplayer_playing = true; + } + #endif + + #if defined(ONBOARD_EMULATOR) && defined(ONBOARD_SIDPLAYER) + if (sidplayer_playing) { + run_emulator(); + } + #endif + + if (!offload_ledrunner) { + led_runner(); + } + #ifdef WRITE_DEBUG /* Only run this queue when needed */ if (usbdata == 1) { writelogging_queue_entry_t l_entry; @@ -699,8 +757,6 @@ void core1_main(void) } } #endif - - led_runner(); } /* Point of no return, this should never be reached */ return; @@ -804,6 +860,9 @@ int main() #ifdef USE_VENDOR_BUFFER vendor_task(); /* Only use this if buffering and fifo are enabled */ #endif + if (offload_ledrunner) { + led_runner(); + } } /* Point of no return, this should never be reached */ diff --git a/src/vu.c b/src/vu.c index 72aa23d..6f656ce 100644 --- a/src/vu.c +++ b/src/vu.c @@ -23,6 +23,7 @@ * */ +#include #include "globals.h" #include "config.h" #include "gpio.h" @@ -39,6 +40,7 @@ extern Config usbsid_config; /* usbsid.c */ extern uint8_t __not_in_flash("usbsid_buffer") sid_memory[(0x20 * 4)] __attribute__((aligned(2 * (0x20 * 4)))); /* usbsid.c */ extern int usbdata; /* usbsid.c */ extern int numsids; /* config.c */ +extern bool offload_ledrunner; /* GPIO externals */ extern void setup_vu(void); @@ -79,9 +81,9 @@ unsigned char o1 = 0, o2 = 0, o3 = 0; void init_rgb(void) { #if defined(USE_RGB) - _rgb = randval(0, 5); /* Select random color to start with */ + _rgb = RANDVAL(0, 5); /* Select random color to start with */ r_ = g_ = b_ = 0; - rgb_value = (ugrb_u32(r_,g_,b_) << 8u); + rgb_value = (UGRB_U32(r_,g_,b_) << 8u); dma_hw->multi_channel_trigger = (1u << dma_rgbled); #endif return; @@ -119,8 +121,8 @@ void led_vumeter_task(void) osc2 = (sid_memory[0x07] * 0.596f); /* Frequency in Hz of SID1 @ $D400 Oscillator 2 */ osc3 = (sid_memory[0x0E] * 0.596f); /* Frequency in Hz of SID1 @ $D400 Oscillator 3 */ - vu = abs((osc1 + osc2 + osc3) / 3.0f); - vu = map(vu, 0, HZ_MAX, 0, VU_MAX); + vu = fabsl(((osc1 + osc2 + osc3) / 3.0f)); + vu = MAP(vu, 0, HZ_MAX, 0, VU_MAX); if (usbsid_config.LED.enabled) { pwm_value = (uint16_t)vu; dma_hw->multi_channel_trigger = (1u << dma_pwmled); @@ -130,10 +132,10 @@ void led_vumeter_task(void) if(usbsid_config.RGBLED.enabled) { int sidno = (usbsid_config.RGBLED.sid_to_use - 1) * 0x20; rgb_value = ( - (ugrb_u32( - rgbb((sid_memory[0x00 + sidno] * 0.596f),usbsid_config.RGBLED.brightness), - rgbb((sid_memory[0x07 + sidno] * 0.596f),usbsid_config.RGBLED.brightness), - rgbb((sid_memory[0x0E + sidno] * 0.596f),usbsid_config.RGBLED.brightness)) + (UGRB_U32( + RGBB((sid_memory[0x00 + sidno] * 0.596f),usbsid_config.RGBLED.brightness), + RGBB((sid_memory[0x07 + sidno] * 0.596f),usbsid_config.RGBLED.brightness), + RGBB((sid_memory[0x0E + sidno] * 0.596f),usbsid_config.RGBLED.brightness)) ) << 8u); dma_hw->multi_channel_trigger = (1u << dma_rgbled); } @@ -167,7 +169,7 @@ void led_breathe_task(void) if (pwm_value <= 0) { updown = 1; #ifdef USE_RGB - _rgb = randval(0, 5); /* Select random color when at 0 brightness */ + _rgb = RANDVAL(0, 5); /* Select random color when at 0 brightness */ #endif } @@ -181,19 +183,19 @@ void led_breathe_task(void) } #if defined(USE_RGB) if (usbsid_config.RGBLED.enabled && usbsid_config.RGBLED.idle_breathe) { - int rgb_ = map(pwm_value, 0, VU_MAX, 0, 31); + int rgb_ = MAP(pwm_value, 0, VU_MAX, 0, 31); r_ = (_rgb == 0 || _rgb == 3 || _rgb == 5) ? (rgb_ * 8) : 0; g_ = (_rgb == 1 || _rgb == 3 || _rgb == 4) ? (rgb_ * 8) : 0; b_ = (_rgb == 2 || _rgb == 4 || _rgb == 5) ? (rgb_ * 8) : 0; rgb_value = ( - (ugrb_u32( - rgbb(r_,usbsid_config.RGBLED.brightness), - rgbb(g_,usbsid_config.RGBLED.brightness), - rgbb(b_,usbsid_config.RGBLED.brightness)) + (UGRB_U32( + RGBB(r_,usbsid_config.RGBLED.brightness), + RGBB(g_,usbsid_config.RGBLED.brightness), + RGBB(b_,usbsid_config.RGBLED.brightness)) ) << 8u); dma_hw->multi_channel_trigger = (1u << dma_rgbled); } else { - rgb_value = ((ugrb_u32(0,0,0)) << 8u); + rgb_value = ((UGRB_U32(0,0,0)) << 8u); dma_hw->multi_channel_trigger = (1u << dma_rgbled); } #endif @@ -216,6 +218,7 @@ void led_runner(void) if (n_checks >= MAX_CHECKS) /* 100 checks */ { n_checks = 0, usbdata = 0, dtype = ntype; /* NOTE: This sets dtype to 0 which causes buffertask write to go to default and error out with many consecutive reads from the bus */ + offload_ledrunner = false; } } return;