diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e0fae02..831dc92 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,6 +20,10 @@ on: # Allows you to run this workflow manually from the Actions tab when needed workflow_dispatch: +concurrency: + group: dev-firmware-build + cancel-in-progress: true + jobs: build: name: Build diff --git a/.github/workflows/buildtools.yml b/.github/workflows/buildtools.yml index 429f984..7dbdf64 100644 --- a/.github/workflows/buildtools.yml +++ b/.github/workflows/buildtools.yml @@ -7,8 +7,8 @@ env: on: push: paths: - - "src/examples/config-tool/**" - - "src/examples/send_sid/**" + - "examples/config-tool/**" + - "examples/send_sid/**" - ".github/workflows/buildtools.yml" # Only run on dev branch branches: [dev] @@ -21,6 +21,10 @@ on: type: boolean default: false +concurrency: + group: dev-tools-build + cancel-in-progress: true + jobs: build-tools: name: Tools @@ -38,10 +42,18 @@ jobs: directory: config-tool, buildname: cfg_usbsid } - { os: ubuntu-latest, shell: bash, directory: send_sid, buildname: send_sid } - - { os: windows-2022, shell: 'msys2 {0}', - directory: config-tool, buildname: cfg_usbsid.exe } - - { os: windows-2022, shell: 'msys2 {0}', - directory: send_sid, buildname: send_sid.exe } + - { os: windows-2022, shell: 'msys2 {0}', + directory: config-tool, buildname: cfg_usbsid } + - { os: windows-2022, shell: 'msys2 {0}', + directory: send_sid, buildname: send_sid } + - { os: macos-14, shell: 'bash', + directory: config-tool, buildname: cfg_usbsid_macos14 } + - { os: macos-14, shell: 'bash', + directory: send_sid, buildname: send_sid_macos14 } + - { os: macos-15-intel, shell: 'bash', + directory: config-tool, buildname: cfg_usbsid_macos15intel } + - { os: macos-15-intel, shell: 'bash', + directory: send_sid, buildname: send_sid_macos15intel } defaults: run: shell: ${{ matrix.shell }} @@ -74,6 +86,12 @@ jobs: mingw-w64-x86_64-pkg-config mingw-w64-x86_64-ninja + # - name: Install dependencies (MacOs) + # if: matrix.os == 'macos-14' || matrix.os == 'macos-15-intel' + # run: | + # brew update + # brew install pkg-config cmake ninja libusb + - name: Remove pre-built binaries run: | pushd repo/examples/${{ matrix.directory }} @@ -84,15 +102,15 @@ jobs: - name: Configure and build ${{ matrix.buildname }} run: | pushd repo/examples/${{ matrix.directory }} - cmake -S . -B build && cmake --build build -j$(nproc) + cmake -S . -B build -DEXECUTABLE=${{ matrix.buildname }} && cmake --build build -j$(nproc) ls -lhai popd - name: Upload uses: actions/upload-artifact@v4 with: - name: ${{ matrix.buildname }}-${{ matrix.os }} + name: tools-${{ matrix.buildname }}-${{ matrix.os }} path: | - repo/examples/${{ matrix.directory }}/${{ matrix.buildname }} + ${{ matrix.os == 'windows-2022' && format('repo/examples/{0}/{1}.exe', matrix.directory, matrix.buildname) || format('repo/examples/{0}/{1}', matrix.directory, matrix.buildname) }} ${{ matrix.os == 'windows-2022' && format('repo/examples/{0}/*.dll', matrix.directory) || '' }} if-no-files-found: ignore diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 04b353b..47c5a95 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -84,7 +84,7 @@ jobs: tag: ${{ env.SOURCE_TAG }} name: ${{ env.SOURCE_TAG }} token: ${{ secrets.GITHUB_TOKEN }} - artifacts: "release/*.uf2" + artifacts: "release/*.uf2,release/*.zip" prerelease: false removeArtifacts: true generateReleaseNotes: true @@ -375,7 +375,7 @@ jobs: - name: Download Tools Artifacts uses: actions/download-artifact@v4 with: - pattern: '*' + pattern: 'tools-*' path: tools-output merge-multiple: true diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e7a1f3..0e8e3e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ 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.6.0-BETA.${MAGIC_SMOKE}") # Generate compile version +set(PROJECT_VERSION "0.6.1-BETA.${MAGIC_SMOKE}") # Generate compile version ### Want a cookie? # NOTICE: ENABLING THESE DEBUGGING DEFINITIONS WILL HAVE SIGNIFICANT IMPACT AND WILL DELAY PLAYING! @@ -40,12 +40,15 @@ if(NOT DEFINED $ENV{DISABLE_DEBUGGING}) # MATCHES set(USBSID_DEBUGGING 1) # Enable debugging ~ mandatory enable for all other logging types 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(FILENAME_LOGGING 0) # Enable logging of source filename + set(BOOT_LOGGING 0) # Enable bootlog in usbsid.c 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 set(GPIOBUS_DEBUGGING 0) # Enable debugging in gpio.c set(MIDI_DEBUGGING 0) # Enable debugging in midi.c set(MIDIVOICE_DEBUGGING 0) # Enable debugging in midi.c + set(ASID_DEBUGGING 0) # Enable debugging in acid.c and asid_buffer.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 @@ -338,6 +341,7 @@ set(SOURCEFILES ${CMAKE_CURRENT_LIST_DIR}/src/midi.c ${CMAKE_CURRENT_LIST_DIR}/src/midi_handler.c ${CMAKE_CURRENT_LIST_DIR}/src/asid.c + ${CMAKE_CURRENT_LIST_DIR}/src/asid_buffer.c ${CMAKE_CURRENT_LIST_DIR}/src/sysex.c ${CMAKE_CURRENT_LIST_DIR}/src/sid.c ${CMAKE_CURRENT_LIST_DIR}/src/sid_cloneconfig.c @@ -360,7 +364,12 @@ if(ONBOARD_SIDPLAYER EQUAL 1) # NOTICE: SIDPLAYER REQUIRES FULL OPTIMIZATIONS!! set(COMPILE_OPTS ${COMPILE_OPTS} -O3) ## Set sidplayer list directory - set(USPLAYER_LIST_DIR ${CMAKE_CURRENT_LIST_DIR}/lib/usbsid-player) + if(NOT ${EMUDIR} STREQUAL "") + set(USPLAYER_LIST_DIR ${EMUDIR}) + else() + set(USPLAYER_LIST_DIR ${CMAKE_CURRENT_LIST_DIR}/lib/usbsid-player) + endif() + message(DEBUG "USPLAYER_LIST_DIR is set to ${USPLAYER_LIST_DIR}") ### Adjust filenames for user interpretation foreach(FILENAME ${FILENAMES}) @@ -423,7 +432,12 @@ if(ONBOARD_EMULATOR EQUAL 1) set(COMPILE_OPTS ${COMPILE_OPTS} -DEMBEDDED=1) add_compile_definitions(ONBOARD_EMULATOR=1) set(EMULATOR_LIST_DIR ${CMAKE_CURRENT_LIST_DIR}/lib/emulator) - set(EMUDORE_LIST_DIR ${CMAKE_CURRENT_LIST_DIR}/lib/emudore-embedded) + if(NOT ${EMUDIR} STREQUAL "") + set(EMUDORE_LIST_DIR ${EMUDIR}) + else() + set(EMUDORE_LIST_DIR ${CMAKE_CURRENT_LIST_DIR}/lib/emudore-embedded) + endif() + message(DEBUG "EMUDORE_LIST_DIR is set to ${EMUDORE_LIST_DIR}") ### Adjust filenames for user interpretation foreach(FILENAME ${FILENAMES}) @@ -503,7 +517,7 @@ 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) -set(PIO_COUNTER ${CMAKE_CURRENT_LIST_DIR}/src/pio/clock_counter.pio) +set(PIO_COUNTER ${CMAKE_CURRENT_LIST_DIR}/src/pio/cycle_counter.pio) if(USE_PIO_UART EQUAL 1) set(PIO_UART ${CMAKE_CURRENT_LIST_DIR}/src/pio/uart_rx.pio) endif() @@ -538,15 +552,21 @@ if(USBSID_DEBUGGING EQUAL 1) if(DEFAULT_DEBUGGING EQUAL 1) add_compile_definitions(USBSID_DEBUG=1) endif() + if(FILENAME_LOGGING EQUAL 1) + add_compile_definitions(LOG_FILENAME=1) + endif() + if(BOOT_LOGGING EQUAL 1) + add_compile_definitions(USBSID_BOOTLOG=1) + endif() + if(CONFIG_DEBUGGING EQUAL 1) + add_compile_definitions(CONFIG_DEBUG=1) + endif() if(MEMORY_LOGGING EQUAL 1) add_compile_definitions(MEM_DEBUG=1) endif() if(SIDWRITES_DEBUGGING EQUAL 1) add_compile_definitions(WRITE_DEBUG=1) endif() - if(CONFIG_DEBUGGING EQUAL 1) - add_compile_definitions(CONFIG_DEBUG=1) - endif() if(USBIO_DEBUGGING EQUAL 1) add_compile_definitions(USBIO_DEBUG=1) endif() @@ -556,6 +576,9 @@ if(USBSID_DEBUGGING EQUAL 1) if(MIDIVOICE_DEBUGGING EQUAL 1) add_compile_definitions(MIDIVOICE_DEBUG=1) endif() + if(ASID_DEBUGGING EQUAL 1) + add_compile_definitions(ASID_DEBUG=1) + endif() if(GPIOBUS_DEBUGGING EQUAL 1) add_compile_definitions(USBSIDGPIO_DEBUG=1) endif() diff --git a/README.md b/README.md index af33a68..1d69f89 100644 --- a/README.md +++ b/README.md @@ -343,10 +343,10 @@ Any code in this repository that is not written by me automatically falls under For for more information about this license please read the LICENSE document in the root of the USBSID-Pico repository. ### USBSID-Pico v1.3 PCB Hardware License ~ Creative Commons -USBSID-Pico v1.3 PCB © 2025 by LouD is licensed under Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International +USBSID-Pico v1.3 PCB © 2025-2026 by LouD is licensed under Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International ### USBSID-Pico v1.0 PCB Hardware License ~ Creative Commons -USBSID-Pico v1.0 PCB © 2024 by LouD is licensed under Creative Commons Attribution-ShareAlike 4.0 International +USBSID-Pico v1.0 PCB © 2024-2026 by LouD is licensed under Creative Commons Attribution-ShareAlike 4.0 International # Certification ### USBSID-Pico v1.0 PCB OSHWA certification diff --git a/doc/USBSID-Pico-Cynthcart-manual.pdf b/doc/USBSID-Pico-Cynthcart-manual.pdf index 7b83d7b..b40cb48 100644 Binary files a/doc/USBSID-Pico-Cynthcart-manual.pdf and b/doc/USBSID-Pico-Cynthcart-manual.pdf differ diff --git a/doc/USBSID-Pico-PCBv1.0-manual.pdf b/doc/USBSID-Pico-PCBv1.0-manual.pdf index 5ac9246..4bba2cb 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.pdf b/doc/USBSID-Pico-PCBv1.3-manual.pdf index 782faab..847170f 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.pdf b/doc/USBSID-Pico-firmware-manual.pdf index 4ba5248..d7e6935 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.pdf b/doc/USBSID-Pico-software-manual.pdf index b4bda1c..c33843a 100644 Binary files a/doc/USBSID-Pico-software-manual.pdf and b/doc/USBSID-Pico-software-manual.pdf differ diff --git a/doc/USBSID-Player-manual.pdf b/doc/USBSID-Player-manual.pdf index 5d77fdf..4010750 100644 Binary files a/doc/USBSID-Player-manual.pdf and b/doc/USBSID-Player-manual.pdf differ diff --git a/doc/license-hardware.adoc b/doc/license-hardware.adoc index d440158..9409607 100644 --- a/doc/license-hardware.adoc +++ b/doc/license-hardware.adoc @@ -1,11 +1,11 @@ === USBSID-Pico v1.3 PCB Hardware License ~ Creative Commons -https://github.com/LouDnl/USBSID-Pico/tree/master/hardware/USBSID-Pico-v1.3[USBSID-Pico v1.3 PCB] © 2025 by +https://github.com/LouDnl/USBSID-Pico/tree/master/hardware/USBSID-Pico-v1.3[USBSID-Pico v1.3 PCB] © 2025-2026 by https://github.com/LouDnl[LouD] is licensed under + https://creativecommons.org/licenses/by-nc-nd/4.0/[Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International] + image:https://mirrors.creativecommons.org/presskit/icons/cc.svg[link="https://creativecommons.org/licenses/by-nc-nd/4.0/"]image:https://mirrors.creativecommons.org/presskit/icons/by.svg[link="https://creativecommons.org/licenses/by-nc-nd/4.0/"]image:https://mirrors.creativecommons.org/presskit/icons/nc.svg[link="https://creativecommons.org/licenses/by-nc-nd/4.0/"]image:https://mirrors.creativecommons.org/presskit/icons/nd.svg[link="https://creativecommons.org/licenses/by-nc-nd/4.0/"] === USBSID-Pico v1.0 PCB Hardware License ~ Creative Commons -https://github.com/LouDnl/USBSID-Pico/tree/master/hardware/USBSID-Pico-v1.0[USBSID-Pico v1.0 PCB] © 2024 by +https://github.com/LouDnl/USBSID-Pico/tree/master/hardware/USBSID-Pico-v1.0[USBSID-Pico v1.0 PCB] © 2024-2026 by https://github.com/LouDnl[LouD] is licensed under + https://creativecommons.org/licenses/by-sa/4.0/[Creative Commons Attribution-ShareAlike 4.0 International] + image:https://mirrors.creativecommons.org/presskit/icons/cc.svg[link="https://creativecommons.org/licenses/by-sa/4.0/"]image:https://mirrors.creativecommons.org/presskit/icons/by.svg[link="https://creativecommons.org/licenses/by-sa/4.0/"]image:https://mirrors.creativecommons.org/presskit/icons/sa.svg[link="https://creativecommons.org/licenses/by-sa/4.0/"] diff --git a/examples/config-tool/CMakeLists.txt b/examples/config-tool/CMakeLists.txt index a6bdec6..43900d9 100644 --- a/examples/config-tool/CMakeLists.txt +++ b/examples/config-tool/CMakeLists.txt @@ -30,6 +30,7 @@ cmake_minimum_required(VERSION 3.17) ### Project magic sprinkles set(PROJECT_NAME cfg_usbsid) +set(EXECUTABLE ${PROJECT_NAME} CACHE STRING "EXECUTABLE") ### Project type project(${PROJECT_NAME} C ASM) @@ -73,18 +74,18 @@ set(TARGET_INCLUDE_DIRS PRIVATE ) ### Compile time -add_executable(${PROJECT_NAME} ${SOURCEFILES}) +add_executable(${EXECUTABLE} ${SOURCEFILES}) ### Copy build output to main directory add_custom_command(TARGET - ${PROJECT_NAME} + ${EXECUTABLE} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_LIST_DIR}) + COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_LIST_DIR}) ### Remove build output from build directory add_custom_command(TARGET - ${PROJECT_NAME} + ${EXECUTABLE} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E rm $) + COMMAND ${CMAKE_COMMAND} -E rm $) -target_include_directories(${PROJECT_NAME} ${TARGET_INCLUDE_DIRS}) -target_link_libraries(${PROJECT_NAME} ${TARGET_LL}) -target_sources(${PROJECT_NAME} PUBLIC ${SOURCEFILES}) +target_include_directories(${EXECUTABLE} ${TARGET_INCLUDE_DIRS}) +target_link_libraries(${EXECUTABLE} ${TARGET_LL}) +target_sources(${EXECUTABLE} PUBLIC ${SOURCEFILES}) diff --git a/examples/config-tool/cfg_skpico.h b/examples/config-tool/cfg_skpico.h index a61bc39..5eed68a 100644 --- a/examples/config-tool/cfg_skpico.h +++ b/examples/config-tool/cfg_skpico.h @@ -7,7 +7,7 @@ * This file is part of USBSID-Pico (https://github.com/LouDnl/USBSID-Pico) * File author: LouD * - * Copyright (c) 2024-2025 LouD + * Copyright (c) 2024-2026 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 diff --git a/examples/config-tool/cfg_usbsid b/examples/config-tool/cfg_usbsid index 1671498..fb69c88 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 448d971..f725c47 100644 --- a/examples/config-tool/cfg_usbsid.c +++ b/examples/config-tool/cfg_usbsid.c @@ -342,7 +342,7 @@ int usbsid_init(void) } for (int if_num = 0; if_num < 2; if_num++) { - if (libusb_kernel_driver_active(devh, if_num)) { + if (libusb_kernel_driver_active(devh, if_num) == 1) { libusb_detach_kernel_driver(devh, if_num); } rc = libusb_claim_interface(devh, if_num); @@ -354,20 +354,20 @@ int usbsid_init(void) } rc = libusb_control_transfer(devh, 0x21, 0x22, ACM_CTRL_DTR | ACM_CTRL_RTS, 0, NULL, 0, 0); - if (rc < 0) { + if (rc != 0 && rc != 7) { fprintf(stderr, "Error configuring line state during control transfer: %d, %s: %s\n", rc, libusb_error_name(rc), libusb_strerror(rc)); goto out; } rc = libusb_control_transfer(devh, 0x21, 0x20, 0, 0, encoding, count_of(encoding), 0); - if (rc < 0 || rc != 7) { + if (rc != 0 && rc != 7) { fprintf(stderr, "Error configuring line encoding during control transfer: %d, %s: %s\n", rc, libusb_error_name(rc), libusb_strerror(rc)); goto out; } - usid_dev = (rc > 0 && rc == 7) ? 0 : -1; + usid_dev = (rc == 0 || rc == 7) ? 0 : -1; if (usid_dev < 0) { @@ -385,6 +385,7 @@ int usbsid_init(void) out:; if (devh != NULL) usbsid_close(); + rc = -1; return rc; } @@ -1247,7 +1248,7 @@ void config_skpico(int argc, char **argv) skpico_write_config(debug); printf("Start saving default config\n"); - sleep(0.5); + sleep(1); skpico_save_config(debug); printf("Extend config mode\n"); @@ -1373,7 +1374,7 @@ void config_skpico(int argc, char **argv) skpico_write_config(debug); printf("Start saving config\n"); - sleep(0.5); + sleep(1); skpico_save_config(debug); printf("Extend config mode\n"); @@ -1384,7 +1385,7 @@ void config_skpico(int argc, char **argv) skpico_read_config(debug); skpico_end_config_mode(debug); - sleep(0.5); + sleep(1); goto exit; break; } @@ -1439,6 +1440,7 @@ void print_help(void) printf("--[PRESETS]---------------------------------------------------------------------------------------------------------\n"); printf(" (add '-q' before any of the preset commands for a quick change and apply the config without saving and rebooting)\n"); printf(" -single, --single-sid : Socket 1 enabled @ single SID, Socket 2 disabled\n"); + printf(" -single2, --single-sid-s2 : Socket 1 disabled, Socket 2 enabled @ single SID\n"); printf(" -dual, --dual-sid : Socket 1 enabled @ single SID, Socket 2 enabled @ single SID\n"); printf(" -duals1, --dual-sid-socket1 : Socket 1 enabled @ dual SID, Socket 2 disabled\n"); printf(" -duals2, --dual-sid-socket2 : Socket 1 disabled, Socket 2 enabled @ dual SID\n"); @@ -1584,10 +1586,15 @@ void config_usbsidpico(int argc, char **argv) quickchange = 1; }; if (!strcmp(argv[param_count], "-single") || !strcmp(argv[param_count], "--single-sid")) { - printf("Set USBSID-Pico config to single SID\n"); + printf("Set USBSID-Pico config to single SID @ Socket One\n"); write_config_command(SINGLE_SID, quickchange, 0, 0, 0); goto exit; } + if (!strcmp(argv[param_count], "-single2") || !strcmp(argv[param_count], "--single-sid-s2")) { + printf("Set USBSID-Pico config to single SID @ Socket Two\n"); + write_config_command(SINGLE_SID, quickchange, 1, 0, 0); + goto exit; + } if (!strcmp(argv[param_count], "-dual") || !strcmp(argv[param_count], "--dual-sid")) { printf("Set USBSID-Pico config to dual SID\n"); write_config_command(DUAL_SID, quickchange, 0 ,0 ,0); @@ -1721,7 +1728,7 @@ void config_usbsidpico(int argc, char **argv) } if (argc > 8) { uint8_t test_buffer[64] = {0}; - test_buffer[0] = ((COMMAND << 6) | 18); + test_buffer[0] = ((COMMAND << 6) | CONFIG); test_buffer[1] = WRITE_CONFIG; int tb_count = 2; for (int i = 2; i < argc; i++) { diff --git a/examples/config-tool/libwinpthread-1.dll b/examples/config-tool/libwinpthread-1.dll index 18922c7..2c88914 100755 Binary files a/examples/config-tool/libwinpthread-1.dll and b/examples/config-tool/libwinpthread-1.dll differ diff --git a/examples/send_sid/CMakeLists.txt b/examples/send_sid/CMakeLists.txt index efd39a3..deb71d7 100644 --- a/examples/send_sid/CMakeLists.txt +++ b/examples/send_sid/CMakeLists.txt @@ -30,6 +30,7 @@ cmake_minimum_required(VERSION 3.17) ### Project magic sprinkles set(PROJECT_NAME send_sid) +set(EXECUTABLE ${PROJECT_NAME} CACHE STRING "EXECUTABLE") ### Project type project(${PROJECT_NAME} C ASM) @@ -71,18 +72,18 @@ set(TARGET_INCLUDE_DIRS PRIVATE ) ### Compile time -add_executable(${PROJECT_NAME} ${SOURCEFILES}) +add_executable(${EXECUTABLE} ${SOURCEFILES}) ### Copy build output to main directory add_custom_command(TARGET - ${PROJECT_NAME} + ${EXECUTABLE} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_LIST_DIR}) + COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_LIST_DIR}) ### Remove build output from build directory add_custom_command(TARGET - ${PROJECT_NAME} + ${EXECUTABLE} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E rm $) + COMMAND ${CMAKE_COMMAND} -E rm $) -target_include_directories(${PROJECT_NAME} ${TARGET_INCLUDE_DIRS}) -target_link_libraries(${PROJECT_NAME} ${TARGET_LL}) -target_sources(${PROJECT_NAME} PUBLIC ${SOURCEFILES}) +target_include_directories(${EXECUTABLE} ${TARGET_INCLUDE_DIRS}) +target_link_libraries(${EXECUTABLE} ${TARGET_LL}) +target_sources(${EXECUTABLE} PUBLIC ${SOURCEFILES}) diff --git a/examples/send_sid/libusb-1.0.dll b/examples/send_sid/libusb-1.0.dll old mode 100755 new mode 100644 diff --git a/examples/send_sid/send_sid b/examples/send_sid/send_sid index 338908b..803bbf7 100755 Binary files a/examples/send_sid/send_sid and b/examples/send_sid/send_sid differ diff --git a/examples/send_sid/send_sid.c b/examples/send_sid/send_sid.c index 01a0f52..41b1b2d 100644 --- a/examples/send_sid/send_sid.c +++ b/examples/send_sid/send_sid.c @@ -103,7 +103,7 @@ int usbsid_init(void) } for (int if_num = 0; if_num < 2; if_num++) { - if (libusb_kernel_driver_active(devh, if_num)) { + if (libusb_kernel_driver_active(devh, if_num) == 1) { libusb_detach_kernel_driver(devh, if_num); } rc = libusb_claim_interface(devh, if_num); @@ -140,6 +140,7 @@ int usbsid_init(void) if (devh != NULL) libusb_close(devh); libusb_exit(NULL); + rc = -1; return rc; } @@ -412,22 +413,22 @@ int main(int argc, char* argv[]) } goto done; } - if(!strcmp(argv[arg], "-stop") || !strcmp(argv[arg], "stop")) { + if(!strcmp(argv[arg], "-stop") || !strcmp(argv[arg], "stop") || !strcmp(argv[arg], "s")) { fprintf(stdout, "Stopping playback\n"); configbuff[1] = SID_PLAYER_STOP; write_chars(configbuff, 5); } - if(!strcmp(argv[arg], "-pause")) { + if(!strcmp(argv[arg], "-pause") || !strcmp(argv[arg], "pause") || !strcmp(argv[arg], "p")) { fprintf(stdout, "(Un)Pausing playback\n"); configbuff[1] = SID_PLAYER_PAUSE; write_chars(configbuff, 5); } - if(!strcmp(argv[arg], "-next")) { + if(!strcmp(argv[arg], "-next") || !strcmp(argv[arg], "next")|| !strcmp(argv[arg], "n")) { fprintf(stdout, "Playing next subtune\n"); configbuff[1] = SID_PLAYER_NEXT; write_chars(configbuff, 5); } - if(!strcmp(argv[arg], "-prev")) { + if(!strcmp(argv[arg], "-prev") || !strcmp(argv[arg], "prev") || !strcmp(argv[arg], "b")) { fprintf(stdout, "Playing previous subtune\n"); configbuff[1] = SID_PLAYER_PREV; write_chars(configbuff, 5); diff --git a/lib/emulator/emudore_emulator.c b/lib/emulator/emudore_emulator.c index 1c4f771..5814cd8 100644 --- a/lib/emulator/emudore_emulator.c +++ b/lib/emulator/emudore_emulator.c @@ -3,14 +3,14 @@ * 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 + * emodure_emulator.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 + * Copyright (c) 2024-2026 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 diff --git a/lib/emulator/interface.cpp b/lib/emulator/interface.cpp index 8450e78..c90c100 100644 --- a/lib/emulator/interface.cpp +++ b/lib/emulator/interface.cpp @@ -10,7 +10,7 @@ * Any licensing conditions from the above named source automatically * apply to this code * - * Copyright (c) 2024-2025 LouD + * Copyright (c) 2024-2026 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 diff --git a/src/asid.c b/src/asid.c index dce19ca..9eabf84 100644 --- a/src/asid.c +++ b/src/asid.c @@ -43,43 +43,107 @@ #include "logging.h" -/* Config */ +/* config.c */ +extern Config usbsid_config; extern RuntimeCFG cfg; extern char *sidtypes[5]; -/* GPIO */ -extern void __no_inline_not_in_flash_func(cycled_write_operation)(uint8_t address, uint8_t data, uint16_t cycles); +/* gpio.c */ +extern void cycled_write_operation(uint8_t address, uint8_t data, uint16_t cycles); extern void pause_sid(void); extern void reset_sid(void); +extern void reset_sid_registers(void); -/* Vu */ +/* vu.c */ extern uint16_t vu; +/* asid_buffer.c */ +extern uint32_t track_asid_arrival(void); +extern void adjust_buffer_rate_dynamic(uint32_t target_rate); +extern void reset_arrival_tracking(void); +extern void ring_buffer_reset_size(void); +extern void set_buffer_rate(uint16_t rate); + /* Some locals, rural and such */ +static bool buffer_started = false; static bool default_order = false; +static bool default_order_on_start = false; bool write_ordered = false; -struct asid_regpair_t { /* thanks to thomasj */ +/* thanks to thomasj */ +struct asid_regpair_t { uint8_t index; uint8_t wait_us; }; -struct asid_regpair_t asid_to_writeorder[NO_SID_REGISTERS_ASID] = {}; /* thanks to thomasj ~ SF2 Driver 11 no waits */ - +/* thanks to thomasj ~ SF2 Driver 11 no waits */ +struct asid_regpair_t asid_to_writeorder[NO_SID_REGISTERS_ASID] = {}; +/** + * @brief Resets SID write order back to defaults + */ void reset_asid_to_writeorder(void) { - DBG("[ASID] RESET WRITEORDER REGISTERS\n"); + usASID("Reset writeorder registers\n"); write_ordered = false; for (int i = 0; i < NO_SID_REGISTERS_ASID; i++) { asid_to_writeorder[i].index = i; - asid_to_writeorder[i].wait_us = 0; + asid_to_writeorder[i].wait_us = 10; /* 10 cycles as default for rp2350 being too fast */ + } + default_order_on_start = (default_order == false ? true : default_order); + default_order = true; + reset_arrival_tracking(); + ring_buffer_reset_size(); + return; +} + +/** + * @brief Initialize the asid buffer + * + * @param uint16_t framedelta_us ~ the rate to set the buffer to + */ +void init_asid_buffer(uint16_t framedelta_us) +{ + if (!buffer_started) { + usASID("Init buffer queue, timer and irq\n"); + extern void init_buffer_pio(void); + extern void asid_ring_init(void); + + asid_ring_init(); + init_buffer_pio(); + buffer_started = true; + } + /* Always set frame buffer timeout */ + if (framedelta_us != 0) { /* Above zero means always use framedelta_us */ + set_buffer_rate(framedelta_us); + } else { + set_buffer_rate(usbsid_config.refresh_rate); + } + return; +} + +/** + * @brief De-initialize the asid buffer + */ +void deinit_asid_buffer(void) +{ + if (buffer_started) { + usASID("De-init buffer queue, timer and irq\n"); + reset_asid_to_writeorder(); + extern void stop_buffer_pio(void); + extern void asid_ring_deinit(void); + asid_ring_deinit(); + stop_buffer_pio(); + buffer_started = false; } - default_order = (default_order == false ? true : default_order); } +/** + * @brief Initialize ASID on boot + */ void asid_init(void) { - DBG("[%s]\n", __func__); - if (!default_order) reset_asid_to_writeorder(); /* Set defaults once on first write */ + if (!default_order_on_start) reset_asid_to_writeorder(); /* Set defaults once on boot */ + else { ring_buffer_reset_size(); reset_arrival_tracking(); } + usNFO("[ASID] Initialized\n"); } /* Pling, plong, ploink!? */ @@ -122,7 +186,14 @@ void handle_asid_fmoplmessage(uint8_t* buffer) return; } -/* Well, it does what it does */ +/** + * @brief Well, it does what it does + * @note deprecated! + * + * @param uint8_t sid ~ the sidnumber + * @param uint8_t* buffer ~ the buffer to process + * @param int size ~ the size of the buffer + */ void handle_complete_asid_buffer(uint8_t sid, uint8_t* buffer, int size) { /* Assumes byte 0-2 are included in the buffer and skips these */ (void)size; /* Stop calling me fat, I'm just big boned! */ @@ -145,9 +216,16 @@ void handle_complete_asid_buffer(uint8_t sid, uint8_t* buffer, int size) } } } + return; } -/* And this does the same */ +/** + * @brief And this does the same + * @note deprecated! + * + * @param uint8_t sid ~ the sidnumber + * @param uint8_t* buffer ~ the buffer to process + */ void handle_asid_message(uint8_t sid, uint8_t* buffer) { /* Assumes byte 0-2 are not included in the buffer */ unsigned int reg = 0; @@ -169,9 +247,15 @@ void handle_asid_message(uint8_t sid, uint8_t* buffer) } } } + return; } -/* But this one lost track of time */ +/** + * @brief But this one lost track of time + * + * @param uint8_t sid ~ the sidnumber + * @param uint8_t* buffer ~ the buffer to process + */ void handle_writeordered_asid_message(uint8_t sid, uint8_t* buffer) { /* Assumes byte 0-2 are not included in the buffer */ int chip; @@ -199,32 +283,44 @@ void handle_writeordered_asid_message(uint8_t sid, uint8_t* buffer) } writeOrder[chip][asid_to_writeorder[reg].index].reg = asid_sid_registers[mask * 7 + bit]; writeOrder[chip][asid_to_writeorder[reg].index].data = register_value; - // TODO: FIX Pico2 writes /* Pico 2 requires at least 10 cycles between writes * or it will be too damn fast! So if wait_us is lower then 10 we use 10 cycles * and do this for other Pico's aswell */ writeOrder[chip][asid_to_writeorder[reg].index].wait_us = asid_to_writeorder[reg].wait_us; - /* DBG("[ASID1 %d] $%02X:%02X %u\n", asid_to_writeorder[reg].index, (writeOrder[chip][asid_to_writeorder[reg].index].reg |= sid), writeOrder[chip][asid_to_writeorder[reg].index].data, writeOrder[chip][asid_to_writeorder[reg].index].wait_us); */ + /* usASID("[%d] $%02X:%02X %u\n", asid_to_writeorder[reg].index, (writeOrder[chip][asid_to_writeorder[reg].index].reg |= sid), writeOrder[chip][asid_to_writeorder[reg].index].data, writeOrder[chip][asid_to_writeorder[reg].index].wait_us); */ dtype = asid; /* Set data type to asid again */ reg++; } } } - + /* inline extern as only used here */ + extern void asid_ring_write(uint8_t reg, uint8_t val, uint16_t c); for (size_t pos = 0; pos < NO_SID_REGISTERS_ASID; pos++) { if (writeOrder[chip][pos].wait_us != 0xff) { - /* Perform write including wait cycles */ - cycled_write_operation((writeOrder[chip][pos].reg |= sid), writeOrder[chip][pos].data, writeOrder[chip][pos].wait_us); - + /* Push data to ASID ringbuffer */ + asid_ring_write( + (writeOrder[chip][pos].reg |= sid), + writeOrder[chip][pos].data, + /* Account for 1 cycle overhead in PIO bus */ + // ((writeOrder[chip][pos].wait_us >= 0) ? (writeOrder[chip][pos].wait_us - 1) : 0)); + writeOrder[chip][pos].wait_us); + // (write_ordered ? writeOrder[chip][pos].wait_us : 10)); /* Default write order has 10 cycles per write */ WRITEDBG(dtype, pos, NO_SID_REGISTERS_ASID, (writeOrder[chip][pos].reg |= sid), writeOrder[chip][pos].data, writeOrder[chip][pos].wait_us); - /* DBG("[ASID2 %d] $%02X:%02X %u\n", pos, (writeOrder[chip][pos].reg |= sid), writeOrder[chip][pos].data, writeOrder[chip][pos].wait_us); */ + } else { + asid_ring_write(0xffu,0xffu,0xffffu); } } for (size_t pos = 0; pos < NO_SID_REGISTERS_ASID; pos++) { writeOrder[chip][pos].wait_us = 0xff; /* indicate not used */ } + return; } +/** + * @brief Process received writeorder configuration + * + * @param uint8_t* buffer ~ the buffer containing the configuration + */ void handle_asid_writeorder_config(uint8_t* buffer) { /* thanks to thomasj */ uint8_t data; @@ -234,13 +330,54 @@ void handle_asid_writeorder_config(uint8_t* buffer) asid_to_writeorder[i].index = data & 0x1f; /* Regular handling removes 7us, so adjust */ cycles = ((data & 0x40) << 1) + buffer[(i << 1) + 1]; - /* asid_to_writeorder[i].wait_us = max(0, cycles - 7); */ /* USP doesn't have overhead, disabled */ - asid_to_writeorder[i].wait_us = cycles; - CFG("[ASID WRITE ORDER %d] {%02u,%02u}\n", i, asid_to_writeorder[i].index, asid_to_writeorder[i].wait_us); + asid_to_writeorder[i].wait_us = MAX(1, cycles); /* USP has 1 cycle overhead */ + /* asid_to_writeorder[i].wait_us = cycles; */ + usASID("[WO%2d] {%02u,%02u}\n", i, asid_to_writeorder[i].index, asid_to_writeorder[i].wait_us); + } + default_order = false; + return; +} + +/** + * @brief Set ASID environment + * + * @param int refresh_rate + * @param int speed_multiplier + * @param int custom_speed + * @param int buffering + * @param uint16_t framedelta_us + */ +inline void set_asid_env(int refresh_rate, int speed_multiplier, int custom_speed, int buffering, uint16_t framedelta_us) +{ + (void)speed_multiplier; /* Not used */ + (void)custom_speed; /* Not used */ + (void)buffering; /* Not used */ + + { /* apply the new clock_rate based on the refresh_rate if applicable */ + extern void apply_clockrate(int n_clock, bool suspend_sids); + apply_clockrate( + ((refresh_rate == 0) + ? 1 /* PAL */ + : 2), /* NTSC */ + true); } + reset_sid_registers(); + reset_sid(); + + init_asid_buffer(framedelta_us); /* Init on env set */ + ring_buffer_reset_size(); /* Reset buffer to default size for new tune */ + + /* DON'T call reset_arrival_tracking() here */ + /* Instead, just accept that calculated rate will converge to framedelta */ + return; } -void handle_asid_envmessage(uint8_t* buffer) /* TODO: Update clock settings on the fly when env differs from config */ +/** + * @brief Process received environment + * + * @param uint8_t* buffer ~ the buffer containing the environment + */ +void handle_asid_envmessage(uint8_t* buffer) { /* SID environment is only logged and not used for now */ /* Incoming buffer skips first 3 bytes and starts at SETTINGS @@ -258,7 +395,7 @@ void handle_asid_envmessage(uint8_t* buffer) /* TODO: Update clock settings on t int speed_multiplier = (buffer[0] & 0b11110) >> 1; int custom_speed = (buffer[0] & 0b100000) >> 5; int buffering = (buffer[0] & 0b1000000) >> 6; - DBG("[ASID] Settings refresh rate: %s, speed multiplier: %d, custom speed: %d, buffering: %d\n", + usASID("Settings: refresh rate: %s, speed multiplier: %d, custom speed: %d, buffering: %d\n", (refresh_rate == 0 ? "PAL" : "NTSC"), speed_multiplier, custom_speed, buffering); /* @@ -272,8 +409,10 @@ void handle_asid_envmessage(uint8_t* buffer) /* TODO: Update clock settings on t bits1-0: framedelta uS (MSB) bits6-2: 5 bits (reserved) */ - uint16_t framedelta_us = (buffer[1] & 0x7F) | (buffer[2] & 0x7F) << 7 | (buffer[3] & 0x03) << 14; - DBG("[ASID] Framedelta: %d\n", framedelta_us); + uint16_t framedelta_us = ((buffer[1] & 0x7F) | (buffer[2] & 0x7F) << 7 | ((buffer[3] & 0x03) << 14)); + usASID("Framedelta: %d\n", framedelta_us); + set_asid_env(refresh_rate, speed_multiplier, custom_speed, buffering, framedelta_us); + return; } void handle_asid_typemessage(uint8_t* buffer) @@ -284,22 +423,29 @@ void handle_asid_typemessage(uint8_t* buffer) 0xF0, 0x2D, 0x32, SIDNO, SIDTYPE, 0x7F */ int sidtype = ((buffer[1] == 0) ? 3 : (buffer[1] == 1) ? 2 : 0); - DBG("[ASID] Tune SID %d type: %s\n", buffer[0], sidtypes[sidtype]); + usASID("Tune SID %d type: %s\n", buffer[0], sidtypes[sidtype]); + return; } /* Spy vs Spy ? */ void decode_asid_message(uint8_t* buffer, int size) { + static uint32_t rate; /* Tracks the rate of ASID messages */ switch(buffer[2]) { case 0x4C: /* Play start */ - DBG("[ASID] PLAY START\n"); + usASID("Play start\n"); + if (!buffer_started) init_asid_buffer(usbsid_config.refresh_rate); /* Start buffer on play start */ + reset_arrival_tracking(); /* Reset timing on play start */ + ring_buffer_reset_size(); /* Reset buffer to default size for new tune */ midimachine.bus = CLAIMED; break; case 0x4D: /* Play stop */ - DBG("[ASID] PLAY STOP\n"); - reset_sid(); - pause_sid(); + usASID("Play stop\n"); + reset_sid_registers(); if (!default_order) reset_asid_to_writeorder(); + set_buffer_rate(usbsid_config.refresh_rate); + ring_buffer_reset_size(); /* Reset buffer to default size */ + if (buffer_started) deinit_asid_buffer(); /* Stop buffer on play stop */ midimachine.bus = FREE; break; case 0x30: /* Write order timing (order and delay between individual SID register writes, to closely match the C64 driver used) */ @@ -315,21 +461,31 @@ void decode_asid_message(uint8_t* buffer, int size) case 0x4F: /* Display characters */ break; case 0x4E: /* SID 1 */ - if (!default_order) reset_asid_to_writeorder(); /* Set defaults once on first write */ - if (!write_ordered) handle_asid_message(0, &buffer[3]); - else handle_writeordered_asid_message(0, &buffer[3]); + if (!buffer_started) init_asid_buffer(usbsid_config.refresh_rate); /* Start buffer on first write */ + if (!default_order_on_start) reset_asid_to_writeorder(); /* Set defaults once on first write if not set yet */ + /* Only track arrival timing for SID1 - represents actual frame rate. + * Multi-SID tunes send multiple messages per frame (one per SID). */ + rate = track_asid_arrival(); + /* Adjust rate based on buffer state (called for all SIDs) */ + adjust_buffer_rate_dynamic(rate); + handle_writeordered_asid_message(0, &buffer[3]); break; case 0x50: /* SID 2 */ - if (!write_ordered) handle_asid_message(32, &buffer[3]); - else handle_writeordered_asid_message(32, &buffer[3]); + /* Update SID count and adjust rate - tracking only on SID1 for timing */ + extern void update_sid_count(uint8_t sid_num); + update_sid_count(2); + adjust_buffer_rate_dynamic(0); + handle_writeordered_asid_message(32, &buffer[3]); break; case 0x51: /* SID 3 */ - if (!write_ordered) handle_asid_message(64, &buffer[3]); - else handle_writeordered_asid_message(64, &buffer[3]); + update_sid_count(3); + adjust_buffer_rate_dynamic(0); + handle_writeordered_asid_message(64, &buffer[3]); break; case 0x52: /* SID 4 */ - if (!write_ordered) handle_asid_message(96, &buffer[3]); - else handle_writeordered_asid_message(96, &buffer[3]); + update_sid_count(4); + adjust_buffer_rate_dynamic(0); + handle_writeordered_asid_message(96, &buffer[3]); break; case 0x60: /* FMOpl */ if (cfg.fmopl_enabled) { /* Only if FMOpl is enabled, drop otherwise */ diff --git a/src/asid_buffer.c b/src/asid_buffer.c new file mode 100644 index 0000000..d6f925f --- /dev/null +++ b/src/asid_buffer.c @@ -0,0 +1,714 @@ +/* + * 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 + * + * asid_buffer.c + * This file is part of USBSID-Pico (https://github.com/LouDnl/USBSID-Pico) + * File author: LouD + * + * Huge thanks to Thomas Jansson for all his ASID improvement work (https://github.com/thomasj) + * + * 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-2026 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 "globals.h" +#include "config.h" +#include "pio.h" +#include "gpio.h" +#include "logging.h" +#include "asid.h" +#include "sid.h" + + +/* config.c */ +extern Config usbsid_config; + +/* bus.c */ +extern uint32_t clockcycles(void); + +/* PIO */ +PIO raster_pio = pio1; +static uint sm_buffer, offset_buffer; +bool buffer_sm_started = false; +bool buffer_sm_claimed = false; + +/* Arrival rate tracking */ +#define ARRIVAL_HISTORY_SIZE 8 +#define MULTISID_TIMEOUT_FRAMES 30 /* Reset to 1-SID after this many frames without SID2+ */ +#define NOWRITES_TIMEOUT_FRAMES 100 /* Disable everything after this amount of frames */ + +static bool still_receiving = false; +static uint32_t arrival_times[ARRIVAL_HISTORY_SIZE]; +volatile uint8_t arrival_index = 0; +volatile uint8_t arrival_count = 0; +volatile uint32_t calculated_rate = 0; +static uint16_t base_rate = 0; /* The rate from env message */ +static uint8_t sid_count_estimate = 1; /* Estimated number of SIDs in tune */ +volatile /* static */ uint8_t frames_since_nowrites = 0; /* Frames since last SID2/3/4 message */ +static uint8_t frames_since_multisid = 0; /* Frames since last SID2/3/4 message */ + +/* IRQ */ +int pio_irq; +static int8_t buffer_irq; +const int BUFFPIOIRQ = 2; +bool buffer_irq_started = false; +volatile uint32_t irq_now_at = 0; +volatile uint32_t irq_end_at = 0; +volatile uint32_t irq_prev_at = 0; + +/* Ring buffer */ +static const uint8_t ASID_FRAME_WRITES_MAX = 28; +static uint8_t ring_get(void); +static int ring_diff(void); +volatile uint16_t corrected_rate = 0; +uint8_t diff_size = (2 * (4 * ASID_FRAME_WRITES_MAX)); /* = 224 bytes | 112 bytes == 1 frame, was 64 bytes */ +typedef struct { + uint16_t ring_read; + uint16_t ring_write; + bool is_allocated; + uint8_t * __restrict__ ringbuffer; +} ring_buffer_t; +static ring_buffer_t __not_in_flash("asid_buffer") asid_ringbuffer; + +/* Dynamic ring buffer sizing */ +static const uint16_t RING_SIZE_MIN = (10 * 224); /* 2240 bytes - minimum size */ +static const uint16_t RING_SIZE_DEFAULT = (20 * 224); /* 4480 bytes - default/starting size */ +static const uint16_t RING_SIZE_MAX = (150 * 224); /* 33600 bytes - maximum size (~150 frames, ~33KB) */ +static const uint16_t RING_SIZE_STEP = (20 * 224); /* 4480 bytes - grow/shrink increment */ +volatile uint16_t ring_size = RING_SIZE_DEFAULT; /* Current effective size */ +static uint16_t ring_size_allocated = 0; /* Actual allocated size */ +/* TODO: REMOVE ~ TEMPORARY */ +volatile bool in_asid_irq = false; + + +/** + * Here be magicians + */ + +/** + * @brief Set the baseline rate from env message + * + * @param uint16_t rate ~ The framedelta_us from ASID env message + */ +void set_base_rate(uint16_t rate) +{ + base_rate = rate; + /* Reset tracking when base rate changes to avoid stale data */ + arrival_index = 0; + arrival_count = 0; + calculated_rate = 0; + for (int i = 0; i < ARRIVAL_HISTORY_SIZE; i++) { + arrival_times[i] = 0; + } + return; +} + +/** + * @brief Clamp value to asymmetric bounds around base_rate + * + * @param uint32_t rate ~ The rate to clamp + * + * @return uint32_t ~ Clamped rate within bounds + * + * Multi-SID tunes need faster consumption: + * - 2-SID: rate = base_rate / 2 + * - 3-SID: rate = base_rate / 3 + * - 4-SID: rate = base_rate / 4 + * - Fast CIA-timed 2-SID: can need up to base_rate / 6 + * Not working, the buffer just overflows: + * - 7x speed SID tunes: can need up to base_rate / 7 (Callapse_to_Center.sid Mibri) + * + * Allow rate to go as low as base_rate / 6 (~17%) for fast + * CIA-timed multi-SID tunes. + */ +static uint32_t clamp_to_base_rate(uint32_t rate) +{ + if (base_rate == 0) { + return rate; /* No base rate set, can't clamp */ + } + + /* Asymmetric bounds: + * - Minimum: base_rate / 6 (for fast CIA-timed multi-SID) + * - Maximum: base_rate * 1.2 (20% slower is plenty) */ + uint32_t min_rate = base_rate / 6; + if (min_rate < 1000) min_rate = 1000; /* Absolute minimum */ + + uint32_t max_rate = base_rate + (base_rate / 5); /* +20% */ + + if (rate < min_rate) return min_rate; + if (rate > max_rate) return max_rate; + return rate; +} + +/** + * @brief Track packet arrival and calculate dynamic rate + * @note Call this from decode_asid_message for SID1 only + * @note Auto-detects base_rate if not set by env message + * @note Auto-resets on long gaps (new tune detection) + * + * @return uint32_t ~ calculated frame rate in clock cycles (0 if not enough data) + */ +uint32_t track_asid_arrival(void) +{ + still_receiving = true; + + uint32_t now = clockcycles(); + + /* Detect long gap (new tune started without stop/start commands) + * If gap > 500ms (~500000 based on observed timing values), treat as new tune + * Typical frame delta is 16000-20000, so 500000 = ~25-30 frames missed */ + if (arrival_count > 0) { + uint8_t last_idx = (arrival_index + ARRIVAL_HISTORY_SIZE - 1) % ARRIVAL_HISTORY_SIZE; + uint32_t gap = now - arrival_times[last_idx]; + if (gap > 500000) { + /* Long gap detected - reset tracking for new tune */ + usASID("Long gap detected (%u) - new tune assumed\n", gap); + arrival_index = 0; + arrival_count = 0; + sid_count_estimate = 1; + frames_since_multisid = 0; + base_rate = 0; /* Reset base rate for new auto-detection */ + ring_size = RING_SIZE_DEFAULT; /* Reset buffer size for new tune */ + for (int i = 0; i < ARRIVAL_HISTORY_SIZE; i++) { + arrival_times[i] = 0; + } + } + } + + arrival_times[arrival_index] = now; + arrival_index = (arrival_index + 1) % ARRIVAL_HISTORY_SIZE; + + if (arrival_count < ARRIVAL_HISTORY_SIZE) { + arrival_count++; + return 0; /* Not enough samples yet */ + } + + /* Calculate average delta from oldest to newest */ + uint8_t oldest = arrival_index; /* Next write position = oldest */ + uint8_t newest = (arrival_index + ARRIVAL_HISTORY_SIZE - 1) % ARRIVAL_HISTORY_SIZE; + + /* Sanity check: oldest must be non-zero (not from cleared array) */ + if (arrival_times[oldest] == 0) { + return 0; + } + + uint32_t total_delta = arrival_times[newest] - arrival_times[oldest]; + uint32_t avg_delta = total_delta / (ARRIVAL_HISTORY_SIZE - 1); + + /* Absolute sanity bounds (reasonable frame rates: 10Hz to 500Hz) + * Based on log values, typical avg_delta is 5000-25000 + * PAL ~20000, NTSC ~17000, CIA-timed tunes can go much faster */ + if (avg_delta < 1000 || avg_delta > 50000) { + return 0; /* Outside reasonable range */ + } + + /* If base_rate not set (player skipped env message), auto-detect it ONCE. + * Don't update base_rate mid-tune - CIA-timed tunes have variable rates + * and we should let the dynamic adjustment handle that, not keep changing base_rate. */ + if (base_rate == 0) { + /* Use measured rate as base_rate - only set once */ + base_rate = (uint16_t)avg_delta; + usASID("Auto-detected base_rate: %u\n", base_rate); + } + + /* Don't validate against base_rate for CIA-timed tunes. + * Just use the measured rate directly - the clamping will + * keep it within reasonable bounds. */ + calculated_rate = avg_delta; + + return calculated_rate; +} + +/** + * @brief Grow the ring buffer when approaching overflow + * + * @return boolean true ~ if buffer was grown + * @return boolean false ~ if already at max + * + * Handles wrapped ring buffer by relocating data: + * - If write >= read: data is contiguous, just extend size + * - If write < read: data wrapped, need to move the tail portion + */ +static bool ring_buffer_grow(void) +{ + if (ring_size >= RING_SIZE_MAX) { + return false; /* Already at maximum */ + } + + uint16_t new_size = ring_size + RING_SIZE_STEP; + if (new_size > RING_SIZE_MAX) { + new_size = RING_SIZE_MAX; + } + + /* Handle wrapped data: relocate the portion at the start of buffer */ + if (asid_ringbuffer.ring_write < asid_ringbuffer.ring_read) { + /* Data is in two segments: [read..ring_size) and [0..write) + * Move [0..write) to [ring_size..ring_size+write) to make it contiguous */ + if (asid_ringbuffer.ring_write > 0) { + memmove(&asid_ringbuffer.ringbuffer[ring_size], + &asid_ringbuffer.ringbuffer[0], + asid_ringbuffer.ring_write); + asid_ringbuffer.ring_write = ring_size + asid_ringbuffer.ring_write; + } + } + + ring_size = new_size; + usASID("Buffer grown to %u bytes (diff=%d)\n", ring_size, ring_diff()); + return true; +} + +/** + * @brief Reset ring buffer size to default + * @note Call when starting a new tune to reclaim memory + */ +void ring_buffer_reset_size(void) +{ + ring_size = RING_SIZE_DEFAULT; + usASID("Buffer size reset to %u bytes\n", ring_size); + return; +} + +/** + * @brief Update SID count when we see a multi-SID message + * @note Call from decode_asid_message when processing SID2/3/4 messages + * + * @param uint8_t sid_num ~ The SID number (1-4) from the message type + */ +void update_sid_count(uint8_t sid_num) +{ + still_receiving = true; + + /* Reset timeout - we just saw a multi-SID message */ + frames_since_multisid = 0; + + if (sid_num > sid_count_estimate) { + sid_count_estimate = sid_num; + usASID("SID count updated to %u\n", sid_count_estimate); + } + return; +} + +/** + * @brief Dynamically adjust buffer rate based on calculated rate and buffer state + * @param uint32_t target_rate ~ The calculated frame rate from track_asid_arrival (0 if not available) + * + * Strategy: + * 1. Use calculated rate (CR) as the primary guide for rate + * 2. Use actual SID count from received messages (set via update_sid_count) + * 3. Apply buffer-based corrections only when buffer is critically full/empty + * 4. Grow buffer if approaching overflow + */ +void adjust_buffer_rate_dynamic(uint32_t target_rate) +{ + still_receiving = true; + + /* Get current buffer fullness */ + int diff = ring_diff(); + + /* Track frames since last multi-SID message (only on SID1 frames) */ + if (target_rate > 0 && sid_count_estimate > 1) { + frames_since_multisid++; + if (frames_since_multisid > MULTISID_TIMEOUT_FRAMES) { + /* Haven't seen SID2/3/4 for a while - assume single-SID now */ + usASID("No multi-SID messages for %u frames, resetting to 1-SID\n", + frames_since_multisid); + sid_count_estimate = 1; + frames_since_multisid = 0; + } + } + + /* Calculate target rate based on CR and actual SID count */ + int32_t new_rate; + if (target_rate > 0) { + /* Use calculated rate divided by SID count */ + new_rate = (int32_t)(target_rate / sid_count_estimate); + } else { + /* No valid CR yet, use current rate with buffer adjustment */ + new_rate = (int32_t)corrected_rate; + } + + /* Check if buffer is approaching overflow - grow if needed */ + int headroom = (int)ring_size - diff; + if (headroom < (diff_size * 4)) { + /* Less than 4 frames of headroom - try to grow */ + if (!ring_buffer_grow()) { + /* Can't grow - emergency rate reduction needed */ + if (headroom < diff_size) { + /* Critical: less than 1 frame headroom, aggressive reduction */ + new_rate = new_rate * 3 / 4; /* 25% reduction */ + usASID("Emergency rate reduction: %d\n", new_rate); + } + } + } + + /* Apply buffer-based fine-tuning based on buffer fullness percentage */ + int fill_percent = (diff * 100) / (int)ring_size; + if (fill_percent > 95) { + new_rate -= 500; /* Near overflow - aggressive */ + } else if (fill_percent > 90) { + new_rate -= 300; + } else if (fill_percent > 80) { + new_rate -= 150; + } else if (fill_percent > 60) { + new_rate -= 50; + } else if (diff < (diff_size / 2)) { + new_rate += 100; /* Buffer nearly empty */ + } else if (diff < diff_size) { + new_rate += 50; + } + /* else: buffer in acceptable range, use rate as-is */ + + /* Clamp to bounds */ + new_rate = (int32_t)clamp_to_base_rate((uint32_t)(new_rate > 0 ? new_rate : 1)); + + /* Apply if significantly different (small hysteresis) */ + int32_t rate_diff = (int32_t)corrected_rate - new_rate; + if (rate_diff < 0) rate_diff = -rate_diff; + + if (rate_diff > 50) { + pio_sm_put(raster_pio, sm_buffer, (uint32_t)new_rate); + corrected_rate = (uint16_t)new_rate; + } + return; +} + +/** + * @brief Reset arrival tracking state + * @note Clears timestamps and counters but preserves base_rate + * @note base_rate is only set via set_buffer_rate() + */ +void reset_arrival_tracking(void) +{ + arrival_index = 0; + arrival_count = 0; + calculated_rate = 0; + sid_count_estimate = 1; /* Reset SID count estimate */ + frames_since_multisid = 0; /* Reset multi-SID timeout */ + /* Clear stale timestamps to prevent bogus deltas */ + for (int i = 0; i < ARRIVAL_HISTORY_SIZE; i++) { + arrival_times[i] = 0; + } + /* Note: don't reset base_rate here, it's set from set_buffer_rate() */ + return; +} + + +/** + * Here be IRQ and PIO magic mushrooms + */ + +/** + * @brief buffer interrupt handler + * @note writes data from the ringbuffer to the SIDs + */ +void __not_in_flash_func(buffer_irq_handler)(void) +{ + in_asid_irq = true; + irq_prev_at = irq_now_at; + irq_now_at = clockcycles(); + + /* inline extern as only used here */ + extern void cycled_write_operation(uint8_t address, uint8_t data, uint16_t cycles); + + /* Retrieve the current diff */ + int current_diff = ring_diff(); + /* Only start if head and tail are not the same */ + if(asid_ringbuffer.ring_read != asid_ringbuffer.ring_write) { + // if (current_diff > (diff_size + (28 * 4))) { // Ensure we keep diff_size bytes after reading + /* Only consume if we have enough data AND will stay above minimum */ + if (current_diff > diff_size) { // Ensure we keep diff_size bytes after reading + for (size_t pos = 0; pos < 28; pos++) { + uint8_t reg = ring_get(); + uint8_t val = ring_get(); + uint8_t c_hi = ring_get(); + uint8_t c_lo = ring_get(); + if (reg != 0xffu) { + cycled_write_operation(reg,val,(c_hi<<8|c_lo)); + } + } + } + } + + if (!still_receiving) { + frames_since_nowrites++; + if (frames_since_nowrites > NOWRITES_TIMEOUT_FRAMES) { + extern void deinit_asid_buffer(void); + usASID("More then 100 frames since last write, deactivating\n"); + frames_since_nowrites = frames_since_multisid = 0; + base_rate = corrected_rate = calculated_rate = 0; + arrival_index = arrival_count = 0; + irq_prev_at = irq_now_at = irq_end_at = 0; + pio_interrupt_clear(raster_pio, BUFFPIOIRQ); + deinit_asid_buffer(); + return; + } + } + + irq_end_at = clockcycles(); + if ((irq_end_at-irq_now_at) <= 1) { + still_receiving = false; + } else { + frames_since_nowrites = 0; + still_receiving = true; + } + in_asid_irq = false; + + /* Interrupt cleared at end of routine + * if play becomes irregular, irq's might be + * misfiring and moving the clearing to the + * beginning of the routine might help + */ + pio_interrupt_clear(raster_pio, BUFFPIOIRQ); + return; +} + +/** + * @brief initialize the buffer irq + * @note sets the interrupt number and handler + * @note sets the irq source and enables the irq + */ +void init_buffer_irq(void) +{ + if (!buffer_irq_started) { + usASID("Enabling buffer IRQ\n"); + buffer_irq = pis_interrupt2; /* PIO_INTR_SM2_LSB hardware/pio.h */ + pio_irq = pio_get_irq_num(raster_pio, 0); + irq_set_exclusive_handler(pio_irq, buffer_irq_handler); + pio_set_irq0_source_enabled(raster_pio, buffer_irq + sm_buffer, true); + irq_set_enabled(pio_irq, true); + buffer_irq_started = true; + } + return; +} + +/** + * @brief initializes the raster_pio + * @note also claims the pio statemachine + */ +void init_buffer_pio(void) +{ /* buffer cycle counter */ + sm_buffer = 0; /* PIO1 SM0 */ + if (!buffer_sm_claimed) { + usASID("Starting & claiming buffer pio\n"); + pio_sm_claim(raster_pio, sm_buffer); + offset_buffer = pio_add_program(raster_pio, &raster_buffer_program); + pio_sm_config c_buffer = raster_buffer_program_get_default_config(offset_buffer); + sm_config_set_fifo_join(&c_buffer, PIO_FIFO_JOIN_TX); + pio_sm_init(raster_pio, sm_buffer, offset_buffer, &c_buffer); + buffer_sm_claimed = true; + } + return; +} + +/** + * @brief enable the raster_pio statemachine + */ +void start_buffer_pio(void) +{ + if (!buffer_sm_started) { + usASID("Enabling buffer statemachine\n"); + pio_sm_set_enabled(raster_pio, sm_buffer, true); + buffer_sm_started = true; + } + return; +} + +/** + * @brief stop the asid buffer handling + * @note frees the irq and stops the irq_handler + * @note disables the raster_pio statemachine + * @note unclaims the statemadhine on the pio + */ +void stop_buffer_pio(void) +{ + if (buffer_irq_started) { + irq_set_enabled(pio_irq, false); + pio_set_irq0_source_enabled(raster_pio, buffer_irq + sm_buffer, false); + irq_remove_handler(pio_irq, buffer_irq_handler); + buffer_irq_started = false; + usASID("Buffer IRQ released\n"); + } + if (buffer_sm_started) { + pio_sm_set_enabled(raster_pio, sm_buffer, false); + buffer_sm_started = false; + usASID("Buffer statemachine disabled\n"); + } + if (buffer_sm_claimed) { + pio_remove_program(raster_pio, &raster_buffer_program, offset_buffer); + pio_sm_unclaim(raster_pio, sm_buffer); + buffer_sm_claimed = false; + usASID("Buffer statemachine released\n"); + } + return; +} + +/** + * @brief sets the asid buffer raster rate + * @note the raster_rate pio has a 1 cycle overhead + * @note this requires the rate to be corrected with + * @note subtraction of a single cycle. + * @note the function does this if the provided + * @note rate is higher than zero. + * + * @param uint16_t rate ~ the buffer irq rate to set + */ +void set_buffer_rate(uint16_t rate) +{ + corrected_rate = ((rate > 0) ? (rate - 1) : (usbsid_config.refresh_rate - 1)); + + /* Store as base rate for dynamic adjustment bounds */ + set_base_rate(corrected_rate); + + usASID("Rate received %u Rate set %u Base rate %u\n", rate, corrected_rate, base_rate); + if (!buffer_irq_started) init_buffer_irq(); + pio_sm_put(raster_pio, sm_buffer, corrected_rate); + start_buffer_pio(); + return; +} + + +/** + * Here be ringbuffer shizzle + */ + +/** + * @brief reset the head and tail to zero + */ +static void ring_buffer_reset(void) +{ + asid_ringbuffer.ring_read = asid_ringbuffer.ring_write = 0; + return; +} + +/** + * @brief returns the difference between head and tail + * + * @return int ~ the head -> tail difference + */ +static int __not_in_flash_func(ring_diff)(void) +{ + return (asid_ringbuffer.ring_write - asid_ringbuffer.ring_read + ring_size) % ring_size; +} + +/** + * @brief Check if buffer would overflow with next write + * + * @return boolean ~ true if there's no room for another frame (112 bytes) + * @return boolean ~ false if there is + */ +static bool ring_would_overflow(void) +{ + int headroom = (int)ring_size - ring_diff(); + return headroom < 112; /* Need room for at least 1 frame (28 writes * 4 bytes) */ +} + +/** + * @brief put an item into the ringbuffer + * @note Checks for overflow and drops data if buffer is full + * + * @param uint8_t item ~ item to store + */ +static void ring_put(uint8_t item) +{ + /* Check for overflow - if we're about to overwrite unread data, skip this write */ + uint16_t next_write = (asid_ringbuffer.ring_write + 1) % ring_size; + if (next_write == asid_ringbuffer.ring_read) { + /* Buffer full - would overflow. Drop this byte to prevent corruption. */ + usASID("Buffer overflow - dropping data\n"); + return; + } + + asid_ringbuffer.ringbuffer[asid_ringbuffer.ring_write] = item; + asid_ringbuffer.ring_write = next_write; + return; +} + +/** + * @brief retrieves an item from the ring buffer + * + * @return uint8_t ~ the retrieved ring item + */ +static uint8_t __not_in_flash_func(ring_get)(void) +{ + uint8_t item = asid_ringbuffer.ringbuffer[asid_ringbuffer.ring_read]; + asid_ringbuffer.ring_read = (asid_ringbuffer.ring_read + 1) % ring_size; + return item; +} + +/** + * @brief intialize the ring buffer + * @note Allocates maximum size upfront to allow dynamic growth + */ +void asid_ring_init(void) +{ + if (!asid_ringbuffer.is_allocated) { + if (asid_ringbuffer.ringbuffer != NULL) { free(asid_ringbuffer.ringbuffer); } + /* Allocate max size upfront - allows growth without reallocation */ + asid_ringbuffer.ringbuffer = (uint8_t*)calloc(RING_SIZE_MAX, 1); + ring_size_allocated = RING_SIZE_MAX; + ring_size = RING_SIZE_DEFAULT; /* Start with default logical size */ + asid_ringbuffer.is_allocated = true; + ring_buffer_reset(); + usASID("Ringbuffer initialized (allocated=%u, effective=%u)\n", + ring_size_allocated, ring_size); + } + return; +} + +/** + * @brief de-intialize the ring buffer + */ +void asid_ring_deinit(void) +{ + if (asid_ringbuffer.is_allocated) { + ring_buffer_reset(); + free(asid_ringbuffer.ringbuffer); + asid_ringbuffer.ringbuffer = NULL; + asid_ringbuffer.is_allocated = false; + } + return; +} + +/** + * @brief write data to the ringbuffer + * @note writes 4 items per call + * + * @param uint8_t reg ~ SID register + * @param uint8_t val ~ value + * @param uint16_t c ~ delay cycles + */ +void asid_ring_write(uint8_t reg, uint8_t val, uint16_t c) +{ + ring_put(reg); + ring_put(val); + ring_put((uint8_t)((c&0xff00u)>>8)); + ring_put((uint8_t)(c&0xffu)); + return; +} diff --git a/src/bus.c b/src/bus.c index c6c5357..8b7a46a 100644 --- a/src/bus.c +++ b/src/bus.c @@ -38,7 +38,7 @@ #ifdef ONBOARD_EMULATOR extern uint8_t *sid_memory; #else -extern uint8_t __not_in_flash("usbsid_buffer") sid_memory[(0x20 * 4)] __attribute__((aligned(2 * (0x20 * 4)))); +extern uint8_t sid_memory[(0x20 * 4)]; #endif /* config.c */ @@ -54,6 +54,7 @@ extern uint16_t vu; /* dma.c */ extern void setup_dmachannels(void); extern void unclaim_dma_channels(void); +extern volatile uint32_t cycle_count_word; /* pio.c */ extern void setup_piobus(void); @@ -61,7 +62,7 @@ extern void sync_pios(bool at_boot); extern void stop_pios(void); /* globals */ -bool is_muted; /* Global muting state */ +volatile bool is_muted; /* Global muting state */ /* Direct Pio IRQ access */ volatile const uint32_t *IRQState = &pio0_hw->irq; @@ -71,10 +72,15 @@ uint8_t control_word, read_data; uint16_t delay_word; uint32_t data_word, dir_mask; - +/** + * @brief Set the bits going to the PIO databus based on provided address + * + * @param uint8_t address + * @param bool write + */ inline static int __not_in_flash_func(set_bus_bits)(uint8_t address, bool write) { - /* CFG("[BUS BITS]$%02X:%02X ", address, data); */ + /* usCFG("[BUS BITS]$%02X:%02X ", address, data); */ vu = (vu == 0 ? 100 : vu); /* NOTICE: Testfix for core1 setting dtype to 0 */ if __us_likely(write) { control_word = 0b111000; @@ -111,13 +117,22 @@ inline static int __not_in_flash_func(set_bus_bits)(uint8_t address, bool write) break; } data_word = (dir_mask << 16) | data_word; - // CFG("$%02X:%02X $%04X 0b"PRINTF_BINARY_PATTERN_INT32" $%04X 0b"PRINTF_BINARY_PATTERN_INT16"\n", + // usCFG("$%02X:%02X $%04X 0b"PRINTF_BINARY_PATTERN_INT32" $%04X 0b"PRINTF_BINARY_PATTERN_INT16"\n", // address, data, data_word, PRINTF_BYTE_TO_BINARY_INT32(data_word), control_word, PRINTF_BYTE_TO_BINARY_INT16(control_word)); return 1; } +/** + * @brief Write data to or read data from the databus + * @note uses PIO0 SM0, SM1, SM2 & SM3 + * WARNING: DEPRECATED AND NO LONGER WORKS, HERE FOR CODE HISTORY ONLY!! + * + * @param uint8_t command + * @param uint8_t address + * @param uint8_t data + */ 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, HERE FOR CODE HISTORY ONLY!! */ +{ return 0; if __us_unlikely((command & 0xF0) != 0x10) { return 0; // Sync bit not set, ignore operation @@ -155,7 +170,7 @@ uint8_t __no_inline_not_in_flash_func(bus_operation)(uint8_t command, uint8_t ad read_data = 0x0; dma_channel_set_write_addr(dma_rx_data, &read_data, true); dma_channel_wait_for_finish_blocking(dma_rx_data); - GPIODBG("[W]$%08x 0b"PRINTF_BINARY_PATTERN_INT32" $%04x 0b"PRINTF_BINARY_PATTERN_INT16"\n[R]$%08x 0b"PRINTF_BINARY_PATTERN_INT32"\n", + usGPIO("[W]$%08x 0b"PRINTF_BINARY_PATTERN_INT32" $%04x 0b"PRINTF_BINARY_PATTERN_INT16"\n[R]$%08x 0b"PRINTF_BINARY_PATTERN_INT32"\n", data_word, PRINTF_BYTE_TO_BINARY_INT32(data_word), control_word, PRINTF_BYTE_TO_BINARY_INT16(control_word), read_data, PRINTF_BYTE_TO_BINARY_INT32(read_data)); @@ -164,10 +179,17 @@ uint8_t __no_inline_not_in_flash_func(bus_operation)(uint8_t command, uint8_t ad } /* WRITE, G_PAUSE & G_CLEAR_BUS*/ dma_channel_wait_for_finish_blocking(dma_tx_control); - GPIODBG("[W]$%08x 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)); + usGPIO("[W]$%08x 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 0; } +/** + * @brief Cycle delay function + * blocks for supplied number of cycles (65535 max) + * @note uses DMA & PIO0 SM0 & SM3 + * + * @param uint16_t cycles + */ uint16_t __no_inline_not_in_flash_func(cycled_delay_operation)(uint16_t cycles) { /* This is a blocking function! */ if __us_unlikely(cycles == 0) return 0; /* No point in waiting zero cycles */ @@ -188,47 +210,105 @@ uint16_t __no_inline_not_in_flash_func(cycled_delay_operation)(uint16_t cycles) return 0; } -uint8_t __no_inline_not_in_flash_func(cycled_read_operation)(uint8_t address, uint16_t cycles) +/** + * @brief Write data to the bus at address + * does not wait for the PIO write to finish + * @note uses PIO0 SM0, SM1 & SM2 + * + * @param uint8_t address + * @param uint8_t data + */ +void __no_inline_not_in_flash_func(write_operation)(uint8_t address, uint8_t data) { - delay_word = cycles; - if __us_unlikely(set_bus_bits(address, false) != 1) { - return 0x00; + sid_memory[(address & 0x7F)] = data; + if __us_unlikely(set_bus_bits(address, true) != 1) { + return; } - dma_channel_set_read_addr(dma_tx_delay, &delay_word, false); - dma_channel_set_read_addr(dma_tx_control, &control_word, false); - dma_channel_set_read_addr(dma_tx_data, &data_word, false); - dma_channel_set_write_addr(dma_rx_data, &read_data, false); - dma_hw->multi_channel_trigger = ( - 1u << dma_tx_delay /* Delay cycles DMA transfer */ - //#if PICO_PIO_VERSION > 0 /* rp2040 only for now, see notice in setup_dmachannels */ - | 1u << dma_tx_control /* Control lines RW, CS1 & CS2 DMA transfer */ - | 1u << dma_tx_data /* Data & Address DMA transfer */ - //#endif - | 1u << dma_rx_data /* Read data DMA transfer */ - ); - dma_channel_wait_for_finish_blocking(dma_rx_data); /* Wait for data */ - sid_memory[(address & 0x7F)] = (read_data & 0xFF); - return (read_data & 0xFF); + 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, PHI1)); + pio_sm_exec(bus_pio, sm_control, pio_encode_wait_pin(true, PHI1)); + 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(write_operation)(uint8_t address, uint8_t data) +/** + * @brief Write data to the bus at address + * The PIO bus waits n cycles before the write occurs + * does not wait for the PIO write to finish + * @note uses PIO0 SM0, SM1, SM2 & SM3 + * + * @param uint8_t address + * @param uint8_t data + * @param uint16_t cycles + */ +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; if __us_unlikely(set_bus_bits(address, true) != 1) { return; } + 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); + + usGPIO("[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; +} + +/** + * @brief Write data to the bus at address + * The function waits n cycles before the write + * occurs by using `cycled_delay_operation` + * and then waits for the DMA to finish blocking + * @note uses DMA & PIO0 SM0, SM1, SM2 & SM3 + * + * @param uint8_t address + * @param uint8_t data + * @param uint16_t cycles + */ +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 */ + if __us_unlikely(set_bus_bits(address, true) != 1) { + return 0; + } + + 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, PHI1)); pio_sm_exec(bus_pio, sm_control, pio_encode_wait_pin(true, PHI1)); - pio_sm_put_blocking(bus_pio, sm_control, control_word); - pio_sm_put_blocking(bus_pio, sm_data, data_word); + 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; + return cycles; } +/** + * @brief Write data to the bus at address + * and then waits for the DMA to finish blocking + * The PIO bus waits n cycles before the write occurs + * @note uses DMA & PIO0 SM0, SM1, SM2 & SM3 + * + * @param uint8_t address + * @param uint8_t data + * @param uint16_t cycles + */ void __no_inline_not_in_flash_func(cycled_write_operation)(uint8_t address, uint8_t data, uint16_t cycles) { delay_word = cycles; @@ -255,58 +335,56 @@ void __no_inline_not_in_flash_func(cycled_write_operation)(uint8_t address, uint */ dma_channel_wait_for_finish_blocking(dma_tx_control); - GPIODBG("[WC]$%04x 0b"PRINTF_BINARY_PATTERN_INT32" $%04x 0b"PRINTF_BINARY_PATTERN_INT16" $%02X:%02X(%u %u)\n", + usGPIO("[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; } -void __no_inline_not_in_flash_func(cycled_write_operation_nondma)(uint8_t address, uint8_t data, uint16_t cycles) +/** + * @brief Read data from the bus at address + * and then waits for the DMA to finish blocking + * The PIO bus waits n cycles before the read occurs + * @note uses DMA & PIO0 SM0, SM1, SM2 & SM3 + * + * @param uint8_t address + * @param uint16_t cycles + */ +uint8_t __no_inline_not_in_flash_func(cycled_read_operation)(uint8_t address, uint16_t cycles) { delay_word = cycles; - sid_memory[(address & 0x7F)] = data; - if __us_unlikely(set_bus_bits(address, true) != 1) { - return; - } - - 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 */ - if __us_unlikely(set_bus_bits(address, true) != 1) { - return 0; + if __us_unlikely(set_bus_bits(address, false) != 1) { + return 0x00; } + dma_channel_set_read_addr(dma_tx_delay, &delay_word, false); 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, PHI1)); - pio_sm_exec(bus_pio, sm_control, pio_encode_wait_pin(true, PHI1)); + dma_channel_set_write_addr(dma_rx_data, &read_data, false); dma_hw->multi_channel_trigger = ( - 1u << dma_tx_control /* Control lines RW, CS1 & CS2 DMA transfer */ + 1u << dma_tx_delay /* Delay cycles DMA transfer */ + //#if PICO_PIO_VERSION > 0 /* rp2040 only for now, see notice in setup_dmachannels */ + | 1u << dma_tx_control /* Control lines RW, CS1 & CS2 DMA transfer */ | 1u << dma_tx_data /* Data & Address DMA transfer */ + //#endif + | 1u << dma_rx_data /* Read data DMA transfer */ ); - dma_channel_wait_for_finish_blocking(dma_tx_control); - - return cycles; + dma_channel_wait_for_finish_blocking(dma_rx_data); /* Wait for data */ + sid_memory[(address & 0x7F)] = (read_data & 0xFF); + return (read_data & 0xFF); } +/** + * @brief Restart the PIO bus by unclaiming + * the DMA channels, stopping the PIO + * statemachines and then restarting + * everything + * Synchronizes the PIO statemachines + * afterwards + */ void restart_bus(void) { - CFG("[RESTART BUS START]\n"); + usCFG("[RESTART BUS START]\n"); /* unclaim dma channels */ unclaim_dma_channels(); /* stop all pio's */ @@ -317,6 +395,41 @@ void restart_bus(void) setup_dmachannels(); /* sync pios */ sync_pios(false); - CFG("[RESTART BUS END]\n"); + usCFG("[RESTART BUS END]\n"); + return; +} + +/** + * @brief Returns the amount of C64 cpu clock + * cycles counted by the counter SM and updated + * by a continous running DMA channel + * + * @note rp2350 uses a single DMA channel and native endless transfer + * @note rp2040 uses a two chained DMA channels for endless transfer + * + * @returns uint32_t */ +uint32_t clockcycles(void) +{ + return (uint32_t)cycle_count_word; +} + +/** + * @brief Delay for n PHI1 clockcycles + * Will do a cycled delay with cycle counter + * @note rp2350 uses a single DMA channel and native endless transfer + * @note rp2040 uses a two chained DMA channels for endless transfer + * + * NOTICE: Will crap out if delay cycles wrap around __UINT32_MAX__ after ~71 minutes + * + * @param uint32_t n_cycles + */ +void clockcycle_delay(uint32_t n_cycles) +{ /* */ + if __us_unlikely(n_cycles == 0) return; + int32_t now, end; + now = end = clockcycles(); + do { + end = clockcycles(); + } while ((uint32_t)(end - now) < n_cycles); return; } diff --git a/src/config.c b/src/config.c index 802f8b3..0715828 100644 --- a/src/config.c +++ b/src/config.c @@ -56,9 +56,9 @@ extern bool offload_ledrunner; #endif /* GPIO */ -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_delay_operation)(uint16_t cycles); +extern uint8_t cycled_read_operation(uint8_t address, uint16_t cycles); +extern void cycled_write_operation(uint8_t address, uint8_t data, uint16_t cycles); +extern uint16_t cycled_delay_operation(uint16_t cycles); extern void reset_sid(void); extern void restart_bus(void); extern void restart_bus_clocks(void); @@ -188,7 +188,7 @@ void read_config(Config* config) { memset(config_array, 0, sizeof config_array); /* Make sure we don't send garbled old data */ - CFG("[CONFIG] [READ CONFIG] [FROM]0x%X [TO]0x%X [SIZE]%u\n", (uint)config, &config_array, sizeof(Config)); + usCFG("[READ CONFIG] [FROM]0x%X [TO]0x%X [SIZE]%u\n", (uint)config, &config_array, sizeof(Config)); config_array[0] = READ_CONFIG; /* Initiator byte */ config_array[1] = 0x7F; /* Verification byte */ @@ -278,42 +278,41 @@ void __no_inline_not_in_flash_func(default_config)(Config* config) void __no_inline_not_in_flash_func(load_config)(Config* config) { print_cfg_addr(); - CFG("\n"); - CFG("[START LOAD CONFIG]\n"); + usCFG("[START LOAD CONFIG]\n"); int savelocationid = 0; /* counter for finding the current save location */ AGAIN: Config temp_config; /* NOTICE: Do not do any logging here after memcpy or the Pico will freeze! */ 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); + usCFG("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 */ && temp_config.config_saveid == savelocationid) { /* Found previously saved config */ savelocationid++; /* Increase id and try again */ goto AGAIN; } else { /* They are not equal, that means this config is an empty save location or corrupted, load the previous config */ - CFG("[CONFIG] FOUND LATEST CONFIG AT SAVE POSITION %d (255 == empty slot)\n", (savelocationid-1)); + usCFG("FOUND LATEST CONFIG AT SAVE POSITION %d (255 == empty slot)\n", (savelocationid-1)); savelocationid--; memcpy(config, (void *)(XIP_BASE + (FLASH_CONFIG_OFFSET + (FLASH_PAGE_SIZE * savelocationid))), sizeof(Config)); stdio_flush(); } config_saveid = config->config_saveid; /* copy saveid into variable */ - CFG("[CONFIG] LOADED FROM SAVE POSITION: %d\n", config->config_saveid); + usCFG("LOADED FROM SAVE POSITION: %d\n", config->config_saveid); - CFG("[CONFIG] COPIED CONFIG:\n[CONFIG] [FROM]0x%X\n[CONFIG] [TO]0x%X\n[CONFIG] [SIZE]%u\n", + usCFG("COPIED CONFIG:\n[FROM] 0x%X\n[TO] 0x%X\n[SIZE] %u\n", (FLASH_CONFIG_OFFSET + (FLASH_PAGE_SIZE * savelocationid)), (uint)config, sizeof(Config)); - CFG("[CONFIG] COPIED CONFIG ADDRESSES:\n[CONFIG] [&usbsid_config]0x%X\n[CONFIG] [config]0x%X\n[CONFIG] [&config]0x%X\n", + usCFG("COPIED CONFIG ADDRESSES:\n[&usbsid_config] 0x%X\n[config] 0x%X\n[&config] 0x%X\n", (uint)&usbsid_config, (uint)config, (uint)&config); cm_verification = config->magic; /* Store the current magic for later */ if (config->magic != MAGIC_SMOKE) { /* Verify the magic */ - CFG("[CONFIG] [MAGIC ERROR] config->magic: %u != MAGIC_SMOKE: %u\n", config->magic, MAGIC_SMOKE); - CFG("[CONFIG] RESET TO DEFAULT CONFIG!\n"); + usCFG("[MAGIC ERROR] config->magic: %u != MAGIC_SMOKE: %u\n", config->magic, MAGIC_SMOKE); + usCFG("RESET TO DEFAULT CONFIG!\n"); default_config(config); } - CFG("[END LOAD CONFIG]\n"); + usCFG("[END LOAD CONFIG]\n"); return; } @@ -336,7 +335,7 @@ void __no_inline_not_in_flash_func(write_config)(const Config* config) memcpy(config_data, config, sizeof(Config)); int err = flash_safe_execute(write_config_lowlevel, config_data, 100); if (err) { - CFG("[CONFIG] SAVE ERROR: %d\n", err); + usCFG("SAVE ERROR: %d\n", err); } sleep_ms(100); return; @@ -344,21 +343,21 @@ void __no_inline_not_in_flash_func(write_config)(const Config* config) void __no_inline_not_in_flash_func(save_config)(Config* config) { - CFG("[CONFIG] SAVE CONFIG START\n"); + usCFG("SAVE CONFIG START\n"); /* Verify config saveid and increase */ int noerr = (config->config_saveid == config_saveid); if (noerr) { /* Only increase id's if both are equal */ config_saveid++; config_saveid = config->config_saveid = (config_saveid <= 0xF ? config_saveid : 0); - CFG("[CONFIG] SAVING CONFIG WITH ID %d AT 0x%X (%u)\n", config_saveid, + usCFG("SAVING CONFIG WITH ID %d AT 0x%X (%u)\n", config_saveid, (FLASH_CONFIG_OFFSET + (FLASH_PAGE_SIZE * config_saveid)), (FLASH_CONFIG_OFFSET + (FLASH_PAGE_SIZE * config_saveid))); } else { - CFG("[ERROR] CONFIG SAVE ID's are not equal %d != %d. UNABLE TO SAVE CONFIG!!\n", config->config_saveid, config_saveid); + usCFG("[ERROR] CONFIG SAVE ID's are not equal %d != %d. UNABLE TO SAVE CONFIG!!\n", config->config_saveid, config_saveid); return; } write_config(config); - CFG("[CONFIG] SAVE CONFIG END\n"); + usCFG("SAVE CONFIG END\n"); return; } @@ -395,15 +394,15 @@ void write_back_data(size_t buffersize) void handle_config_request(uint8_t * buffer, uint32_t size) { 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]); + usCFG("[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"); + usCFG("[CMD] RESET_USBSID\n"); mcu_reset(); break; case READ_CONFIG: - CFG("[CMD] READ_CONFIG\n"); + usCFG("[CMD] READ_CONFIG\n"); /* ISSUE: Although 4 writes are performed, only the first 2 are received */ read_config(&usbsid_config); print_cfg(config_array, count_of(config_array)); @@ -415,7 +414,7 @@ void handle_config_request(uint8_t * buffer, uint32_t size) } break; case READ_SOCKETCFG: - CFG("[CMD] READ_SOCKETCFG\n"); + usCFG("[CMD] READ_SOCKETCFG\n"); read_socket_config(&usbsid_config); print_cfg(socket_config_array, 10); memset(write_buffer_p, 0, 64); @@ -423,23 +422,23 @@ void handle_config_request(uint8_t * buffer, uint32_t size) write_back_data(10); break; case READ_NUMSIDS: - CFG("[CMD] READ_NUMSIDS: %u\n", (uint8_t)cfg.numsids); + usCFG("[CMD] READ_NUMSIDS: %u\n", (uint8_t)cfg.numsids); memset(write_buffer_p, 0, 64); write_buffer_p[0] = (uint8_t)cfg.numsids; write_back_data(1); break; case READ_FMOPLSID: - CFG("[CMD] READ_FMOPLSID\n"); + usCFG("[CMD] READ_FMOPLSID\n"); memset(write_buffer_p, 0, 64); write_buffer_p[0] = (uint8_t)cfg.fmopl_sid; write_back_data(1); break; case APPLY_CONFIG: - CFG("[CMD] APPLY_CONFIG\n"); + usCFG("[CMD] APPLY_CONFIG\n"); apply_config(false, true); break; case RELOAD_CONFIG: - CFG("[CMD] RELOAD_CONFIG\n"); + usCFG("[CMD] RELOAD_CONFIG\n"); load_config(&usbsid_config); apply_config(false, true); for (uint i = 0; i < count_of(clockrates); i++) { @@ -449,7 +448,7 @@ void handle_config_request(uint8_t * buffer, uint32_t size) } break; case SET_CONFIG: - CFG("[CMD] SET_CONFIG\n"); + usCFG("[CMD] SET_CONFIG\n"); switch (buffer[1]) { case 0: /* clock_rate */ /* will always be available to change the setting since it doesn't apply it */ @@ -619,17 +618,17 @@ void handle_config_request(uint8_t * buffer, uint32_t size) }; break; case SAVE_CONFIG: - CFG("[CMD] SAVE_CONFIG and RESET_MCU\n"); + usCFG("[CMD] SAVE_CONFIG and RESET_MCU\n"); save_config(&usbsid_config); load_config(&usbsid_config); mcu_reset(); break; case SAVE_NORESET: - CFG("[CMD] SAVE_CONFIG no RESET\n"); + usCFG("[CMD] SAVE_CONFIG no RESET\n"); save_load_apply_config(false, true); break; case RESET_CONFIG: - CFG("[CMD] RESET_CONFIG\n"); + usCFG("[CMD] RESET_CONFIG\n"); default_config(&usbsid_config); save_config(&usbsid_config); if (buffer[1] != 0) { @@ -641,7 +640,7 @@ void handle_config_request(uint8_t * buffer, uint32_t size) break; case WRITE_CONFIG: /* TODO: FINISH */ /* Max size of incoming buffer = 61 */ - CFG("[CMD] WRITE_CONFIG\n"); + usCFG("[CMD] WRITE_CONFIG\n"); print_cfg(buffer, size); switch (buffer[1]) { case FULL_CONFIG: @@ -653,110 +652,120 @@ void handle_config_request(uint8_t * buffer, uint32_t size) } break; case SINGLE_SID: - CFG("[CMD] SINGLE_SID\n"); - set_socket_config(buffer[1], true, false, usbsid_config.socketOne.chiptype, false, false, usbsid_config.socketTwo.chiptype, false); + int single_socket = ((buffer[2] == 1) ? 2 : 0); + usCFG("[CMD] SINGLE_SID SOCKET %d\n", single_socket); + if (single_socket == 2) { + set_socket_config(buffer[1], false, false, usbsid_config.socketOne.chiptype, true, false, usbsid_config.socketTwo.chiptype, false); + } else { + set_socket_config(buffer[1], true, false, usbsid_config.socketOne.chiptype, false, false, usbsid_config.socketTwo.chiptype, false); + } + break; + case FLIP_SOCKETS: + usCFG("[CMD] FLIP_SOCKETS\n"); + extern void flip_sockets(void); + flip_sockets(); break; case MIRRORED_SID: - CFG("[CMD] MIRRORED_SID\n"); + usCFG("[CMD] MIRRORED_SID\n"); set_socket_config(buffer[1], true, false, usbsid_config.socketOne.chiptype, true, false, usbsid_config.socketTwo.chiptype, true); break; case DUAL_SID: - CFG("[CMD] DUAL_SID\n"); + usCFG("[CMD] DUAL_SID\n"); set_socket_config(buffer[1], true, false, usbsid_config.socketOne.chiptype, true, false, usbsid_config.socketTwo.chiptype, false); break; case DUAL_SOCKET1: - CFG("[CMD] DUAL_SOCKET 1\n"); + usCFG("[CMD] DUAL_SOCKET 1\n"); set_socket_config(buffer[1], true, true, usbsid_config.socketOne.chiptype, false, false, usbsid_config.socketTwo.chiptype, false); break; case DUAL_SOCKET2: - CFG("[CMD] DUAL_SOCKET 2\n"); + usCFG("[CMD] DUAL_SOCKET 2\n"); set_socket_config(buffer[1], false, false, usbsid_config.socketOne.chiptype, true, true, usbsid_config.socketTwo.chiptype, false); break; case QUAD_SID: - CFG("[CMD] QUAD_SID\n"); + usCFG("[CMD] QUAD_SID\n"); set_socket_config(buffer[1], true, true, 1, true, true, 1, false); break; case TRIPLE_SID: - CFG("[CMD] TRIPLE_SID SOCKET 1\n"); + usCFG("[CMD] TRIPLE_SID SOCKET 1\n"); set_socket_config(buffer[1], true, true, 1, true, false, usbsid_config.socketTwo.chiptype, false); break; case TRIPLE_SID_TWO: - CFG("[CMD] TRIPLE_SID SOCKET 2\n"); + usCFG("[CMD] TRIPLE_SID SOCKET 2\n"); set_socket_config(buffer[1], true, false, usbsid_config.socketOne.chiptype, true, true, 1, false); break; case LOAD_MIDI_STATE: /* Load from config into midimachine and apply to SIDs */ - // CFG("[CMD] LOAD_MIDI_STATE\n"); + // usCFG("[CMD] LOAD_MIDI_STATE\n"); // for (int i = 0; i < 4; i++) { - // CFG("[SID %d]", (i + 1)); + // usCFG("[SID %d]", (i + 1)); // for (int j = 0; j < 32; j++) { // /* ISSUE: this only loads 1 channel state and should actually save all channel states */ // midimachine.channel_states[curr_midi_channel][i][j] = usbsid_config.Midi.sid_states[i][j]; // midimachine.channelkey_states[curr_midi_channel][i][i] = 0; /* Make sure extras is always initialized @ zero */ - // CFG(" %02x", midimachine.channel_states[curr_midi_channel][i][j]); + // usCFG(" %02x", midimachine.channel_states[curr_midi_channel][i][j]); // midi_bus_operation((0x20 * i) | j, midimachine.channel_states[curr_midi_channel][i][j]); // } - // CFG("\n"); + // usCFG("\n"); // } break; case SAVE_MIDI_STATE: /* Save from midimachine into config and save to flash */ - // CFG("[CMD] SAVE_MIDI_STATE\n"); + // usCFG("[CMD] SAVE_MIDI_STATE\n"); // for (int i = 0; i < 4; i++) { - // CFG("[SID %d]", (i + 1)); + // usCFG("[SID %d]", (i + 1)); // for (int j = 0; j < 32; j++) { // /* ISSUE: this only loads 1 channel state and should actually save all channel states */ // usbsid_config.Midi.sid_states[i][j] = midimachine.channel_states[curr_midi_channel][i][j]; - // CFG(" %02x", usbsid_config.Midi.sid_states[i][j]); + // usCFG(" %02x", usbsid_config.Midi.sid_states[i][j]); // } - // CFG("\n"); + // usCFG("\n"); // } // save_config(&usbsid_config); break; case RESET_MIDI_STATE: /* Reset all settings to zero */ - // CFG("[CMD] RESET_MIDI_STATE\n"); + // usCFG("[CMD] RESET_MIDI_STATE\n"); // for (int i = 0; i < 4; i++) { - // CFG("[SID %d]", (i + 1)); + // usCFG("[SID %d]", (i + 1)); // for (int j = 0; j < 32; j++) { // // BUG: this only resets 1 channel state // usbsid_config.Midi.sid_states[i][j] = midimachine.channel_states[curr_midi_channel][i][j] = 0; - // CFG(" %02x", usbsid_config.Midi.sid_states[i][j]); + // usCFG(" %02x", usbsid_config.Midi.sid_states[i][j]); // midi_bus_operation((0x20 * i) | j, midimachine.channel_states[curr_midi_channel][i][j]); // } - // CFG("\n"); + // usCFG("\n"); // } // save_config(&usbsid_config); /* mcu_reset(); */ break; case SET_CLOCK: /* Change SID clock frequency by array id */ - CFG("[CMD] SET_CLOCK\n"); + usCFG("[CMD] SET_CLOCK\n"); /* locked clockrate check is done in apply_clockrate */ bool suspend_sids = (buffer[2] == 1) ? true : false; /* Set RES low while changing clock? */ apply_clockrate((int)buffer[1], suspend_sids); break; case GET_CLOCK: /* Returns the clockrate as array id in byte 0 */ - CFG("[CMD] GET_CLOCK\n"); + usCFG("[CMD] GET_CLOCK\n"); int clk_rate_id = return_clockrate(); memset(write_buffer_p, 0, 64); write_buffer_p[0] = clk_rate_id; write_back_data(1); break; case LOCK_CLOCK: /* Locks the clockrate from being changed, saved in config */ - CFG("[CMD] LOCK_CLOCK\n"); + usCFG("[CMD] LOCK_CLOCK\n"); if (buffer[1] == 0 || buffer[1] == 1) { /* Verify correct data */ usbsid_config.lock_clockrate = (bool)buffer[1]; } else { - CFG("[LOCK_CLOCK] Received incorrect value of %d\n", buffer[1]); + usCFG("[LOCK_CLOCK] Received incorrect value of %d\n", buffer[1]); } if (buffer[2] == 1) { /* Save and apply if set to a 1 */ - CFG("[LOCK_CLOCK] SAVE_CONFIG\n"); + usCFG("[LOCK_CLOCK] SAVE_CONFIG\n"); save_load_apply_config(false, true); } break; case TOGGLE_AUDIO: /* Toggle the audio state regardless of config setting */ - CFG("[CMD] TOGGLE_AUDIO\n"); + usCFG("[CMD] TOGGLE_AUDIO\n"); toggle_audio_switch(); /* if HAS_AUDIOSWITCH is not defined, this doesn't do anything */ break; case SET_AUDIO: /* Set the audio state from buffer setting (saves config if provided) */ - CFG("[CMD] SET_AUDIO\n"); + usCFG("[CMD] SET_AUDIO\n"); if (!usbsid_config.lock_audio_sw) { usbsid_config.stereo_en = (buffer[1] == 0 || buffer[1] == 1) @@ -764,11 +773,11 @@ void handle_config_request(uint8_t * buffer, uint32_t size) : true; /* Default to 1 ~ stereo if incorrect value */ set_audio_switch(usbsid_config.stereo_en); if (buffer[2] == 1) { /* Save and apply if set to a 1 */ - CFG("[SET_AUDIO] SAVE_CONFIG\n"); + usCFG("[SET_AUDIO] SAVE_CONFIG\n"); save_load_apply_config(false, true); } } else { - CFG("[CONFIG] Audio switch is locked at %d (%s), requested change to %d (%s)\n", + usCFG("Audio switch is locked at %d (%s), requested change to %d (%s)\n", (int)usbsid_config.stereo_en, mono_stereo[(int)usbsid_config.stereo_en], buffer[1], mono_stereo[buffer[1]]); return; } @@ -776,19 +785,19 @@ void handle_config_request(uint8_t * buffer, uint32_t size) case GET_AUDIO: /* TODO: Finish */ break; case LOCK_AUDIO: - CFG("[CMD] LOCK_AUDIO\n"); + usCFG("[CMD] LOCK_AUDIO\n"); usbsid_config.lock_audio_sw = (buffer[1] == 0 || buffer[1] == 1) ? (bool)buffer[1] : false; /* Default to false if incorrect value ~ don't lock */ if (buffer[2] == 1) { /* Save and apply if set to a 1 */ - CFG("[SET_AUDIO] SAVE_CONFIG\n"); + usCFG("[SET_AUDIO] SAVE_CONFIG\n"); save_load_apply_config(false, true); } break; case DETECT_SIDS: /* Detect SID types per socket */ if (buffer[1] == 0) { - CFG("[CMD] DETECT_SIDS (ALL)\n"); + usCFG("[CMD] DETECT_SIDS (ALL)\n"); detect_sid_type(&usbsid_config.socketOne, &usbsid_config.socketOne.sid1); if (usbsid_config.socketOne.dualsid) detect_sid_type(&usbsid_config.socketOne, &usbsid_config.socketOne.sid2); detect_sid_type(&usbsid_config.socketTwo, &usbsid_config.socketOne.sid1); @@ -806,13 +815,13 @@ void handle_config_request(uint8_t * buffer, uint32_t size) } } else if (buffer[1] == 1) { /* Only if 1, else just skip! */ if (buffer[2] < 4) { - CFG("[CMD] SID DETECTION @ $%02x\n", buffer[3]); + usCFG("[CMD] SID DETECTION @ $%02x\n", buffer[3]); sid_detection[buffer[2]](buffer[3]); } } break; case DETECT_CLONES: - CFG("[CMD] DETECT_CLONES\n"); + usCFG("[CMD] DETECT_CLONES\n"); detect_clone_type(&usbsid_config.socketOne); detect_clone_type(&usbsid_config.socketTwo); memset(write_buffer_p, 0 ,64); /* Empty the write buffer pointer */ @@ -828,7 +837,7 @@ void handle_config_request(uint8_t * buffer, uint32_t size) } break; case AUTO_DETECT: - CFG("[CMD] AUTO_DETECT\n"); + usCFG("[CMD] AUTO_DETECT\n"); auto_detect_routine(true, true); /* Double tap! */ if (buffer[1] == 1) { /* Save and reboot */ save_config_ext(); @@ -838,10 +847,10 @@ void handle_config_request(uint8_t * buffer, uint32_t size) } break; case TEST_ALLSIDS: - CFG("[CMD] TEST_ALLSIDS\n"); + usCFG("[CMD] TEST_ALLSIDS\n"); running_tests = true; for (int s = 0; s < cfg.numsids; s++) { - CFG("[START TEST SID %d]\n", s); + usCFG("[START TEST SID %d]\n", s); if (running_tests) { sidtest_queue_entry_t s_entry = {sid_test, s, '1', 'A'}; queue_try_add(&sidtest_queue, &s_entry); @@ -866,17 +875,17 @@ void handle_config_request(uint8_t * buffer, uint32_t size) : buffer[2] == 3 ? 'P' /* Pulse */ : buffer[2] == 4 ? 'N' /* Noise */ : 'P'); /* Fallback to pulse waveform */ - CFG("[CMD] TEST_SID %d TEST: %c WF: %c\n", (s + 1), t, wf); + usCFG("[CMD] TEST_SID %d TEST: %c WF: %c\n", (s + 1), t, wf); running_tests = true; sidtest_queue_entry_t s_entry = {sid_test, s, t, wf}; queue_try_add(&sidtest_queue, &s_entry); break; case STOP_TESTS: - CFG("[CMD] STOP_TESTS\n"); + usCFG("[CMD] STOP_TESTS\n"); running_tests = false; break; case USBSID_VERSION: - CFG("[CMD] READ_FIRMWARE_VERSION\n"); + usCFG("[CMD] READ_FIRMWARE_VERSION\n"); memset(p_version_array, 0, count_of(p_version_array)); read_firmware_version(); memset(write_buffer_p, 0, MAX_BUFFER_SIZE); @@ -891,7 +900,7 @@ void handle_config_request(uint8_t * buffer, uint32_t size) } break; case US_PCB_VERSION: - CFG("[CMD] READ_PCB_VERSION\n"); + usCFG("[CMD] READ_PCB_VERSION\n"); if (buffer[1] == 0) { /* Large write 64 bytes */ memset(p_version_array, 0, count_of(p_version_array)); read_pcb_version(); @@ -913,45 +922,45 @@ void handle_config_request(uint8_t * buffer, uint32_t size) } break; case RESTART_BUS: - CFG("[CMD] RESTART_BUS\n"); + usCFG("[CMD] RESTART_BUS\n"); restart_bus(); break; case RESTART_BUS_CLK: - CFG("[CMD] RESTART_BUS_CLK\n"); + usCFG("[CMD] RESTART_BUS_CLK\n"); restart_bus_clocks(); break; case SYNC_PIOS: - CFG("[CMD] SYNC_PIOS\n"); + usCFG("[CMD] SYNC_PIOS\n"); sync_pios(false); break; case TEST_FN: /* TODO: Remove before v1 release */ if (buffer[1] == 0) { - CFG("[CMD] TEST_FN\n"); - CFG("[FLASH_CONFIG_OFFSET]0x%x\n", FLASH_CONFIG_OFFSET); - CFG("[PICO_FLASH_SIZE_BYTES]0x%x\n", PICO_FLASH_SIZE_BYTES); - CFG("[FLASH_SECTOR_SIZE]0x%x\n", FLASH_SECTOR_SIZE); - CFG("[FLASH_PAGE_SIZE]0x%x\n", FLASH_PAGE_SIZE); - CFG("[CONFIG_SIZE]0x%x\n", CONFIG_SIZE); - CFG("A %x %x %d\n", usbsid_config.magic, MAGIC_SMOKE, usbsid_config.magic != MAGIC_SMOKE); - CFG("A %x %x %d\n", (uint32_t)usbsid_config.magic, (uint32_t)MAGIC_SMOKE, usbsid_config.magic != MAGIC_SMOKE); - CFG("A %d %d\n", (int)usbsid_config.magic, (int)MAGIC_SMOKE); - CFG("A %d\n", usbsid_config.magic == MAGIC_SMOKE); + usCFG("[CMD] TEST_FN\n"); + usCFG("[FLASH_CONFIG_OFFSET]0x%x\n", FLASH_CONFIG_OFFSET); + usCFG("[PICO_FLASH_SIZE_BYTES]0x%x\n", PICO_FLASH_SIZE_BYTES); + usCFG("[FLASH_SECTOR_SIZE]0x%x\n", FLASH_SECTOR_SIZE); + usCFG("[FLASH_PAGE_SIZE]0x%x\n", FLASH_PAGE_SIZE); + usCFG("[CONFIG_SIZE]0x%x\n", CONFIG_SIZE); + usCFG("A %x %x %d\n", usbsid_config.magic, MAGIC_SMOKE, usbsid_config.magic != MAGIC_SMOKE); + usCFG("A %x %x %d\n", (uint32_t)usbsid_config.magic, (uint32_t)MAGIC_SMOKE, usbsid_config.magic != MAGIC_SMOKE); + usCFG("A %d %d\n", (int)usbsid_config.magic, (int)MAGIC_SMOKE); + usCFG("A %d\n", usbsid_config.magic == MAGIC_SMOKE); - CFG("[TEST_CONFIG_START]\n"); - CFG("[MAGIC_SMOKE ERROR?] config: %u header: %u cm_verification: %u\n", usbsid_config.magic, MAGIC_SMOKE, cm_verification); + usCFG("[TEST_CONFIG_START]\n"); + usCFG("[MAGIC_SMOKE ERROR?] config: %u header: %u cm_verification: %u\n", usbsid_config.magic, MAGIC_SMOKE, cm_verification); Config test_config; memcpy(&test_config, (void *)(XIP_BASE + FLASH_CONFIG_OFFSET), sizeof(Config)); - CFG("A %x %x %d\n", test_config.magic, MAGIC_SMOKE, test_config.magic != MAGIC_SMOKE); - CFG("A %x %x %d\n", (uint32_t)test_config.magic, (uint32_t)MAGIC_SMOKE, test_config.magic != MAGIC_SMOKE); - CFG("A %d %d\n", (int)test_config.magic, (int)MAGIC_SMOKE); - CFG("A %d\n", test_config.magic == MAGIC_SMOKE); + usCFG("A %x %x %d\n", test_config.magic, MAGIC_SMOKE, test_config.magic != MAGIC_SMOKE); + usCFG("A %x %x %d\n", (uint32_t)test_config.magic, (uint32_t)MAGIC_SMOKE, test_config.magic != MAGIC_SMOKE); + usCFG("A %d %d\n", (int)test_config.magic, (int)MAGIC_SMOKE); + usCFG("A %d\n", test_config.magic == MAGIC_SMOKE); read_config(&test_config); print_cfg(config_array, count_of(config_array)); - CFG("[TEST_CONFIG_END]\n"); + usCFG("[TEST_CONFIG_END]\n"); } if (buffer[1] == 1) { - CFG("[USBSID_SID_MEMORY]\n"); + usCFG("[USBSID_SID_MEMORY]\n"); print_cfg(sid_memory, (cfg.numsids * 0x20)); } break; @@ -959,13 +968,13 @@ void handle_config_request(uint8_t * buffer, uint32_t size) uint8_t st = 0xFF; #ifdef ONBOARD_EMULATOR if (buffer[1] == 0) { - CFG("START EMULATOR\n"); + usCFG("START EMULATOR\n"); emulator_running = false; offload_ledrunner = true; starting_emulator = true; } if (buffer[1] == 1) { - CFG("STOP EMULATOR\n"); + usCFG("STOP EMULATOR\n"); stopping_emulator = true; stop_cynthcart(); } @@ -981,23 +990,22 @@ void handle_config_request(uint8_t * buffer, uint32_t size) uint16_t dcyc = 1000; if (buffer[2] != 0 || buffer[3] != 0) dcyc = (buffer[2] << 8) | buffer[3]; - CFG("[CFG] DELAY TESTING FOR %ld US/CYCLES\n", dcyc); + usCFG("[CFG] DELAY TESTING FOR %ld US/CYCLES\n", dcyc); uint64_t test_before = to_us_since_boot(get_absolute_time()); sleep_ms(dcyc/1000); uint64_t test_after = to_us_since_boot(get_absolute_time()); - CFG("[CFG] SLEEP_MS before: %lld after: %lld difference %lld\n", test_before, test_after, (test_after - test_before)); + usCFG("[CFG] SLEEP_MS before: %lld after: %lld difference %lld\n", test_before, test_after, (test_after - test_before)); test_before = to_us_since_boot(get_absolute_time()); uint16_t waited_cycles = cycled_delay_operation(dcyc); test_after = to_us_since_boot(get_absolute_time()); - CFG("[CFG] DELAY_CYCLES %u = %.4fµs, ACTUAL: %uµs (including printf delay)\n", waited_cycles, (float)(waited_cycles * sid_us), (test_after - test_before)); } if (buffer[1] == 6) { detect_fmopl(buffer[2]); } if (buffer[1] == 7) { - CFG("[CONFIG] SAVE ID BEFORE: %d (%d)\n", config_saveid, usbsid_config.config_saveid); + usCFG("SAVE ID BEFORE: %d (%d)\n", config_saveid, usbsid_config.config_saveid); config_saveid = usbsid_config.config_saveid = 0; /* reset saveid */ - CFG("[CONFIG] SAVE ID AFTER: %d (%d)\n", config_saveid, usbsid_config.config_saveid); + usCFG("SAVE ID AFTER: %d (%d)\n", config_saveid, usbsid_config.config_saveid); } if (buffer[1] == 8) { read_fpgasid_configuration(buffer[2]); @@ -1013,23 +1021,23 @@ void handle_config_request(uint8_t * buffer, uint32_t size) } break; case TEST_FN3: - CFG("[SID MEMORY]\n"); + usCFG("[SID MEMORY]\n"); for (uint i = 0; i < (4*0x20); i++) { - if (i!=0 && i%0x20 == 0) { CFG("\n");}; - CFG("$%02X ", sid_memory[i]); + if (i!=0 && i%0x20 == 0) { usCFG("\n");}; + usCFG("$%02X ", sid_memory[i]); } - CFG("\n"); + usCFG("\n"); break; case FPGASID: break; /* Reserved for config implementation */ case SKPICO: break; /* Reserved for config implementation */ case ARMSID: break; /* Reserved for config implementation */ case PDSID: - CFG("[TOGGLE PDSID TYPE]\n"); + usCFG("[TOGGLE PDSID TYPE]\n"); switch_pdsid_type(); break; #if defined(ONBOARD_SIDPLAYER) case UPLOAD_SID_START: - CFG("[UPLOAD_SID_START %d]\n",buffer[1]); + usCFG("[UPLOAD_SID_START %d]\n",buffer[1]); receiving_sidfile = true; sidbytes_received = 0; is_prg = ((buffer[1] == PRG_FILE) ? true : false); @@ -1042,7 +1050,7 @@ void handle_config_request(uint8_t * buffer, uint32_t size) } break; case UPLOAD_SID_DATA: - if (sidbytes_received == 0) CFG("[UPLOAD_SID_DATA]\n"); + if (sidbytes_received == 0) usCFG("[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]; @@ -1051,27 +1059,27 @@ void handle_config_request(uint8_t * buffer, uint32_t size) } break; case UPLOAD_SID_END: - CFG("[UPLOAD_SID_END]\n"); - DBG("Received %u bytes\n", sidbytes_received); + usCFG("[UPLOAD_SID_END]\n"); + usDBG("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"); + usCFG("[UPLOAD_SID_SIZE]\n"); sidfile_size = (buffer[1]<<8|buffer[2]); - DBG("Received SID file size: %u\n", sidfile_size); + usDBG("Received SID file size: %u\n", sidfile_size); break; case SID_PLAYER_TUNE: - CFG("[SID_PLAYER_TUNE] %d\n", buffer[1]); - CFG("[CONFIG BUFFER SIZE] %d\n", count_of(buffer)); + usCFG("[SID_PLAYER_TUNE] %d\n", buffer[1]); + usCFG("[CONFIG BUFFER SIZE] %d\n", count_of(buffer)); tuneno = buffer[2]; /* Should be 0 if not supplied */ - CFG("[SUBTUNE] %d\n", tuneno); + usCFG("[SUBTUNE] %d\n", tuneno); unmute_sid(); /* Must unmute before play start or some tunes will be silent */ sidplayer_init = true; case SID_PLAYER_START: - CFG("[SID_PLAYER_START] %d\n", sidplayer_init); + usCFG("[SID_PLAYER_START] %d\n", sidplayer_init); if (sidplayer_init) { offload_ledrunner = true; sidplayer_start = true; @@ -1079,7 +1087,7 @@ void handle_config_request(uint8_t * buffer, uint32_t size) sidplayer_init = false; break; case SID_PLAYER_STOP: - CFG("[SID_PLAYER_STOP]\n"); + usCFG("[SID_PLAYER_STOP]\n"); if (sidplayer_playing) { sidplayer_stop = true; } @@ -1089,15 +1097,15 @@ void handle_config_request(uint8_t * buffer, uint32_t size) /* SID resets are handled in the emulator */ break; case SID_PLAYER_PAUSE: - CFG("[SID_PLAYER_PAUSE]\n"); + usCFG("[SID_PLAYER_PAUSE]\n"); sidplayer_playing = !sidplayer_playing; break; case SID_PLAYER_NEXT: - CFG("[SID_PLAYER_NEXT]\n"); + usCFG("[SID_PLAYER_NEXT]\n"); sidplayer_next = true; break; case SID_PLAYER_PREV: - CFG("[SID_PLAYER_PREV]\n"); + usCFG("[SID_PLAYER_PREV]\n"); sidplayer_prev = true; break; #endif @@ -1117,7 +1125,7 @@ void apply_led_config(void) break; } } - CFG("[CONFIG] RGBLED REQUESTED: %d\n", usbsid_config.RGBLED.sid_to_use); + usCFG("RGBLED REQUESTED: %d\n", usbsid_config.RGBLED.sid_to_use); /* check if requested sidno is actually configured */ usbsid_config.RGBLED.sid_to_use = (stou > cfg.numsids) @@ -1127,7 +1135,7 @@ void apply_led_config(void) ? sid /* use the first SID that is either 8580 or 6581 */ : 1 /* else default to SID 1 */ : usbsid_config.RGBLED.sid_to_use; /* Else use the programmed SID to use */ - CFG("[CONFIG] RGBLED CALCULATED: %d\n", usbsid_config.RGBLED.sid_to_use); + usCFG("RGBLED CALCULATED: %d\n", usbsid_config.RGBLED.sid_to_use); return; } @@ -1141,9 +1149,8 @@ void print_config(void) void apply_config(bool at_boot, bool print_cfg) { - CFG("\n"); - CFG("[START CONFIG APPLY]\n"); - CFG("[CONFIG] Verifying socket settings\n"); + usCFG("[START CONFIG APPLY]\n"); + usCFG("Verifying socket settings\n"); verify_socket_settings(); verify_sid_addr(print_cfg); @@ -1152,7 +1159,7 @@ void apply_config(bool at_boot, bool print_cfg) apply_fmopl_config(false); if (!at_boot) { - CFG("[CONFIG] Applying bus clock settings\n"); + usCFG("Applying bus clock settings\n"); stop_dma_channels(); restart_bus_clocks(); sync_pios(false); @@ -1160,12 +1167,12 @@ void apply_config(bool at_boot, bool print_cfg) } if (RGB_ENABLED) { - CFG("[CONFIG] Applying RGBLED SID\n"); + usCFG("Applying RGBLED SID\n"); apply_led_config(); } else { - CFG("[CONFIG] RGBLED not available\n"); + usCFG("RGBLED not available\n"); } - CFG("[END CONFIG APPLY]\n"); + usCFG("[END CONFIG APPLY]\n"); /* Don't print anything on auto config run */ if (auto_config) return; @@ -1173,14 +1180,11 @@ void apply_config(bool at_boot, bool print_cfg) /* Print config at end of apply if requested */ if (print_cfg) print_config(); - CFG("\n"); - return; } void save_load_apply_config(bool at_boot, bool print_cfg) { - CFG("\n"); save_config(&usbsid_config); load_config(&usbsid_config); apply_config(at_boot, print_cfg); @@ -1189,30 +1193,29 @@ void save_load_apply_config(bool at_boot, bool print_cfg) void save_config_ext(void) { /* For saving the config outside of config.c */ - CFG("\n"); save_config(&usbsid_config); return; } void detect_default_config(void) { - CFG("[CONFIG] DETECT DEFAULT CONFIG START\n"); - CFG("[CONFIG] IS DEFAULT CONFIG? %s\n", + usCFG("DETECT DEFAULT CONFIG START\n"); + usCFG("IS DEFAULT CONFIG? %s\n", true_false[usbsid_config.default_config]); if(usbsid_config.default_config == 1) { - CFG("[CONFIG] DETECTED DEFAULT CONFIG!\n"); - CFG("[CONFIG] [MAGIC_SMOKE ADDRESS] config struct: 0x%X cm_verification: 0x%X\n", + usCFG("DETECTED DEFAULT CONFIG!\n"); + usCFG("[MAGIC_SMOKE ADDRESS] config struct: 0x%X cm_verification: 0x%X\n", &usbsid_config.magic, &cm_verification); - CFG("[CONFIG] [MAGIC_SMOKE VERIFICATION] config_struct: %u header: %u cm_verification: %u\n", + usCFG("[MAGIC_SMOKE VERIFICATION] config_struct: %u header: %u cm_verification: %u\n", usbsid_config.magic, MAGIC_SMOKE, cm_verification); usbsid_config.default_config = 0; - CFG("[CONFIG] DEFAULT CONFIG STATE SET TO %d\n", usbsid_config.default_config); + usCFG("DEFAULT CONFIG STATE SET TO %d\n", usbsid_config.default_config); first_boot = true; /* Only at first boot the link popup will be sent */ auto_detect_routine(false, true); /* default auto detect routine based on default config */ save_config(&usbsid_config); - CFG("[CONFIG] CONFIG SAVED\n"); + usCFG("CONFIG SAVED\n"); } - CFG("[CONFIG] DETECT DEFAULT FINISHED\n"); + usCFG("DETECT DEFAULT FINISHED\n"); return; } @@ -1232,19 +1235,19 @@ void apply_clockrate(int n_clock, bool suspend_sids) if (!usbsid_config.lock_clockrate) { if (clockrates[n_clock] != usbsid_config.clock_rate) { if (suspend_sids) { - CFG("[CONFIG] [DISABLE SID]\n"); + usCFG("[DISABLE SID]\n"); disable_sid(); } - CFG("[CONFIG] [CLOCK FROM]%d [CLOCK TO]%d\n", usbsid_config.clock_rate, clockrates[n_clock]); + usCFG("[CLOCK FROM]%d [CLOCK TO]%d\n", usbsid_config.clock_rate, clockrates[n_clock]); usbsid_config.clock_rate = clockrates[n_clock]; - usbsid_config.refresh_rate = refreshrates[n_clock]; /* Experimental */ - usbsid_config.raster_rate = rasterrates[n_clock]; /* Experimental */ + usbsid_config.refresh_rate = refreshrates[n_clock]; /* Used by ASID */ + usbsid_config.raster_rate = rasterrates[n_clock]; /* Used by the Vu and the ASID buffer */ /* Cycled write buffer vars */ sid_hz = usbsid_config.clock_rate; sid_mhz = (sid_hz / 1000 / 1000); sid_us = (1 / sid_mhz); - CFG("[CONFIG] [CFG PICO] %lu Hz, %.0f MHz, %.4f uS\n", clock_get_hz(clk_sys), cpu_mhz, cpu_us); - CFG("[CONFIG] [CFG C64] %.0f Hz, %.6f MHz, %.4f uS\n", sid_hz, sid_mhz, sid_us); + usCFG("[CFG PICO] %lu Hz, %.0f MHz, %.4f uS\n", clock_get_hz(clk_sys), cpu_mhz, cpu_us); + usCFG("[CFG C64] %.0f Hz, %.6f MHz, %.4f uS\n", sid_hz, sid_mhz, sid_us); /* Start clock set */ // ISSUE: EVEN THOUGH THIS IS BETTER IT DOES NOT SOLVE THE CRACKLING/BUS ROT ISSUE! stop_dma_channels(); @@ -1252,7 +1255,7 @@ void apply_clockrate(int n_clock, bool suspend_sids) start_dma_channels(); sync_pios(false); if (suspend_sids) { - CFG("[ENABLE SID WITH UNMUTE]\n"); + usCFG("[ENABLE SID WITH UNMUTE]\n"); enable_sid(true); } // ISSUE: WHEN THE BUS IS RESTARTED THE CRACKLING ON CYCLE EXACT TUNES IS IMMENSE! @@ -1260,11 +1263,11 @@ void apply_clockrate(int n_clock, bool suspend_sids) // restart_bus(); return; } else { - CFG("[CONFIG] [CLOCK FROM]%d AND [CLOCK TO]%d ARE THE SAME, SKIPPING SET_CLOCK\n", usbsid_config.clock_rate, clockrates[n_clock]); + usCFG("[CLOCK FROM]%d AND [CLOCK TO]%d ARE THE SAME, SKIPPING SET_CLOCK\n", usbsid_config.clock_rate, clockrates[n_clock]); return; } } else { - CFG("[CONFIG] [CLOCK] Clockrate is locked, change from %d to %d not applied\n", usbsid_config.clock_rate, clockrates[n_clock]); + usCFG("[CLOCK] Clockrate is locked, change from %d to %d not applied\n", usbsid_config.clock_rate, clockrates[n_clock]); return; } } @@ -1281,7 +1284,7 @@ void verify_clockrate(void) case CLOCK_DREAN: break; default: - CFG("[CONFIG] [CLOCK ERROR] Detected unconventional clockrate (%ld) error in config, revert to default\n", usbsid_config.clock_rate); + usCFG("[CLOCK ERROR] Detected unconventional clockrate (%ld) error in config, revert to default\n", usbsid_config.clock_rate); usbsid_config.clock_rate = clockrates[0]; usbsid_config.refresh_rate = refreshrates[0]; /* Experimental */ usbsid_config.raster_rate = rasterrates[0]; /* Experimental */ diff --git a/src/config.h b/src/config.h index fd91983..8337f04 100644 --- a/src/config.h +++ b/src/config.h @@ -110,18 +110,18 @@ extern uint32_t ADDR_PERSISTENT[]; /* USBSID-Pico config struct */ typedef struct SIDChip { - uint8_t id; /* ID for this SID 0 ~ 4, 255 = disabled */ - uint8_t addr; /* Starting address to use for this SID, 255 = disabled */ - uint8_t type; /* 0 = unknown, 1 = N/A, 2 = MOS8580, 3 = MOS6581, 4 = FMopl */ + uint8_t id; /* ID for this SID 0 ~ 4, 255 = disabled */ + uint8_t addr; /* Starting address to use for this SID, 255 = disabled */ + uint8_t type; /* 0 = unknown, 1 = N/A, 2 = MOS8580, 3 = MOS6581, 4 = FMopl */ } SIDChip; typedef struct Socket { - uint8_t chiptype; /* 0 = real, 1 = clone, 2 = unknown */ - uint8_t clonetype; /* 0 = disabled, 1 = other, 2 = SKPico, 3 = ARMSID, 4 = FPGASID, 5 = RedipSID */ + uint8_t chiptype; /* 0 = real, 1 = clone, 2 = unknown */ + uint8_t clonetype; /* 0 = disabled, 1 = other, 2 = SKPico, 3 = ARMSID, 4 = FPGASID, 5 = RedipSID */ SIDChip sid1; SIDChip sid2; - bool enabled : 1; /* enable / disable this socket */ - bool dualsid : 1; /* enable / disable dual SID support for this socket (requires clone) */ + bool enabled : 1; /* enable / disable this socket */ + bool dualsid : 1; /* enable / disable dual SID support for this socket (requires clone) */ } Socket; typedef struct Config { @@ -155,7 +155,6 @@ typedef struct Config { bool enabled : 1; } Asid; /* 7 */ struct { - // uint8_t sid_states[4][32]; /* Stores states of each SID ~ 4 sids max */ bool enabled : 1; } Midi; /* 8 */ struct { @@ -166,8 +165,7 @@ typedef struct Config { bool lock_clockrate : 1; /* lock the set clockspeed from being changed */ bool stereo_en : 1; /* audio switch is off (mono) or on (stereo) ~ (PCB v1.3+ only) */ bool lock_audio_sw : 1; /* lock the audio switch into it's current stateand prevent it from being changed ~ (PCB v1.3+ only) */ - bool mirrored : 1; /* act as socket 1 */ - bool fauxstereo : 1; /* faux stereo effect */ + bool mirrored : 1; /* act as socket 1 */ } Config; #define USBSID_DEFAULT_CONFIG_INIT { \ @@ -240,7 +238,6 @@ typedef struct Config { .stereo_en = false, \ .lock_audio_sw = false, \ .mirrored = false, \ - .fauxstereo = false, \ } \ static const Config usbsid_default_config = USBSID_DEFAULT_CONFIG_INIT; @@ -316,6 +313,7 @@ enum MIRRORED_SID = 0x45, /* Socket Two is linked to Socket One */ DUAL_SOCKET1 = 0x46, /* Two SID's in socket One, Socket Two disabled */ DUAL_SOCKET2 = 0x47, /* Two SID's in socket Two, Socket One disabled */ + FLIP_SOCKETS = 0x48, /* Socket Two is Socket One and vice versa */ SET_CLOCK = 0x50, /* Change SID clock frequency by array id */ DETECT_SIDS = 0x51, /* Try to detect the SID types per socket ~ routines see sid_detection.c */ diff --git a/src/config_bus.c b/src/config_bus.c index 16f597a..651a3e8 100644 --- a/src/config_bus.c +++ b/src/config_bus.c @@ -152,14 +152,14 @@ void apply_bus_config_OLD(void) } } } - CFG("[TEST OLD] ONE:%02X ONE:%02X TWO:%02X TWO:%02X THREE:%02X THREE:%02X FOUR:%02X FOUR:%02X\n", + usCFG("[TEST OLD] ONE:%02X ONE:%02X TWO:%02X TWO:%02X THREE:%02X THREE:%02X FOUR:%02X FOUR:%02X\n", cfg.one, cfg.one_mask, cfg.two, cfg.two_mask, cfg.three, cfg.three_mask, cfg.four, cfg.four_mask); return; } void apply_bus_config(bool quiet) // ISSUE: FINISH { /* bus config doesn't care if the sid is real or fmopl */ - if (!quiet) CFG("[CONFIG] Applying bus settings\n"); + if (!quiet) usCFG("Applying bus settings\n"); /* Default everything first */ memset(cfg.ids, 4, 4); /* Default to 4 N/A */ @@ -213,7 +213,7 @@ void apply_bus_config(bool quiet) // ISSUE: FINISH if (!quiet) { for (int id = 0; id < 4; id++) { - CFG("[TEST0] ID:%d IDS:%d SIDID:%d TYPE:%02X ADDR:%02X MASK:%02X ADDRMASK:%02X\n", + usCFG("[TEST0] ID:%d IDS:%d SIDID:%d TYPE:%02X ADDR:%02X MASK:%02X ADDRMASK:%02X\n", id, cfg.ids[id], cfg.sidid[id], cfg.sidtype[id], cfg.sidaddr[id], cfg.sidmask[cfg.ids[id]], cfg.addrmask[cfg.ids[id]]); } } @@ -243,7 +243,7 @@ void apply_bus_config(bool quiet) // ISSUE: FINISH cfg.three_mask = cfg.ids[2] != 4 ? cfg.addrmask[cfg.sidid[cfg.ids[2]]] : addrmask_default[cfg.ids[2]]; cfg.four_mask = cfg.ids[3] != 4 ? cfg.addrmask[cfg.sidid[cfg.ids[3]]] : addrmask_default[cfg.ids[3]]; - if (!quiet) CFG("[TEST 1] ONE:%02X ONE:%02X TWO:%02X TWO:%02X THREE:%02X THREE:%02X FOUR:%02X FOUR:%02X\n", + if (!quiet) usCFG("[TEST 1] ONE:%02X ONE:%02X TWO:%02X TWO:%02X THREE:%02X THREE:%02X FOUR:%02X FOUR:%02X\n", cfg.one, cfg.one_mask, cfg.two, cfg.two_mask, cfg.three, cfg.three_mask, cfg.four, cfg.four_mask); /* EVERYTHING WORKS UP TO HERE BUT IGNORES SOCKET SETTINGS */ @@ -269,7 +269,7 @@ void apply_bus_config(bool quiet) // ISSUE: FINISH } - if (!quiet) CFG("[TEST 2] ONE:%02X ONE:%02X TWO:%02X TWO:%02X THREE:%02X THREE:%02X FOUR:%02X FOUR:%02X\n", + if (!quiet) usCFG("[TEST 2] ONE:%02X ONE:%02X TWO:%02X TWO:%02X THREE:%02X THREE:%02X FOUR:%02X FOUR:%02X\n", cfg.one, cfg.one_mask, cfg.two, cfg.two_mask, cfg.three, cfg.three_mask, cfg.four, cfg.four_mask); } diff --git a/src/config_logging.c b/src/config_logging.c index 6591cb0..ccc6a82 100644 --- a/src/config_logging.c +++ b/src/config_logging.c @@ -51,38 +51,37 @@ const char __in_flash("usbsid_vars") *mono_stereo[2] = { "Mono", "Stereo" }; void print_cfg(const uint8_t *buf, size_t len) { - CFG("[PRINT CFG START]\n"); + usCFG("[PRINT CFG START]\n"); for (size_t i = 0; i < len; ++i) { if (i == 0) - CFG("[R%03d] ", i); - CFG("%02x", buf[i]); + usNFO("[R%03d] ", i); + usNFO("%02x", buf[i]); if (i == (len - 1)) { - CFG("\n"); + usNFO("\n"); } else if ((i != 0) && (i % 16 == 15)) { - CFG("\n[R%03d] ", i); + usNFO("\n[R%03d] ", i); } else { - CFG(" "); + usNFO(" "); } } - CFG("[PRINT CFG END]\n"); + usCFG("[PRINT CFG END]\n"); return; } void print_cfg_addr(void) { - CFG("\n"); - CFG("[CONFIG] [XIP_BASE]0x%X (%u)\n\ -[CONFIG] [PICO_FLASH_SIZE_BYTES]0x%X (%u)\n\ -[CONFIG] [FLASH_PAGE_SIZE]0x%X (%u)\n\ -[CONFIG] [FLASH_SECTOR_SIZE]0x%X (%u)\n\ -[CONFIG] [ADDR_PERSISTENT_BASE_ADDR]0x%X (%u)\n\ -[CONFIG] [FLASH_PERSISTENT_OFFSET]0x%X (%u)\n\ -[CONFIG] [FLASH_PERSISTENT_SIZE]0x%X (%u)\n\ -[CONFIG] [FLASH_CONFIG_OFFSET]0x%X (%u)\n\ -[CONFIG] [XIP_BASE + FLASH_CONFIG_OFFSET]0x%X (%u)\n\ -[CONFIG] [CONFIG_SIZE]0x%X (%u)\n\ -[CONFIG] [SIZEOF_CONFIG]0x%X (%u)\n", + usCFG("\n[XIP_BASE] 0x%X (%u)\n\ +[PICO_FLASH_SIZE_BYTES] 0x%X (%u)\n\ +[FLASH_PAGE_SIZE] 0x%X (%u)\n\ +[FLASH_SECTOR_SIZE] 0x%X (%u)\n\ +[ADDR_PERSISTENT_BASE_ADDR] 0x%X (%u)\n\ +[FLASH_PERSISTENT_OFFSET] 0x%X (%u)\n\ +[FLASH_PERSISTENT_SIZE] 0x%X (%u)\n\ +[FLASH_CONFIG_OFFSET] 0x%X (%u)\n\ +[XIP_BASE + FLASH_CONFIG_OFFSET] 0x%X (%u)\n\ +[CONFIG_SIZE] 0x%X (%u)\n\ +[SIZEOF_CONFIG] 0x%X (%u)\n", XIP_BASE, XIP_BASE, PICO_FLASH_SIZE_BYTES, PICO_FLASH_SIZE_BYTES, FLASH_PAGE_SIZE, FLASH_PAGE_SIZE, FLASH_SECTOR_SIZE, FLASH_SECTOR_SIZE, ADDR_PERSISTENT_BASE_ADDR, ADDR_PERSISTENT_BASE_ADDR, @@ -95,135 +94,135 @@ void print_cfg_addr(void) void print_pico_features(void) { - CFG("\n"); /* new line before the actual pico features are printed */ - CFG("[START PRINT PICO DEFAULT FEATURES]\n"); + usCFG("\n[START PRINT PICO DEFAULT FEATURES]\n"); - CFG("PICO_PIO_VERSION = %d\n", PICO_PIO_VERSION); /* pio.h */ + usCFG("PICO_PIO_VERSION = %d\n", PICO_PIO_VERSION); /* pio.h */ #if defined(PICO_DEFAULT_LED_PIN) - CFG("PICO_DEFAULT_LED_PIN = %d\n", PICO_DEFAULT_LED_PIN); /* pico*.h */ + usCFG("PICO_DEFAULT_LED_PIN = %d\n", PICO_DEFAULT_LED_PIN); /* pico*.h */ #elif defined(CYW43_WL_GPIO_LED_PIN) - CFG("CYW43_WL_GPIO_LED_PIN = %d\n", CYW43_WL_GPIO_LED_PIN); /* pico*.h */ + usCFG("CYW43_WL_GPIO_LED_PIN = %d\n", CYW43_WL_GPIO_LED_PIN); /* pico*.h */ #endif - CFG("LED_PWM = %d\n", LED_PWM); /* config.h */ + usCFG("LED_PWM = %d\n", LED_PWM); /* config.h */ - CFG("[END PRINT PICO DEFAULT FEATURES]\n"); + usCFG("[END PRINT PICO DEFAULT FEATURES]\n"); + usCFG("\n"); return; } void print_config_settings(void) { - CFG("\n"); /* new line before the actual settings are printed */ - CFG("[START PRINT CONFIG SETTINGS]\n"); + usCFG("\n"); /* new line before the actual settings are printed */ + usCFG("[START PRINT CONFIG SETTINGS]\n"); - CFG("[USBSID PCB VERSION] %s\n", pcb_version); - CFG("[USBSID FIRMWARE VERSION] %s\n", project_version); + usCFG("[USBSID PCB VERSION] %s\n", pcb_version); + usCFG("[USBSID FIRMWARE VERSION] %s\n", project_version); - CFG("[CLOCK] %s @%d\n", + usCFG("[CLOCK] %s @%d\n", int_ext[(int)usbsid_config.external_clock], (int)usbsid_config.clock_rate); - CFG("[CLOCK RATE LOCKED] %s\n", + usCFG("[CLOCK RATE LOCKED] %s\n", true_false[(int)usbsid_config.lock_clockrate]); - CFG("[RASTER RATE] @%d\n", + usCFG("[RASTER RATE] @%d\n", (int)usbsid_config.raster_rate); - CFG("[SOCKET ONE] %s as %s\n", + usCFG("[SOCKET ONE] %s as %s\n", enabled[(int)usbsid_config.socketOne.enabled], ((int)usbsid_config.socketOne.dualsid == 1 ? single_dual[0] : single_dual[1])); - CFG("[SOCKET ONE] CHIP TYPE: %s, CLONE TYPE: %s\n", + usCFG("[SOCKET ONE] CHIP TYPE: %s, CLONE TYPE: %s\n", chiptypes[usbsid_config.socketOne.chiptype], clonetypes[usbsid_config.socketOne.clonetype]); - CFG("[SOCKET ONE] SID 1 TYPE: %s, SID 2 TYPE: %s\n", + usCFG("[SOCKET ONE] SID 1 TYPE: %s, SID 2 TYPE: %s\n", sidtypes[usbsid_config.socketOne.sid1.type], sidtypes[usbsid_config.socketOne.sid2.type]); - CFG("[SOCKET ONE] SID 1 ID: %d, SID 2 ID: %d\n", + usCFG("[SOCKET ONE] SID 1 ID: %d, SID 2 ID: %d\n", usbsid_config.socketOne.sid1.id, usbsid_config.socketOne.sid2.id); - CFG("[SOCKET ONE] SID 1 ADDR: 0x%02X, SID 2 ADDR: 0x%02X\n", + usCFG("[SOCKET ONE] SID 1 ADDR: 0x%02X, SID 2 ADDR: 0x%02X\n", usbsid_config.socketOne.sid1.addr, usbsid_config.socketOne.sid2.addr); - CFG("[SOCKET TWO] %s as %s\n", + usCFG("[SOCKET TWO] %s as %s\n", enabled[(int)usbsid_config.socketTwo.enabled], ((int)usbsid_config.socketTwo.dualsid == 1 ? single_dual[0] : single_dual[1])); - CFG("[SOCKET TWO] CHIP TYPE: %s, CLONE TYPE: %s\n", + usCFG("[SOCKET TWO] CHIP TYPE: %s, CLONE TYPE: %s\n", chiptypes[usbsid_config.socketTwo.chiptype], clonetypes[usbsid_config.socketTwo.clonetype]); - CFG("[SOCKET TWO] SID 1 TYPE: %s, SID 2 TYPE: %s\n", + usCFG("[SOCKET TWO] SID 1 TYPE: %s, SID 2 TYPE: %s\n", sidtypes[usbsid_config.socketTwo.sid1.type], sidtypes[usbsid_config.socketTwo.sid2.type]); - CFG("[SOCKET ONE] SID 1 ID: %d, SID 2 ID: %d\n", + usCFG("[SOCKET ONE] SID 1 ID: %d, SID 2 ID: %d\n", usbsid_config.socketTwo.sid1.id, usbsid_config.socketTwo.sid2.id); - CFG("[SOCKET ONE] SID 1 ADDR: 0x%02X, SID 2 ADDR: 0x%02X\n", + usCFG("[SOCKET ONE] SID 1 ADDR: 0x%02X, SID 2 ADDR: 0x%02X\n", usbsid_config.socketTwo.sid1.addr, usbsid_config.socketTwo.sid2.addr); - CFG("[SOCKET TWO AS ONE (MIRRORED)] %s\n", + usCFG("[SOCKET TWO AS ONE (MIRRORED)] %s\n", true_false[(int)usbsid_config.mirrored]); - CFG("[LED] %s, Idle breathe? %s\n", + usCFG("[LED] %s, Idle breathe? %s\n", enabled[(int)usbsid_config.LED.enabled], true_false[(int)usbsid_config.LED.idle_breathe]); - CFG("[RGBLED] %s, Idle breathe? %s\n", + usCFG("[RGBLED] %s, Idle breathe? %s\n", enabled[(int)usbsid_config.RGBLED.enabled], true_false[(int)usbsid_config.RGBLED.idle_breathe]); - CFG("[RGBLED SIDTOUSE] %d\n", + usCFG("[RGBLED SIDTOUSE] %d\n", (int)usbsid_config.RGBLED.sid_to_use); - CFG("[RGBLED BRIGHTNESS] %d\n", + usCFG("[RGBLED BRIGHTNESS] %d\n", (int)usbsid_config.RGBLED.brightness); - CFG("[CDC] %s\n", + usCFG("[CDC] %s\n", enabled[(int)usbsid_config.Cdc.enabled]); - CFG("[WebUSB] %s\n", + usCFG("[WebUSB] %s\n", enabled[(int)usbsid_config.WebUSB.enabled]); - CFG("[Asid] %s\n", + usCFG("[Asid] %s\n", enabled[(int)usbsid_config.Asid.enabled]); - CFG("[Midi] %s\n", + usCFG("[Midi] %s\n", enabled[(int)usbsid_config.Midi.enabled]); - CFG("[FMOpl] %s\n", + usCFG("[FMOpl] %s\n", enabled[(int)usbsid_config.FMOpl.enabled]); - CFG("[FMOpl] SIDno %d\n", + usCFG("[FMOpl] SIDno %d\n", usbsid_config.FMOpl.sidno); #if defined(HAS_AUDIOSWITCH) - CFG("[AUDIO_SWITCH] %s\n", + usCFG("[AUDIO_SWITCH] %s\n", mono_stereo[(int)usbsid_config.stereo_en]); - CFG("[AUDIO_SWITCH_LOCKED] %s\n", + usCFG("[AUDIO_SWITCH_LOCKED] %s\n", true_false[(int)usbsid_config.lock_audio_sw]); #endif - CFG("[END PRINT CONFIG SETTINGS]\n"); + usCFG("[END PRINT CONFIG SETTINGS]\n"); return; } void print_socket_config(void) { - CFG("\n"); /* new line before the actual socket settings are printed */ - CFG("[START PRINT SOCKET CONFIG]\n"); + usCFG("\n"); /* new line before the actual socket settings are printed */ + usCFG("[START PRINT SOCKET CONFIG]\n"); - CFG("SOCK_ONE EN: %s SOCK_TWO EN: %s\nACT_AS_ONE: %s\nNO SIDS\nSOCK_ONE #%d\nSOCK_TWO #%d\nTOTAL #%d\n", + usCFG("\nSOCK_ONE EN: %s SOCK_TWO EN: %s\nACT_AS_ONE: %s\nNO SIDS\nSOCK_ONE #%d\nSOCK_TWO #%d\nTOTAL #%d\n", true_false[cfg.sock_one], true_false[cfg.sock_two], true_false[cfg.mirrored], cfg.sids_one, cfg.sids_two, cfg.numsids); - CFG("[END PRINT SOCKET CONFIG]\n"); + usCFG("[END PRINT SOCKET CONFIG]\n"); return; } void print_bus_config(void) { - CFG("\n"); /* new line before the actual bus config is printed */ - CFG("[START PRINT BUS CONFIG]\n"); + usCFG("\n"); /* new line before the actual bus config is printed */ + usCFG("[START PRINT BUS CONFIG]\n"); - CFG("BUS\nONE: %02x 0b"PRINTF_BINARY_PATTERN_INT8"\nTWO: %02x 0b"PRINTF_BINARY_PATTERN_INT8"\nTHREE: %02x 0b"PRINTF_BINARY_PATTERN_INT8"\nFOUR: %02x 0b"PRINTF_BINARY_PATTERN_INT8"\n", + usCFG("BUS\nONE: %02x 0b"PRINTF_BINARY_PATTERN_INT8"\nTWO: %02x 0b"PRINTF_BINARY_PATTERN_INT8"\nTHREE: %02x 0b"PRINTF_BINARY_PATTERN_INT8"\nFOUR: %02x 0b"PRINTF_BINARY_PATTERN_INT8"\n", cfg.one, PRINTF_BYTE_TO_BINARY_INT8(cfg.one), cfg.two, PRINTF_BYTE_TO_BINARY_INT8(cfg.two), cfg.three, PRINTF_BYTE_TO_BINARY_INT8(cfg.three), cfg.four, PRINTF_BYTE_TO_BINARY_INT8(cfg.four)); - CFG("ADDRESS MASKS\n"); - CFG("MASK_ONE: 0x%02x 0b"PRINTF_BINARY_PATTERN_INT8"\n", cfg.one_mask, PRINTF_BYTE_TO_BINARY_INT8(cfg.one_mask)); - CFG("MASK_TWO: 0x%02x 0b"PRINTF_BINARY_PATTERN_INT8"\n", cfg.two_mask, PRINTF_BYTE_TO_BINARY_INT8(cfg.two_mask)); - CFG("MASK_THREE: 0x%02x 0b"PRINTF_BINARY_PATTERN_INT8"\n", cfg.three_mask, PRINTF_BYTE_TO_BINARY_INT8(cfg.three_mask)); - CFG("MASK_FOUR: 0x%02x 0b"PRINTF_BINARY_PATTERN_INT8"\n", cfg.four_mask, PRINTF_BYTE_TO_BINARY_INT8(cfg.four_mask)); + usCFG("ADDRESS MASKS\n"); + usCFG("MASK_ONE: 0x%02x 0b"PRINTF_BINARY_PATTERN_INT8"\n", cfg.one_mask, PRINTF_BYTE_TO_BINARY_INT8(cfg.one_mask)); + usCFG("MASK_TWO: 0x%02x 0b"PRINTF_BINARY_PATTERN_INT8"\n", cfg.two_mask, PRINTF_BYTE_TO_BINARY_INT8(cfg.two_mask)); + usCFG("MASK_THREE: 0x%02x 0b"PRINTF_BINARY_PATTERN_INT8"\n", cfg.three_mask, PRINTF_BYTE_TO_BINARY_INT8(cfg.three_mask)); + usCFG("MASK_FOUR: 0x%02x 0b"PRINTF_BINARY_PATTERN_INT8"\n", cfg.four_mask, PRINTF_BYTE_TO_BINARY_INT8(cfg.four_mask)); - CFG("[END PRINT BUS CONFIG]\n"); + usCFG("[END PRINT BUS CONFIG]\n"); return; } diff --git a/src/config_socket.c b/src/config_socket.c index 8fc259d..b1ced6b 100644 --- a/src/config_socket.c +++ b/src/config_socket.c @@ -92,7 +92,7 @@ void verify_socket_settings(void) void verify_chipdetection_results(bool quiet) { /* Is run only from sid_detection.c:auto_detect_routine after detection in auto_config mode */ - if (!quiet) CFG("[SID] VERIFY SOCKET DETECTION RESULTS\n"); + if (!quiet) usCFG("[SID] VERIFY SOCKET DETECTION RESULTS\n"); /* Socket One */ if (usbsid_config.socketOne.sid1.type != 0 && usbsid_config.socketOne.sid2.type == 1) { /* Unidentified SID as sid2? */ @@ -104,7 +104,7 @@ void verify_chipdetection_results(bool quiet) usbsid_config.socketOne.enabled = false; /* Disable the socket */ } } - if (!quiet) CFG("[SID] SOCKET ONE CHIPTYPE: %d CLONETYPE: %d ENABLED: %d DUALSID: %d\n", + if (!quiet) usCFG("[SID] SOCKET ONE CHIPTYPE: %d CLONETYPE: %d ENABLED: %d DUALSID: %d\n", usbsid_config.socketOne.chiptype, usbsid_config.socketOne.clonetype, usbsid_config.socketOne.enabled, usbsid_config.socketOne.dualsid); @@ -119,14 +119,14 @@ void verify_chipdetection_results(bool quiet) usbsid_config.socketTwo.enabled = false; /* Disable the socket */ } } - if (!quiet) CFG("[SID] SOCKET TWO CHIPTYPE: %d CLONETYPE: %d ENABLED: %d DUALSID: %d\n", + if (!quiet) usCFG("[SID] SOCKET TWO CHIPTYPE: %d CLONETYPE: %d ENABLED: %d DUALSID: %d\n", usbsid_config.socketTwo.chiptype, usbsid_config.socketTwo.clonetype, usbsid_config.socketTwo.enabled, usbsid_config.socketTwo.dualsid); } void verify_sid_addr(bool quiet) { /* Is run only from sid_detection.c:auto_detect_routine after detection in auto_config mode */ - if (!quiet) CFG("[SID] REASSIGN SID ADDRESS AND ID BY SOCKET CONFIG\n"); + if (!quiet) usCFG("[SID] REASSIGN SID ADDRESS AND ID BY SOCKET CONFIG\n"); /* Socket One */ if (usbsid_config.socketOne.enabled) { if (usbsid_config.socketOne.dualsid) { @@ -308,6 +308,31 @@ void set_sid_id_addr(int socket, int sid, int id) return; } +/** + * @brief Flip socket id's and addresses at runtime + * + */ +void flip_sockets(void) +{ + uint8_t ids[4] = { + usbsid_config.socketOne.sid1.id, + usbsid_config.socketOne.sid2.id, + usbsid_config.socketTwo.sid1.id, + usbsid_config.socketTwo.sid2.id + }; + usbsid_config.socketOne.sid1.id = ids[2]; + usbsid_config.socketOne.sid1.addr = sidaddr_default[ids[2]]; + usbsid_config.socketOne.sid2.id = ids[3]; + usbsid_config.socketOne.sid2.addr = sidaddr_default[ids[3]]; + usbsid_config.socketTwo.sid1.id = ids[0]; + usbsid_config.socketTwo.sid1.addr = sidaddr_default[ids[0]]; + usbsid_config.socketTwo.sid2.id = ids[1]; + usbsid_config.socketTwo.sid2.addr = sidaddr_default[ids[1]]; + extern void apply_bus_config(bool quiet); + apply_bus_config(false); + return; +} + /* Called from apply_config apply_socket_change */ int verify_fmopl_sidno(void) { /* TODO: THIS USES CONFIG AND RUNTIMECFG CROSSED, THIS MUST BE CONFIG ONLY */ @@ -347,11 +372,11 @@ int verify_fmopl_sidno(void) void apply_fmopl_config(bool quiet) { /* TODO: REWORK */ - if (!quiet) CFG("[CONFIG] Checking for optional FMOpl\n"); + if (!quiet) usCFG("Checking for optional FMOpl\n"); /* FMOpl */ int fmoplsid = verify_fmopl_sidno(); if (fmoplsid != -1) { - if (!quiet) CFG("[CONFIG] FMOpl @ SIDNO %d\n", fmoplsid); + if (!quiet) usCFG("FMOpl @ SIDNO %d\n", fmoplsid); cfg.fmopl_enabled = usbsid_config.FMOpl.enabled = true; usbsid_config.FMOpl.sidno = cfg.fmopl_sid = fmoplsid; } else { @@ -403,7 +428,7 @@ void set_socket_config(uint8_t cmd, bool s1en, bool s1dual, uint8_t s1chip, bool void apply_socket_config(bool quiet) { - if (!quiet) CFG("[CONFIG] Applying socket settings\n"); + if (!quiet) usCFG("Applying socket settings\n"); cfg.mirrored = usbsid_config.mirrored; cfg.sock_one = usbsid_config.socketOne.enabled; @@ -492,7 +517,7 @@ bool check_socket_config_errors(void) */ void socket_config_fallback(void) { - CFG("[SET DEFAULT FALLBACK SOCKET CONFIG]\n"); + usCFG("[SET DEFAULT FALLBACK SOCKET CONFIG]\n"); /* Socket One */ usbsid_config.socketOne.chiptype = 2; /* unknown */ usbsid_config.socketOne.clonetype = 0; /* disabled */ diff --git a/src/dma.c b/src/dma.c index 5a58963..0e6a97b 100644 --- a/src/dma.c +++ b/src/dma.c @@ -31,14 +31,17 @@ #include "sid.h" -/* imports */ +/* pio.c */ extern PIO bus_pio, clkcnt_pio; extern uint sm_control, sm_data, sm_clock, sm_delay, sm_clkcnt; -/* locals */ +/* DMA */ int dma_tx_control, dma_tx_data, dma_rx_data, dma_tx_delay; -int dma_clkcnt_control; -volatile uint32_t clkcnt_word; +int dma_counter; +#if PICO_RP2040 +int dma_counter_chain; +#endif +volatile uint32_t cycle_count_word; /* Shiny things */ #if defined(PICO_DEFAULT_LED_PIN) @@ -55,7 +58,7 @@ uint32_t rgb_value = 0; void setup_dmachannels(void) { /* NOTE: Do not manually assign DMA channels, this causes a Panic on the PicoW */ - CFG("[DMA CHANNELS INIT] START\n"); + usCFG("[DMA CHANNELS INIT] START\n"); /* NOTICE: DMA read address is disabled for now, it is causing confirmed desync on the rp2040 (rp2350 seems to works, but needs improving) */ /* NOTICE: DMA chaining on rp2350 causes desync with cycled writes, probably due to RP2350-E8 */ @@ -65,7 +68,10 @@ void setup_dmachannels(void) dma_tx_data = dma_claim_unused_channel(true); dma_rx_data = dma_claim_unused_channel(true); dma_tx_delay = dma_claim_unused_channel(true); - dma_clkcnt_control = dma_claim_unused_channel(true); + dma_counter = dma_claim_unused_channel(true); +#if PICO_RP2040 + dma_counter_chain = dma_claim_unused_channel(true); +#endif { /* dma controlbus */ dma_channel_config tx_config_control = dma_channel_get_default_config(dma_tx_control); @@ -108,33 +114,72 @@ void setup_dmachannels(void) //#endif dma_channel_configure(dma_tx_delay, &tx_config_delay, &bus_pio->txf[sm_delay], NULL, 1, false); } - #if PICO_RP2350 /* NOTE: endless transfer not supported on rp2040 */ +#if PICO_RP2350 /* RP2350 has native endless transfer support */ { /* dma rx clock counter ~ should be an endless updating item */ - dma_channel_config clkcnt_config_data = dma_channel_get_default_config(dma_clkcnt_control); + dma_channel_config clkcnt_config_data = dma_channel_get_default_config(dma_counter); channel_config_set_transfer_data_size(&clkcnt_config_data, DMA_SIZE_32); channel_config_set_read_increment(&clkcnt_config_data, false); channel_config_set_write_increment(&clkcnt_config_data, false); channel_config_set_dreq(&clkcnt_config_data, DREQ_PIO1_RX3); - // channel_config_set_irq_ignore(&dma_clkcnt_control, false); - // dma_channel_configure(dma_clkcnt_control, &clkcnt_config_data, &clkcnt_word, &bus_pio->rxf[sm_clkcnt], 1, false); - clkcnt_word = 0; + // channel_config_set_irq_ignore(&dma_counter, false); + // dma_channel_configure(dma_counter, &clkcnt_config_data, &cycle_count_word, &bus_pio->rxf[sm_clkcnt], 1, false); + cycle_count_word = 0; dma_channel_configure( - dma_clkcnt_control, + dma_counter, &clkcnt_config_data, - &clkcnt_word, + &cycle_count_word, &clkcnt_pio->rxf[sm_clkcnt], - dma_encode_endless_transfer_count(), /* ENDLESS transfer count */ // BUG: Spinlocks the Pico - // dma_encode_transfer_count_with_self_trigger(1), /* Self triggered transfer count */ // BUG: Spinlocks the Pico + dma_encode_endless_transfer_count(), /* ENDLESS transfer count */ true /* Start transfers immediately */ - // false ); } - #endif +#else /* RP2040: ping-pong chain for continuous transfer */ + { + cycle_count_word = 0; + /* Channel A */ + dma_channel_config cfg_a = dma_channel_get_default_config(dma_counter); + channel_config_set_transfer_data_size(&cfg_a, DMA_SIZE_32); + channel_config_set_read_increment(&cfg_a, false); + channel_config_set_write_increment(&cfg_a, false); + channel_config_set_dreq(&cfg_a, DREQ_PIO1_RX3); + channel_config_set_chain_to(&cfg_a, dma_counter_chain); + dma_channel_configure( + dma_counter, + &cfg_a, + &cycle_count_word, + &clkcnt_pio->rxf[sm_clkcnt], + 1, + false + ); - CFG("[DMA CHANNELS CLAIMED] C:%d TX:%d RX:%d D:%d CNT:%d\n", - dma_tx_control, dma_tx_data, dma_rx_data, dma_tx_delay, dma_clkcnt_control); + /* Channel B — identical transfer, chains back to A */ + dma_channel_config cfg_b = dma_channel_get_default_config(dma_counter_chain); + channel_config_set_transfer_data_size(&cfg_b, DMA_SIZE_32); + channel_config_set_read_increment(&cfg_b, false); + channel_config_set_write_increment(&cfg_b, false); + channel_config_set_dreq(&cfg_b, DREQ_PIO1_RX3); + channel_config_set_chain_to(&cfg_b, dma_counter); + dma_channel_configure( + dma_counter_chain, + &cfg_b, + &cycle_count_word, + &clkcnt_pio->rxf[sm_clkcnt], + 1, + false); + + /* Start channel A — it will chain to B, B chains back, forever */ + dma_channel_start(dma_counter_chain); + } +#endif +#if PICO_RP2350 + usCFG("[DMA CHANNELS CLAIMED] C:%d TX:%d RX:%d D:%d CNT:%d\n", + dma_tx_control, dma_tx_data, dma_rx_data, dma_tx_delay, dma_counter); +#else + usCFG("[DMA CHANNELS CLAIMED] C:%d TX:%d RX:%d D:%d CNTA:%d CNTB:%d\n", + dma_tx_control, dma_tx_data, dma_rx_data, dma_tx_delay, dma_counter, dma_counter_chain); +#endif - CFG("[DMA CHANNELS INIT] FINISHED\n"); + usCFG("[DMA CHANNELS INIT] FINISHED\n"); return; } @@ -164,42 +209,9 @@ void setup_vu_dma(void) #endif } -/** - * @brief returns the amount of C64 cpu clock - * cycles counted by the counter SM and updated - * by a continous running DMA channel - * - * @returns uint32_t */ -uint32_t clockcycles(void) -{ - #if PICO_RP2350 - return (uint32_t)clkcnt_word; - #else - return 0; /* Not supported on rp2040 */ - #endif -} - -/** - * @brief delay for n PHI1 clockcycles - * Will do a cycled delay if not rp2350 - * with cycle counter - * - * @param uint32_t n_cycles - */ -void clockcycle_delay(uint32_t n_cycles) -{ /* ISSUE: Will crap out if delay cycles wrap around __UINT32_MAX__ */ - if __us_unlikely(n_cycles == 0) return; - int32_t now, end; - now = end = clockcycles(); - do { - end = clockcycles(); - } while (end < (now + n_cycles)); - return; -} - void stop_dma_channels(void) { // TODO: Fix and finish per RP2040-E13 and RP2350-E5 - // CFG("[STOP DMA CHANNELS]\n"); + // usCFG("[STOP DMA CHANNELS]\n"); /* Clear any Interrupt enable bits as per RP2040-E13 */ // TODO: FINISH /* Atomically abort channels */ @@ -219,7 +231,7 @@ void stop_dma_channels(void) void start_dma_channels(void) { /* NOTE: DO NOT USE, THIS STARTS A TRANSFER IN THE CURRENT CONFIG */ /* Trigger -> start dma channels all at once */ - // CFG("[START DMA CHANNELS]\n"); + // usCFG("[START DMA CHANNELS]\n"); // dma_hw->multi_channel_trigger = (1 << dma_tx_delay) | (1 << dma_rx_data) | (1 << dma_tx_data) | (1 << dma_tx_control); return; } @@ -237,6 +249,6 @@ void unclaim_dma_channels(void) return; } -// dma_hw->abort = (1 << dma_clkcnt_control); +// dma_hw->abort = (1 << dma_counter); // while (dma_hw->abort) tight_loop_contents(); -// while (dma_hw->ch[dma_clkcnt_control].ctrl_trig & DMA_CH0_CTRL_TRIG_BUSY_BITS) tight_loop_contents(); +// while (dma_hw->ch[dma_counter].ctrl_trig & DMA_CH0_CTRL_TRIG_BUSY_BITS) tight_loop_contents(); diff --git a/src/gpio.c b/src/gpio.c index 003b93a..452407d 100644 --- a/src/gpio.c +++ b/src/gpio.c @@ -42,11 +42,7 @@ extern char *mono_stereo[2]; * Partly copied from and inspired by SKPico code by frenetic * see: https://github.com/frntc/SIDKick-pico */ -#if PICO_RP2350 -register uint32_t b asm( "r13" ); -#else register uint32_t b asm( "r10" ); -#endif volatile const uint32_t *BUSState = &sio_hw->gpio_in; @@ -76,7 +72,7 @@ void init_gpio(void) /* Detect clock signal */ int detect_clocksignal(void) { - CFG("[DETECT CLOCK] START\n"); + usCFG("[DETECT CLOCK] START\n"); int c = 0, r = 0; gpio_init(PHI1); gpio_set_pulls(PHI1, false, true); @@ -84,22 +80,22 @@ int detect_clocksignal(void) b = *BUSState; /* read complete bus */ r |= c = (b & bPIN(PHI1)) >> PHI1; } - CFG("[RESULT] %d: %s\n", r, (r == 0 ? "INTERNAL CLOCK" : "EXTERNAL CLOCK")); - CFG("[DETECT CLOCK] END\n"); + usCFG("[RESULT] %d: %s\n", r, (r == 0 ? "INTERNAL CLOCK" : "EXTERNAL CLOCK")); + usCFG("[DETECT CLOCK] END\n"); return r; /* 1 if clock detected */ } -void toggle_audio_switch(void) /* BUG: This _can_ cause a hardfault on rp2350 */ +void toggle_audio_switch(void) { /* Toggle the SPST switch stereo <-> mono */ #if defined(HAS_AUDIOSWITCH) if (!usbsid_config.lock_audio_sw) { b = *BUSState; /* read complete bus */ int audio_state = (b & bPIN(AU_SW)) >> AU_SW; /* Pinpoint current audio switch state */ audio_state ^= 1; - CFG("[CONFIG] TOGGLE AUDIO SWITCH TO: %d (%s)\n", audio_state, mono_stereo[audio_state]); + usCFG("TOGGLE AUDIO SWITCH TO: %d (%s)\n", (int)audio_state, mono_stereo[(int)audio_state]); tPIN(AU_SW); /* toggle mono <-> stereo */ } else { - CFG("[CONFIG] Audio switch is locked at %d (%s), toggle not applied\n", + usCFG("Audio switch is locked at %d (%s), toggle not applied\n", (int)usbsid_config.stereo_en, mono_stereo[(int)usbsid_config.stereo_en]); return; } @@ -110,12 +106,12 @@ void set_audio_switch(bool state) { /* Set the SPST switch */ #if defined(HAS_AUDIOSWITCH) if (!usbsid_config.lock_audio_sw) { - CFG("[CONFIG] SET AUDIO SWITCH TO: %d (%s)\n", state, mono_stereo[state]); + usCFG("SET AUDIO SWITCH TO: %d (%s)\n", (int)state, mono_stereo[(int)state]); if (state) { sPIN(AU_SW); /* set mono <-> stereo pin */ } else cPIN(AU_SW); /* clear mono <-> stereo pin */ } else { - CFG("[CONFIG] Audio switch is locked at %d (%s), requested change to %d (%s) ignored\n", + usCFG("Audio switch is locked at %d (%s), requested change to %d (%s) ignored\n", (int)usbsid_config.stereo_en, mono_stereo[(int)usbsid_config.stereo_en], state, mono_stereo[state]); return; } diff --git a/src/logging.h b/src/logging.h index c927a7b..da32ec0 100644 --- a/src/logging.h +++ b/src/logging.h @@ -31,7 +31,6 @@ extern "C" { /* Logging to USB uart */ - #ifdef USB_PRINTF /* TinyUSB libs */ #if __has_include("bsp/board_api.h") /* Needed to account for update in tinyUSB */ @@ -58,47 +57,71 @@ do { \ /* Logging macro's */ - -#ifdef MEM_DEBUG -#define MDBG(...) _US_DBG(__VA_ARGS__) +#ifdef LOG_FILENAME +/* Searches for '/' (Unix) or '\' (Windows) */ +#define __FILENAME__ \ + (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : \ + strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) + #define __DBG(fmt, ...) \ + _US_DBG("[%s:%d] " fmt, __FILENAME__, __LINE__ __VA_OPT__(,) __VA_ARGS__) #else -#define MDBG(...) ((void)0) + #define __DBG(...) _US_DBG(__VA_ARGS__) #endif +#define usNFO(...) __DBG(__VA_ARGS__) /* Info logging, cannot be turned off */ + #ifdef USBSID_DEBUG -#define DBG(...) _US_DBG(__VA_ARGS__) +#define usDBG(fmt, ...) __DBG("[DBG] " fmt __VA_OPT__(,) __VA_ARGS__) #else -#define DBG(...) ((void)0) +#define usDBG(...) ((void)0) #endif -#ifdef USBIO_DEBUG -#define IODBG(...) _US_DBG(__VA_ARGS__) +#ifdef USBSID_BOOTLOG +#define usBOOT(fmt, ...) __DBG("[BOOT] " fmt __VA_OPT__(,) __VA_ARGS__) #else -#define IODBG(...) ((void)0) +#define usBOOT(...) ((void)0) #endif #ifdef CONFIG_DEBUG -#define CFG(...) _US_DBG(__VA_ARGS__) +#define usCFG(fmt, ...) __DBG("[CFG] " fmt __VA_OPT__(,) __VA_ARGS__) +#else +#define usCFG(...) ((void)0) +#endif + +#ifdef MEM_DEBUG +#define usMEM(fmt, ...) __DBG("[MEM] " fmt __VA_OPT__(,) __VA_ARGS__) +#else +#define usMEM(...) ((void)0) +#endif + +#ifdef USBIO_DEBUG +#define usIO(fmt, ...) __DBG("[IO] " fmt __VA_OPT__(,) __VA_ARGS__) #else -#define CFG(...) ((void)0) +#define usIO(...) ((void)0) #endif #ifdef USBSIDGPIO_DEBUG -#define GPIODBG(...) _US_DBG(__VA_ARGS__) +#define usGPIO(fmt, ...) __DBG("[GPIO] " fmt __VA_OPT__(,) __VA_ARGS__) #else -#define GPIODBG(...) ((void)0) +#define usGPIO(...) ((void)0) #endif #ifdef MIDI_DEBUG -#define MIDBG(...) _US_DBG(__VA_ARGS__) +#define usMIDI(fmt, ...) __DBG("[MIDI] " fmt __VA_OPT__(,) __VA_ARGS__) #else -#define MIDBG(...) ((void)0) +#define usMIDI(...) ((void)0) #endif #ifdef MIDIVOICE_DEBUG -#define MVDBG(...) _US_DBG(__VA_ARGS__) +#define usMVCE(fmt, ...) __DBG("[MVOICE] " fmt __VA_OPT__(,) __VA_ARGS__) +#else +#define usMVCE(...) ((void)0) +#endif + +#ifdef ASID_DEBUG +#define usASID(fmt, ...) __DBG("[ASID] " fmt __VA_OPT__(,) __VA_ARGS__) #else -#define MVDBG(...) ((void)0) +#define usASID(...) ((void)0) #endif diff --git a/src/mcu.c b/src/mcu.c index 5a9cbbf..07bd36f 100644 --- a/src/mcu.c +++ b/src/mcu.c @@ -47,7 +47,7 @@ uint64_t mcu_get_unique_id(void) void mcu_reset(void) { - CFG("[MCU_RESET]\n"); + usCFG("[MCU_RESET]\n"); sleep_ms(100); // sleep some ms to let commands prior to reset settle or finish /* watchdog_enable(1, 1); */ watchdog_reboot(0, 0, 0); diff --git a/src/midi.c b/src/midi.c index fd2c090..aa7be52 100644 --- a/src/midi.c +++ b/src/midi.c @@ -44,7 +44,7 @@ const midi_ccvalues midi_ccvalues_defaults = MIDI_DEFAULT_CCVALUES_INIT; /* GPIO */ -extern uint8_t __no_inline_not_in_flash_func(cycled_write_operation)(uint8_t address, uint8_t data, uint16_t cycles); +extern uint8_t cycled_write_operation(uint8_t address, uint8_t data, uint16_t cycles); extern void reset_sid(void); /* Midi handler */ @@ -69,7 +69,7 @@ queue_t cynthcart_queue; /* Initialize the midi handlers */ void midi_init(void) { - CFG("[MIDI INIT] START\n"); + usNFO("[MIDI] Init start\n"); /* Set initial stream state and index */ midimachine.bus = FREE; @@ -84,7 +84,7 @@ void midi_init(void) /* Start the processor of midi buffers */ midi_processor_init(); - CFG("[MIDI INIT] FINISHED\n"); + usNFO("[MIDI] Init finished\n"); } #ifdef ONBOARD_EMULATOR @@ -135,7 +135,7 @@ void emulator_disable(void) inline void emulator_reset(void) { - DBG("[MIDI] Emulator reset not implemented yet!\n"); + usMIDI("Emulator reset not implemented yet!\n"); return; } @@ -165,7 +165,7 @@ inline void handle_emulator_cc(void) inline void midi_buffer_task(uint8_t buffer) { if (midimachine.index != 0) { - if (midimachine.type != SYSEX) MIDBG(" [B%d]$%02x#%03d", midimachine.index, buffer, buffer); + if (midimachine.type != SYSEX) usMIDI(" [B%d]$%02x#%03d", midimachine.index, buffer, buffer); } if (buffer & 0x80) { /* Handle start byte */ @@ -214,7 +214,7 @@ inline void midi_buffer_task(uint8_t buffer) dtype = midi; /* Set data type to midi */ 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); + if (midimachine.index == 0) usMIDI("[M][B%d]$%02x#%03d", midimachine.index, buffer, buffer); midimachine.type = MIDI; midimachine.state = RECEIVING; midimachine.bus = CLAIMED; @@ -232,7 +232,7 @@ inline void midi_buffer_task(uint8_t buffer) dtype = midi; /* Set data type to midi */ 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); + if (midimachine.index == 0) usMIDI("[M][B%d]$%02x#%03d", midimachine.index, buffer, buffer); midimachine.type = MIDI; midimachine.state = RECEIVING; midimachine.bus = CLAIMED; @@ -253,7 +253,7 @@ inline void midi_buffer_task(uint8_t buffer) if (midimachine.type == MIDI) { /* if (midimachine.streambuffer[0] >= 0x80 || midimachine.streambuffer[0] <= 0xEF) { */ if (midimachine.index == midimachine.midi_bytes) { - MIDBG("\n"); + usMIDI("\n"); dtype = midi; /* Set data type to midi */ /* Do something fancy now */ @@ -282,11 +282,11 @@ inline void midi_buffer_task(uint8_t buffer) } else { /* Buffer is full, receiving to much data too handle, wait for message to end */ midimachine.state = WAITING_FOR_END; - MIDBG("[EXCESS][IDX]%02d %02x \n", midimachine.index, buffer); + usMIDI("[EXCESS][IDX]%02d %02x \n", midimachine.index, buffer); } } else if (midimachine.state == WAITING_FOR_END) { /* Consuming SysEx messages, nothing else to do */ - MIDBG("[EXCESS][IDX]%02d %02x \n", midimachine.index, buffer); + usMIDI("[EXCESS][IDX]%02d %02x \n", midimachine.index, buffer); } } } diff --git a/src/midi_handler.c b/src/midi_handler.c index 73d7189..aa88a66 100644 --- a/src/midi_handler.c +++ b/src/midi_handler.c @@ -51,8 +51,8 @@ extern RuntimeCFG cfg; /* GPIO */ -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); +extern uint8_t cycled_write_operation(uint8_t address, uint8_t data, uint16_t cycles); +extern uint16_t cycled_delay_operation(uint16_t cycles); /* Initialize variables */ extern const midi_ccvalues midi_ccvalues_defaults; /* midi.c */ @@ -103,14 +103,14 @@ void midi_programs_init(void) void midi_processor_init(void) { - CFG("[START MIDI HANLDER INIT]\n"); + usCFG("Start Midi handler init\n"); /* NOTE: Temporary - always init defaults */ memcpy(&CC, &midi_ccvalues_defaults, sizeof(midi_ccvalues)); midi_programs_init(); - CFG("[END MIDI HANLDER INIT]\n"); + usCFG("End Midi handler init\n"); } @@ -176,7 +176,7 @@ void process_midi(uint8_t *buffer, int size) } 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); + // usDBG("%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 ;) */ @@ -185,6 +185,6 @@ void process_midi(uint8_t *buffer, int size) } } if (((buffer[0] & 0xF0) == 0x80) && (keys_pressed > 0)) keys_pressed--; - // DBG("[K]%d\n", keys_pressed); + // usDBG("[K]%d\n", keys_pressed); return; } diff --git a/src/pio.c b/src/pio.c index f06a8f8..394d974 100644 --- a/src/pio.c +++ b/src/pio.c @@ -54,12 +54,6 @@ uint sm_delay, offset_delay; /* pio0 */ uint sm_clkcnt, offset_clkcnt; /* pio1 */ float sidclock_frequency, busclock_frequency; -/* Clock cycle counter */ -#if 0 && PICO_RP2350 && !USE_PIO_UART /* Only on rp2350 for testing and when not using PIO Uart */ -PIO sid2_pio = pio2; -uint sm_clock2, offset_clock2; -#endif - /* Shiny things */ #if defined(PICO_DEFAULT_LED_PIN) PIO led_pio = pio1; @@ -124,8 +118,8 @@ void setup_piobus(void) uint32_t pico_hz = clock_get_hz(clk_sys); 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]@%luMHz [DIV]@%.2f [BUS CLK]@%.2f [CFG SID CLK]%d\n", + usBOOT("[BUS CLK INIT] START\n"); + usDBG("[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), @@ -162,7 +156,7 @@ void setup_piobus(void) pio_sm_set_enabled(bus_pio, sm_data, true); } - { /* delay counter */ + { /* delay cycle counter */ sm_delay = 3; /* PIO0 SM3 */ pio_sm_claim(bus_pio, sm_delay); offset_delay = pio_add_program(bus_pio, &delay_timer_program); @@ -182,23 +176,23 @@ void setup_piobus(void) pio_sm_init(clkcnt_pio, sm_clkcnt, offset_clkcnt, &clkcnt_delay); pio_sm_set_enabled(clkcnt_pio, sm_clkcnt, true); } - CFG("[BUS CLK INIT] FINISHED\n"); + usDBG("[BUS CLK INIT] FINISHED\n"); return; } -void sync_pios(bool at_boot) // TODO: SYNC COUNTER PIO WITH BUS PIO +void sync_pios(bool at_boot) { /* Sync PIO's */ #if PICO_PIO_VERSION == 0 - CFG("[RESTART PIOS] Pico & Pico_w\n"); + usDBG("[RESTART PIOS] Pico & Pico_w\n"); pio_sm_restart(bus_pio, 0b1111); - #elif PICO_PIO_VERSION > 0 // NOTE: rp2350 only - CFG("[SYNC PIOS] Pico2\n"); + #elif PICO_PIO_VERSION > 0 /* NOTE: rp2350 only */ + usDBG("[SYNC PIOS] Pico2\n"); pio_clkdiv_restart_sm_multi_mask(bus_pio, 0, 0b1111, 0); - // pio_clkdiv_restart_sm_multi_mask(clkcnt_pio, 0, 0b0011, 0); + // pio_clkdiv_restart_sm_multi_mask(clkcnt_pio, 0, 0b0011, 0); /* TODO: SYNC COUNTER PIO WITH BUS PIO */ pio_clkdiv_restart_sm_multi_mask(clkcnt_pio, 0, 0b1000, 0); #endif if __us_likely(!at_boot) { - pio_sm_clear_fifos(bus_pio, sm_clock); // TODO: TEST! + pio_sm_clear_fifos(bus_pio, sm_clock); pio_sm_clear_fifos(bus_pio, sm_control); pio_sm_clear_fifos(bus_pio, sm_data); pio_sm_clear_fifos(bus_pio, sm_delay); @@ -208,30 +202,27 @@ void sync_pios(bool at_boot) // TODO: SYNC COUNTER PIO WITH BUS PIO void restart_bus_clocks(void) { - CFG("[CLK RE-INIT] START\n"); + usDBG("[CLK RE-INIT] START\n"); uint32_t pico_hz = clock_get_hz(clk_sys); busclock_frequency = (float)pico_hz / (usbsid_config.clock_rate * 32) / 2; /* Clock frequency is 8 times the SID clock */ sidclock_frequency = (float)pico_hz / usbsid_config.clock_rate / 2; pio_sm_set_clkdiv(bus_pio, sm_clock, sidclock_frequency); -#if 0 && PICO_RP2350 && !USE_PIO_UART /* Only on rp2350 for testing and when not using PIO Uart */ - pio_sm_set_clkdiv(sid2_pio, sm_clock2, sidclock_frequency); -#endif - pio_sm_set_clkdiv(clkcnt_pio, sm_clkcnt, busclock_frequency); pio_sm_set_clkdiv(bus_pio, sm_control, busclock_frequency); pio_sm_set_clkdiv(bus_pio, sm_data, busclock_frequency); pio_sm_set_clkdiv(bus_pio, sm_delay, busclock_frequency); + pio_sm_set_clkdiv(clkcnt_pio, sm_clkcnt, busclock_frequency); - CFG("[PI CLK]@%luMHz [DIV]@%.2f [BUS CLK]@%.2f [CFG SID CLK]%d\n", + usDBG("[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]@%luMHz [DIV]@%.2f [SID CLK]@%.2f [CFG SID CLK]%d\n", + usDBG("[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), (int)usbsid_config.clock_rate); - CFG("[CLK RE-INIT] FINISHED\n"); + usDBG("[CLK RE-INIT] FINISHED\n"); return; } @@ -262,8 +253,8 @@ void init_sidclock(void) uint32_t pico_hz = clock_get_hz(clk_sys); sidclock_frequency = (float)pico_hz / usbsid_config.clock_rate / 2; - CFG("[SID CLK INIT] START\n"); - CFG("[PI CLK]@%luMHz [DIV]@%.2f [SID CLK]@%.2f [CFG SID CLK]%d\n", + usBOOT("[SID] CLK INIT START\n"); + usNFO("[NFO] [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), @@ -272,23 +263,8 @@ void init_sidclock(void) sm_clock = 0; /* PIO0 SM0 */ pio_sm_claim(bus_pio, sm_clock); clock_program_init(bus_pio, sm_clock, offset_clock, PHI1, sidclock_frequency); - CFG("[SID CLK INIT] FINISHED\n"); + usBOOT("[SID] CLK INIT FINISHED\n"); -/* DISABLED */ -#if 0 && PICO_RP2350 && !USE_PIO_UART /* Only on rp2350 for testing and when not using PIO Uart */ - CFG("[SID CLK2 INIT] START\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), - (int)usbsid_config.clock_rate); - offset_clock2 = pio_add_program(sid2_pio, &clock_program); - sm_clock2 = 0; /* PIO2 SM0 */ - pio_sm_claim(sid2_pio, sm_clock2); - clock_program_init(sid2_pio, sm_clock2, offset_clock2, PHI2, sidclock_frequency); - // clock_program_init(sid2_pio, sm_clock2, offset_clock2, PHI2, sidclock_frequency); - CFG("[SID CLK2 INIT] FINISHED\n"); -#endif return; } @@ -324,10 +300,8 @@ void setup_sidclock(void) /* De-init nMHz square wave output */ void deinit_sidclock(void) { - CFG("[DE-INIT CLOCK]\n"); + usDBG("[SID] CLK DE-INIT\n"); clock_program_deinit(bus_pio, sm_clock, offset_clock, clock_program); -#if 0 && PICO_RP2350 && !USE_PIO_UART /* Only on rp2350 for testing and when not using PIO Uart */ - clock_program_deinit(sid2_pio, sm_clock2, offset_clock2, clock_program); -#endif + return; } diff --git a/src/pio.h b/src/pio.h index d698cad..5089362 100644 --- a/src/pio.h +++ b/src/pio.h @@ -41,7 +41,7 @@ /* PIO */ #include "bus_control.pio.h" /* Busje komt zo! */ -#include "clock_counter.pio.h" /* !<(O.O)>! */ +#include "cycle_counter.pio.h" /* !<(O.O)>! */ #include "clock.pio.h" /* TikTak */ #include "vu.pio.h" /* Kiem em goan! */ #if defined(USE_RGB) @@ -49,26 +49,45 @@ #endif -/* PIO & Statemachine usage +/* NOTICE: PIO & Statemachine usage * PIO0 - * SM0: PHI1 SID clock - * SM1: Control bus - * SM2: Data bus - * SM3: Delay timer + * SM0: sm_clkcnt - PHI1 SID clock (clock.pio / pio.c) + * SM1: sm_control - Bus control write and data read (bus_control.pio / pio.c) + * SM2: sm_data - Data and address bus write (bus_control.pio / pio.c) + * SM3: sm_delay - Delay cycle counter interrupt for bus SM1 & SM2 (bus_control.pio / pio.c) * PIO1 - * SM0: RGB LED control - * SM1: LED PWM control - * SM2: Uart RX - * SM3: PHI1 Cycle counter - * - * rp2350 only! - * PIO2 - * SM0: SID2 clock - * SM1: SID2 Control bus - * SM2: SID2 Data bus - * SM3: PHI2 Cycle counter + * SM0: Buffer raster cycle counter (ASID) (bus_control.pio / asid_buffer.c) + * SM1: LED PWM control (Non Wifi boards only, unused otherwise) (vu.pio) + * SM2: RGB LED control (as LED but for RGB Boards only, unused otherwise) (vu_rgb.pio) + * SM3: PHI1 Clock cycle counter (cycle_counter.pio) + * PIO2 (rp2350 only!) + * SM0: Uart RX (uart_rx.pio / uart.c) + * SM1: + * SM2: + * SM3: */ + /* NOTICE: PIO <-> DMA information + * all pio statemachines have one or more corresponding DMA + * configurations in dma.c where the corresponding DREQ is also set + * PIO0 + * SM0: - no DMA use + * SM1: dma_tx_control - DMA_SIZE_8 - DREQ_PIO0_TX1 + * SM1: dma_rx_data - DMA_SIZE_8 - DREQ_PIO0_RX1 + * SM2: dma_tx_data - DMA_SIZE_32 - DREQ_PIO0_TX2 + * SM3: dma_tx_delay - DMA_SIZE_16 - DREQ_PIO0_TX3 + * PIO1 + * SM0: - no DMA use + * SM1: dma_pwmled - DMA_SIZE_32 - DREQ_PIO1_TX0 + * SM2: dma_rgbled - DMA_SIZE_32 - DREQ_PIO1_TX1 + * SM3: dma_counter - DMA_SIZE_32 - DREQ_PIO1_RX3 (dual channel on rp2040) + * PIO2 (rp2350 only!) + * SM0: + * SM1: + * SM2: + * SM3: + */ + /* IRQ's */ #define PIO_IRQ0 0 diff --git a/src/pio/bus_control.pio b/src/pio/bus_control.pio index d7171c1..38c8699 100644 --- a/src/pio/bus_control.pio +++ b/src/pio/bus_control.pio @@ -62,8 +62,10 @@ .define PUBLIC DATABUS 1 ; 0b001 .define PUBLIC RASTER 2 ; 0b010 + ; Bus control program ~ PIO0 SM1 .program bus_control + .wrap_target pull block ; Pull data from TX fifo, block if no data wait 1 irq CONTROL ; Wait for IRQ signal @@ -82,9 +84,11 @@ done: out pins 3 ; Set control to next 3 bits from TX fifo .wrap + ; Data and address bus program ~ PIO0 SM2 ; pinstate stays the same until next write .program data_bus + .wrap_target pull block ; Pull data from FIFO, block if no data wait 1 irq DATABUS ; Wait for IRQ signal ~ should trigger exactly 1 cycle after CONTROL @@ -95,8 +99,10 @@ done: wait 0 gpio CLK ; Wait for clock to go low .wrap + ; Delay counter program ~ PIO0 SM3 .program delay_timer + .wrap_target pull block ; Pull data from FIFO, block if no data out x 16 ; Move data into scratch register X @@ -108,9 +114,11 @@ delay: irq wait DATABUS ; Set IRQ and wait for its release .wrap + ; Buffer raster cycle counter program ~ PIO1 SM0 -; If used, triggers an IRQ after each n raster cycles provided +; Triggers an IRQ after each n raster cycles provided when enabled .program raster_buffer + .wrap_target pull noblock ; Pull data from FIFO, if empty re-use previous data stored in X mov x osr ; Copy pulled data into OSR diff --git a/src/pio/clock.pio b/src/pio/clock.pio index 4f0af90..418327c 100644 --- a/src/pio/clock.pio +++ b/src/pio/clock.pio @@ -33,6 +33,8 @@ ; empty. Write the least significant bit to the OUT pin group. ; + +; PHI1 SID Clock ~ PIO0 SM0 .program clock .wrap_target ; Free 0 cycle unconditional jump diff --git a/src/pio/clock_counter.pio b/src/pio/cycle_counter.pio similarity index 86% rename from src/pio/clock_counter.pio rename to src/pio/cycle_counter.pio index dd68f75..2735e4f 100644 --- a/src/pio/clock_counter.pio +++ b/src/pio/cycle_counter.pio @@ -24,8 +24,13 @@ .define PUBLIC CLK 22 -; Infinite cycle counter, wraps at 32bit and starts over + +; Infinite cycle counter ~ PIO1 SM3 +; rp2350: Requires DMA for `dma_encode_endless_transfer_count()` +; rp2040: Requires 2 chained DMA channels for endless transfer +; wraps at 32bit and starts over after approximately ~71 minutes .program cycle_counter + .wrap_target init: set x 0 ; Set X to 0 diff --git a/src/pio/uart_rx.pio b/src/pio/uart_rx.pio index 0e2c314..c66c2f2 100644 --- a/src/pio/uart_rx.pio +++ b/src/pio/uart_rx.pio @@ -26,6 +26,8 @@ ; along with this program. If not, see . ; + +; Uart RX on steroids ~ PIO2 SM0 .program uart_rx ; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and diff --git a/src/pio/vu.pio b/src/pio/vu.pio index 5490350..2b9aec1 100644 --- a/src/pio/vu.pio +++ b/src/pio/vu.pio @@ -28,7 +28,10 @@ ; along with this program. If not, see . ; + +; LED there be light! ~ PIO1 SM1 .program vu + .side_set 1 opt pull noblock side 0 ; Pull from FIFO to OSR if available, else copy X to OSR. diff --git a/src/pio/vu_rgb.pio b/src/pio/vu_rgb.pio index 0588aa5..a36a58a 100644 --- a/src/pio/vu_rgb.pio +++ b/src/pio/vu_rgb.pio @@ -28,7 +28,10 @@ ; along with this program. If not, see . ; + +; My precious ~ PIO1 SM2 .program vu_rgb + .side_set 1 .define public T1 3 diff --git a/src/sid.c b/src/sid.c index 06c76bc..f37ea7a 100644 --- a/src/sid.c +++ b/src/sid.c @@ -34,7 +34,7 @@ #ifdef ONBOARD_EMULATOR extern uint8_t *sid_memory; #else -extern uint8_t __not_in_flash("usbsid_buffer") sid_memory[(0x20 * 4)] __attribute__((aligned(2 * (0x20 * 4)))); +extern uint8_t sid_memory[(0x20 * 4)]; #endif extern int usbdata; @@ -46,12 +46,8 @@ extern RuntimeCFG cfg; extern uint16_t vu; /* bus.c */ -#if PICO_RP2350 extern void clockcycle_delay(uint32_t n_cycles); -#else -extern uint16_t __no_inline_not_in_flash_func(cycled_delay_operation)(uint16_t cycles); -#endif -extern void __no_inline_not_in_flash_func(cycled_write_operation)(uint8_t address, uint8_t data, uint16_t cycles); +extern void cycled_write_operation(uint8_t address, uint8_t data, uint16_t cycles); /* (hot) locals */ static bool paused_state, reset_state; @@ -60,7 +56,7 @@ static uint8_t volume_state[4] = {0}; static void log_memory(uint8_t * sid_memory) { - DBG("[%c:%d][PWM]$%04x[V1]$%02X%02X$%02X%02X$%02X$%02X$%02X[V2]$%02X%02X$%02X%02X$%02X$%02X$%02X[V3]$%02X%02X$%02X%02X$%02X$%02X$%02X[FC]$%02x%02x$%02x[VOL]$%02x\n", + usDBG("[%c:%d][PWM]$%04x[V1]$%02X%02X$%02X%02X$%02X$%02X$%02X[V2]$%02X%02X$%02X%02X$%02X$%02X$%02X[V3]$%02X%02X$%02X%02X$%02X$%02X$%02X[FC]$%02x%02x$%02x[VOL]$%02x\n", dtype, usbdata, vu, sid_memory[0x01], sid_memory[0x00], sid_memory[0x03], sid_memory[0x02], sid_memory[0x04], sid_memory[0x05], sid_memory[0x06], sid_memory[0x08], sid_memory[0x07], sid_memory[0x0A], sid_memory[0x09], sid_memory[0x0B], sid_memory[0x0C], sid_memory[0x0D], @@ -139,14 +135,14 @@ bool get_paused_state(void) */ void unmute_sid(void) { - DBG("[UNMUTE]\n"); + usDBG("[UNMUTE]\n"); /* is_muted = false; */ /* Is globally handled from usbsid.c */ for (int i = 0; i < cfg.numsids; i++) { uint8_t addr = ((0x20 * i) + 0x18); if ((volume_state[i] & 0xF) == 0) volume_state[i] = (volume_state[i] & 0xF0) | 0x0E; sid_memory[addr] = volume_state[i]; cycled_write_operation(((0x20 * i) + 0x18), volume_state[i], 0); /* Volume back */ - DBG("[%d] $%02X:%02X\n", i, addr, volume_state[i]); + usDBG("[%d] $%02X:%02X\n", i, addr, volume_state[i]); } return; } @@ -156,12 +152,12 @@ void unmute_sid(void) */ void mute_sid(void) { - DBG("[MUTE]\n"); + usDBG("[MUTE]\n"); for (int i = 0; i < cfg.numsids; i++) { uint8_t addr = ((0x20 * i) + 0x18); volume_state[i] = sid_memory[addr]; cycled_write_operation(addr, (volume_state[i] & 0xF0), 0); /* Volume to 0 */ - DBG("[%d] $%02X:%02X\n", i, addr, (volume_state[i] & 0xF0)); + usDBG("[%d] $%02X:%02X\n", i, addr, (volume_state[i] & 0xF0)); } /* is_muted = true; */ /* Is globally handled from usbsid.c */ return; @@ -214,14 +210,14 @@ void pause_sid(void) void pause_sid_withmute(void) { - DBG("[PAUSE STATE PRE] %d\n", paused_state); + usDBG("[PAUSE STATE PRE] %d\n", paused_state); if (!paused_state) mute_sid(); if (paused_state) unmute_sid(); // set_gpio(CS1, 1); // set_gpio(CS2, 1); pause_sid(); set_paused_state(!paused_state); - DBG("[PAUSE STATE POST] %d\n", paused_state); + usDBG("[PAUSE STATE POST] %d\n", paused_state); return; } @@ -234,11 +230,7 @@ void reset_sid(void) cPIN(RES); if (cfg.chip_one == 0 || cfg.chip_two == 0) { /* 10x PHI1(02) cycles as per datasheet for REAL SIDs only */ -#if PICO_RP2350 clockcycle_delay(10); -#else - cycled_delay_operation(10); -#endif } sPIN(RES); set_reset_state(false); @@ -247,20 +239,21 @@ void reset_sid(void) /** * @brief Clear SID register / reset registers + * 6 cycle delay for each write to simulate LDA (2) + STA (4) * @note https://csdb.dk/forums/?roomid=11&topicid=85713&showallposts=1 * @note thanks Wilfred for pointing this out! - * @param sidno + * @param int sidno */ void clear_sid_registers(int sidno) { for (uint reg = 0; reg < count_of(sid_registers) - 4; reg++) { - cycled_write_operation(((sidno * 0x20) | sid_registers[reg]), 0xff, 0); + cycled_write_operation(((sidno * 0x20) | sid_registers[reg]), 0xff, 6); } for (uint reg = 0; reg < count_of(sid_registers) - 4; reg++) { - cycled_write_operation(((sidno * 0x20) | sid_registers[reg]), 0x08, 0); + cycled_write_operation(((sidno * 0x20) | sid_registers[reg]), 0x08, 6); } for (uint reg = 0; reg < count_of(sid_registers) - 4; reg++) { - cycled_write_operation(((sidno * 0x20) | sid_registers[reg]), 0x0, 0); + cycled_write_operation(((sidno * 0x20) | sid_registers[reg]), 0x0, 6); } memset(sid_memory, 0, (4 * 0x20)); return; diff --git a/src/sid_cloneconfig.c b/src/sid_cloneconfig.c index f3cb1fa..bc6cfa1 100644 --- a/src/sid_cloneconfig.c +++ b/src/sid_cloneconfig.c @@ -33,8 +33,8 @@ /* GPIO */ -extern void __no_inline_not_in_flash_func(cycled_write_operation)(uint8_t address, uint8_t data, uint16_t cycles); -extern uint8_t __no_inline_not_in_flash_func(cycled_read_operation)(uint8_t address, uint16_t cycles); +extern void cycled_write_operation(uint8_t address, uint8_t data, uint16_t cycles); +extern uint8_t cycled_read_operation(uint8_t address, uint16_t cycles); /* SID */ extern void clear_sid_memory(void); @@ -69,19 +69,20 @@ void print_fpgasid_sidconfig(int slot, int sidno, uint8_t * configarray) int addr3 = ((configarray[1] & 0b1) == 1 ? 3 : 4); int addr = ((addr1 + addr2 + addr3) == 0 ? 12 : 4); - CFG("\n"); - CFG("[FPGASID CURRENT CONFIG SLOT%s SID %d]\n", slots[slot], sidno); + usCFG("\n"); + usCFG("[FPGASID CURRENT CONFIG SLOT%s SID %d]\n", slots[slot], sidno); if (sidno == 1) { - CFG("OUTPUT MODE: %s\n", outputmode[outp]); - CFG("SID2 ADDRESSES: %s%s%s%s\n", sid2addr[addr], sid2addr[addr1], sid2addr[addr2], sid2addr[addr3]); + usCFG("OUTPUT MODE: %s\n", outputmode[outp]); + usCFG("SID2 ADDRESSES: %s%s%s%s\n", sid2addr[addr], sid2addr[addr1], sid2addr[addr2], sid2addr[addr3]); } - CFG("SOURCE EXTIN: %s\n", extinsource[extin]); - CFG("REGISTER READ: %s\n", readback[readb]); - CFG("REGISTER DELAY: %s\n", regdelay[regd]); - CFG("MIXED WAVEFORM: %s\n", mixedwave[mixw]); - CFG("CRUNCHY DAC: %s\n", crunchydac[crunch]); - CFG("ANALOG FILTER: %s\n", filtermode[fltr]); - CFG("DIGIFIX VALUE: %02X\n", configarray[0]); + usCFG("SOURCE EXTIN: %s\n", extinsource[extin]); + usCFG("REGISTER READ: %s\n", readback[readb]); + usCFG("REGISTER DELAY: %s\n", regdelay[regd]); + usCFG("MIXED WAVEFORM: %s\n", mixedwave[mixw]); + usCFG("CRUNCHY DAC: %s\n", crunchydac[crunch]); + usCFG("ANALOG FILTER: %s\n", filtermode[fltr]); + usCFG("DIGIFIX VALUE: %02X\n", configarray[0]); + usCFG("\n"); } void read_fpgasid_configuration(uint8_t base_address) @@ -89,7 +90,7 @@ void read_fpgasid_configuration(uint8_t base_address) 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", + usCFG("[SID] ERROR INCORRECT ADDRESS (0x%02x) AND CLONETYPE (%d %d)\n", base_address, usbsid_config.socketOne.clonetype, usbsid_config.socketTwo.clonetype); return; /* Do nothing if no FPGASID configured */ } @@ -100,7 +101,7 @@ void read_fpgasid_configuration(uint8_t base_address) uint8_t sid_two_a[3]; uint8_t sid_one_b[3]; uint8_t sid_two_b[3]; - CFG("[SID] READING CONFIGURATION FROM FPGASID @ 0x%02X\n", base_address); + usCFG("[SID] READING CONFIGURATION FROM FPGASID @ 0x%02X\n", base_address); /* Enable diag mode */ cycled_write_operation((0x19 + base_address), 0xEE, 6); /* Write magic cookie Hi */ cycled_write_operation((0x1A + base_address), 0xAB, 6); /* Write magic cookie Lo */ @@ -110,7 +111,7 @@ void read_fpgasid_configuration(uint8_t base_address) idHi = cycled_read_operation((0x1 + base_address), 4); /* Read identify Lo */ uint16_t fpgasid_id = (idHi << 8 | idLo); if (fpgasid_id != FPGASID_IDENTIFIER) { - CFG("[SID] ERROR: 0x%04X != 0x%04X FPGASID NOT FOUND @ 0x%02X\n", fpgasid_id, FPGASID_IDENTIFIER, base_address); + usCFG("[SID] ERROR: 0x%04X != 0x%04X FPGASID NOT FOUND @ 0x%02X\n", fpgasid_id, FPGASID_IDENTIFIER, base_address); return; } @@ -150,31 +151,31 @@ void read_fpgasid_configuration(uint8_t base_address) cycled_write_operation((0x19 + base_address), 0x0, 6); /* Clear magic cookie Hi */ cycled_write_operation((0x1A + base_address), 0x0, 6); /* Clear magic cookie Lo */ - CFG("\n"); - CFG("[FPGASID DIAGNOSTIC RESULT]\n"); - CFG("ID: %04X (FPGASID)\n", fpgasid_id); - CFG("CPLD REVISION: %02X\n", cpld); - CFG("FPGA REVISION: %02X\n", fpga); - CFG("PCA REVISION: %02X\n", pca); - CFG("UNIQUE IDENTIFIER: %02X%02X%02X%02X%02X%02X%02X%02X\n", + usCFG("\n"); + usCFG("[FPGASID DIAGNOSTIC RESULT]\n"); + usCFG("ID: %04X (FPGASID)\n", fpgasid_id); + usCFG("CPLD REVISION: %02X\n", cpld); + usCFG("FPGA REVISION: %02X\n", fpga); + usCFG("PCA REVISION: %02X\n", pca); + usCFG("UNIQUE IDENTIFIER: %02X%02X%02X%02X%02X%02X%02X%02X\n", unique_id[0], unique_id[1], unique_id[2], unique_id[3], unique_id[4], unique_id[5], unique_id[6], unique_id[7]); - CFG("CLOCK FREQUENCY READS: %.3f uS\n", frequency); - CFG("SELECT PINS: %02X\n", select_pins); - CFG("INDEX CFG A: %02X\n", idxa); - CFG("SID 1 A: %02X%02X%02X\n", sid_one_a[0], sid_one_a[1], sid_one_a[2]); - CFG("SID 2 A: %02X%02X%02X\n", sid_two_a[0], sid_two_a[1], sid_two_a[2]); - CFG("FILTERBIAS A SID1/SID2: %02X\n", flta); - CFG("INDEX CFG B: %02X\n", idxb); - CFG("SID 1 B: %02X%02X%02X\n", sid_one_b[0], sid_one_b[1], sid_one_b[2]); - CFG("SID 2 B: %02X%02X%02X\n", sid_two_b[0], sid_two_b[1], sid_two_b[2]); - CFG("FILTERBIAS B SID1/SID2: %02X\n", fltb); + usCFG("CLOCK FREQUENCY READS: %.3f uS\n", frequency); + usCFG("SELECT PINS: %02X\n", select_pins); + usCFG("INDEX CFG A: %02X\n", idxa); + usCFG("SID 1 A: %02X%02X%02X\n", sid_one_a[0], sid_one_a[1], sid_one_a[2]); + usCFG("SID 2 A: %02X%02X%02X\n", sid_two_a[0], sid_two_a[1], sid_two_a[2]); + usCFG("FILTERBIAS A SID1/SID2: %02X\n", flta); + usCFG("INDEX CFG B: %02X\n", idxb); + usCFG("SID 1 B: %02X%02X%02X\n", sid_one_b[0], sid_one_b[1], sid_one_b[2]); + usCFG("SID 2 B: %02X%02X%02X\n", sid_two_b[0], sid_two_b[1], sid_two_b[2]); + usCFG("FILTERBIAS B SID1/SID2: %02X\n", fltb); print_fpgasid_sidconfig(0, 1, sid_one_a); print_fpgasid_sidconfig(0, 2, sid_two_a); print_fpgasid_sidconfig(1, 1, sid_one_b); print_fpgasid_sidconfig(1, 2, sid_two_b); - CFG("\n"); + usCFG("\n"); return; } @@ -182,52 +183,54 @@ void read_fpgasid_configuration(uint8_t base_address) void print_skpico_configuration(uint8_t base_address, uint8_t * configarray) { - CFG("\n"); - CFG("[SIDKICK-pico @ 0x%02X CONFIG]\n", base_address); + usCFG("\n"); + usCFG("[SIDKICK-pico @ 0x%02X CONFIG]\n", base_address); for (size_t i = 0; i < 64; i++) { if (i >= 4 && i <= 7) continue; if (i >= 13 && i <= 56) continue; if (i == 62 || i == 63) continue; if (i == 0 || i == 8) { - CFG("[%02ld] %s: %02X ~ %s\n", i, config_names[i], configarray[i], (configarray[i] < s_sid_types) ? (char*)sid_types[configarray[i]] : (char*)error_type[0]); + usCFG("[%02ld] %s: %02X ~ %s\n", i, config_names[i], configarray[i], (configarray[i] < s_sid_types) ? (char*)sid_types[configarray[i]] : (char*)error_type[0]); continue; } if (i == 10) { - CFG("[%02ld] %s: %02X ~ %s\n", i, config_names[i], configarray[i], (configarray[i] < s_sid2_address) ? (char*)sid2_address[configarray[i]] : (char*)error_type[0]); + usCFG("[%02ld] %s: %02X ~ %s\n", i, config_names[i], configarray[i], (configarray[i] < s_sid2_address) ? (char*)sid2_address[configarray[i]] : (char*)error_type[0]); continue; } if (i == 59) { - CFG("[%02ld] %s: %02X ~ %s\n", i, config_names[i], configarray[i], (configarray[i] < s_clock_speed) ? (char*)clock_speed[configarray[i]] : (char*)error_type[0]); + usCFG("[%02ld] %s: %02X ~ %s\n", i, config_names[i], configarray[i], (configarray[i] < s_clock_speed) ? (char*)clock_speed[configarray[i]] : (char*)error_type[0]); continue; } - CFG("[%02ld] %s: %02X\n", i, config_names[i], configarray[i]); + usCFG("[%02ld] %s: %02X\n", i, config_names[i], configarray[i]); } - CFG("[PRINT CFG SETTINGS END]\n"); + usCFG("[PRINT CFG SETTINGS END]\n"); + usCFG("\n"); + } void read_skpico_configuration(uint8_t base_address) { /* Enter config mode */ cycled_write_operation((init_configmode[0] + base_address), init_configmode[1], 6); - /* CFG("[W]$%02X:%02X\n", (init_configmode[0] + base_address), init_configmode[1]); */ + /* usCFG("[W]$%02X:%02X\n", (init_configmode[0] + base_address), init_configmode[1]); */ /* Read config from SKPico */ for (int i = 0; i <= 63; ++i) { sleep_us(1); skpico_config[i] = cycled_read_operation((0x1D + base_address), 0); - /* CFG("[R%d]$%02X:%02X\n", i, (0x1D + base_address), skpico_config[i]); */ + /* usCFG("[R%d]$%02X:%02X\n", i, (0x1D + base_address), skpico_config[i]); */ } /* Exit config mode */ cycled_write_operation((config_exit[0] + base_address), config_exit[1], 6); - /* CFG("[W]$%02X:%02X\n", (config_exit[0] + base_address), config_exit[1]); */ + /* usCFG("[W]$%02X:%02X\n", (config_exit[0] + base_address), config_exit[1]); */ - CFG("\n"); - CFG("[SKPICO RECEIVED BUFFER]\n"); + usCFG("\n"); + usCFG("[SKPICO RECEIVED BUFFER]\n"); print_cfg(skpico_config, 64); print_skpico_configuration(base_address, skpico_config); - CFG("\n"); + usCFG("\n"); } @@ -242,11 +245,11 @@ void switch_pdsid_type(void) set_paused_state(false); // paused_state = 0; clear_volume_state(); // memset(volume_state, 0, 4); clear_sid_memory(); // memset(sid_memory, 0, count_of(sid_memory)); - CFG("[SID] RST PIN LOW\n"); + usCFG("[SID] RST PIN LOW\n"); cPIN(RES); // gpio_put(RES, 0); - CFG("[SID] SLEEP\n"); + usCFG("[SID] SLEEP\n"); sleep_ms(6000); - CFG("[SID] RST PIN HIGH\n"); + usCFG("[SID] RST PIN HIGH\n"); sPIN(RES); // gpio_put(RES, 1); set_reset_state(false); // reset_state = 0; return; diff --git a/src/sid_detection.c b/src/sid_detection.c index ab4c734..613a354 100644 --- a/src/sid_detection.c +++ b/src/sid_detection.c @@ -34,8 +34,8 @@ /* GPIO */ -extern void __no_inline_not_in_flash_func(cycled_write_operation)(uint8_t address, uint8_t data, uint16_t cycles); -extern uint8_t __no_inline_not_in_flash_func(cycled_read_operation)(uint8_t address, uint16_t cycles); +extern void cycled_write_operation(uint8_t address, uint8_t data, uint16_t cycles); +extern uint8_t cycled_read_operation(uint8_t address, uint16_t cycles); extern void clear_bus(int sidno); /* Config */ @@ -69,7 +69,7 @@ uint8_t (*sid_detection[4])(uint8_t) = { detect_sid_model, detect_sid_version, d /* This routine works on real MOS SID chips and does not work on SKPico */ uint8_t detect_sid_model(uint8_t start_addr) { /* https://github.com/GideonZ/1541ultimate/blob/master/software/6502/sidcrt/player/advanced/detection.asm */ - CFG("[SID] DETECT SID MODEL\n"); + usCFG("[SID] DETECT SID MODEL\n"); clear_bus(start_addr / 0x20); int restart = 0; restart: @@ -90,24 +90,24 @@ uint8_t detect_sid_model(uint8_t start_addr) if (restart == 3) goto end; if (sidtype != 0 && sidtype != 1) { restart++; - CFG("[SID] RESTART %d (ST:%u)\n", restart, sidtype); + usCFG("[SID] RESTART %d (ST:%u)\n", restart, sidtype); goto restart; } end: /* output 0 = 8580, 1 = 6581, 2 = unknown * that is: Carry flag is set for 6581, and clear for 8580. */ - CFG("[SID] 0x%02X detect_sid_model sidtype raw %02X\n", start_addr, sidtype); - CFG("[SID] 0x%02X detect_sid_model readtest %02X\n", start_addr, readtest); /* SHOULD READ 3 */ + usCFG("[SID] 0x%02X detect_sid_model sidtype raw %02X\n", start_addr, sidtype); + usCFG("[SID] 0x%02X detect_sid_model readtest %02X\n", start_addr, readtest); /* SHOULD READ 3 */ sidtype = (sidtype == 0 ? 2 : sidtype == 1 ? 3 : 0); /* return 0 = unknown, 2 = 8580, 3 = 6581 */ if (readtest != 3) sidtype = 0; /* if the readtest does not read 3, return unknown */ - CFG("[SID] 0x%02X detect_sid_model return %u\n", start_addr, sidtype); + usCFG("[SID] 0x%02X detect_sid_model return %u\n", start_addr, sidtype); return sidtype; } /* This routine works on real MOS SID chips and does not work on SKPico */ uint8_t detect_sid_version(uint8_t start_addr) { /* https://codebase64.org/doku.php?id=base:detecting_sid_type_-_safe_method */ - CFG("[SID] DETECT SID VERSION\n"); + usCFG("[SID] DETECT SID VERSION\n"); int restart = 0; restart: /* LDA #$ff ~ 2 cycles */ @@ -126,21 +126,21 @@ uint8_t detect_sid_version(uint8_t start_addr) if (restart == 3) goto end; if (sidtype != 2 && sidtype != 3) { restart++; - CFG("[SID] RESTART %d (ST:%u)\n", restart, sidtype); + usCFG("[SID] RESTART %d (ST:%u)\n", restart, sidtype); goto restart; } end: restart = 0; - CFG("[SID] 0x%02X detect_sid_version raw %02X\n", start_addr, sidtype); + usCFG("[SID] 0x%02X detect_sid_version raw %02X\n", start_addr, sidtype); // sidtype = (sidtype < 4 ? sidtype : 0); sidtype = ((sidtype >= 1) && (sidtype % 2) == 0 ? 2 : 3); - CFG("[SID] 0x%02X detect_sid_version return %02X\n", start_addr, sidtype); + usCFG("[SID] 0x%02X detect_sid_version return %02X\n", start_addr, sidtype); return sidtype; } 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"); + usCFG("[SID] DETECT SID UNSAFE\n"); /* clear sid registers */ for (uint reg = 0; reg < count_of(sid_registers) - 4; reg++) { /* STA $D400,x ~ 5 cycles */ @@ -160,17 +160,17 @@ uint8_t detect_sid_unsafe(uint8_t start_addr) /* LDA $d41b ~ 4 cycles */ uint8_t sidtype = cycled_read_operation((start_addr + 0x1B), 8); - CFG("[SID] 0x%02X detect_sid_version raw %02X\n", start_addr, sidtype); + usCFG("[SID] 0x%02X detect_sid_version raw %02X\n", start_addr, sidtype); // sidtype = (sidtype < 4 ? sidtype : 0); sidtype = ((sidtype >= 1) && (sidtype % 2) == 0 ? 2 : 3); - CFG("[SID] 0x%02X detect_sid_version return %02X\n", start_addr, sidtype); + usCFG("[SID] 0x%02X detect_sid_version return %02X\n", start_addr, sidtype); return sidtype; } /* This routine works on SKPico and does not work on real MOS SID chips */ uint8_t detect_sid_version_skpico(uint8_t start_addr) /* Not working on real SIDS!? */ { /* https://codebase64.org/doku.php?id=base:detecting_sid_type_-_safe_method */ - CFG("[SID] DETECT SID VERSION SKPICO\n"); + usCFG("[SID] DETECT SID VERSION SKPICO\n"); int restart = 0; restart: /* LDA #$ff ~ 2 cycles */ @@ -191,20 +191,20 @@ uint8_t detect_sid_version_skpico(uint8_t start_addr) /* Not working on real SI if (restart == 3) goto end; if (sidtype != 2 && sidtype != 3) { restart++; - CFG("[SID] RESTART %d (ST:%u)\n", restart, sidtype); + usCFG("[SID] RESTART %d (ST:%u)\n", restart, sidtype); goto restart; } end: restart = 0; - CFG("[SID] 0x%02X detect_sid_version_skpico raw %02X\n", start_addr, sidtype); + usCFG("[SID] 0x%02X detect_sid_version_skpico raw %02X\n", start_addr, sidtype); sidtype = (sidtype < 4 ? sidtype : 0); - CFG("[SID] 0x%02X detect_sid_version_skpico %02X\n", start_addr, sidtype); + usCFG("[SID] 0x%02X detect_sid_version_skpico %02X\n", start_addr, sidtype); return sidtype; /* that is: Carry flag is set for 6581, and clear for 8580. */ } bool detect_skpico(uint8_t base_address) { - CFG("[SID] CHECKING FOR SIDKICK-pico @ 0x%02X\n", base_address); + usCFG("[SID] CHECKING FOR SIDKICK-pico @ 0x%02X\n", base_address); /* SKPico routine */ char skpico_version[36] = {0}; cycled_write_operation((0x1F + base_address), 0xFF, 10); /* Init config mode */ @@ -222,7 +222,7 @@ bool detect_skpico(uint8_t base_address) && skpico_version[3] == 0x69 && skpico_version[4] == 0x63 && skpico_version[5] == 0x6F) { - CFG("[SID] SIDKICK-pico @ 0x%02X version is: %.36s\n", base_address, skpico_version); + usCFG("[SID] SIDKICK-pico @ 0x%02X version is: %.36s\n", base_address, skpico_version); return true; } return false; @@ -230,7 +230,7 @@ bool detect_skpico(uint8_t base_address) bool detect_fpgasid(uint8_t base_address) { - CFG("[SID] CHECKING FOR FPGASID @ 0x%02X\n", base_address); + usCFG("[SID] CHECKING FOR FPGASID @ 0x%02X\n", base_address); uint8_t idHi, idLo; /* Enable configuration mode (if available) */ cycled_write_operation((0x19 + base_address), 0x80, 6); /* Write magic cookie Hi */ @@ -243,9 +243,9 @@ bool detect_fpgasid(uint8_t base_address) cycled_write_operation((0x19 + base_address), 0x0, 6); /* Clear magic cookie Hi */ cycled_write_operation((0x1A + base_address), 0x0, 6); /* Clear magic cookie Lo */ uint16_t fpgasid_id = (idHi << 8 | idLo); - CFG("[SID] READ IDENTIFY 0x%04X (0x%02X,0x%02X) @ 0x%02X\n", fpgasid_id, idHi, idLo, base_address); + usCFG("[SID] READ IDENTIFY 0x%04X (0x%02X,0x%02X) @ 0x%02X\n", fpgasid_id, idHi, idLo, base_address); if (fpgasid_id == FPGASID_ID) { - CFG("[SID] Found FPGASID @ 0x%02X\n", base_address); + usCFG("[SID] Found FPGASID @ 0x%02X\n", base_address); return true; } return false; @@ -253,7 +253,7 @@ bool detect_fpgasid(uint8_t base_address) bool detect_fmopl(uint8_t base_address) { - CFG("[SID] DETECT FMOPL @: %02X\n", base_address); + usCFG("[SID] DETECT FMOPL @: %02X\n", base_address); int restart = 0; restart: cycled_write_operation(base_address, 0x04, 10); @@ -261,7 +261,7 @@ bool detect_fmopl(uint8_t base_address) cycled_write_operation(base_address, 0x04, 10); cycled_write_operation((base_address + 0x10), 0x80, 10); uint8_t r = cycled_read_operation(base_address, 10); - CFG("[SID] READ FMOPL = 0xC0? %02X\n", r); + usCFG("[SID] READ FMOPL = 0xC0? %02X\n", r); if (restart == 3) goto end; if (r != 0xC0) { restart++; @@ -306,7 +306,7 @@ uint8_t detect_sid_type(Socket * socket, SIDChip * sidchip) int detection_routine = (socket->clonetype != 2 ? 0 : 2); if (sidchip->addr != 0xFF) { uint8_t sid = sid_detection[detection_routine](sidchip->addr); - CFG("[CONFIG] [READ SID%d] [%02x %s]\n", (sidchip->id + 1), sid, sidtypes[sid]); + usCFG("[READ SID%d] [%02x %s]\n", (sidchip->id + 1), sid, sidtypes[sid]); sidchip->type = sid; goto done_sid; } @@ -320,7 +320,7 @@ uint8_t detect_sid_type(Socket * socket, SIDChip * sidchip) apply_fmopl_config(false); }; } - CFG("[CONFIG] SOCKET ONE SID%d TYPE: %s\n", sidchip->id, sidtypes[sidchip->type]); + usCFG("SOCKET ONE SID%d TYPE: %s\n", sidchip->id, sidtypes[sidchip->type]); return sidchip->type; } @@ -330,10 +330,10 @@ uint8_t detect_sid_type(Socket * socket, SIDChip * sidchip) */ void auto_detect_routine(bool auto_config, bool with_delay) { - CFG("\n"); - CFG("[START AUTO DETECT ROUTINE]\n"); + usCFG("\n"); + usCFG("[START AUTO DETECT ROUTINE]\n"); if (auto_config) { - CFG("[SID] SET AUTO CONFIG DEFAULT VALUES\n"); + usCFG("[SID] SET AUTO CONFIG DEFAULT VALUES\n"); usbsid_config.mirrored = false; /* Yeah let's just disable that for now okay? */ /* Socket One */ @@ -364,11 +364,11 @@ void auto_detect_routine(bool auto_config, bool with_delay) apply_socket_change(true); if (with_delay) sleep_ms(250); /* Stupid workaround for SKPico requiring a zillion ms to boot up */ } - CFG("[SID] START CHIP TYPE DETECTION FOR SOCKET ONE\n"); + usCFG("[SID] START CHIP TYPE DETECTION FOR SOCKET ONE\n"); if (with_delay) sleep_ms(500); /* Stupid workaround for SKPico requiring a zillion ms to boot up */ /* SocketOne (twice if failed) */ if (detect_clone_type(&usbsid_config.socketOne) == 0) detect_clone_type(&usbsid_config.socketOne); - CFG("[SID] START CHIP TYPE DETECTION FOR SOCKET TWO\n"); + usCFG("[SID] START CHIP TYPE DETECTION FOR SOCKET TWO\n"); if (with_delay) sleep_ms(500); /* SocketTwo (twice if failed) */ if (detect_clone_type(&usbsid_config.socketTwo) == 0) detect_clone_type(&usbsid_config.socketTwo); @@ -378,11 +378,11 @@ void auto_detect_routine(bool auto_config, bool with_delay) if (with_delay) sleep_ms(250); /* Stupid workaround for SKPico requiring a zillion ms to boot up */ /* Detect SID types at default config once, uses the chiptype to define the detection routine */ - CFG("[SID] START SID TYPE DETECTION FOR SOCKET ONE\n"); + usCFG("[SID] START SID TYPE DETECTION FOR SOCKET ONE\n"); detect_sid_type(&usbsid_config.socketOne, &usbsid_config.socketOne.sid1); if (usbsid_config.socketOne.dualsid) detect_sid_type(&usbsid_config.socketOne, &usbsid_config.socketOne.sid2); - CFG("[SID] START SID TYPE DETECTION FOR SOCKET TWO\n"); + usCFG("[SID] START SID TYPE DETECTION FOR SOCKET TWO\n"); detect_sid_type(&usbsid_config.socketTwo, &usbsid_config.socketTwo.sid1); if (usbsid_config.socketTwo.dualsid) detect_sid_type(&usbsid_config.socketTwo, &usbsid_config.socketTwo.sid2); @@ -393,10 +393,11 @@ void auto_detect_routine(bool auto_config, bool with_delay) /* Apply new socket and bus config */ apply_socket_change(true); - CFG("[END AUTO DETECT ROUTINE]\n"); + usCFG("[END AUTO DETECT ROUTINE]\n"); if (check_socket_config_errors()) { - CFG("[AUTO DETECT CONFIG ERROR DETECTED]\n"); + usCFG("[AUTO DETECT CONFIG ERROR DETECTED]\n"); socket_config_fallback(); } + usCFG("\n"); } diff --git a/src/sid_tests.c b/src/sid_tests.c index 51cb97b..4d9e518 100644 --- a/src/sid_tests.c +++ b/src/sid_tests.c @@ -31,7 +31,7 @@ /* GPIO */ -extern void __no_inline_not_in_flash_func(cycled_write_operation)(uint8_t address, uint8_t data, uint16_t cycles); +extern void cycled_write_operation(uint8_t address, uint8_t data, uint16_t cycles); extern void clear_sid_registers(int sidno); extern void reset_sid_registers(void); @@ -83,29 +83,29 @@ void test_all_waveforms(uint8_t addr, uint8_t voices[3]) test_operation((sid_registers[MODVOL] + addr), 0x0F); /* Volume to full */ for (int v = 0; v < 3; v++) { if (!running_tests) { reset_sid_registers(); return; }; - DBG("TEST VOICE %d\n", (v + 1)); - DBG("WAVEFORM TESTS\n"); + usDBG("TEST VOICE %d\n", (v + 1)); + usDBG("WAVEFORM TESTS\n"); test_operation((voices[v] + sid_registers[ATTDEC]), 33); /* ATTDEC 2*16+1 */ test_operation((voices[v] + sid_registers[SUSREL]), 242); /* SUSREL 15*16+2 */ test_operation((voices[v] + sid_registers[PWMHI]), 8); /* PWMHI */ - DBG("TRIANGLE TESTING "); + usDBG("TRIANGLE TESTING "); wave_form_test(voices, v, 17, 16); - DBG("COMPLETE\n"); - DBG("SAWTOOTH TESTING "); + usDBG("COMPLETE\n"); + usDBG("SAWTOOTH TESTING "); wave_form_test(voices, v, 33, 32); - DBG("COMPLETE\n"); - DBG("PULSE TESTING "); + usDBG("COMPLETE\n"); + usDBG("PULSE TESTING "); wave_form_test(voices, v, 65, 64); - DBG("COMPLETE\n"); - DBG("NOISE TESTING "); + usDBG("COMPLETE\n"); + usDBG("NOISE TESTING "); wave_form_test(voices, v, 129, 128); - DBG("COMPLETE\n"); + usDBG("COMPLETE\n"); - DBG("PULSE WIDTH SWEEP TESTING "); + usDBG("PULSE WIDTH SWEEP TESTING "); test_operation((voices[v] + sid_registers[NOTEHI]), 40); /* NOTEHI */ pulse_sweep_test(voices, v, 65, 64); - DBG("COMPLETE\n"); + usDBG("COMPLETE\n"); } } @@ -113,18 +113,18 @@ void filter_tests(uint8_t addr, uint8_t voices[3], int wf) { if (!running_tests) { reset_sid_registers(); return; }; test_operation((sid_registers[MODVOL] + addr), 0x0F); /* Volume to full */ - DBG("FILTER TESTS %s\n", (wf == 0 ? "TRIANGLE" : wf == 1 ? "SAWTOOTH" : wf == 2 ? "PULSE" : "NOISE")); + usDBG("FILTER TESTS %s\n", (wf == 0 ? "TRIANGLE" : wf == 1 ? "SAWTOOTH" : wf == 2 ? "PULSE" : "NOISE")); for (int fq = 15; fq <= 45; fq += 15) { if (!running_tests) { reset_sid_registers(); return; }; - DBG("HIGH FILTER FREQUENCY = %d\n", fq); + usDBG("HIGH FILTER FREQUENCY = %d\n", fq); test_operation(sid_registers[RESFLT], 87); /* RESFLT 5*16+1+2+4 */ for (int flt = 1; flt <= 3; flt++) { if (!running_tests) { reset_sid_registers(); return; }; - DBG("%s PASS\n", (flt == 1 ? "LOW" : flt == 2 ? "BAND" : "HIGH")); + usDBG("%s PASS\n", (flt == 1 ? "LOW" : flt == 2 ? "BAND" : "HIGH")); test_operation(sid_registers[MODVOL], (flt == 1 ? 31 : flt == 2 ? 47 : 79)); /* MODVOL */ for (int v = 0; v < 3; v++) { if (!running_tests) { reset_sid_registers(); return; }; - DBG("VOICE %d TESTING ", (v + 1)); + usDBG("VOICE %d TESTING ", (v + 1)); test_operation((voices[v] + sid_registers[NOTEHI]), fq); /* NOTEHI */ test_operation((voices[v] + sid_registers[ATTDEC]), 0); /* ATTDEC */ test_operation((voices[v] + sid_registers[SUSREL]), 240); /* SUSREL */ @@ -136,7 +136,7 @@ void filter_tests(uint8_t addr, uint8_t voices[3], int wf) sleep_ms(8); } test_operation((voices[v] + sid_registers[CONTR]), waveforms[wf]); /* CONTR */ - DBG("COMPLETE\n"); + usDBG("COMPLETE\n"); } } } @@ -146,10 +146,10 @@ void envelope_tests(uint8_t addr, uint8_t voices[3], int wf) { if (!running_tests) { reset_sid_registers(); return; }; test_operation((sid_registers[MODVOL] + addr), 0x0F); /* Volume to full */ - DBG("A D S R TESTS %s\n", (wf == 0 ? "TRIANGLE" : wf == 1 ? "SAWTOOTH" : wf == 2 ? "PULSE" : "NOISE")); + usDBG("A D S R TESTS %s\n", (wf == 0 ? "TRIANGLE" : wf == 1 ? "SAWTOOTH" : wf == 2 ? "PULSE" : "NOISE")); for (int v = 0; v < 3; v++) { if (!running_tests) { reset_sid_registers(); return; }; - DBG("VOICE %d A D S R TESTING ", (v + 1)); + usDBG("VOICE %d A D S R TESTING ", (v + 1)); test_operation((voices[v] + sid_registers[ATTDEC]), 170); /* ATTDEC 10*16+10 */ test_operation((voices[v] + sid_registers[SUSREL]), 58); /* SUSREL 3*16+10 */ test_operation((voices[v] + sid_registers[NOTEHI]), 40); /* NOTEHI */ @@ -158,38 +158,38 @@ void envelope_tests(uint8_t addr, uint8_t voices[3], int wf) if (!running_tests) { reset_sid_registers(); return; }; sleep_ms(3000); test_operation((voices[v] + sid_registers[CONTR]), waveforms[wf]); /* CONTR */ - DBG("RELEASE "); + usDBG("RELEASE "); if (!running_tests) { reset_sid_registers(); return; }; sleep_ms(1000); - DBG("COMPLETE\n"); + usDBG("COMPLETE\n"); if (!running_tests) { reset_sid_registers(); return; }; sleep_ms(600); - DBG("VOICE %d S R TESTING ", (v + 1)); + usDBG("VOICE %d S R TESTING ", (v + 1)); test_operation((voices[v] + sid_registers[ATTDEC]), 0); /* ATTDEC */ test_operation((voices[v] + sid_registers[SUSREL]), 250); /* SUSREL 15*16+10 */ test_operation((voices[v] + sid_registers[CONTR]), (waveforms[wf] + 1)); /* CONTR */ if (!running_tests) { reset_sid_registers(); return; }; sleep_ms(600); test_operation((voices[v] + sid_registers[CONTR]), waveforms[wf]); /* CONTR */ - DBG("RELEASE "); + usDBG("RELEASE "); if (!running_tests) { reset_sid_registers(); return; }; sleep_ms(600); - DBG("COMPLETE\n"); + usDBG("COMPLETE\n"); if (!running_tests) { reset_sid_registers(); return; }; sleep_ms(600); - DBG("VOICE %d A D TESTING ", (v + 1)); + usDBG("VOICE %d A D TESTING ", (v + 1)); test_operation((voices[v] + sid_registers[ATTDEC]), 170); /* ATTDEC 10*16+10 */ test_operation((voices[v] + sid_registers[SUSREL]), 0); /* SUSREL */ test_operation((voices[v] + sid_registers[CONTR]), (waveforms[wf] + 1)); /* CONTR */ if (!running_tests) { reset_sid_registers(); return; }; sleep_ms(2000); test_operation((voices[v] + sid_registers[CONTR]), waveforms[wf]); /* CONTR */ - DBG("RELEASE "); + usDBG("RELEASE "); if (!running_tests) { reset_sid_registers(); return; }; sleep_ms(600); - DBG("COMPLETE\n"); + usDBG("COMPLETE\n"); if (!running_tests) { reset_sid_registers(); return; }; sleep_ms(600); } @@ -199,11 +199,11 @@ void modulation_tests(uint8_t addr, uint8_t voices[3], int wf) { if (!running_tests) { reset_sid_registers(); return; }; test_operation((sid_registers[MODVOL] + addr), 0x0F); /* Volume to full */ - DBG("RING MODULATION TESTS %s\n", (wf == 0 ? "TRIANGLE" : wf == 1 ? "SAWTOOTH" : wf == 2 ? "PULSE" : "NOISE")); + usDBG("RING MODULATION TESTS %s\n", (wf == 0 ? "TRIANGLE" : wf == 1 ? "SAWTOOTH" : wf == 2 ? "PULSE" : "NOISE")); for (int v = 0; v < 3; v++) { if (!running_tests) { reset_sid_registers(); return; }; int v2 = (v == 1 ? 0 : v == 2 ? 1 : 2); - DBG("VOICE %d WITH VOICE %d ", (v + 1), (v2 + 1)); + usDBG("VOICE %d WITH VOICE %d ", (v + 1), (v2 + 1)); test_operation((voices[v] + sid_registers[PWMHI]), 8); /* PWMHI */ test_operation((voices[v] + sid_registers[ATTDEC]), 0); /* ATTDEC */ test_operation((voices[v] + sid_registers[SUSREL]), 250); /* SUSREL 15*16+10 */ @@ -215,7 +215,7 @@ void modulation_tests(uint8_t addr, uint8_t voices[3], int wf) sleep_ms(24); } test_operation((voices[v] + sid_registers[CONTR]), 0); /* CONTR */ - DBG("COMPLETE\n"); + usDBG("COMPLETE\n"); } } diff --git a/src/uart.c b/src/uart.c index fcb7121..13cf47b 100644 --- a/src/uart.c +++ b/src/uart.c @@ -28,29 +28,28 @@ */ #ifdef USE_PIO_UART +#if PICO_RP2350 #include "globals.h" #include "uart.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 */ +/* usbsid.c */ +extern uint8_t uart_buffer[64]; extern int usbdata; extern char ntype, dtype, uart; extern bool offload_ledrunner; +/* gpio.c */ +extern uint16_t cycled_delay_operation(uint16_t cycles); +extern uint8_t cycled_read_operation(uint8_t address, uint16_t cycles); +extern void cycled_write_operation(uint8_t address, uint8_t data, uint16_t cycles); +extern uint16_t cycled_delayed_write_operation(uint8_t address, uint8_t data, uint16_t cycles); +extern void reset_sid(void); + /* Locals */ -static PIO uart_pio = pio1; +static PIO uart_pio = pio2; static uint sm_uartrx; static int8_t pioirq_uartrx; static queue_t fifo_uartrx; @@ -120,11 +119,11 @@ static void async_worker_func(__unused async_context_t *async_context, __unused 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]); + // usDBG("[%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"); + usDBG("[UART CONFIG] RESET\n"); memset(uart_buffer, 0, 8); bytes_per_rxpacket = 8; bytes_rxed = 0; @@ -151,7 +150,7 @@ static void async_worker_func(__unused async_context_t *async_context, __unused && 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); + usDBG("[UART CONFIG] BYTES PER PACKET SET TO %d\n", bytes_per_rxpacket); memset(uart_buffer, 0, 8); bytes_rxed = 0; } @@ -236,4 +235,5 @@ void deinit_uart(void) return; } +#endif /* PICO_RP2350 */ #endif /* USE_PIO_UART */ diff --git a/src/uart.h b/src/uart.h index 05473a6..45dd08e 100644 --- a/src/uart.h +++ b/src/uart.h @@ -32,6 +32,7 @@ #endif #ifdef USE_PIO_UART +#if PICO_RP2350 /* Default includes */ @@ -58,6 +59,7 @@ #define UART_FIFO_SIZE 65535 /* TODO: Verify size */ +#endif /* PICO_RP2350 */ #endif /* USE_PIO_UART */ #ifdef __cplusplus diff --git a/src/usbsid.c b/src/usbsid.c index 540eb63..b099c10 100644 --- a/src/usbsid.c +++ b/src/usbsid.c @@ -92,9 +92,9 @@ extern void reset_sid_registers(void); extern void enable_sid(bool unmute); extern void disable_sid(void); extern void clear_bus_all(void); -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 cycled_delay_operation(uint16_t cycles); +extern uint8_t cycled_read_operation(uint8_t address, uint16_t cycles); +extern void cycled_write_operation(uint8_t address, uint8_t data, uint16_t cycles); extern bool is_muted; /* Uart */ @@ -165,8 +165,13 @@ midi_machine midimachine; queue_t sidtest_queue; queue_t logging_queue; -/* Declare local variables */ -static semaphore_t core0_init, core1_init; +/* Multicore sync using atomic memory - avoids semaphore spin locks AND + * FIFO (which is consumed by flash_safe_execute IRQ handler) */ +static volatile uint32_t core_sync_state = 0; +#define SYNC_CORE1_STAGE1 0x11 /* Core 1 finished flash_safe_execute_core_init */ +#define SYNC_CORE0_STAGE1 0x01 /* Core 0 finished config loading */ +#define SYNC_CORE1_STAGE2 0x12 /* Core 1 finished queue/uart init */ +#define SYNC_CORE0_STAGE2 0x02 /* Core 0 finished hardware init */ /* WebUSB Description URL */ static const tusb_desc_webusb_url_t desc_url = @@ -184,27 +189,27 @@ static const tusb_desc_webusb_url_t desc_url = void reset_reason(void) { #if PICO_RP2040 - DBG("[RESET] Button double tapped? %d\n", flagged); + usNFO("[RESET] Button double tapped? %d\n", flagged); io_rw_32 *rr = (io_rw_32 *) (VREG_AND_CHIP_RESET_BASE + VREG_AND_CHIP_RESET_CHIP_RESET_OFFSET); if (*rr & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_POR_BITS) - DBG("[RESET] Caused by power-on reset or brownout detection\n"); + usNFO("[RESET] Caused by power-on reset or brownout detection\n"); if (*rr & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_RUN_BITS) - DBG("[RESET] Caused by RUN pin trigger ~ manual or ISA RESET signal\n"); + usNFO("[RESET] Caused by RUN pin trigger ~ manual or ISA RESET signal\n"); if (*rr & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_PSM_RESTART_BITS) - DBG("[RESET] Caused by debug port\n"); + usNFO("[RESET] Caused by debug port\n"); #elif PICO_RP2350 /* io_rw_32 *rr = (io_rw_32 *) (POWMAN_BASE + POWMAN_CHIP_RESET_OFFSET); */ - DBG("[RESET] Button double tapped? %d %X\n", flagged, powman_hw->chip_reset); + usNFO("[RESET] Button double tapped? %d %X\n", flagged, powman_hw->chip_reset); if (/* *rr */ powman_hw->chip_reset & POWMAN_CHIP_RESET_HAD_DP_RESET_REQ_BITS) - DBG("[RESET] Caused by arm debugger\n"); + usNFO("[RESET] Caused by arm debugger\n"); if (/* *rr */ powman_hw->chip_reset & POWMAN_CHIP_RESET_HAD_RESCUE_BITS) - DBG("[RESET] Caused by rescure reset from arm debugger\n"); + usNFO("[RESET] Caused by rescure reset from arm debugger\n"); if (/* *rr */ powman_hw->chip_reset & POWMAN_CHIP_RESET_HAD_RUN_LOW_BITS) - DBG("[RESET] Caused by RUN pin trigger ~ manual or ISA RESET signal\n"); + usNFO("[RESET] Caused by RUN pin trigger ~ manual or ISA RESET signal\n"); if (/* *rr */ powman_hw->chip_reset & POWMAN_CHIP_RESET_HAD_BOR_BITS) - DBG("[RESET] Caused by brownout detection\n"); + usNFO("[RESET] Caused by brownout detection\n"); if (/* *rr */ powman_hw->chip_reset & POWMAN_CHIP_RESET_HAD_POR_BITS) - DBG("[RESET] Caused by power-on reset\n"); + usNFO("[RESET] Caused by power-on reset\n"); #endif return; } @@ -219,7 +224,7 @@ void init_logging(void) stdio_uart_init_full(uart0, BAUD_RATE, TX, RX); sleep_ms(100); /* leave time for uart to settle */ stdio_flush(); - DBG("\n[%s]\n", __func__); + usNFO("[NFO] Uart logging initialized\n"); #endif return; } @@ -230,7 +235,7 @@ void init_logging(void) /* Write from device to host */ void cdc_write(uint8_t * itf, uint32_t n) { /* No need to check if write available with current driver code */ - IODBG("[O %d] [%c] $%02X:%02X\n", n, dtype, sid_buffer[1], write_buffer[0]); + usIO("[O %d] [%c] $%02X:%02X\n", n, dtype, sid_buffer[1], write_buffer[0]); tud_cdc_n_write(*itf, write_buffer, n); /* write n bytes of data to client */ tud_cdc_n_write_flush(*itf); return; @@ -239,7 +244,7 @@ void cdc_write(uint8_t * itf, uint32_t n) /* Write from device to host */ void webserial_write(uint8_t * itf, uint32_t n) { /* No need to check if write available with current driver code */ - IODBG("[O %d] [%c] $%02X:%02X\n", n, dtype, sid_buffer[1], write_buffer[0]); + usIO("[O %d] [%c] $%02X:%02X\n", n, dtype, sid_buffer[1], write_buffer[0]); tud_vendor_write(write_buffer, n); tud_vendor_flush(); return; @@ -253,7 +258,7 @@ int __no_inline_not_in_flash_func(do_buffer_tick)(int top, int step) static int i = 1; cycled_write_operation(sid_buffer[i], sid_buffer[i + 1], (step == 4 ? (sid_buffer[i + 2] << 8 | sid_buffer[i + 3]) : MIN_CYCLES)); WRITEDBG(dtype, i, top, sid_buffer[i], sid_buffer[i + 1], (step == 4 ? (sid_buffer[i + 2] << 8 | sid_buffer[i + 3]) : MIN_CYCLES)); - IODBG("[I %d] [%c] $%02X:%02X (%u)\n", i, dtype, sid_buffer[i], sid_buffer[i + 1], (step == 4 ? (sid_buffer[i + 2] << 8 | sid_buffer[i + 3]) : MIN_CYCLES)); + usIO("[I %d] [%c] $%02X:%02X (%u)\n", i, dtype, sid_buffer[i], sid_buffer[i + 1], (step == 4 ? (sid_buffer[i + 2] << 8 | sid_buffer[i + 3]) : MIN_CYCLES)); if (i+step >= top) { i = 1; return i; @@ -286,7 +291,7 @@ void __no_inline_not_in_flash_func(process_buffer)(uint8_t * itf, uint32_t * n) if __us_unlikely(n_bytes == 0) { cycled_write_operation(sid_buffer[1], sid_buffer[2], (sid_buffer[3] << 8 | sid_buffer[4])); WRITEDBG(dtype, n_bytes, n_bytes, sid_buffer[1], sid_buffer[2], (sid_buffer[3] << 8 | sid_buffer[4])); - IODBG("[I %d] [%c] $%02X:%02X (%u)\n", n_bytes, dtype, sid_buffer[1], sid_buffer[2], (sid_buffer[3] << 8 | sid_buffer[4])); + usIO("[I %d] [%c] $%02X:%02X (%u)\n", n_bytes, dtype, sid_buffer[1], sid_buffer[2], (sid_buffer[3] << 8 | sid_buffer[4])); } else { buffer_task(n_bytes, 4); } @@ -297,14 +302,14 @@ void __no_inline_not_in_flash_func(process_buffer)(uint8_t * itf, uint32_t * n) if __us_likely(n_bytes == 0) { cycled_write_operation(sid_buffer[1], sid_buffer[2], 6); /* Add 6 cycles to each write for LDA(2) & STA(4) */ WRITEDBG(dtype, n_bytes, n_bytes, sid_buffer[1], sid_buffer[2], 6); - IODBG("[I %d] [%c] $%02X:%02X (%u)\n", n_bytes, dtype, sid_buffer[1], sid_buffer[2], 6); + usIO("[I %d] [%c] $%02X:%02X (%u)\n", n_bytes, dtype, sid_buffer[1], sid_buffer[2], 6); } else { buffer_task(n_bytes, 2); } return; }; if __us_unlikely(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]); + usIO("[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 (rtype) { /* write the result to the USB client */ case 'C': @@ -314,7 +319,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", rtype); + usIO("[WRITE ERROR]%c\n", rtype); break; }; vu = (vu == 0 ? 100 : vu); /* NOTICE: Testfix for core1 setting dtype to 0 */ @@ -323,7 +328,7 @@ void __no_inline_not_in_flash_func(process_buffer)(uint8_t * itf, uint32_t * n) if (command == COMMAND) { switch (subcommand) { case CYCLED_READ: - IODBG("[I %d] [%c] $%02X %u\n", n_bytes, dtype, sid_buffer[1], (sid_buffer[2] << 8 | sid_buffer[3])); + usIO("[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 (rtype) { /* write the result to the USB client */ case 'C': @@ -333,7 +338,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", rtype); + usIO("[WRITE ERROR]%c\n", rtype); break; }; vu = (vu == 0 ? 100 : vu); /* NOTICE: Testfix for core1 setting dtype to 0 */ @@ -342,44 +347,44 @@ void __no_inline_not_in_flash_func(process_buffer)(uint8_t * itf, uint32_t * n) cycled_delay_operation((sid_buffer[1] << 8 | sid_buffer[2])); return; case PAUSE: - DBG("[PAUSE_SID]\n"); + usDBG("[PAUSE_SID]\n"); pause_sid(); break; case MUTE: - DBG("[MUTE_SID] %d\n",sid_buffer[1]); + usDBG("[MUTE_SID] %d\n",sid_buffer[1]); mute_sid(); if (sid_buffer[1] == 1) is_muted = true; break; case UNMUTE: - DBG("[UNMUTE_SID] %d\n",sid_buffer[1]); + usDBG("[UNMUTE_SID] %d\n",sid_buffer[1]); if (sid_buffer[1] == 1) is_muted = false; unmute_sid(); break; case RESET_SID: if (sid_buffer[1] == 0) { - DBG("[RESET_SID]\n"); + usDBG("[RESET_SID]\n"); reset_sid(); } if (sid_buffer[1] == 1) { - DBG("[RESET_SID_REGISTERS]\n"); + usDBG("[RESET_SID_REGISTERS]\n"); reset_sid_registers(); } break; case DISABLE_SID: - DBG("[DISABLE_SID]\n"); + usDBG("[DISABLE_SID]\n"); disable_sid(); break; case ENABLE_SID: - DBG("[ENABLE_SID]\n"); + usDBG("[ENABLE_SID]\n"); enable_sid(true); break; case CLEAR_BUS: - DBG("[CLEAR_BUS]\n"); + usDBG("[CLEAR_BUS]\n"); clear_bus_all(); break; case CONFIG: if (sid_buffer[1] < 0xD0) { /* Don't log incoming buffer to avoid spam above this region */ - DBG("[CONFIG]\n"); + usDBG("[CONFIG]\n"); } /* Copy incoming buffer ignoring the command byte */ memcpy(config_buffer, (sid_buffer + 1), (int)*n - 1); @@ -387,11 +392,11 @@ void __no_inline_not_in_flash_func(process_buffer)(uint8_t * itf, uint32_t * n) memset(config_buffer, 0, count_of(config_buffer)); break; case RESET_MCU: - DBG("[RESET_MCU]\n"); + usDBG("[RESET_MCU]\n"); mcu_reset(); break; case BOOTLOADER: - DBG("[BOOTLOADER]\n"); + usDBG("[BOOTLOADER]\n"); mcu_jump_to_bootloader(); break; default: @@ -407,27 +412,27 @@ void __no_inline_not_in_flash_func(process_buffer)(uint8_t * itf, uint32_t * n) void tud_mount_cb(void) { - DBG("[%s]\n", __func__); + usDBG("[%s]\n", __func__); usb_connected = 1; } void tud_umount_cb(void) { usb_connected = 0, usbdata = 0, dtype = rtype = ntype; - DBG("[%s]\n", __func__); + usDBG("[%s]\n", __func__); disable_sid(); /* NOTICE: Testing if this is causing the random lockups */ } void tud_suspend_cb(bool remote_wakeup_en) { /* (void) remote_wakeup_en; */ - DBG("[%s] remote_wakeup_en:%d\n", __func__, remote_wakeup_en); + usDBG("[%s] remote_wakeup_en:%d\n", __func__, remote_wakeup_en); usb_connected = 0, usbdata = 0, dtype = rtype = ntype; } void tud_resume_cb(void) { - DBG("[%s]\n", __func__); + usDBG("[%s]\n", __func__); usb_connected = 1; } @@ -509,20 +514,20 @@ void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) { (void)itf; (void)wanted_char; - /* DBG("[%s]\n", __func__); */ /* Disabled due to possible uart spam */ + /* usDBG("[%s]\n", __func__); */ /* Disabled due to possible uart spam */ } void tud_cdc_tx_complete_cb(uint8_t itf) { (void)itf; - /* DBG("[%s]\n", __func__); */ /* Disabled due to uart spam */ + /* usDBG("[%s]\n", __func__); */ /* Disabled due to uart spam */ } void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) { /* (void) itf; */ /* (void) rts; */ - DBG("[%s] itf:%x, dtr:%d, rts:%d\n", __func__, itf, dtr, rts); + usDBG("[%s] itf:%x, dtr:%d, rts:%d\n", __func__, itf, dtr, rts); if ( dtr ) { /* Terminal connected */ @@ -539,14 +544,14 @@ void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding) { /* (void)itf; */ /* (void)p_line_coding; */ - DBG("[%s] itf:%x, bit_rate:%u, stop_bits:%u, parity:%u, data_bits:%u\n", __func__, itf, (int)p_line_coding->bit_rate, p_line_coding->stop_bits, p_line_coding->parity, p_line_coding->data_bits); + usDBG("[%s] itf:%x, bit_rate:%u, stop_bits:%u, parity:%u, data_bits:%u\n", __func__, itf, (int)p_line_coding->bit_rate, p_line_coding->stop_bits, p_line_coding->parity, p_line_coding->data_bits); } void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms) { /* (void)itf; */ /* (void)duration_ms; */ - DBG("[%s] its:%x, duration_ms:%x\n", __func__, itf, duration_ms); + usDBG("[%s] its:%x, duration_ms:%x\n", __func__, itf, duration_ms); } @@ -591,7 +596,7 @@ void tud_vendor_rx_cb(uint8_t itf, uint8_t const* buffer, uint16_t bufsize) void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes) { (void)itf; - DBG("[%s] %lu\n", __func__, sent_bytes); + usDBG("[%s] %lu\n", __func__, sent_bytes); } @@ -600,7 +605,7 @@ void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes) /* Handle incoming vendor and webusb data */ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) { - DBG("[%s] stage:%x, rhport:%x, bRequest:0x%x, wValue:%d, wIndex:%x, wLength:%x, bmRequestType:%x, type:%x, recipient:%x, direction:%x\n", + usDBG("[%s] stage:%x, rhport:%x, bRequest:0x%x, wValue:%d, wIndex:%x, wLength:%x, bmRequestType:%x, type:%x, recipient:%x, direction:%x\n", __func__, stage, rhport, request->bRequest, request->wValue, request->wIndex, request->wLength, request->bmRequestType, request->bmRequestType_bit.type, request->bmRequestType_bit.recipient, request->bmRequestType_bit.direction); @@ -612,25 +617,25 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ break; case TUSB_REQ_TYPE_CLASS: /* 1 */ if (request->bRequest == WEBUSB_COMMAND) { - DBG("request->bRequest == WEBUSB_COMMAND\n"); + usDBG("request->bRequest == WEBUSB_COMMAND\n"); if (request->wValue == WEBUSB_RESET) { - DBG("request->wValue == WEBUSB_RESET\n"); + usDBG("request->wValue == WEBUSB_RESET\n"); // BUG: NO WURKY CURKY /* reset_sid_registers(); */ // BUG: Temporary disabled reset_sid(); // NOTICE: Temporary until fixed! /* unmute_sid(); */ } if (request->wValue == RESET_SID) { - DBG("request->wValue == RESET_SID\n"); + usDBG("request->wValue == RESET_SID\n"); reset_sid(); } if (request->wValue == PAUSE) { - DBG("request->wValue == PAUSE\n"); + usDBG("request->wValue == PAUSE\n"); pause_sid(); mute_sid(); } if (request->wValue == WEBUSB_CONTINUE) { - DBG("request->wValue == WEBUSB_CONTINUE\n"); + usDBG("request->wValue == WEBUSB_CONTINUE\n"); pause_sid(); unmute_sid(); } @@ -681,26 +686,23 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ /* MAIN */ -/* Semaphore ping pong +/* Multicore sync using atomic memory (avoids semaphore spin locks AND + * FIFO which is consumed by flash_safe_execute IRQ handler) * - * Core 0 -> init semapohre core1_init * Core 0 -> launch core 1 - * Core 0 -> wait for core1_init signal + * Core 0 -> poll for SYNC_CORE1_STAGE1 * Core 1 -> init flash safe execute - * Core 1 -> release semaphore core1_init - * Core 0 -> continue to load and apply config - * Core 0 -> init SID clock - * Core 1 -> init semaphore core0_init - * Core 1 -> wait for core0_init signal - * Core 0 -> release semaphore core0_init - * Core 0 -> wait for core1_init signal - * Core 1 -> continue startup RGB & Vu - * Core 1 -> release semaphore core1_init - * Core 1 -> wait for core0_init signal - * Core 0 -> continue startup - * Core 0 -> release semaphore core0_init + * Core 1 -> set SYNC_CORE1_STAGE1 + * Core 1 -> poll for SYNC_CORE0_STAGE1 + * Core 0 -> load and apply config + * Core 0 -> set SYNC_CORE0_STAGE1 + * Core 0 -> poll for SYNC_CORE1_STAGE2 + * Core 1 -> init queues and PIO uart + * Core 1 -> set SYNC_CORE1_STAGE2 + * Core 1 -> poll for SYNC_CORE0_STAGE2 + * Core 0 -> init GPIO, SID clock, PIO, DMA, etc. + * Core 0 -> set SYNC_CORE0_STAGE2 * Core 0 -> enter while loop - * Core 1 -> continue startup * Core 1 -> enter while loop */ void core1_main(void) @@ -708,23 +710,18 @@ void core1_main(void) /* Set core locking for flash saving ~ note this makes SIO_IRQ_PROC1 unavailable */ flash_safe_execute_core_init(); /* This needs to start before any flash actions take place! */ - /* Workaround to make sure flash_safe_execute is executed - * before everything else if a default config is detected - * This just ping pongs bootup around with Core 0 - * - * Release core 1 semaphore */ - sem_release(&core1_init); + /* Signal Core 0 we're ready (sync point 1) */ + usBOOT(" Signaling core0 ready ~ 1\n"); + __dmb(); /* Memory barrier before write */ + core_sync_state = SYNC_CORE1_STAGE1; + __sev(); /* Signal event to wake Core 0 from WFE */ - /* Create a blocking semaphore with max 1 permit */ - sem_init(&core0_init, 0, 1); - /* Wait for core 0 to signal back */ - sem_acquire_blocking(&core0_init); - - /* Clear the dirt */ - memset(sid_memory, 0, sizeof sid_memory); - - /* Start the VU */ - init_vu(); + /* Wait for Core 0 to finish config loading */ + usBOOT(" Waiting for core0 sync ~ 1\n"); + while (core_sync_state != SYNC_CORE0_STAGE1) { + __wfe(); /* Wait for event - low power wait */ + } + __dmb(); /* Memory barrier after read */ /* Init queues */ queue_init(&sidtest_queue, sizeof(sidtest_queue_entry_t), 1); /* 1 entry deep */ @@ -737,13 +734,34 @@ void core1_main(void) init_uart(); #endif - /* Release semaphore when core 1 is started */ - sem_release(&core1_init); + /* Signal Core 0 we're ready (sync point 2) */ + usBOOT(" Signaling core0 ready ~ 2\n"); + __dmb(); + core_sync_state = SYNC_CORE1_STAGE2; + __sev(); - /* Wait for core 0 to signal boot finished */ - sem_acquire_blocking(&core0_init); + /* Wait for Core 0 to finish hardware init */ + usBOOT(" Waiting for core0 sync ~ 2\n"); + while (core_sync_state != SYNC_CORE0_STAGE2) { + __wfe(); + } + __dmb(); while (1) { + + /* Check SID test queue */ + if (running_tests) { + sidtest_queue_entry_t s_entry; + if (queue_try_remove(&sidtest_queue, &s_entry)) { + s_entry.func(s_entry.s, s_entry.t, s_entry.wf); + } + } + + /* Blinky blinky? */ + if (!offload_ledrunner) { + led_runner(); + } + #if ONBOARD_SIDPLAYER if (sidplayer_init) { sidplayer_init = false; @@ -804,28 +822,17 @@ void core1_main(void) } #endif /* ONBOARD_EMULATOR */ - /* Check SID test queue */ - if (running_tests) { - sidtest_queue_entry_t s_entry; - if (queue_try_remove(&sidtest_queue, &s_entry)) { - s_entry.func(s_entry.s, s_entry.t, s_entry.wf); - } - } - - if (!offload_ledrunner) { - led_runner(); - } - #ifdef WRITE_DEBUG /* Only run this queue when needed */ if (usbdata == 1) { writelogging_queue_entry_t l_entry; if (queue_try_remove(&logging_queue, &l_entry)) { - DBG("[CORE2 %5u] [WRITE %c:%02d/%02d] $%02X:%02X %u\n", + usDBG("[CORE2 %5u] [WRITE %c:%02d/%02d] $%02X:%02X %u\n", queue_get_level(&logging_queue), l_entry.dtype, l_entry.n, l_entry.s, l_entry.reg, l_entry.val, l_entry.cycles); } } #endif + } /* Point of no return, this should never be reached */ return; @@ -842,7 +849,7 @@ int main() set_sys_clock_pll(1500000000, 6, 2); #endif #elif PICO_RP2350 -/* Onboard SID player requires atleast 200MHz! */ + /* Onboard SID player requires atleast 200MHz! */ #if ONBOARD_SIDPLAYER /* System clock @ 200MHz */ set_sys_clock_khz(200000, true); @@ -864,18 +871,18 @@ int main() reset_reason(); /* Clear flagged */ - if (flagged) { auto_config = true; flagged = 0; } /* BUG: NOT WORKING ON RP2350 */ - - /* Workaround to make sure flash_safe_execute is executed - * before everything else if a default config is detected - * This just ping pongs bootup around with Core 1 - * - * Create a blocking semaphore with max 1 permit */ - sem_init(&core1_init, 0, 1); - /* Init core 1 */ + if (flagged) { auto_config = true; flagged = 0; } /* NOTE: Does not work on rp2350 */ + + /* Launch Core 1 and wait for flash_safe_execute_core_init to complete */ + usBOOT("CORE0 Launching core1\n"); multicore_launch_core1(core1_main); - /* Wait for core 1 to signal back */ - sem_acquire_blocking(&core1_init); + + /* Wait for Core 1 to signal ready (sync point 1) */ + usBOOT("CORE0 Waiting for core1 ready ~ 1\n"); + while (core_sync_state != SYNC_CORE1_STAGE1) { + __wfe(); /* Wait for event - low power wait */ + } + __dmb(); /* Insert memory barrier after read */ /* Load config before init of USBSID settings ~ NOTE: This cannot be run from Core 1! */ load_config(&usbsid_config); @@ -889,36 +896,63 @@ int main() sid_mhz = (sid_hz / 1000 / 1000); sid_us = (1 / sid_mhz); if (!auto_config) { - CFG("[BOOT PICO] %lu Hz, %.0f MHz, %.4f uS\n", clock_get_hz(clk_sys), cpu_mhz, cpu_us); - CFG("[BOOT C64] %.0f Hz, %.6f MHz, %.4f uS\n", sid_hz, sid_mhz, sid_us); - CFG("[BOOT C64 RATES] REFRESH_RATE %lu Cycles, RASTER_RATE %lu Cycles\n", usbsid_config.refresh_rate, usbsid_config.raster_rate); + usNFO("[NFO] [PICO] %lu Hz, %.0f MHz, %.4f uS\n", clock_get_hz(clk_sys), cpu_mhz, cpu_us); + usNFO("[NFO] [C64] %.0f Hz, %.6f MHz, %.4f uS\n", sid_hz, sid_mhz, sid_us); + usNFO("[NFO] [C64] REFRESH_RATE %lu Cycles, RASTER_RATE %lu Cycles\n", usbsid_config.refresh_rate, usbsid_config.raster_rate); } - /* Release core 0 semaphore */ - sem_release(&core0_init); - /* Wait for core one to finish startup */ - sem_acquire_blocking(&core1_init); + + /* Signal Core 1 to continue (sync point 1) */ + usBOOT(" Signaling core1 ~ 1\n"); + __dmb(); /* Insert memory barrier after read */ + core_sync_state = SYNC_CORE0_STAGE1; + __sev(); /* Signal event to wake Core 1 from WFE */ + + /* Wait for Core 1 to finish queue/uart init (sync point 2) */ + usBOOT(" Waiting for core1 ready ~ 2\n"); + while (core_sync_state != SYNC_CORE1_STAGE2) { + __wfe(); /* Wait for event - low power wait */ + } + __dmb(); /* Insert memory barrier after read */ /* Init GPIO */ + usBOOT("Initializing GPIO\n"); init_gpio(); /* Start verification, detect and init sequence of SID clock */ + usBOOT("Setup SID clock\n"); setup_sidclock(); /* Init PIO */ + usBOOT("Setup PIO bus\n"); setup_piobus(); /* Sync PIOS */ + usBOOT("Synchronize PIO's\n"); sync_pios(true); /* Init DMA */ + usBOOT("Setup DMA channels\n"); setup_dmachannels(); + /* Start the VU */ + usBOOT("Initialize Vu\n"); + init_vu(); /* Init midi */ + usBOOT("Initialize Midi\n"); midi_init(); /* Init ASID */ + usBOOT("Initialize ASID\n"); asid_init(); /* Enable SID chips */ + usBOOT("Enable SID chips\n"); enable_sid(false); + /* Clear the dirt */ +#if !defined(ONBOARD_EMULATOR) || !defined(ONBOARD_SIDPLAYER) + memset(sid_memory, 0, sizeof sid_memory); +#endif + /* Check for default config bit * NOTE: This cannot be run from Core 1! */ - if (!auto_config) detect_default_config(); - if (auto_config) { /* ISSUE: NOT WORKING ON RP2350 */ + if (!auto_config) { + detect_default_config(); + } + if (auto_config) { /* NOTE: Does not work on rp2350 */ auto_detect_routine(auto_config, true); /* Double tap! */ save_config_ext(); auto_config = false; @@ -927,8 +961,11 @@ int main() /* Print config once at end of boot routine */ print_config(); - /* Release core 0 semaphore to signal boot finished */ - sem_release(&core0_init); + /* Signal Core 1 to enter main loop (sync point 2) */ + usBOOT(" Signaling core1 ~ 2\n"); + __dmb(); /* Memory barrier after read */ + core_sync_state = SYNC_CORE0_STAGE2; + __sev(); /* Signal event to wake Core 1 from WFE */ /* Loop IO tasks forever */ while (1) { @@ -939,6 +976,7 @@ int main() #ifdef USE_VENDOR_BUFFER vendor_task(); /* Only use this if buffering and fifo are enabled */ #endif + if (offload_ledrunner) { led_runner(); } diff --git a/src/vu.c b/src/vu.c index 5dd630c..766bd36 100644 --- a/src/vu.c +++ b/src/vu.c @@ -39,7 +39,7 @@ extern Config usbsid_config; /* usbsid.c */ #ifdef ONBOARD_EMULATOR extern uint8_t *sid_memory; #else -extern uint8_t __not_in_flash("usbsid_buffer") sid_memory[(0x20 * 4)] __attribute__((aligned(2 * (0x20 * 4)))); /* usbsid.c */ +extern uint8_t sid_memory[(0x20 * 4)]; /* usbsid.c */ #endif extern int usbdata; /* usbsid.c */ extern int numsids; /* config.c */ @@ -144,7 +144,7 @@ void led_vumeter_task(void) } #endif - MDBG("[%c:%d][PWM]$%04x[V1]$%02X%02X$%02X%02X$%02X$%02X$%02X[V2]$%02X%02X$%02X%02X$%02X$%02X$%02X[V3]$%02X%02X$%02X%02X$%02X$%02X$%02X[FC]$%02x%02x$%02x[VOL]$%02x\n", + usMEM("[%c:%d][PWM]$%04x[V1]$%02X%02X$%02X%02X$%02X$%02X$%02X[V2]$%02X%02X$%02X%02X$%02X$%02X$%02X[V3]$%02X%02X$%02X%02X$%02X$%02X$%02X[FC]$%02x%02x$%02x[VOL]$%02x\n", dtype, usbdata, vu, sid_memory[0x01], sid_memory[0x00], sid_memory[0x03], sid_memory[0x02], sid_memory[0x04], sid_memory[0x05], sid_memory[0x06], sid_memory[0x08], sid_memory[0x07], sid_memory[0x0A], sid_memory[0x09], sid_memory[0x0B], sid_memory[0x0C], sid_memory[0x0D], @@ -218,10 +218,18 @@ void led_runner(void) us_now = to_us_since_boot(get_absolute_time()); if (vu == 0 && usbdata == 1) { n_checks++; - if (n_checks >= MAX_CHECKS) /* 100 checks */ - { + 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; + /** + * @brief Let's make sure we always reset the write order + * when the interface is no longer mounted + */ + extern bool tud_midi_n_mounted (uint8_t itf); + if (!tud_midi_n_mounted(MIDI_ITF)) { + extern void reset_asid_to_writeorder(void); + reset_asid_to_writeorder(); + } } } return;