diff --git a/3rdparty/portmidi b/3rdparty/portmidi new file mode 160000 index 00000000..3920301c --- /dev/null +++ b/3rdparty/portmidi @@ -0,0 +1 @@ +Subproject commit 3920301ce1234031007550cd0b99b4d6649e3283 diff --git a/CMakeLists.txt b/CMakeLists.txt index 52710fab..78d00dff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,131 +21,10 @@ if(NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) endif() -#=========================================================================================== -# Strip garbage -if(APPLE) - set(LINK_FLAGS_RELEASE "${LINK_FLAGS_RELEASE} -dead_strip") -elseif(NOT MSVC AND NOT MSDOS AND NOT OPENBSD_LOCALBASE) - string(REGEX REPLACE "-O3" "" - CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") - string(REGEX REPLACE "-O3" "" - CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2 -fdata-sections -ffunction-sections") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -fdata-sections -ffunction-sections") - if(ANDROID) - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -funwind-tables") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -funwind-tables") - endif() - if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s -Wl,--gc-sections -Wl,-s") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s -Wl,--gc-sections -Wl,-s") - set(LINK_FLAGS_RELEASE "${LINK_FLAGS_RELEASE} -Wl,--gc-sections -Wl,-s") - endif() -endif() - -if(NOT MSVC AND NOT MSDOS) -# Global optimization flags - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fno-omit-frame-pointer") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-omit-frame-pointer") -# Turn on all warnings - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") -# Deny undefined symbols - if(NOT APPLE) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-undefined" ) - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined" ) - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-undefined" ) - endif() -# Supress the std::vector::insert() GCC change warning - if(VITA) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DVITA -DVITA=1 -fcompare-debug-second") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVITA -DVITA=1 -fcompare-debug-second") - endif() - if(NINTENDO_3DS OR NINTENDO_WII OR NINTENDO_WIIU OR NINTENDO_SWITCH) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fcompare-debug-second") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcompare-debug-second") - endif() -endif() - -if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR CMAKE_C_COMPILER_ID STREQUAL "Clang") - if(NINTENDO_3DS OR NINTENDO_WII OR NINTENDO_WIIU OR NINTENDO_SWITCH) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu90") - else() - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c89") - endif() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++98") -endif() - -if(DEFINED CMAKE_BUILD_TYPE) - string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER) -endif() -if(CMAKE_BUILD_TYPE_LOWER EQUAL "release") - add_definitions(-DNDEBUG) -ENDIF() +set(CMAKE_CXX_FLAGS "-O3 -g") -if(CMAKE_BUILD_TYPE_LOWER STREQUAL "debug") - add_definitions(-DDEBUG_BUILD) - if(CMAKE_COMPILER_IS_GNUCXX) - add_definitions(-D_GLIBCXX_DEBUG=1 -D_GLIBCXX_ASSERTIONS=1) - endif() -endif() - -# Disable bogus MSVC warnings -if(MSVC) - add_definitions(-D_CRT_SECURE_NO_WARNINGS) -endif() - -if(OPENBSD_LOCALBASE) - message("OpenBSD Detected!") - include_directories(${OPENBSD_LOCALBASE}/include) -endif() - -if(NOT WIN32 AND CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) - check_cxx_compiler_flag("-no-pie" HAS_NO_PIE) -endif() - -function(set_nopie _target) - if(NOT WIN32 AND HAS_NO_PIE AND CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) - set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS " -no-pie") - endif() -endfunction() - -function(set_legacy_standard destTarget) - if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) - # Turn on warnings and legacy C/C++ standards to support more compilers - target_compile_options(${destTarget} PRIVATE - $<$:-Wall -pedantic -std=gnu90 -Wno-long-long> - $<$:-Wall -pedantic -std=gnu++98> - ) - endif() -endfunction() - -function(set_visibility_hidden destTarget) - if(CMAKE_C_COMPILER_ID MATCHES "^(GNU|Clang)$" AND NOT DJGPP) - if(CMAKE_VERSION VERSION_GREATER 3.2) - target_compile_options(${destTarget} PRIVATE - $<$:-fvisibility-inlines-hidden> -fvisibility=hidden) - else() - target_compile_options(${destTarget} PRIVATE -fvisibility=hidden) - endif() - target_compile_definitions(${destTarget} PRIVATE LIBADLMIDI_VISIBILITY=) - endif() -endfunction() #=========================================================================================== -if(NOT WIN32 AND NOT NINTENDO_SWITCH AND (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)) - check_cxx_compiler_flag("-no-pie" HAS_NO_PIE) -endif() - -function(nuked-sc55_set_nopie _target) - set_target_properties(${_target} PROPERTIES - POSITION_INDEPENDENT_CODE False - ) - if(HAS_NO_PIE AND (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)) - set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS " -no-pie") - endif() -endfunction() - function(nuked-sc55_find_SDL2) if(NOT TARGET ADLMIDI_SDL2) find_package(SDL2 REQUIRED) @@ -171,43 +50,21 @@ endif() include(3rdparty/Utf8Main/utf8main.cmake) -if(NOT WIN32 AND PKG_CONFIG_FOUND) - set(USE_RTMIDI TRUE) - option(USE_SYSTEM_RTMIDI "Use system libraries for RtMidi" OFF) -endif() - find_package(SDL2 REQUIRED) -if(USE_RTMIDI) - if(USE_SYSTEM_RTMIDI) - pkg_check_modules(SYSTEM_RTMIDI rtmidi REQUIRED) - else() - include(RtMidi) - endif() -endif() - - set(SC55_SRC src/mcu.cpp src/mcu.h # main() is here! src/lcd.cpp src/lcd.h src/lcd_font.h src/mcu_interrupt.cpp src/mcu_interrupt.h src/mcu_opcodes.cpp src/mcu_opcodes.h src/mcu_timer.cpp src/mcu_timer.h - src/midi.h src/pcm.cpp src/pcm.h src/submcu.cpp src/submcu.h src/utils/files.cpp src/utils/files.h ) -if(USE_RTMIDI) - list(APPEND SC55_SRC src/midi_rtmidi.cpp) -elseif(WIN32) - list(APPEND SC55_SRC src/midi_win32.cpp) -endif() - -add_executable(nuked-sc55 ${SC55_SRC} ${UTF8MAIN_SRCS}) -set_nopie(nuked-sc55) +add_library(nuked-sc55 STATIC ${SC55_SRC} ${UTF8MAIN_SRCS}) if(TARGET SDL2::SDL2) target_link_libraries(nuked-sc55 PRIVATE SDL2::SDL2) @@ -217,26 +74,6 @@ else() target_link_libraries(nuked-sc55 PRIVATE ${SDL2_LIBRARIES}) endif() -if(USE_RTMIDI) - if(USE_SYSTEM_RTMIDI) - target_compile_options(nuked-sc55 PRIVATE ${SYSTEM_RTMIDI_CFLAGS}) - target_include_directories(nuked-sc55 PRIVATE ${SYSTEM_RTMIDI_INCLUDE_DIRS}) - target_link_libraries(nuked-sc55 PRIVATE ${SYSTEM_RTMIDI_LIBRARIES}) - else() - target_link_libraries(nuked-sc55 PRIVATE RtMidi) - endif() -endif() - -if(WIN32) - target_link_libraries(nuked-sc55 PRIVATE shlwapi winmm) -endif() - -if(APPLE) - find_library(LIBCoreAudio CoreAudio) - target_link_libraries(nuked-sc55 PRIVATE ${LIBCoreAudio}) -endif() - - set(SC55_INSTALL_FILES) # Copy ROM files into runtime directory diff --git a/sc55AU2/sc55AU2/sc55AU2.xcodeproj/project.pbxproj b/sc55AU2/sc55AU2/sc55AU2.xcodeproj/project.pbxproj new file mode 100644 index 00000000..7423832f --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2.xcodeproj/project.pbxproj @@ -0,0 +1,843 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 5E0B43372BBEEB600028D51B /* EmulatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E0B43362BBEEB600028D51B /* EmulatorView.swift */; }; + 5E0B43B72BC45C3C0028D51B /* jv880_waverom1.bin in Resources */ = {isa = PBXBuildFile; fileRef = 5E0B43B32BC45C3B0028D51B /* jv880_waverom1.bin */; }; + 5E0B43B82BC45C3C0028D51B /* jv880_rom1.bin in Resources */ = {isa = PBXBuildFile; fileRef = 5E0B43B42BC45C3C0028D51B /* jv880_rom1.bin */; }; + 5E0B43B92BC45C3C0028D51B /* jv880_waverom2.bin in Resources */ = {isa = PBXBuildFile; fileRef = 5E0B43B52BC45C3C0028D51B /* jv880_waverom2.bin */; }; + 5E0B43BA2BC45C3C0028D51B /* jv880_rom2.bin in Resources */ = {isa = PBXBuildFile; fileRef = 5E0B43B62BC45C3C0028D51B /* jv880_rom2.bin */; }; + 5E9FCCF42BBC8E25009EE67D /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E9FCCF32BBC8E25009EE67D /* ContentView.swift */; }; + 5E9FCCF82BBC8E25009EE67D /* ViewControllerRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E9FCCF72BBC8E25009EE67D /* ViewControllerRepresentable.swift */; }; + 5E9FCCFB2BBC8E25009EE67D /* Synth.aif in Resources */ = {isa = PBXBuildFile; fileRef = 5E9FCCFA2BBC8E25009EE67D /* Synth.aif */; }; + 5E9FCCFD2BBC8E25009EE67D /* SimplePlayEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E9FCCFC2BBC8E25009EE67D /* SimplePlayEngine.swift */; }; + 5E9FCD002BBC8E25009EE67D /* MIDIManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E9FCCFF2BBC8E25009EE67D /* MIDIManager.swift */; }; + 5E9FCD022BBC8E25009EE67D /* TypeAliases.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E9FCD012BBC8E25009EE67D /* TypeAliases.swift */; }; + 5E9FCD052BBC8E25009EE67D /* StringHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E9FCD042BBC8E25009EE67D /* StringHelpers.swift */; }; + 5E9FCD082BBC8E25009EE67D /* AudioUnitHostModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E9FCD072BBC8E25009EE67D /* AudioUnitHostModel.swift */; }; + 5E9FCD0A2BBC8E25009EE67D /* AudioUnitViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E9FCD092BBC8E25009EE67D /* AudioUnitViewModel.swift */; }; + 5E9FCD0C2BBC8E25009EE67D /* sc55AU2App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E9FCD0B2BBC8E25009EE67D /* sc55AU2App.swift */; }; + 5E9FCD0F2BBC8E25009EE67D /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5E9FCD0E2BBC8E25009EE67D /* Preview Assets.xcassets */; }; + 5E9FCD112BBC8E27009EE67D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5E9FCD102BBC8E27009EE67D /* Assets.xcassets */; }; + 5E9FCD182BBC8E27009EE67D /* sc55AU2Extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 5E9FCD172BBC8E27009EE67D /* sc55AU2Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 5E9FCD1D2BBC8E27009EE67D /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 5E9FCD1C2BBC8E27009EE67D /* README.md */; }; + 5E9FCD222BBC8E27009EE67D /* ParameterSpecBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E9FCD212BBC8E27009EE67D /* ParameterSpecBase.swift */; }; + 5E9FCD252BBC8E27009EE67D /* CrossPlatform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E9FCD242BBC8E27009EE67D /* CrossPlatform.swift */; }; + 5E9FCD272BBC8E27009EE67D /* String+Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E9FCD262BBC8E27009EE67D /* String+Utils.swift */; }; + 5E9FCD2B2BBC8E27009EE67D /* sc55AU2ExtensionAudioUnit.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5E9FCD2A2BBC8E27009EE67D /* sc55AU2ExtensionAudioUnit.mm */; }; + 5E9FCD2E2BBC8E27009EE67D /* sc55AU2ExtensionAUProcessHelper.hpp in Resources */ = {isa = PBXBuildFile; fileRef = 5E9FCD2D2BBC8E27009EE67D /* sc55AU2ExtensionAUProcessHelper.hpp */; }; + 5E9FCD322BBC8E27009EE67D /* Parameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E9FCD312BBC8E27009EE67D /* Parameters.swift */; }; + 5E9FCD362BBC8E27009EE67D /* sc55AU2ExtensionDSPKernel.hpp in Resources */ = {isa = PBXBuildFile; fileRef = 5E9FCD352BBC8E27009EE67D /* sc55AU2ExtensionDSPKernel.hpp */; }; + 5E9FCD392BBC8E27009EE67D /* sc55AU2ExtensionMainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E9FCD382BBC8E27009EE67D /* sc55AU2ExtensionMainView.swift */; }; + 5E9FCD3B2BBC8E27009EE67D /* ParameterSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E9FCD3A2BBC8E27009EE67D /* ParameterSlider.swift */; }; + 5E9FCD402BBC8E27009EE67D /* Base in Resources */ = {isa = PBXBuildFile; fileRef = 5E9FCD3F2BBC8E27009EE67D /* Base */; }; + 5E9FCD422BBC8E27009EE67D /* ObservableAUParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E9FCD412BBC8E27009EE67D /* ObservableAUParameter.swift */; }; + 5E9FCD442BBC8E27009EE67D /* AudioUnitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E9FCD432BBC8E27009EE67D /* AudioUnitViewController.swift */; }; + 5E9FCD572BBCABC2009EE67D /* libnuked-sc55.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9FCD562BBCABB7009EE67D /* libnuked-sc55.a */; }; + 5E9FCD592BBCABE8009EE67D /* libSDL2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9FCD582BBCABDF009EE67D /* libSDL2.a */; }; + 5E9FCD5F2BBCB1F6009EE67D /* back.data in Resources */ = {isa = PBXBuildFile; fileRef = 5E9FCD5E2BBCB1F6009EE67D /* back.data */; }; + 5E9FCD652BBCB206009EE67D /* rom_sm.bin in Resources */ = {isa = PBXBuildFile; fileRef = 5E9FCD602BBCB206009EE67D /* rom_sm.bin */; }; + 5E9FCD662BBCB206009EE67D /* rom2.bin in Resources */ = {isa = PBXBuildFile; fileRef = 5E9FCD612BBCB206009EE67D /* rom2.bin */; }; + 5E9FCD672BBCB206009EE67D /* waverom1.bin in Resources */ = {isa = PBXBuildFile; fileRef = 5E9FCD622BBCB206009EE67D /* waverom1.bin */; }; + 5E9FCD682BBCB206009EE67D /* waverom2.bin in Resources */ = {isa = PBXBuildFile; fileRef = 5E9FCD632BBCB206009EE67D /* waverom2.bin */; }; + 5E9FCD692BBCB206009EE67D /* rom1.bin in Resources */ = {isa = PBXBuildFile; fileRef = 5E9FCD642BBCB206009EE67D /* rom1.bin */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 5E9FCD192BBC8E27009EE67D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5E9FCCE82BBC8E25009EE67D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5E9FCD162BBC8E27009EE67D; + remoteInfo = sc55AU2Extension; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 5E9FCD4B2BBC8E27009EE67D /* Embed Foundation Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + 5E9FCD182BBC8E27009EE67D /* sc55AU2Extension.appex in Embed Foundation Extensions */, + ); + name = "Embed Foundation Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 5E0B43362BBEEB600028D51B /* EmulatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmulatorView.swift; sourceTree = ""; }; + 5E0B43B32BC45C3B0028D51B /* jv880_waverom1.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = jv880_waverom1.bin; path = ../../../../build/jv880_waverom1.bin; sourceTree = ""; }; + 5E0B43B42BC45C3C0028D51B /* jv880_rom1.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = jv880_rom1.bin; path = ../../../../build/jv880_rom1.bin; sourceTree = ""; }; + 5E0B43B52BC45C3C0028D51B /* jv880_waverom2.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = jv880_waverom2.bin; path = ../../../../build/jv880_waverom2.bin; sourceTree = ""; }; + 5E0B43B62BC45C3C0028D51B /* jv880_rom2.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = jv880_rom2.bin; path = ../../../../build/jv880_rom2.bin; sourceTree = ""; }; + 5E9FCCF02BBC8E25009EE67D /* sc55AU2.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = sc55AU2.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E9FCCF32BBC8E25009EE67D /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 5E9FCCF72BBC8E25009EE67D /* ViewControllerRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewControllerRepresentable.swift; sourceTree = ""; }; + 5E9FCCFA2BBC8E25009EE67D /* Synth.aif */ = {isa = PBXFileReference; lastKnownFileType = file; path = Synth.aif; sourceTree = ""; }; + 5E9FCCFC2BBC8E25009EE67D /* SimplePlayEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimplePlayEngine.swift; sourceTree = ""; }; + 5E9FCCFF2BBC8E25009EE67D /* MIDIManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MIDIManager.swift; sourceTree = ""; }; + 5E9FCD012BBC8E25009EE67D /* TypeAliases.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypeAliases.swift; sourceTree = ""; }; + 5E9FCD042BBC8E25009EE67D /* StringHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringHelpers.swift; sourceTree = ""; }; + 5E9FCD072BBC8E25009EE67D /* AudioUnitHostModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioUnitHostModel.swift; sourceTree = ""; }; + 5E9FCD092BBC8E25009EE67D /* AudioUnitViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioUnitViewModel.swift; sourceTree = ""; }; + 5E9FCD0B2BBC8E25009EE67D /* sc55AU2App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = sc55AU2App.swift; sourceTree = ""; }; + 5E9FCD0E2BBC8E25009EE67D /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 5E9FCD102BBC8E27009EE67D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 5E9FCD122BBC8E27009EE67D /* sc55AU2.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = sc55AU2.entitlements; sourceTree = ""; }; + 5E9FCD172BBC8E27009EE67D /* sc55AU2Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = sc55AU2Extension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E9FCD1C2BBC8E27009EE67D /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 5E9FCD1F2BBC8E27009EE67D /* sc55AU2Extension-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "sc55AU2Extension-Bridging-Header.h"; sourceTree = ""; }; + 5E9FCD212BBC8E27009EE67D /* ParameterSpecBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParameterSpecBase.swift; sourceTree = ""; }; + 5E9FCD242BBC8E27009EE67D /* CrossPlatform.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrossPlatform.swift; sourceTree = ""; }; + 5E9FCD262BBC8E27009EE67D /* String+Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Utils.swift"; sourceTree = ""; }; + 5E9FCD292BBC8E27009EE67D /* sc55AU2ExtensionAudioUnit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sc55AU2ExtensionAudioUnit.h; sourceTree = ""; }; + 5E9FCD2A2BBC8E27009EE67D /* sc55AU2ExtensionAudioUnit.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = sc55AU2ExtensionAudioUnit.mm; sourceTree = ""; }; + 5E9FCD2D2BBC8E27009EE67D /* sc55AU2ExtensionAUProcessHelper.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = sc55AU2ExtensionAUProcessHelper.hpp; sourceTree = ""; }; + 5E9FCD302BBC8E27009EE67D /* sc55AU2ExtensionParameterAddresses.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sc55AU2ExtensionParameterAddresses.h; sourceTree = ""; }; + 5E9FCD312BBC8E27009EE67D /* Parameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Parameters.swift; sourceTree = ""; }; + 5E9FCD352BBC8E27009EE67D /* sc55AU2ExtensionDSPKernel.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = sc55AU2ExtensionDSPKernel.hpp; sourceTree = ""; }; + 5E9FCD382BBC8E27009EE67D /* sc55AU2ExtensionMainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = sc55AU2ExtensionMainView.swift; sourceTree = ""; }; + 5E9FCD3A2BBC8E27009EE67D /* ParameterSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParameterSlider.swift; sourceTree = ""; }; + 5E9FCD3F2BBC8E27009EE67D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = AudioUnitViewController.xib; sourceTree = ""; }; + 5E9FCD412BBC8E27009EE67D /* ObservableAUParameter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObservableAUParameter.swift; sourceTree = ""; }; + 5E9FCD432BBC8E27009EE67D /* AudioUnitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioUnitViewController.swift; sourceTree = ""; }; + 5E9FCD452BBC8E27009EE67D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5E9FCD562BBCABB7009EE67D /* libnuked-sc55.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libnuked-sc55.a"; path = "../../build/libnuked-sc55.a"; sourceTree = ""; }; + 5E9FCD582BBCABDF009EE67D /* libSDL2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libSDL2.a; path = ../../../../../../../opt/homebrew/Cellar/sdl2/2.28.5/lib/libSDL2.a; sourceTree = ""; }; + 5E9FCD5A2BBCAF82009EE67D /* sc55AU2Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = sc55AU2Extension.entitlements; sourceTree = ""; }; + 5E9FCD5E2BBCB1F6009EE67D /* back.data */ = {isa = PBXFileReference; lastKnownFileType = file; name = back.data; path = ../../../../data/back.data; sourceTree = ""; }; + 5E9FCD602BBCB206009EE67D /* rom_sm.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = rom_sm.bin; path = ../../../../build/rom_sm.bin; sourceTree = ""; }; + 5E9FCD612BBCB206009EE67D /* rom2.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = rom2.bin; path = ../../../../build/rom2.bin; sourceTree = ""; }; + 5E9FCD622BBCB206009EE67D /* waverom1.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = waverom1.bin; path = ../../../../build/waverom1.bin; sourceTree = ""; }; + 5E9FCD632BBCB206009EE67D /* waverom2.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = waverom2.bin; path = ../../../../build/waverom2.bin; sourceTree = ""; }; + 5E9FCD642BBCB206009EE67D /* rom1.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = rom1.bin; path = ../../../../build/rom1.bin; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E9FCCED2BBC8E25009EE67D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5E9FCD142BBC8E27009EE67D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E9FCD592BBCABE8009EE67D /* libSDL2.a in Frameworks */, + 5E9FCD572BBCABC2009EE67D /* libnuked-sc55.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E9FCCE72BBC8E25009EE67D = { + isa = PBXGroup; + children = ( + 5E9FCCF22BBC8E25009EE67D /* sc55AU2 */, + 5E9FCD1B2BBC8E27009EE67D /* sc55AU2Extension */, + 5E9FCCF12BBC8E25009EE67D /* Products */, + 5E9FCD552BBCABB7009EE67D /* Frameworks */, + ); + sourceTree = ""; + }; + 5E9FCCF12BBC8E25009EE67D /* Products */ = { + isa = PBXGroup; + children = ( + 5E9FCCF02BBC8E25009EE67D /* sc55AU2.app */, + 5E9FCD172BBC8E27009EE67D /* sc55AU2Extension.appex */, + ); + name = Products; + sourceTree = ""; + }; + 5E9FCCF22BBC8E25009EE67D /* sc55AU2 */ = { + isa = PBXGroup; + children = ( + 5E9FCCF32BBC8E25009EE67D /* ContentView.swift */, + 5E9FCD0B2BBC8E25009EE67D /* sc55AU2App.swift */, + 5E9FCD102BBC8E27009EE67D /* Assets.xcassets */, + 5E9FCD122BBC8E27009EE67D /* sc55AU2.entitlements */, + 5E9FCCF52BBC8E25009EE67D /* Common */, + 5E9FCD062BBC8E25009EE67D /* Model */, + 5E9FCD0D2BBC8E25009EE67D /* Preview Content */, + ); + path = sc55AU2; + sourceTree = ""; + }; + 5E9FCCF52BBC8E25009EE67D /* Common */ = { + isa = PBXGroup; + children = ( + 5E9FCD012BBC8E25009EE67D /* TypeAliases.swift */, + 5E9FCCF62BBC8E25009EE67D /* UI */, + 5E9FCCF92BBC8E25009EE67D /* Audio */, + 5E9FCCFE2BBC8E25009EE67D /* MIDI */, + 5E9FCD032BBC8E25009EE67D /* String */, + ); + path = Common; + sourceTree = ""; + }; + 5E9FCCF62BBC8E25009EE67D /* UI */ = { + isa = PBXGroup; + children = ( + 5E9FCCF72BBC8E25009EE67D /* ViewControllerRepresentable.swift */, + ); + path = UI; + sourceTree = ""; + }; + 5E9FCCF92BBC8E25009EE67D /* Audio */ = { + isa = PBXGroup; + children = ( + 5E9FCCFA2BBC8E25009EE67D /* Synth.aif */, + 5E9FCCFC2BBC8E25009EE67D /* SimplePlayEngine.swift */, + ); + path = Audio; + sourceTree = ""; + }; + 5E9FCCFE2BBC8E25009EE67D /* MIDI */ = { + isa = PBXGroup; + children = ( + 5E9FCCFF2BBC8E25009EE67D /* MIDIManager.swift */, + ); + path = MIDI; + sourceTree = ""; + }; + 5E9FCD032BBC8E25009EE67D /* String */ = { + isa = PBXGroup; + children = ( + 5E9FCD042BBC8E25009EE67D /* StringHelpers.swift */, + ); + path = String; + sourceTree = ""; + }; + 5E9FCD062BBC8E25009EE67D /* Model */ = { + isa = PBXGroup; + children = ( + 5E9FCD072BBC8E25009EE67D /* AudioUnitHostModel.swift */, + 5E9FCD092BBC8E25009EE67D /* AudioUnitViewModel.swift */, + ); + path = Model; + sourceTree = ""; + }; + 5E9FCD0D2BBC8E25009EE67D /* Preview Content */ = { + isa = PBXGroup; + children = ( + 5E9FCD0E2BBC8E25009EE67D /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; + 5E9FCD1B2BBC8E27009EE67D /* sc55AU2Extension */ = { + isa = PBXGroup; + children = ( + 5E9FCD5D2BBCB1E8009EE67D /* Resources */, + 5E9FCD5A2BBCAF82009EE67D /* sc55AU2Extension.entitlements */, + 5E9FCD1C2BBC8E27009EE67D /* README.md */, + 5E9FCD452BBC8E27009EE67D /* Info.plist */, + 5E9FCD1E2BBC8E27009EE67D /* Common */, + 5E9FCD2F2BBC8E27009EE67D /* Parameters */, + 5E9FCD332BBC8E27009EE67D /* DSP */, + 5E9FCD372BBC8E27009EE67D /* UI */, + ); + path = sc55AU2Extension; + sourceTree = ""; + }; + 5E9FCD1E2BBC8E27009EE67D /* Common */ = { + isa = PBXGroup; + children = ( + 5E9FCD1F2BBC8E27009EE67D /* sc55AU2Extension-Bridging-Header.h */, + 5E9FCD202BBC8E27009EE67D /* Parameters */, + 5E9FCD232BBC8E27009EE67D /* Utility */, + 5E9FCD282BBC8E27009EE67D /* Audio Unit */, + 5E9FCD2C2BBC8E27009EE67D /* DSP */, + 5E9FCD3C2BBC8E27009EE67D /* UI */, + ); + path = Common; + sourceTree = ""; + }; + 5E9FCD202BBC8E27009EE67D /* Parameters */ = { + isa = PBXGroup; + children = ( + 5E9FCD212BBC8E27009EE67D /* ParameterSpecBase.swift */, + ); + path = Parameters; + sourceTree = ""; + }; + 5E9FCD232BBC8E27009EE67D /* Utility */ = { + isa = PBXGroup; + children = ( + 5E9FCD242BBC8E27009EE67D /* CrossPlatform.swift */, + 5E9FCD262BBC8E27009EE67D /* String+Utils.swift */, + ); + path = Utility; + sourceTree = ""; + }; + 5E9FCD282BBC8E27009EE67D /* Audio Unit */ = { + isa = PBXGroup; + children = ( + 5E9FCD292BBC8E27009EE67D /* sc55AU2ExtensionAudioUnit.h */, + 5E9FCD2A2BBC8E27009EE67D /* sc55AU2ExtensionAudioUnit.mm */, + ); + path = "Audio Unit"; + sourceTree = ""; + }; + 5E9FCD2C2BBC8E27009EE67D /* DSP */ = { + isa = PBXGroup; + children = ( + 5E9FCD2D2BBC8E27009EE67D /* sc55AU2ExtensionAUProcessHelper.hpp */, + ); + path = DSP; + sourceTree = ""; + }; + 5E9FCD2F2BBC8E27009EE67D /* Parameters */ = { + isa = PBXGroup; + children = ( + 5E9FCD302BBC8E27009EE67D /* sc55AU2ExtensionParameterAddresses.h */, + 5E9FCD312BBC8E27009EE67D /* Parameters.swift */, + ); + path = Parameters; + sourceTree = ""; + }; + 5E9FCD332BBC8E27009EE67D /* DSP */ = { + isa = PBXGroup; + children = ( + 5E9FCD352BBC8E27009EE67D /* sc55AU2ExtensionDSPKernel.hpp */, + ); + path = DSP; + sourceTree = ""; + }; + 5E9FCD372BBC8E27009EE67D /* UI */ = { + isa = PBXGroup; + children = ( + 5E9FCD382BBC8E27009EE67D /* sc55AU2ExtensionMainView.swift */, + 5E9FCD3A2BBC8E27009EE67D /* ParameterSlider.swift */, + 5E0B43362BBEEB600028D51B /* EmulatorView.swift */, + ); + path = UI; + sourceTree = ""; + }; + 5E9FCD3C2BBC8E27009EE67D /* UI */ = { + isa = PBXGroup; + children = ( + 5E9FCD412BBC8E27009EE67D /* ObservableAUParameter.swift */, + 5E9FCD432BBC8E27009EE67D /* AudioUnitViewController.swift */, + 5E9FCD3D2BBC8E27009EE67D /* Base.lproj */, + ); + path = UI; + sourceTree = ""; + }; + 5E9FCD3D2BBC8E27009EE67D /* Base.lproj */ = { + isa = PBXGroup; + children = ( + 5E9FCD3E2BBC8E27009EE67D /* AudioUnitViewController.xib */, + ); + path = Base.lproj; + sourceTree = ""; + }; + 5E9FCD552BBCABB7009EE67D /* Frameworks */ = { + isa = PBXGroup; + children = ( + 5E9FCD582BBCABDF009EE67D /* libSDL2.a */, + 5E9FCD562BBCABB7009EE67D /* libnuked-sc55.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 5E9FCD5D2BBCB1E8009EE67D /* Resources */ = { + isa = PBXGroup; + children = ( + 5E0B43B42BC45C3C0028D51B /* jv880_rom1.bin */, + 5E0B43B62BC45C3C0028D51B /* jv880_rom2.bin */, + 5E0B43B32BC45C3B0028D51B /* jv880_waverom1.bin */, + 5E0B43B52BC45C3C0028D51B /* jv880_waverom2.bin */, + 5E9FCD602BBCB206009EE67D /* rom_sm.bin */, + 5E9FCD642BBCB206009EE67D /* rom1.bin */, + 5E9FCD612BBCB206009EE67D /* rom2.bin */, + 5E9FCD622BBCB206009EE67D /* waverom1.bin */, + 5E9FCD632BBCB206009EE67D /* waverom2.bin */, + 5E9FCD5E2BBCB1F6009EE67D /* back.data */, + ); + path = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E9FCCEF2BBC8E25009EE67D /* sc55AU2 */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E9FCD4C2BBC8E27009EE67D /* Build configuration list for PBXNativeTarget "sc55AU2" */; + buildPhases = ( + 5E9FCCEC2BBC8E25009EE67D /* Sources */, + 5E9FCCED2BBC8E25009EE67D /* Frameworks */, + 5E9FCCEE2BBC8E25009EE67D /* Resources */, + 5E9FCD4B2BBC8E27009EE67D /* Embed Foundation Extensions */, + ); + buildRules = ( + ); + dependencies = ( + 5E9FCD1A2BBC8E27009EE67D /* PBXTargetDependency */, + ); + name = sc55AU2; + productName = sc55AU2; + productReference = 5E9FCCF02BBC8E25009EE67D /* sc55AU2.app */; + productType = "com.apple.product-type.application"; + }; + 5E9FCD162BBC8E27009EE67D /* sc55AU2Extension */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E9FCD482BBC8E27009EE67D /* Build configuration list for PBXNativeTarget "sc55AU2Extension" */; + buildPhases = ( + 5E9FCD132BBC8E27009EE67D /* Sources */, + 5E9FCD142BBC8E27009EE67D /* Frameworks */, + 5E9FCD152BBC8E27009EE67D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = sc55AU2Extension; + productName = sc55AU2Extension; + productReference = 5E9FCD172BBC8E27009EE67D /* sc55AU2Extension.appex */; + productType = "com.apple.product-type.app-extension"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E9FCCE82BBC8E25009EE67D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1530; + LastUpgradeCheck = 1530; + TargetAttributes = { + 5E9FCCEF2BBC8E25009EE67D = { + CreatedOnToolsVersion = 15.3; + }; + 5E9FCD162BBC8E27009EE67D = { + CreatedOnToolsVersion = 15.3; + }; + }; + }; + buildConfigurationList = 5E9FCCEB2BBC8E25009EE67D /* Build configuration list for PBXProject "sc55AU2" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E9FCCE72BBC8E25009EE67D; + productRefGroup = 5E9FCCF12BBC8E25009EE67D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E9FCCEF2BBC8E25009EE67D /* sc55AU2 */, + 5E9FCD162BBC8E27009EE67D /* sc55AU2Extension */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E9FCCEE2BBC8E25009EE67D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E9FCD0F2BBC8E25009EE67D /* Preview Assets.xcassets in Resources */, + 5E9FCD112BBC8E27009EE67D /* Assets.xcassets in Resources */, + 5E9FCCFB2BBC8E25009EE67D /* Synth.aif in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5E9FCD152BBC8E27009EE67D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E9FCD1D2BBC8E27009EE67D /* README.md in Resources */, + 5E9FCD5F2BBCB1F6009EE67D /* back.data in Resources */, + 5E0B43BA2BC45C3C0028D51B /* jv880_rom2.bin in Resources */, + 5E9FCD362BBC8E27009EE67D /* sc55AU2ExtensionDSPKernel.hpp in Resources */, + 5E9FCD2E2BBC8E27009EE67D /* sc55AU2ExtensionAUProcessHelper.hpp in Resources */, + 5E9FCD662BBCB206009EE67D /* rom2.bin in Resources */, + 5E9FCD682BBCB206009EE67D /* waverom2.bin in Resources */, + 5E9FCD672BBCB206009EE67D /* waverom1.bin in Resources */, + 5E0B43B72BC45C3C0028D51B /* jv880_waverom1.bin in Resources */, + 5E9FCD652BBCB206009EE67D /* rom_sm.bin in Resources */, + 5E9FCD692BBCB206009EE67D /* rom1.bin in Resources */, + 5E9FCD402BBC8E27009EE67D /* Base in Resources */, + 5E0B43B92BC45C3C0028D51B /* jv880_waverom2.bin in Resources */, + 5E0B43B82BC45C3C0028D51B /* jv880_rom1.bin in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E9FCCEC2BBC8E25009EE67D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E9FCD082BBC8E25009EE67D /* AudioUnitHostModel.swift in Sources */, + 5E9FCD0A2BBC8E25009EE67D /* AudioUnitViewModel.swift in Sources */, + 5E9FCCF42BBC8E25009EE67D /* ContentView.swift in Sources */, + 5E9FCCF82BBC8E25009EE67D /* ViewControllerRepresentable.swift in Sources */, + 5E9FCD0C2BBC8E25009EE67D /* sc55AU2App.swift in Sources */, + 5E9FCD052BBC8E25009EE67D /* StringHelpers.swift in Sources */, + 5E9FCD002BBC8E25009EE67D /* MIDIManager.swift in Sources */, + 5E9FCD022BBC8E25009EE67D /* TypeAliases.swift in Sources */, + 5E9FCCFD2BBC8E25009EE67D /* SimplePlayEngine.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5E9FCD132BBC8E27009EE67D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E9FCD322BBC8E27009EE67D /* Parameters.swift in Sources */, + 5E9FCD222BBC8E27009EE67D /* ParameterSpecBase.swift in Sources */, + 5E9FCD422BBC8E27009EE67D /* ObservableAUParameter.swift in Sources */, + 5E9FCD252BBC8E27009EE67D /* CrossPlatform.swift in Sources */, + 5E9FCD272BBC8E27009EE67D /* String+Utils.swift in Sources */, + 5E9FCD442BBC8E27009EE67D /* AudioUnitViewController.swift in Sources */, + 5E9FCD3B2BBC8E27009EE67D /* ParameterSlider.swift in Sources */, + 5E0B43372BBEEB600028D51B /* EmulatorView.swift in Sources */, + 5E9FCD392BBC8E27009EE67D /* sc55AU2ExtensionMainView.swift in Sources */, + 5E9FCD2B2BBC8E27009EE67D /* sc55AU2ExtensionAudioUnit.mm in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 5E9FCD1A2BBC8E27009EE67D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 5E9FCD162BBC8E27009EE67D /* sc55AU2Extension */; + targetProxy = 5E9FCD192BBC8E27009EE67D /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 5E9FCD3E2BBC8E27009EE67D /* AudioUnitViewController.xib */ = { + isa = PBXVariantGroup; + children = ( + 5E9FCD3F2BBC8E27009EE67D /* Base */, + ); + name = AudioUnitViewController.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 5E9FCD462BBC8E27009EE67D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 5E9FCD472BBC8E27009EE67D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + }; + name = Release; + }; + 5E9FCD492BBC8E27009EE67D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; + CODE_SIGN_ENTITLEMENTS = sc55AU2Extension/sc55AU2Extension.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + ENABLE_APP_SANDBOX = NO; + ENABLE_HARDENED_RUNTIME = NO; + ENABLE_USER_SELECTED_FILES = readwrite; + GENERATE_INFOPLIST_FILE = YES; + HEADER_SEARCH_PATHS = ( + "/Users/giuliozausa/personal/programming/Nuked-SC55/src", + "/opt/homebrew/Cellar/sdl2/2.28.5/include/**", + ); + INFOPLIST_FILE = sc55AU2Extension/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = sc55AU2Extension; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@executable_path/../../../../Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "/Users/giuliozausa/personal/programming/Nuked-SC55/build", + /opt/homebrew/Cellar/sdl2/2.28.5/lib, + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = giulioz.sc55AU2.sc55AU2Extension; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OBJC_BRIDGING_HEADER = "sc55AU2Extension/Common/sc55AU2Extension-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5E9FCD4A2BBC8E27009EE67D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; + CODE_SIGN_ENTITLEMENTS = sc55AU2Extension/sc55AU2Extension.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + ENABLE_APP_SANDBOX = NO; + ENABLE_HARDENED_RUNTIME = NO; + ENABLE_USER_SELECTED_FILES = readwrite; + GENERATE_INFOPLIST_FILE = YES; + HEADER_SEARCH_PATHS = ( + "/Users/giuliozausa/personal/programming/Nuked-SC55/src", + "/opt/homebrew/Cellar/sdl2/2.28.5/include/**", + ); + INFOPLIST_FILE = sc55AU2Extension/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = sc55AU2Extension; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@executable_path/../../../../Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "/Users/giuliozausa/personal/programming/Nuked-SC55/build", + /opt/homebrew/Cellar/sdl2/2.28.5/lib, + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = giulioz.sc55AU2.sc55AU2Extension; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OBJC_BRIDGING_HEADER = "sc55AU2Extension/Common/sc55AU2Extension-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 5E9FCD4D2BBC8E27009EE67D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = sc55AU2/sc55AU2.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"sc55AU2/Preview Content\""; + ENABLE_APP_SANDBOX = YES; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_PREVIEWS = YES; + ENABLE_USER_SELECTED_FILES = readonly; + GENERATE_INFOPLIST_FILE = YES; + HEADER_SEARCH_PATHS = "/Users/giuliozausa/personal/programming/Nuked-SC55/src"; + INFOPLIST_KEY_CFBundleDisplayName = sc55AU2; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + LIBRARY_SEARCH_PATHS = "/Users/giuliozausa/personal/programming/Nuked-SC55/build"; + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "-framework", + AudioToolbox, + "-framework", + AVFoundation, + ); + PRODUCT_BUNDLE_IDENTIFIER = giulioz.sc55AU2; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5E9FCD4E2BBC8E27009EE67D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = sc55AU2/sc55AU2.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"sc55AU2/Preview Content\""; + ENABLE_APP_SANDBOX = YES; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_PREVIEWS = YES; + ENABLE_USER_SELECTED_FILES = readonly; + GENERATE_INFOPLIST_FILE = YES; + HEADER_SEARCH_PATHS = "/Users/giuliozausa/personal/programming/Nuked-SC55/src"; + INFOPLIST_KEY_CFBundleDisplayName = sc55AU2; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + LIBRARY_SEARCH_PATHS = "/Users/giuliozausa/personal/programming/Nuked-SC55/build"; + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "-framework", + AudioToolbox, + "-framework", + AVFoundation, + ); + PRODUCT_BUNDLE_IDENTIFIER = giulioz.sc55AU2; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E9FCCEB2BBC8E25009EE67D /* Build configuration list for PBXProject "sc55AU2" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E9FCD462BBC8E27009EE67D /* Debug */, + 5E9FCD472BBC8E27009EE67D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E9FCD482BBC8E27009EE67D /* Build configuration list for PBXNativeTarget "sc55AU2Extension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E9FCD492BBC8E27009EE67D /* Debug */, + 5E9FCD4A2BBC8E27009EE67D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E9FCD4C2BBC8E27009EE67D /* Build configuration list for PBXNativeTarget "sc55AU2" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E9FCD4D2BBC8E27009EE67D /* Debug */, + 5E9FCD4E2BBC8E27009EE67D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E9FCCE82BBC8E25009EE67D /* Project object */; +} diff --git a/sc55AU2/sc55AU2/sc55AU2.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/sc55AU2/sc55AU2/sc55AU2.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/sc55AU2/sc55AU2/sc55AU2.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/sc55AU2/sc55AU2/sc55AU2.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/sc55AU2/sc55AU2/sc55AU2.xcodeproj/project.xcworkspace/xcuserdata/giuliozausa.xcuserdatad/UserInterfaceState.xcuserstate b/sc55AU2/sc55AU2/sc55AU2.xcodeproj/project.xcworkspace/xcuserdata/giuliozausa.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 00000000..09b9a1e2 Binary files /dev/null and b/sc55AU2/sc55AU2/sc55AU2.xcodeproj/project.xcworkspace/xcuserdata/giuliozausa.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/sc55AU2/sc55AU2/sc55AU2.xcodeproj/xcshareddata/xcschemes/sc55AU2Extension.xcscheme b/sc55AU2/sc55AU2/sc55AU2.xcodeproj/xcshareddata/xcschemes/sc55AU2Extension.xcscheme new file mode 100644 index 00000000..aa981df2 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2.xcodeproj/xcshareddata/xcschemes/sc55AU2Extension.xcscheme @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sc55AU2/sc55AU2/sc55AU2.xcodeproj/xcuserdata/giuliozausa.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/sc55AU2/sc55AU2/sc55AU2.xcodeproj/xcuserdata/giuliozausa.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 00000000..970dc442 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2.xcodeproj/xcuserdata/giuliozausa.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,6 @@ + + + diff --git a/sc55AU2/sc55AU2/sc55AU2.xcodeproj/xcuserdata/giuliozausa.xcuserdatad/xcschemes/xcschememanagement.plist b/sc55AU2/sc55AU2/sc55AU2.xcodeproj/xcuserdata/giuliozausa.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 00000000..96dfbe5c --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2.xcodeproj/xcuserdata/giuliozausa.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,27 @@ + + + + + SchemeUserState + + sc55AU2Extension.xcscheme_^#shared#^_ + + orderHint + 0 + + + SuppressBuildableAutocreation + + 5E9FCCEF2BBC8E25009EE67D + + primary + + + 5E9FCD162BBC8E27009EE67D + + primary + + + + + diff --git a/sc55AU2/sc55AU2/sc55AU2/Assets.xcassets/AccentColor.colorset/Contents.json b/sc55AU2/sc55AU2/sc55AU2/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 00000000..eb878970 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/sc55AU2/sc55AU2/sc55AU2/Assets.xcassets/AppIcon.appiconset/Contents.json b/sc55AU2/sc55AU2/sc55AU2/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..3f00db43 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,58 @@ +{ + "images" : [ + { + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/sc55AU2/sc55AU2/sc55AU2/Assets.xcassets/Contents.json b/sc55AU2/sc55AU2/sc55AU2/Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/sc55AU2/sc55AU2/sc55AU2/Assets.xcassets/LargeIcon.imageset/Contents.json b/sc55AU2/sc55AU2/sc55AU2/Assets.xcassets/LargeIcon.imageset/Contents.json new file mode 100644 index 00000000..a19a5492 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2/Assets.xcassets/LargeIcon.imageset/Contents.json @@ -0,0 +1,20 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/sc55AU2/sc55AU2/sc55AU2/Common/Audio/SimplePlayEngine.swift b/sc55AU2/sc55AU2/sc55AU2/Common/Audio/SimplePlayEngine.swift new file mode 100644 index 00000000..e589f3fc --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2/Common/Audio/SimplePlayEngine.swift @@ -0,0 +1,308 @@ +// +// SimplePlayEngine.swift +// sc55AU2 +// +// Created by Giulio Zausa on 02.04.24. +// + +import Foundation +import CoreAudioKit +import AVFoundation + +#if os(iOS) +import UIKit +#elseif os(macOS) +import AppKit +#endif + +/// Wraps and Audio Unit extension and provides helper functions. +extension AVAudioUnit { + + var wantsAudioInput: Bool { + let componentType = self.auAudioUnit.componentDescription.componentType + return componentType == kAudioUnitType_MusicEffect || componentType == kAudioUnitType_Effect + } + + static fileprivate func findComponent(type: String, subType: String, manufacturer: String) -> AVAudioUnitComponent? { + // Make a component description matching any Audio Unit of the selected component type. + let description = AudioComponentDescription(componentType: type.fourCharCode!, + componentSubType: subType.fourCharCode!, + componentManufacturer: manufacturer.fourCharCode!, + componentFlags: 0, + componentFlagsMask: 0) + return AVAudioUnitComponentManager.shared().components(matching: description).first + } + + fileprivate func loadAudioUnitViewController(completion: @escaping (ViewController?) -> Void) { + auAudioUnit.requestViewController { [weak self] viewController in + DispatchQueue.main.async { + if #available(macOS 13.0, iOS 16.0, *) { + if let self = self, viewController == nil { + let genericViewController = AUGenericViewController() + genericViewController.auAudioUnit = self.auAudioUnit + completion(genericViewController) + return + } + } + completion(viewController) + } + } + } +} + +/// Manages the interaction with the AudioToolbox and AVFoundation frameworks. +public class SimplePlayEngine { + + private var avAudioUnit: AVAudioUnit? + + // Synchronizes starting/stopping the engine and scheduling file segments. + private let stateChangeQueue = DispatchQueue(label: "com.example.apple-samplecode.StateChangeQueue") + + // Playback engine. + private let engine = AVAudioEngine() + + // Engine's player node. + private let player = AVAudioPlayerNode() + + // File to play. + private var file: AVAudioFile? + + // Whether we are playing. + private (set) var isPlaying = false + + // This block will be called every render cycle and will receive MIDI events + private let midiOutBlock: AUMIDIOutputEventBlock = { sampleTime, cable, length, data in return noErr } + + // This block can be used to send MIDI UMP events to the Audio Unit + var scheduleMIDIEventListBlock: AUMIDIEventListBlock? = nil + + // MARK: Initialization + + public init() { + engine.attach(player) + + guard let fileURL = Bundle.main.url(forResource: "Synth", withExtension: "aif") else { + fatalError("\"Synth.aif\" file not found.") + } + setPlayerFile(fileURL) + + engine.prepare() + setupMIDI() + } + + private func setupMIDI() { + if !MIDIManager.shared.setupPort(midiProtocol: MIDIProtocolID._2_0, receiveBlock: { [weak self] eventList, _ in + if let scheduleMIDIEventListBlock = self?.scheduleMIDIEventListBlock { + _ = scheduleMIDIEventListBlock(AUEventSampleTimeImmediate, 0, eventList) + } + }) { + fatalError("Failed to setup Core MIDI") + } + } + + func initComponent(type: String, subType: String, manufacturer: String, completion: @escaping (Result, ViewController?) -> Void) { + // Reset the engine to remove any configured audio units. + reset() + + guard let component = AVAudioUnit.findComponent(type: type, subType: subType, manufacturer: manufacturer) else { + fatalError("Failed to find component with type: \(type), subtype: \(subType), manufacturer: \(manufacturer))" ) + } + + // Instantiate the audio unit. + AVAudioUnit.instantiate(with: component.audioComponentDescription, + options: AudioComponentInstantiationOptions.loadOutOfProcess) { avAudioUnit, error in + + guard let audioUnit = avAudioUnit, error == nil else { + completion(.failure(error!), nil) + return + } + + self.avAudioUnit = audioUnit + + self.connect(avAudioUnit: audioUnit) + + // Load view controller and call completion handler + audioUnit.loadAudioUnitViewController { viewController in + completion(.success(true), viewController) + } + } + } + + private func setPlayerFile(_ fileURL: URL) { + do { + let file = try AVAudioFile(forReading: fileURL) + self.file = file + engine.connect(player, to: engine.mainMixerNode, format: file.processingFormat) + } catch { + fatalError("Could not create AVAudioFile instance. error: \(error).") + } + } + + private func setSessionActive(_ active: Bool) { +#if os(iOS) + do { + let session = AVAudioSession.sharedInstance() + try session.setCategory(.playback, mode: .default) + try session.setActive(active) + } catch { + fatalError("Could not set Audio Session active \(active). error: \(error).") + } +#endif + } + + // MARK: Playback State + + public func startPlaying() { + stateChangeQueue.sync { + if !self.isPlaying { self.startPlayingInternal() } + } + } + + public func stopPlaying() { + stateChangeQueue.sync { + if self.isPlaying { self.stopPlayingInternal() } + } + } + + public func togglePlay() -> Bool { + if isPlaying { + stopPlaying() + } else { + startPlaying() + } + return isPlaying + } + + private func startPlayingInternal() { + guard let avAudioUnit = self.avAudioUnit else { + return + } + + // assumptions: we are protected by stateChangeQueue. we are not playing. + setSessionActive(true) + + if avAudioUnit.wantsAudioInput { + // Schedule buffers on the player. + scheduleEffectLoop() + scheduleEffectLoop() + } + + let hardwareFormat = engine.outputNode.outputFormat(forBus: 0) + engine.connect(engine.mainMixerNode, to: engine.outputNode, format: hardwareFormat) + + // Start the engine. + do { + try engine.start() + } catch { + isPlaying = false + fatalError("Could not start engine. error: \(error).") + } + + if avAudioUnit.wantsAudioInput { + // Start the player. + player.play() + } + + isPlaying = true + } + + private func stopPlayingInternal() { + guard let avAudioUnit = self.avAudioUnit else { + return + } + + if avAudioUnit.wantsAudioInput { + player.stop() + } + engine.stop() + isPlaying = false + setSessionActive(false) + } + + private func scheduleEffectLoop() { + guard let file = file else { + fatalError("`file` must not be nil in \(#function).") + } + + player.scheduleFile(file, at: nil) { + self.stateChangeQueue.async { + if self.isPlaying { + self.scheduleEffectLoop() + } + } + } + } + + private func resetAudioLoop() { + guard let avAudioUnit = self.avAudioUnit else { + return + } + + if avAudioUnit.wantsAudioInput { + // Connect player -> mixer. + guard let format = file?.processingFormat else { fatalError("No AVAudioFile defined (processing format unavailable).") } + engine.connect(player, to: engine.mainMixerNode, format: format) + } + } + + public func reset() { + connect(avAudioUnit: nil) + } + + public func connect(avAudioUnit: AVAudioUnit?, completion: @escaping (() -> Void) = {}) { + guard let avAudioUnit = self.avAudioUnit else { + return + } + + // Break the audio unit -> mixer connection + engine.disconnectNodeInput(engine.mainMixerNode) + + resetAudioLoop() + + // We're done with the unit; release all references. + engine.detach(avAudioUnit) + + // Internal function to resume playing and call the completion handler. + func rewiringComplete() { + scheduleMIDIEventListBlock = auAudioUnit.scheduleMIDIEventListBlock + if isPlaying { + player.play() + } + completion() + } + + let hardwareFormat = engine.outputNode.outputFormat(forBus: 0) + + // Connect the main mixer -> output node + engine.connect(engine.mainMixerNode, to: engine.outputNode, format: hardwareFormat) + + // Pause the player before re-wiring it. It is not simple to keep it playing across an insertion or deletion. + if isPlaying { + player.pause() + } + + let auAudioUnit = avAudioUnit.auAudioUnit + + if !auAudioUnit.midiOutputNames.isEmpty { + auAudioUnit.midiOutputEventBlock = midiOutBlock + } + + // Attach the AVAudioUnit the the graph. + engine.attach(avAudioUnit) + + if avAudioUnit.wantsAudioInput { + // Disconnect the player -> mixer. + engine.disconnectNodeInput(engine.mainMixerNode) + + // Connect the player -> effect -> mixer. + if let format = file?.processingFormat { + engine.connect(player, to: avAudioUnit, format: format) + engine.connect(avAudioUnit, to: engine.mainMixerNode, format: format) + } + } else { + let stereoFormat = AVAudioFormat(standardFormatWithSampleRate: hardwareFormat.sampleRate, channels: 2) + engine.connect(avAudioUnit, to: engine.mainMixerNode, format: stereoFormat) + } + rewiringComplete() + } +} diff --git a/sc55AU2/sc55AU2/sc55AU2/Common/Audio/Synth.aif b/sc55AU2/sc55AU2/sc55AU2/Common/Audio/Synth.aif new file mode 100644 index 00000000..a90d7359 Binary files /dev/null and b/sc55AU2/sc55AU2/sc55AU2/Common/Audio/Synth.aif differ diff --git a/sc55AU2/sc55AU2/sc55AU2/Common/MIDI/MIDIManager.swift b/sc55AU2/sc55AU2/sc55AU2/Common/MIDI/MIDIManager.swift new file mode 100644 index 00000000..c7f5d7c9 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2/Common/MIDI/MIDIManager.swift @@ -0,0 +1,98 @@ +// +// MIDIManager.swift +// sc55AU2 +// +// Created by Giulio Zausa on 02.04.24. +// + +import Foundation +import CoreMIDI + +class MIDIManager: Identifiable, ObservableObject { + let id = UUID() + private var client = MIDIClientRef() + private var port = MIDIPortRef() + + static let shared = MIDIManager() + + private var clientName: CFString { + guard let bundleName = Bundle.main.infoDictionary?["CFBundleName"] as? String else { + return "MIDIManager_Client" as CFString + } + return "\(bundleName)_MIDIClient" as CFString + } + + private var sources: [MIDIEndpointRef] { + var srcs = [MIDIEndpointRef]() + + for index in 0.. Bool { + let status = MIDIClientCreateWithBlock(clientName, &client, { notificationPointer in + let pointer = UnsafeRawPointer(notificationPointer) + + switch notificationPointer.pointee.messageID { + case .msgObjectAdded: + let msg = pointer.assumingMemoryBound(to: MIDIObjectAddRemoveNotification.self).pointee + guard msg.childType == .source else { + break + } + + let res = MIDIPortConnectSource(self.port, msg.child, nil) + if res != noErr { + print("Failed to connect to MIDI Source: \(msg.child)") + } + + case .msgObjectRemoved: + let msg = pointer.assumingMemoryBound(to: MIDIObjectAddRemoveNotification.self).pointee + guard msg.childType == .source else { + break + } + + let res = MIDIPortDisconnectSource(self.port, msg.child) + if res != noErr { + print("Failed to disconnect MIDI Source: \(msg.child)") + } + + case .msgIOError: + let msg = pointer.assumingMemoryBound(to: MIDIIOErrorNotification.self).pointee + print("IO Error Occurred: \(msg.errorCode)") + + default: + break + } + }) + + guard status == noErr else { + print("Failed to create MIDI Client") + return false + } + return true + } + + func setupPort(midiProtocol: MIDIProtocolID, receiveBlock: @escaping MIDIReceiveBlock) -> Bool { + guard setupClient() else { + return false + } + + if MIDIInputPortCreateWithProtocol(client, portName, midiProtocol, &port, receiveBlock) != noErr { + return false + } + + for source in self.sources { + if MIDIPortConnectSource(port, source, nil) != noErr { + print("Failed to connect to source \(source)") + return false + } + } + return true + } +} diff --git a/sc55AU2/sc55AU2/sc55AU2/Common/String/StringHelpers.swift b/sc55AU2/sc55AU2/sc55AU2/Common/String/StringHelpers.swift new file mode 100644 index 00000000..c24d53a4 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2/Common/String/StringHelpers.swift @@ -0,0 +1,22 @@ +// +// StringHelpers.swift +// sc55AU2 +// +// Created by Giulio Zausa on 02.04.24. +// + +import Foundation + +extension String { + var fourCharCode: FourCharCode? { + guard self.count == 4 && self.utf8.count == 4 else { + return nil + } + + var code: FourCharCode = 0 + for character in self.utf8 { + code = code << 8 + FourCharCode(character) + } + return code + } +} diff --git a/sc55AU2/sc55AU2/sc55AU2/Common/TypeAliases.swift b/sc55AU2/sc55AU2/sc55AU2/Common/TypeAliases.swift new file mode 100644 index 00000000..2bfdebdb --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2/Common/TypeAliases.swift @@ -0,0 +1,23 @@ +// +// TypeAliases.swift +// sc55AU2 +// +// Created by Giulio Zausa on 02.04.24. +// + +import CoreMIDI +import AudioToolbox + +#if os(iOS) +import UIKit +public typealias KitColor = UIColor + +public typealias KitView = UIView +public typealias ViewController = UIViewController +#elseif os(macOS) +import AppKit +public typealias KitColor = NSColor + +public typealias KitView = NSView +public typealias ViewController = NSViewController +#endif diff --git a/sc55AU2/sc55AU2/sc55AU2/Common/UI/ViewControllerRepresentable.swift b/sc55AU2/sc55AU2/sc55AU2/Common/UI/ViewControllerRepresentable.swift new file mode 100644 index 00000000..77b5975d --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2/Common/UI/ViewControllerRepresentable.swift @@ -0,0 +1,60 @@ +// +// ViewControllerRepresentable.swift +// sc55AU2 +// +// Created by Giulio Zausa on 02.04.24. +// + +import SwiftUI + +#if os(iOS) +class WrapperVC: ViewController { + override func loadView() { + view = KitView() + } +} + +struct AUViewControllerUI: UIViewControllerRepresentable { + var auViewController: UIViewController? + + init(viewController: UIViewController?) { + self.auViewController = viewController + } + + func makeUIViewController(context: Context) -> UIViewController { + let viewController = WrapperVC() + guard let auViewController = self.auViewController else { + return viewController + } + + viewController.addChild(auViewController) + + let frame: CGRect = viewController.view.bounds + auViewController.view.frame = frame + + viewController.view.addSubview(auViewController.view) + return viewController + } + + func updateUIViewController(_ uiViewController: UIViewController, context: Context) { + // No opp + } +} +#elseif os(macOS) +struct AUViewControllerUI: NSViewControllerRepresentable { + + var auViewController: NSViewController? + + init(viewController: NSViewController?) { + self.auViewController = viewController + } + + func makeNSViewController(context: Context) -> NSViewController { + return self.auViewController! + } + + func updateNSViewController(_ nsViewController: NSViewController, context: Context) { + // No opp + } +} +#endif diff --git a/sc55AU2/sc55AU2/sc55AU2/ContentView.swift b/sc55AU2/sc55AU2/sc55AU2/ContentView.swift new file mode 100644 index 00000000..76ce3697 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2/ContentView.swift @@ -0,0 +1,57 @@ +// +// ContentView.swift +// sc55AU2 +// +// Created by Giulio Zausa on 02.04.24. +// + +import AudioToolbox +import SwiftUI + +struct ContentView: View { + @ObservedObject var hostModel: AudioUnitHostModel + var margin = 10.0 + var doubleMargin: Double { + margin * 2.0 + } + + var body: some View { + VStack() { + Text("\(hostModel.viewModel.title )") + .textSelection(.enabled) + .padding() + VStack(alignment: .center) { + if let viewController = hostModel.viewModel.viewController { + AUViewControllerUI(viewController: viewController) + .padding(margin) + } else { + VStack() { + Text(hostModel.viewModel.message) + .padding() + } + .frame(minWidth: 400, minHeight: 200) + } + } + .padding(doubleMargin) + + if hostModel.viewModel.showAudioControls { + Text("Audio Playback") + Button { + hostModel.isPlaying ? hostModel.stopPlaying() : hostModel.startPlaying() + + } label: { + Text(hostModel.isPlaying ? "Stop" : "Play") + } + } + if hostModel.viewModel.showMIDIContols { + Text("MIDI Input: Enabled") + } + Spacer() + .frame(height: margin) + } + } +} + +#Preview { + ContentView(hostModel: AudioUnitHostModel()) +} diff --git a/sc55AU2/sc55AU2/sc55AU2/Model/AudioUnitHostModel.swift b/sc55AU2/sc55AU2/sc55AU2/Model/AudioUnitHostModel.swift new file mode 100644 index 00000000..1c4496ce --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2/Model/AudioUnitHostModel.swift @@ -0,0 +1,88 @@ +// +// AudioUnitHostModel.swift +// sc55AU2 +// +// Created by Giulio Zausa on 02.04.24. +// + +import SwiftUI +import CoreMIDI +import AudioToolbox + +class AudioUnitHostModel: ObservableObject { + /// The playback engine used to play audio. + private let playEngine = SimplePlayEngine() + + /// The model providing information about the current Audio Unit + @Published private(set) var viewModel = AudioUnitViewModel() + + var isPlaying: Bool { + playEngine.isPlaying + } + + /// Audio Component Description + let type: String + let subType: String + let manufacturer: String + + let wantsAudio: Bool + let wantsMIDI: Bool + let isFreeRunning: Bool + + let auValString: String + + init(type: String = "aumu", subType: String = "SC55", manufacturer: String = "SC55") { + self.type = type + self.subType = subType + self.manufacturer = manufacturer + let wantsAudio = type.fourCharCode == kAudioUnitType_MusicEffect || type.fourCharCode == kAudioUnitType_Effect + self.wantsAudio = wantsAudio + + let wantsMIDI = type.fourCharCode == kAudioUnitType_MIDIProcessor || + type.fourCharCode == kAudioUnitType_MusicDevice || + type.fourCharCode == kAudioUnitType_MusicEffect + self.wantsMIDI = wantsMIDI + + let isFreeRunning = type.fourCharCode == kAudioUnitType_MIDIProcessor || + type.fourCharCode == kAudioUnitType_MusicDevice || + type.fourCharCode == kAudioUnitType_Generator + self.isFreeRunning = isFreeRunning + + auValString = "\(type) \(subType) \(manufacturer)" + + loadAudioUnit() + } + + private func loadAudioUnit() { + playEngine.initComponent(type: type, + subType: subType, + manufacturer: manufacturer) { [self] result, viewController in + switch result { + case .success(_): + self.viewModel = AudioUnitViewModel(showAudioControls: self.wantsAudio, + showMIDIContols: self.wantsMIDI, + title: self.auValString, + message: "Successfully loaded (\(self.auValString))", + viewController: viewController) + + if self.isFreeRunning { + self.playEngine.startPlaying() + } + case .failure(let error): + self.viewModel = AudioUnitViewModel(showAudioControls: false, + showMIDIContols: false, + title: self.auValString, + message: "Failed to load Audio Unit with error: \(error.localizedDescription)", + viewController: nil) + } + } + } + + func startPlaying() { + playEngine.startPlaying() + } + + func stopPlaying() { + playEngine.stopPlaying() + } +} diff --git a/sc55AU2/sc55AU2/sc55AU2/Model/AudioUnitViewModel.swift b/sc55AU2/sc55AU2/sc55AU2/Model/AudioUnitViewModel.swift new file mode 100644 index 00000000..d0522563 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2/Model/AudioUnitViewModel.swift @@ -0,0 +1,18 @@ +// +// AudioUnitViewModel.swift +// sc55AU2 +// +// Created by Giulio Zausa on 02.04.24. +// + +import SwiftUI +import AudioToolbox +import CoreAudioKit + +struct AudioUnitViewModel { + var showAudioControls: Bool = false + var showMIDIContols: Bool = false + var title: String = "-" + var message: String = "No Audio Unit loaded.." + var viewController: ViewController? +} diff --git a/sc55AU2/sc55AU2/sc55AU2/Preview Content/Preview Assets.xcassets/Contents.json b/sc55AU2/sc55AU2/sc55AU2/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/sc55AU2/sc55AU2/sc55AU2/sc55AU2.entitlements b/sc55AU2/sc55AU2/sc55AU2/sc55AU2.entitlements new file mode 100644 index 00000000..bc04cfb9 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2/sc55AU2.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.network.client + + + diff --git a/sc55AU2/sc55AU2/sc55AU2/sc55AU2App.swift b/sc55AU2/sc55AU2/sc55AU2/sc55AU2App.swift new file mode 100644 index 00000000..6af90ce6 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2/sc55AU2App.swift @@ -0,0 +1,20 @@ +// +// sc55AU2App.swift +// sc55AU2 +// +// Created by Giulio Zausa on 02.04.24. +// + +import CoreMIDI +import SwiftUI + +@main +struct sc55AU2App: App { + @ObservedObject private var hostModel = AudioUnitHostModel() + + var body: some Scene { + WindowGroup { + ContentView(hostModel: hostModel) + } + } +} diff --git a/sc55AU2/sc55AU2/sc55AU2Extension/Common/Audio Unit/sc55AU2ExtensionAudioUnit.h b/sc55AU2/sc55AU2/sc55AU2Extension/Common/Audio Unit/sc55AU2ExtensionAudioUnit.h new file mode 100644 index 00000000..33215ef8 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2Extension/Common/Audio Unit/sc55AU2ExtensionAudioUnit.h @@ -0,0 +1,16 @@ +// +// sc55AU2ExtensionAudioUnit.h +// sc55AU2Extension +// +// Created by Giulio Zausa on 02.04.24. +// + +#import +#import + +@interface sc55AU2ExtensionAudioUnit : AUAudioUnit +- (void)setupParameterTree:(AUParameterTree *)parameterTree; +- (void)SC55_Reset; +- (uint32_t*)LCD_Update; +- (void)LCD_SendButton:(uint8_t)button :(int)state; +@end diff --git a/sc55AU2/sc55AU2/sc55AU2Extension/Common/Audio Unit/sc55AU2ExtensionAudioUnit.mm b/sc55AU2/sc55AU2/sc55AU2Extension/Common/Audio Unit/sc55AU2ExtensionAudioUnit.mm new file mode 100644 index 00000000..1a2270ac --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2Extension/Common/Audio Unit/sc55AU2ExtensionAudioUnit.mm @@ -0,0 +1,203 @@ +// +// sc55AU2ExtensionAudioUnit.mm +// sc55AU2Extension +// +// Created by Giulio Zausa on 02.04.24. +// + +#import "sc55AU2ExtensionAudioUnit.h" + +#import +#import + +#import "sc55AU2ExtensionAUProcessHelper.hpp" +#import "sc55AU2ExtensionDSPKernel.hpp" + + +// Define parameter addresses. + +@interface sc55AU2ExtensionAudioUnit () + +@property (nonatomic, readwrite) AUParameterTree *parameterTree; +@property AUAudioUnitBusArray *outputBusArray; +@property (nonatomic, readonly) AUAudioUnitBus *outputBus; +@end + + +@implementation sc55AU2ExtensionAudioUnit { + // C++ members need to be ivars; they would be copied on access if they were properties. + sc55AU2ExtensionDSPKernel _kernel; + std::unique_ptr _processHelper; +} + +@synthesize parameterTree = _parameterTree; + +- (instancetype)initWithComponentDescription:(AudioComponentDescription)componentDescription options:(AudioComponentInstantiationOptions)options error:(NSError **)outError { + self = [super initWithComponentDescription:componentDescription options:options error:outError]; + + if (self == nil) { return nil; } + + [self setupAudioBuses]; + + return self; +} + +#pragma mark - AUAudioUnit Setup + +- (void)setupAudioBuses { + // Create the output bus first + AVAudioFormat *format = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:44100 channels:2]; + _outputBus = [[AUAudioUnitBus alloc] initWithFormat:format error:nil]; + _outputBus.maximumChannelCount = 8; + + // then an array with it + _outputBusArray = [[AUAudioUnitBusArray alloc] initWithAudioUnit:self + busType:AUAudioUnitBusTypeOutput + busses: @[_outputBus]]; +} + +- (void)setupParameterTree:(AUParameterTree *)parameterTree { + _parameterTree = parameterTree; + + // Send the Parameter default values to the Kernel before setting up the parameter callbacks, so that the defaults set in the Kernel.hpp don't propagate back to the AUParameters via GetParameter + for (AUParameter *param in _parameterTree.allParameters) { + _kernel.setParameter(param.address, param.value); + } + + [self setupParameterCallbacks]; +} + +- (void)setupParameterCallbacks { + // Make a local pointer to the kernel to avoid capturing self. + + __block sc55AU2ExtensionDSPKernel *kernel = &_kernel; + + // implementorValueObserver is called when a parameter changes value. + _parameterTree.implementorValueObserver = ^(AUParameter *param, AUValue value) { + kernel->setParameter(param.address, value); + }; + + // implementorValueProvider is called when the value needs to be refreshed. + _parameterTree.implementorValueProvider = ^(AUParameter *param) { + return kernel->getParameter(param.address); + }; + + // A function to provide string representations of parameter values. + _parameterTree.implementorStringFromValueCallback = ^(AUParameter *param, const AUValue *__nullable valuePtr) { + AUValue value = valuePtr == nil ? param.value : *valuePtr; + + return [NSString stringWithFormat:@"%.f", value]; + }; +} + +#pragma mark - AUAudioUnit Overrides + +- (AUAudioFrameCount)maximumFramesToRender { + return _kernel.maximumFramesToRender(); +} + +- (void)setMaximumFramesToRender:(AUAudioFrameCount)maximumFramesToRender { + _kernel.setMaximumFramesToRender(maximumFramesToRender); +} + +// An audio unit's audio output connection points. +// Subclassers must override this property getter and should return the same object every time. +// See sample code. +- (AUAudioUnitBusArray *)outputBusses { + return _outputBusArray; +} + +- (void)setShouldBypassEffect:(BOOL)shouldBypassEffect { + _kernel.setBypass(shouldBypassEffect); +} + +- (BOOL)shouldBypassEffect { + return _kernel.isBypassed(); +} + +// Allocate resources required to render. +// Subclassers should call the superclass implementation. +- (BOOL)allocateRenderResourcesAndReturnError:(NSError **)outError { + const auto outputChannelCount = [self.outputBusses objectAtIndexedSubscript:0].format.channelCount; + const auto outputFormat = [self.outputBusses objectAtIndexedSubscript:0].format.streamDescription; + + _kernel.setMusicalContextBlock(self.musicalContextBlock); + _kernel.initialize(outputChannelCount, _outputBus.format.sampleRate, outputFormat); + _processHelper = std::make_unique(_kernel, outputChannelCount); + return [super allocateRenderResourcesAndReturnError:outError]; +} + +// Deallocate resources allocated in allocateRenderResourcesAndReturnError: +// Subclassers should call the superclass implementation. +- (void)deallocateRenderResources { + + // Deallocate your resources. + _kernel.deInitialize(); + + [super deallocateRenderResources]; +} + +#pragma mark - MIDI + +- (MIDIProtocolID)AudioUnitMIDIProtocol { + return _kernel.AudioUnitMIDIProtocol(); +} + +#pragma mark - AUAudioUnit (AUAudioUnitImplementation) + +// Block which subclassers must provide to implement rendering. +- (AUInternalRenderBlock)internalRenderBlock { + /* + Capture in locals to avoid ObjC member lookups. If "self" is captured in + render, we're doing it wrong. + */ + // Specify captured objects are mutable. + __block sc55AU2ExtensionDSPKernel *kernel = &_kernel; + __block std::unique_ptr &processHelper = _processHelper; + + return ^AUAudioUnitStatus(AudioUnitRenderActionFlags *actionFlags, + const AudioTimeStamp *timestamp, + AVAudioFrameCount frameCount, + NSInteger outputBusNumber, + AudioBufferList *outputData, + const AURenderEvent *realtimeEventListHead, + AURenderPullInputBlock __unsafe_unretained pullInputBlock) { + + if (frameCount > kernel->maximumFramesToRender()) { + return kAudioUnitErr_TooManyFramesToProcess; + } + + /* + Important: + If the caller passed non-null output pointers (outputData->mBuffers[x].mData), use those. + + If the caller passed null output buffer pointers, process in memory owned by the Audio Unit + and modify the (outputData->mBuffers[x].mData) pointers to point to this owned memory. + The Audio Unit is responsible for preserving the validity of this memory until the next call to render, + or deallocateRenderResources is called. + + If your algorithm cannot process in-place, you will need to preallocate an output buffer + and use it here. + + See the description of the canProcessInPlace property. + */ + processHelper->processWithEvents(outputData, timestamp, frameCount, realtimeEventListHead); + + return noErr; + }; +} + +- (void)SC55_Reset { + _kernel.mcu->SC55_Reset(); +}; + +- (uint32_t*)LCD_Update { + return _kernel.mcu->lcd.LCD_Update(); +}; + +- (void)LCD_SendButton:(uint8_t) button: (int) state { + _kernel.mcu->lcd.LCD_SendButton(button, state); +}; + +@end + diff --git a/sc55AU2/sc55AU2/sc55AU2Extension/Common/DSP/sc55AU2ExtensionAUProcessHelper.hpp b/sc55AU2/sc55AU2/sc55AU2Extension/Common/DSP/sc55AU2ExtensionAUProcessHelper.hpp new file mode 100644 index 00000000..6fa57369 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2Extension/Common/DSP/sc55AU2ExtensionAUProcessHelper.hpp @@ -0,0 +1,82 @@ +// +// sc55AU2ExtensionAUProcessHelper.hpp +// sc55AU2Extension +// +// Created by Giulio Zausa on 02.04.24. +// + +#pragma once + +#import +#import + +#include +#include "sc55AU2ExtensionDSPKernel.hpp" + +//MARK:- AUProcessHelper Utility Class +class AUProcessHelper +{ +public: + AUProcessHelper(sc55AU2ExtensionDSPKernel& kernel, UInt32 outputChannelCount) + : mKernel{kernel}{ + } + + /** + This function handles the event list processing and rendering loop for you. + Call it inside your internalRenderBlock. + */ + void processWithEvents(AudioBufferList* outBufferList, AudioTimeStamp const *timestamp, AUAudioFrameCount frameCount, AURenderEvent const *events) { + + AUEventSampleTime now = AUEventSampleTime(timestamp->mSampleTime); + AUAudioFrameCount framesRemaining = frameCount; + AURenderEvent const *nextEvent = events; // events is a linked list, at the beginning, the nextEvent is the first event + + auto callProcess = [this] (AudioBufferList* outBufferListPtr, AUEventSampleTime now, AUAudioFrameCount frameCount, AUAudioFrameCount const frameOffset) { + mKernel.process(now, frameCount, outBufferListPtr); + }; + + while (framesRemaining > 0) { + // If there are no more events, we can process the entire remaining segment and exit. + if (nextEvent == nullptr) { + AUAudioFrameCount const frameOffset = frameCount - framesRemaining; + callProcess(outBufferList, now, frameCount, frameOffset); + return; + } + + // HACK + + // // **** start late events late. + // auto timeZero = AUEventSampleTime(0); + // auto headEventTime = nextEvent->head.eventSampleTime; + // AUAudioFrameCount framesThisSegment = AUAudioFrameCount(std::max(timeZero, headEventTime - now)); + + // // Compute everything before the next event. + // if (framesThisSegment > 0) { + // AUAudioFrameCount const frameOffset = frameCount - framesRemaining; + // callProcess(outBufferList, now, framesThisSegment, frameOffset); + + // // Advance frames. + // framesRemaining -= framesThisSegment; + + // // Advance time. + // now += AUEventSampleTime(framesThisSegment); + // } + + nextEvent = performAllSimultaneousEvents(now, nextEvent); + } + } + + AURenderEvent const * performAllSimultaneousEvents(AUEventSampleTime now, AURenderEvent const *event) { + do { + mKernel.handleOneEvent(now, event); + + // Go to next event. + event = event->head.next; + + // While event is not null and is simultaneous (or late). + } while (event && event->head.eventSampleTime <= now); + return event; + } +private: + sc55AU2ExtensionDSPKernel& mKernel; +}; diff --git a/sc55AU2/sc55AU2/sc55AU2Extension/Common/Parameters/ParameterSpecBase.swift b/sc55AU2/sc55AU2/sc55AU2Extension/Common/Parameters/ParameterSpecBase.swift new file mode 100644 index 00000000..2ffb49cd --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2Extension/Common/Parameters/ParameterSpecBase.swift @@ -0,0 +1,154 @@ +// +// ParameterSpecBase.swift +// sc55AU2Extension +// +// Created by Giulio Zausa on 02.04.24. +// + +import Foundation +import AudioToolbox + +public protocol NodeSpec {} + +extension NodeSpec { + static func validateID(_ name: String) -> String { + let msg = "Parameter identifier should: not be empty, begin with a letter, and only contain alpha numeric characters or underscores. Hint: Use camelCase." + assert(name.isAlphanumeric(), msg) + return name + } +} + +@resultBuilder struct ParameterGroupBuilder { + static func buildBlock() -> [NodeSpec] { [] } + static func buildBlock(_ nodes: NodeSpec...) -> [NodeSpec] { nodes } +} + +/// Specification for a group of parameters. +public struct ParameterGroupSpec: NodeSpec { + let identifier: String + let name: String + let children: [NodeSpec] + + init(identifier: String, name: String, @ParameterGroupBuilder _ children: () -> [NodeSpec]) { + self.identifier = ParameterGroupSpec.validateID(identifier) + self.name = name + self.children = children() + } +} + +public struct ParameterTreeSpec: NodeSpec { + let children: [NodeSpec] + init(@ParameterGroupBuilder _ children: () -> [NodeSpec]) { self.children = children() } +} + +/// ParameterSpec mirrors what gets passed to +/// AUParameterTree.createParameter, but also provides a default value +public struct ParameterSpec: NodeSpec { + let identifier: String + let name: String + let address: AUParameterAddress + let minValue: AUValue + let maxValue: AUValue + let defaultValue: AUValue + let units: AudioUnitParameterUnit + let unitName: String? + let flags: AudioUnitParameterOptions + let valueStrings: [String]? + let dependentParameters: [NSNumber]? + + /// Init a new parameter spec + /// - Parameters: + /// - address: A unique AUParameterAddress (Integer) which represents the parameter + /// - identifier: A unique String which is used to access the parameter + /// - name: The localized display name of the parameter + /// - units: The parameters unit of measurement + /// - valueRange: The parameters range in above units + /// - defaultValue: The default value of the parameter + /// - unitName: The name of the units of measurement + /// - flags: A set of the parameters options + /// - valueStrings: String representation of each value + /// - dependentParameters: The addresses of dependant parameters + init( + address: AUParameterAddress, + identifier: String, + name: String, + units: AudioUnitParameterUnit, + valueRange: ClosedRange, + defaultValue: AUValue, + unitName: String? = nil, + flags: AudioUnitParameterOptions = [AudioUnitParameterOptions.flag_IsWritable, AudioUnitParameterOptions.flag_IsReadable], + valueStrings: [String]? = nil, + dependentParameters: [NSNumber]? = nil + ) { + self.identifier = ParameterSpec.validateID(identifier) + self.name = name + self.address = address + self.minValue = valueRange.lowerBound + self.maxValue = valueRange.upperBound + self.defaultValue = defaultValue + self.units = units + self.unitName = unitName + self.flags = flags + self.valueStrings = valueStrings + self.dependentParameters = dependentParameters + } +} + +// MARK: - Tree factory for parameter spec + +extension AUParameterTree { + + class func createNode(from spec: NodeSpec) -> AUParameterNode { + switch spec { + case let parameterSpec as ParameterSpec: + return AUParameterTree.createParameter(from: parameterSpec) + case let groupSpec as ParameterGroupSpec: + return AUParameterTree.createParameterGroup(from: groupSpec) + default: + return AUParameterNode() + } + } + + class func createParameterGroup(from spec: ParameterGroupSpec) -> AUParameterGroup { + return self.createGroup( + withIdentifier: spec.identifier, + name: spec.name, + children: spec.children.createAUParameterNodes() + ) + } + + class func createParameter(from spec: ParameterSpec) -> AUParameter { + let param = self.createParameter( + withIdentifier: spec.identifier, + name: spec.name, + address: spec.address, + min: spec.minValue, + max: spec.maxValue, + unit: spec.units, + unitName: spec.unitName, + flags: spec.flags, + valueStrings: spec.valueStrings, + dependentParameters: spec.dependentParameters + ) + param.value = spec.defaultValue + return param + } +} + +extension Array where Element == NodeSpec { + func createAUParameterNodes() -> [AUParameterNode] { + self.map { spec in + AUParameterTree.createNode(from: spec) + } + } + + func createAUParameterTree() -> AUParameterTree { + AUParameterTree.createTree(withChildren: self.createAUParameterNodes()) + } +} + +extension ParameterTreeSpec { + func createAUParameterTree() -> AUParameterTree { + AUParameterTree.createTree(withChildren: self.children.createAUParameterNodes()) + } +} diff --git a/sc55AU2/sc55AU2/sc55AU2Extension/Common/UI/AudioUnitViewController.swift b/sc55AU2/sc55AU2/sc55AU2Extension/Common/UI/AudioUnitViewController.swift new file mode 100644 index 00000000..c5433a3f --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2Extension/Common/UI/AudioUnitViewController.swift @@ -0,0 +1,124 @@ +// +// AudioUnitViewController.swift +// sc55AU2Extension +// +// Created by Giulio Zausa on 02.04.24. +// + +import Combine +import CoreAudioKit +import os +import SwiftUI + +private let log = Logger(subsystem: "giulioz.sc55AU2Extension", category: "AudioUnitViewController") + +public class AudioUnitViewController: AUViewController, AUAudioUnitFactory { + var audioUnit: AUAudioUnit? + + var hostingController: HostingController? + + private var observation: NSKeyValueObservation? + + /* iOS View lifcycle + public override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + // Recreate any view related resources here.. + } + + public override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + // Destroy any view related content here.. + } + */ + + /* macOS View lifcycle + public override func viewWillAppear() { + super.viewWillAppear() + + // Recreate any view related resources here.. + } + + public override func viewDidDisappear() { + super.viewDidDisappear() + + // Destroy any view related content here.. + } + */ + + deinit { + } + + public override func viewDidLoad() { + super.viewDidLoad() + + // Accessing the `audioUnit` parameter prompts the AU to be created via createAudioUnit(with:) + guard let audioUnit = self.audioUnit else { + return + } + configureSwiftUIView(audioUnit: audioUnit) + } + + public func createAudioUnit(with componentDescription: AudioComponentDescription) throws -> AUAudioUnit { + audioUnit = try sc55AU2ExtensionAudioUnit(componentDescription: componentDescription, options: []) + + guard let audioUnit = self.audioUnit as? sc55AU2ExtensionAudioUnit else { + log.error("Unable to create sc55AU2ExtensionAudioUnit") + return audioUnit! + } + + defer { + // Configure the SwiftUI view after creating the AU, instead of in viewDidLoad, + // so that the parameter tree is set up before we build our @AUParameterUI properties + DispatchQueue.main.async { + self.configureSwiftUIView(audioUnit: audioUnit) + } + } + + audioUnit.setupParameterTree(sc55AU2ExtensionParameterSpecs.createAUParameterTree()) + + self.observation = audioUnit.observe(\.allParameterValues, options: [.new]) { object, change in + guard let tree = audioUnit.parameterTree else { return } + + // This insures the Audio Unit gets initial values from the host. + for param in tree.allParameters { param.value = param.value } + } + + guard audioUnit.parameterTree != nil else { + log.error("Unable to access AU ParameterTree") + return audioUnit + } + + return audioUnit + } + + private func configureSwiftUIView(audioUnit: AUAudioUnit) { + if let host = hostingController { + host.removeFromParent() + host.view.removeFromSuperview() + } + + guard let observableParameterTree = audioUnit.observableParameterTree else { + return + } + let content = sc55AU2ExtensionMainView( + //parameterTree: observableParameterTree, + audioUnit: audioUnit as! sc55AU2ExtensionAudioUnit + ) + let host = HostingController(rootView: content) + self.addChild(host) + host.view.frame = self.view.bounds + self.view.addSubview(host.view) + hostingController = host + + // Make sure the SwiftUI view fills the full area provided by the view controller + host.view.translatesAutoresizingMaskIntoConstraints = false + host.view.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true + host.view.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true + host.view.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true + host.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true + self.view.bringSubviewToFront(host.view) + } + +} diff --git a/sc55AU2/sc55AU2/sc55AU2Extension/Common/UI/Base.lproj/AudioUnitViewController.xib b/sc55AU2/sc55AU2/sc55AU2Extension/Common/UI/Base.lproj/AudioUnitViewController.xib new file mode 100644 index 00000000..a3a97e94 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2Extension/Common/UI/Base.lproj/AudioUnitViewController.xib @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sc55AU2/sc55AU2/sc55AU2Extension/Common/UI/ObservableAUParameter.swift b/sc55AU2/sc55AU2/sc55AU2Extension/Common/UI/ObservableAUParameter.swift new file mode 100644 index 00000000..ddf90a33 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2Extension/Common/UI/ObservableAUParameter.swift @@ -0,0 +1,223 @@ +// +// ObservableAUParameter.swift +// sc55AU2Extension +// +// Created by Giulio Zausa on 02.04.24. +// + +import SwiftUI +import AudioToolbox + +/// Base-class for SwiftUI-capable AUParameterNodes +/// +/// This implementation provides a central point AUParameterGroup nodes to build a set of +/// observable children, and also enables us to traverse the parameter tree using dynamicMemberLookup +/// and subscript notation (i.e. parameterTree.paramGroup.parameter) +/// +/// This does *not* provide any of Swift's usual type-safety benefits, and may result in fatal errors if the +/// implementation attempts to access the subscript of an ObservableAUParameter (which has no children, as it's not a group). +@dynamicMemberLookup +class ObservableAUParameterNode { + + /// Create an ObservableAUParameterNode + /// + /// This creates the appropriate subclass, depending on the type of the passed in AUParameterNode + class func create(_ parameterNode: AUParameterNode) -> ObservableAUParameterNode { + switch parameterNode { + case let parameter as AUParameter: + return ObservableAUParameter(parameter) + case let group as AUParameterGroup: + return ObservableAUParameterGroup(group) + default: + fatalError("Unexpected AUParameterNode subclass") + } + } + + subscript(dynamicMember identifier: String) -> T { + guard let groupSelf = self as? ObservableAUParameterGroup else { + fatalError("Calling subscript is only supported on ObservableAUParameterGroups, you called it on \(self)") + } + + guard let node = groupSelf.children[identifier] else { + if groupSelf.children.isEmpty { + fatalError("This group has no children") + } + + let availableChildren = groupSelf.children.keys.joined(separator: "\n") + + print("Parameter Group \(groupSelf) doesn't have a child node named \(identifier), did you mean one of: \n \(availableChildren)") + fatalError() + } + + guard let subNode = node as? T else { + fatalError("Parameter node named \(identifier) cannot be converted to the requested type") + } + + return subNode + } + + subscript(dynamicMember identifier: String) -> ObservableAUParameterNode { + guard let groupSelf = self as? ObservableAUParameterGroup else { + fatalError("Calling subscript is only supported on ObservableAUParameterGroups, you called it on \(self)") + } + + guard let parameter = groupSelf.children[identifier] else { + if groupSelf.children.isEmpty { + fatalError("This group has no children") + } + + let availableChildren = groupSelf.children.keys.joined(separator: "\n") + + print("Parameter Group \(groupSelf) doesn't have a child node named \(identifier), did you mean one of: \n \(availableChildren)") + fatalError() + } + + return parameter + } + + private func asParameter() -> ObservableAUParameter { + guard let parameter = self as? ObservableAUParameter else { + fatalError("Node is not a parameter") + } + return parameter + } + + subscript(dynamicMember keyPath: ReferenceWritableKeyPath) -> Float { + get { self.asParameter()[keyPath: keyPath] } + set { self.asParameter()[keyPath: keyPath] = newValue } + } +} + +/// An Observable version of AUParameterGroup +/// +/// The primary purpose here is to expose observable versions of the group's child parameters. +/// +final class ObservableAUParameterGroup: ObservableAUParameterNode { + + private(set) var children: [String: ObservableAUParameterNode] + + init(_ parameterGroup: AUParameterGroup) { + children = parameterGroup.children.reduce( + into: [String: ObservableAUParameterNode]() + ) { dict, node in + let observableNode = ObservableAUParameterNode.create(node) + dict[node.identifier] = observableNode + } + } +} + +/// An Observable version of AUParameter +/// +/// ObservableAUParameter is intended to be used directly in SwiftUI views as an ObservedObject, +/// allowing us to expose a binding to the parameter's value, as well as associated parameter data, +/// like the minimum, maximum, and default values for the parameter. +/// +/// The ObservableAUParameter can also manage automation event types by calling +/// `onEditingChanged()` whenever a UI element will change its editing state. +final class ObservableAUParameter: ObservableAUParameterNode, ObservableObject { + + private weak var parameter: AUParameter? + private var observerToken: AUParameterObserverToken! + private var editingState: EditingState = .inactive + + let min: AUValue + let max: AUValue + let displayName: String + let defaultValue: AUValue = 0.0 + let unit: AudioUnitParameterUnit + + init(_ parameter: AUParameter) { + self.parameter = parameter + self.value = parameter.value + self.min = parameter.minValue + self.max = parameter.maxValue + self.displayName = parameter.displayName + self.unit = parameter.unit + super.init() + + /// Use the parameter.token(byAddingParameterObserver:) function to monitor for parameter + /// changes from the host. The only role of this callback is to update the UI if the value is changed by the host. + self.observerToken = parameter.token { (_ address: AUParameterAddress, _ auValue: AUValue) in + guard address == self.parameter?.address else { return } + + DispatchQueue.main.async { + // Don't update the UI if the user is currently interacting + guard self.editingState == .inactive else { return } + + self.editingState = .hostUpdate + self.value = auValue + self.editingState = .inactive + } + } + } + + @Published var value: AUValue { + didSet { + /// If the editing state is .hostUpdate, don't propagate this back to the host + guard editingState != .hostUpdate else { return } + + let automationEventType = resolveEventType() + parameter?.setValue( + value, + originator: observerToken, + atHostTime: 0, + eventType: automationEventType + ) + print("Param was set \(value)") + } + } + + /// A callback for UI elements to notify the Parameter when UI editing state changes + /// + /// This is the core mechanism for ensuring correct automation behavior. With native SwiftUI elements like `Slider`, + /// this method should be passed directly into the `onEditingChanged:` argument. + /// + /// As long as the UI Element correctly sets the editing state, then the ObservableAUParameter's calls to + /// AUParameter.setValue will contain the correct automation event type. + /// + /// `onEditingChanged` should be called with `true` before the first value is sent, so that it can be sent with a + /// `.touch` event. It's expected that `onEditingChanged` is called with a value of `false` to mark the end + /// of interaction *after* the last value has been sent, since this is how SwiftUI's `Slider` and `Stepper` views behave. + func onEditingChanged(_ editing: Bool) { + if editing { + editingState = .began + } else { + editingState = .ended + + // We set the value here again to prompt its `didSet` implementation, so that we can send the appropriate `.release` event. + value = value + } + } + + private func resolveEventType() -> AUParameterAutomationEventType { + let eventType: AUParameterAutomationEventType + switch editingState { + case .began: + eventType = .touch + editingState = .active + case .ended: + eventType = .release + editingState = .inactive + default: + eventType = .value + } + return eventType + } + + private enum EditingState { + case inactive + case began + case active + case ended + case hostUpdate + } +} + +extension AUAudioUnit { + // Can we subclass the Parameter tree to set that on the AUAudioUnit? + + var observableParameterTree: ObservableAUParameterGroup? { + guard let paramTree = self.parameterTree else { return nil } + return ObservableAUParameterGroup(paramTree) + } +} diff --git a/sc55AU2/sc55AU2/sc55AU2Extension/Common/Utility/CrossPlatform.swift b/sc55AU2/sc55AU2/sc55AU2Extension/Common/Utility/CrossPlatform.swift new file mode 100644 index 00000000..e339b38f --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2Extension/Common/Utility/CrossPlatform.swift @@ -0,0 +1,22 @@ +// +// CrossPlatform.swift +// sc55AU2Extension +// +// Created by Giulio Zausa on 02.04.24. +// + +import Foundation +import SwiftUI + +#if os(iOS) +typealias HostingController = UIHostingController +#elseif os(macOS) +typealias HostingController = NSHostingController + +extension NSView { + + func bringSubviewToFront(_ view: NSView) { + // This function is a no-opp for macOS + } +} +#endif diff --git a/sc55AU2/sc55AU2/sc55AU2Extension/Common/Utility/String+Utils.swift b/sc55AU2/sc55AU2/sc55AU2Extension/Common/Utility/String+Utils.swift new file mode 100644 index 00000000..d63dbf54 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2Extension/Common/Utility/String+Utils.swift @@ -0,0 +1,23 @@ +// +// String+Utils.swift +// sc55AU2Extension +// +// Created by Giulio Zausa on 02.04.24. +// + +import Foundation + +extension String { + var range: NSRange { + NSRange(location: 0, length: count) + } + + func isAlphanumeric() -> Bool { + if self.isEmpty { return false } + let regex = try! NSRegularExpression(pattern: "^[a-zA-Z0-9_-]*$", options: .caseInsensitive) + guard regex.firstMatch(in: self, options: [], range: range) != nil else { + return false + } + return true + } +} diff --git a/sc55AU2/sc55AU2/sc55AU2Extension/Common/sc55AU2Extension-Bridging-Header.h b/sc55AU2/sc55AU2/sc55AU2Extension/Common/sc55AU2Extension-Bridging-Header.h new file mode 100644 index 00000000..fe2049e6 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2Extension/Common/sc55AU2Extension-Bridging-Header.h @@ -0,0 +1,35 @@ +// +// sc55AU2Extension-Bridging-Header.h +// sc55AU2Extension +// +// Created by Giulio Zausa on 02.04.24. +// + +#import "sc55AU2ExtensionAudioUnit.h" +#import "sc55AU2ExtensionParameterAddresses.h" + +// void SC55_Reset(); +// uint32_t* LCD_Update(void); +// void LCD_SendButton(uint8_t button, int state); + +enum { + MCU_BUTTON_POWER = 0, + MCU_BUTTON_INST_L = 3, + MCU_BUTTON_INST_R = 4, + MCU_BUTTON_INST_MUTE = 5, + MCU_BUTTON_INST_ALL = 6, + MCU_BUTTON_MIDI_CH_L = 7, + MCU_BUTTON_MIDI_CH_R = 8, + MCU_BUTTON_CHORUS_L = 9, + MCU_BUTTON_CHORUS_R = 10, + MCU_BUTTON_PAN_L = 11, + MCU_BUTTON_PAN_R = 12, + MCU_BUTTON_PART_R = 13, + MCU_BUTTON_KEY_SHIFT_L = 14, + MCU_BUTTON_KEY_SHIFT_R = 15, + MCU_BUTTON_REVERB_L = 16, + MCU_BUTTON_REVERB_R = 17, + MCU_BUTTON_LEVEL_L = 18, + MCU_BUTTON_LEVEL_R = 19, + MCU_BUTTON_PART_L = 20 +}; diff --git a/sc55AU2/sc55AU2/sc55AU2Extension/DSP/sc55AU2ExtensionDSPKernel.hpp b/sc55AU2/sc55AU2/sc55AU2Extension/DSP/sc55AU2ExtensionDSPKernel.hpp new file mode 100644 index 00000000..51e075eb --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2Extension/DSP/sc55AU2ExtensionDSPKernel.hpp @@ -0,0 +1,226 @@ +// +// sc55AU2ExtensionDSPKernel.hpp +// sc55AU2Extension +// +// Created by Giulio Zausa on 02.04.24. +// + +#pragma once + +#import +#import +//#include + +#import "sc55AU2Extension-Swift.h" +#import "sc55AU2ExtensionParameterAddresses.h" +#import + +OSStatus EncoderDataProc(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, + AudioBufferList *ioData, + AudioStreamPacketDescription **outDataPacketDescription, + void *inUserData); + +/* + sc55AU2ExtensionDSPKernel + As a non-ObjC class, this is safe to use from render thread. + */ +class sc55AU2ExtensionDSPKernel { +public: + void initialize(int channelCount, double inSampleRate, const AudioStreamBasicDescription *outputFormat) { + nInits++; + printf("Init %d\n", nInits); + + destFormat = *outputFormat; + + AudioStreamBasicDescription sourceDescription; + sourceDescription.mSampleRate = 66207; + sourceDescription.mBytesPerFrame = 4; + sourceDescription.mBitsPerChannel = 16; + sourceDescription.mFormatID = kAudioFormatLinearPCM; + sourceDescription.mBytesPerPacket = 4; + sourceDescription.mChannelsPerFrame = 2; + sourceDescription.mFormatFlags = kAudioFormatFlagIsSignedInteger; + sourceDescription.mFramesPerPacket = 1; + sourceDescription.mReserved = 0; + + AudioConverterNew(&sourceDescription, &destFormat, &audioConverterRef); + + auto path = std::string(NSBundle.mainBundle.bundleURL.absoluteString.UTF8String).substr(7) + "Contents/Resources"; + mcu = new MCU(); + mcu->startSC55(&path); + } + + void deInitialize() { + printf("Deinit %d\n", nInits); + delete mcu; + } + + // MARK: - Bypass + bool isBypassed() { + return mBypassed; + } + + void setBypass(bool shouldBypass) { + mBypassed = shouldBypass; + } + + // MARK: - Parameter Getter / Setter + // Add a case for each parameter in sc55AU2ExtensionParameterAddresses.h + void setParameter(AUParameterAddress address, AUValue value) { + switch (address) { + case sc55AU2ExtensionParameterAddress::gain: + break; + } + } + + AUValue getParameter(AUParameterAddress address) { + // Return the goal. It is not thread safe to return the ramping value. + + switch (address) { + case sc55AU2ExtensionParameterAddress::gain: + return (AUValue)0; + + default: return 0.f; + } + } + + // MARK: - Max Frames + AUAudioFrameCount maximumFramesToRender() const { + return mMaxFramesToRender; + } + + void setMaximumFramesToRender(const AUAudioFrameCount &maxFrames) { + mMaxFramesToRender = maxFrames; + } + + // MARK: - Musical Context + void setMusicalContextBlock(AUHostMusicalContextBlock contextBlock) { + mMusicalContextBlock = contextBlock; + } + + // MARK: - MIDI Protocol + MIDIProtocolID AudioUnitMIDIProtocol() const { + return kMIDIProtocol_1_0; + } + + /** + MARK: - Internal Process + + This function does the core siginal processing. + Do your custom DSP here. + */ + void process(AUEventSampleTime bufferStartTime, AUAudioFrameCount frameCount, AudioBufferList* outBufferList) { + // auto start = std::chrono::high_resolution_clock::now(); + + UInt32 ioOutputDataPackets = frameCount * destFormat.mFramesPerPacket; + AudioConverterFillComplexBuffer(audioConverterRef, EncoderDataProc, + (void *)this, &ioOutputDataPackets, + outBufferList, NULL); + + + // auto stop = std::chrono::high_resolution_clock::now(); + // auto duration = std::chrono::duration_cast(stop - start).count(); + // if (duration > 8) { + // printf("process took %lld ms\n", duration); + // fflush(stdout); + // } + } + + void handleOneEvent(AUEventSampleTime now, AURenderEvent const *event) { + switch (event->head.eventType) { + case AURenderEventParameter: { + handleParameterEvent(now, event->parameter); + break; + } + + case AURenderEventMIDIEventList: { + handleMIDIEventList(now, &event->MIDIEventsList); + break; + } + + default: + break; + } + } + + void handleParameterEvent(AUEventSampleTime now, AUParameterEvent const& parameterEvent) { + // Implement handling incoming Parameter events as needed + } + + void handleMIDIEventList(AUEventSampleTime now, AUMIDIEventList const* midiEvent) { + auto visitor = [] (void* context, MIDITimeStamp timeStamp, MIDIUniversalMessage message) { + auto thisObject = static_cast(context); + + switch (message.type) { + case kMIDIMessageTypeChannelVoice1: { + thisObject->handleMIDI1VoiceMessage(message); + break; + } + + default: + break; + } + }; + + MIDIEventListForEachEvent(&midiEvent->eventList, visitor, this); + } + + void handleMIDI1VoiceMessage(const struct MIDIUniversalMessage& message) { + uint8_t messageBytes[8]; + int length = message.channelVoice1.status == kMIDICVStatusNoteOn + || message.channelVoice1.status == kMIDICVStatusNoteOff + || message.channelVoice1.status == kMIDICVStatusPolyPressure + || message.channelVoice1.status == kMIDICVStatusControlChange + || message.channelVoice1.status == kMIDICVStatusPitchBend ? 3 : 2; + messageBytes[0] = message.channelVoice1.status << 4 | message.channelVoice1.channel; + if (message.channelVoice1.status == kMIDICVStatusPitchBend) { + messageBytes[1] = message.channelVoice1.pitchBend & 0x7F; + messageBytes[2] = (message.channelVoice1.pitchBend >> 7) & 0x7F; + } else { + messageBytes[1] = message.channelVoice1.note.number; + messageBytes[2] = message.channelVoice1.note.velocity; + } + mcu->postMidiSC55(messageBytes, length); + } + + // MARK: - Member Variables + AUHostMusicalContextBlock mMusicalContextBlock; + + bool mBypassed = false; + AUAudioFrameCount mMaxFramesToRender = 1024; + + AudioConverterRef audioConverterRef; + AudioStreamBasicDescription destFormat; + + int16_t *lastBufferData; + + int nInits = 0; + +public: + MCU *mcu; +}; + +OSStatus EncoderDataProc(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, + AudioBufferList *ioData, + AudioStreamPacketDescription **outDataPacketDescription, + void *inUserData) { + sc55AU2ExtensionDSPKernel *_this = (sc55AU2ExtensionDSPKernel *)inUserData; + + if (_this->lastBufferData) { + free(_this->lastBufferData); + } + + unsigned int amountToWrite = *ioNumberDataPackets; + + unsigned int dataSize = amountToWrite * 2 * 2; + int16_t *dataBuff = (int16_t *)malloc(dataSize); +// memset(dataBuff, 0, dataSize); + _this->mcu->updateSC55(dataBuff, dataSize); + _this->lastBufferData = dataBuff; + + ioData->mNumberBuffers = 1; + ioData->mBuffers[0].mData = dataBuff; + ioData->mBuffers[0].mDataByteSize = dataSize; + + return 0; +} diff --git a/sc55AU2/sc55AU2/sc55AU2Extension/Info.plist b/sc55AU2/sc55AU2/sc55AU2Extension/Info.plist new file mode 100644 index 00000000..a6a6b01a --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2Extension/Info.plist @@ -0,0 +1,41 @@ + + + + + NSExtension + + NSExtensionAttributes + + AudioComponents + + + description + sc55AU2Extension + factoryFunction + $(PRODUCT_MODULE_NAME).AudioUnitViewController + manufacturer + SC55 + name + GIulio Zausa: sc55AU2Extension + sandboxSafe + + subtype + SC55 + tags + + Synthesizer + + type + aumu + version + 67072 + + + + NSExtensionPointIdentifier + com.apple.AudioUnit-UI + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).AudioUnitViewController + + + diff --git a/sc55AU2/sc55AU2/sc55AU2Extension/Parameters/Parameters.swift b/sc55AU2/sc55AU2/sc55AU2Extension/Parameters/Parameters.swift new file mode 100644 index 00000000..9feadd22 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2Extension/Parameters/Parameters.swift @@ -0,0 +1,48 @@ +// +// Parameters.swift +// sc55AU2Extension +// +// Created by Giulio Zausa on 02.04.24. +// + +import Foundation +import AudioToolbox + +let sc55AU2ExtensionParameterSpecs = ParameterTreeSpec { + ParameterGroupSpec(identifier: "global", name: "Global") { + ParameterSpec( + address: .gain, + identifier: "gain", + name: "Output Gain", + units: .linearGain, + valueRange: 0.0...1.0, + defaultValue: 0.25 + ) + } +} + +extension ParameterSpec { + init( + address: sc55AU2ExtensionParameterAddress, + identifier: String, + name: String, + units: AudioUnitParameterUnit, + valueRange: ClosedRange, + defaultValue: AUValue, + unitName: String? = nil, + flags: AudioUnitParameterOptions = [AudioUnitParameterOptions.flag_IsWritable, AudioUnitParameterOptions.flag_IsReadable], + valueStrings: [String]? = nil, + dependentParameters: [NSNumber]? = nil + ) { + self.init(address: address.rawValue, + identifier: identifier, + name: name, + units: units, + valueRange: valueRange, + defaultValue: defaultValue, + unitName: unitName, + flags: flags, + valueStrings: valueStrings, + dependentParameters: dependentParameters) + } +} diff --git a/sc55AU2/sc55AU2/sc55AU2Extension/Parameters/sc55AU2ExtensionParameterAddresses.h b/sc55AU2/sc55AU2/sc55AU2Extension/Parameters/sc55AU2ExtensionParameterAddresses.h new file mode 100644 index 00000000..1e94557c --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2Extension/Parameters/sc55AU2ExtensionParameterAddresses.h @@ -0,0 +1,22 @@ +// +// sc55AU2ExtensionParameterAddresses.h +// sc55AU2Extension +// +// Created by Giulio Zausa on 02.04.24. +// + +#pragma once + +#include + +#ifdef __cplusplus +namespace sc55AU2ExtensionParameterAddress { +#endif + +typedef NS_ENUM(AUParameterAddress, sc55AU2ExtensionParameterAddress) { + gain = 0 +}; + +#ifdef __cplusplus +} +#endif diff --git a/sc55AU2/sc55AU2/sc55AU2Extension/README.md b/sc55AU2/sc55AU2/sc55AU2Extension/README.md new file mode 100644 index 00000000..d7b26433 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2Extension/README.md @@ -0,0 +1,126 @@ +# Audio Unit Extension +This template serves as a starting point to create a custom plug-in using the latest Audio Unit standard (AUv3). The AUv3 standard builds on the App Extensions model, which means you deliver your plug-in as an extension that’s contained in an app distributed through the App Store or your own store. + +There are 5 types of Audio Unit Extensions, each type is represented by a four character code. + +|Name|Four Character Code| +|---|---| +|Effect|aufx| +|Music Effect|aumf| +|MIDI Processor|aumi| +|Instrument|aumu| +|Generator|augn| + + +## Languages +This template uses Swift and SwiftUI for business logic and user interface, C++ for real-time constrained areas and Objective-C for interacting between Swift and C++. + +## Project Layout +This template is designed to make Audio Unit development as easy as possible. In most cases you should only need to edit files in the top level groups; `Parameters`, `DSP` and `UI` groups. + +* /Common - Contains common code split by functionality which should rarely need to be modified. + * `Audio Unit/sc55AU2ExtensionAudioUnit.mm/h` - A subclass of AUAudioUnit, this is the actual Audio Unit implementation. You may in advanced cases need to change this file to add additional functionality from AUAudioUnit. +* /Parameters + * `sc55AU2ExtensionParameterAddresses.h` - A pure `C` enum containing parameter addresses used by Swift and C++ to reference parameters. + + * `Parameters.swift` - Contains a ParameterTreeSpec object made up of ParameterGroupSpec's and ParameterSpec's which allow you describe your plug-in's parameters and the layout of those parameters. + +* /DSP + * `sc55AU2ExtensionDSPKernel.hpp` - A pure C++ class to handle the real-time aspects of the Audio Unit Extension. DSP and processing should be done here. Note: Be aware of the constraints of real-time audio processing. +* /UI + * `sc55AU2ExtensionMainView.swift` - SwiftUI based main view, add your SwiftUI views and controls here. + +## Adding a parameter +1. Add a new parameter address to the `sc55AU2ExtensionParameterAddress` enum in `sc55AU2ExtensionParameterAddresses.h` + + +Example: + +```c +typedef NS_ENUM(AUParameterAddress, sc55AU2ExtensionParameterAddress) { + sendNote = 0, + .... + attack +``` + +2. Create a new `ParameterSpec` in `Parameters.swift` using the enum value (created in step 1) as the address. + +Example: + +```swift +ParameterGroupSpec(identifier: "global", name: "Global") { + .... + ParameterSpec( + address: .attack, + identifier: "attack", + name: "Attack", + units: .milliseconds, + valueRange: 0.0...1000.0, + defaultValue: 100.0 + ) + ... +``` +Note: the identifier will be used to interact with this parameter from SwiftUI. + +3. In order to manipulate the DSP side of the Audio Unit we must handle changes to our new parameter in `sc55AU2ExtensionDSPKernel.hpp`. In the `setParameter` and `getParameter` methods add a case for the new parameter address. + +Example: + +```cpp + void setParameter(AUParameterAddress address, AUValue value) { + switch (address) { + .... + case sc55AU2ExtensionExtensionParameterAddress:: attack: + mAttack = value; + break; + ... + } + + AUValue getParameter(AUParameterAddress address) { + switch (address) { + .... + case sc55AU2ExtensionExtensionParameterAddress::attack: + return (AUValue) mAttack; + ... + } + + // You can now apply attack your DSP algorithm using `mAttack` in the `process` call. +``` + +4. For Audio Units that present a user interface, you should expose or access the new parameter in your SwiftUI view. The parameter can be accessed using its identifier (defined in step 2). It is accessed using dot notation as follows parameterTree... + +Example + +```Swift +// Access the attack parameters value from SwiftUI +parameterTree.global.attack.value + +// Set the attack parameters value from SwiftUI +parameterTree.global.attack.value = 0.5 + +// Bind the parameter to a slider +struct EqualizerExtensionMainView: View { + ... + var body: some View { + ParameterSlider(param: parameterTree.global.attack) + } + ... +} + +/* +Note: the parameterTree. must match the structure and identifier of the parameter defined in `Parameters.swift`. +*/ +``` + +## Catalyst / iPhone and iPad apps on Mac with Apple silicon +To build this template in a Catalyst or iPhone/iPad App on Mac with Apple silicon, perform the following steps: + +1. Select your Xcode project in the left hand side file browser +2. Select your app target under the 'TARGETS' menu +3. Under 'Deployment Info' select 'Mac Catalyst' (Note: Skip this step for iPhone and iPad apps on Mac with Apple silicon) +4. Select the 'General' tab in the top menu bar +5. Under 'Frameworks, Libraries, and Embedded Content' click the button next to the iOS filter +6. In the pop-up menu select 'Allow any platforms' + +## More Information +[Apple Audio Developer Documentation](https://developer.apple.com/audio/) diff --git a/sc55AU2/sc55AU2/sc55AU2Extension/UI/EmulatorView.swift b/sc55AU2/sc55AU2/sc55AU2Extension/UI/EmulatorView.swift new file mode 100644 index 00000000..668ed5e9 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2Extension/UI/EmulatorView.swift @@ -0,0 +1,270 @@ +// +// EmulatorView.swift +// sc55AU2Extension +// +// Created by Giulio Zausa on 04.04.24. +// + +import SwiftUI + +public struct Color { + public var r, g, b, a: UInt8 + + public init(r: UInt8, g: UInt8, b: UInt8, a: UInt8 = 255) { + self.r = r + self.g = g + self.b = b + self.a = a + } +} + +extension Image { + init?(bitmap: Bitmap) { + let alphaInfo = CGImageAlphaInfo.premultipliedLast + let bytesPerPixel = MemoryLayout.size + let bytesPerRow = bitmap.width * bytesPerPixel + + guard let providerRef = CGDataProvider(data: Data( + bytes: bitmap.pixels, count: bitmap.height * bytesPerRow + ) as CFData) else { + return nil + } + + guard let cgImage = CGImage( + width: bitmap.width, + height: bitmap.height, + bitsPerComponent: 8, + bitsPerPixel: bytesPerPixel * 8, + bytesPerRow: bytesPerRow, + space: CGColorSpaceCreateDeviceRGB(), + bitmapInfo: CGBitmapInfo(rawValue: alphaInfo.rawValue), + provider: providerRef, + decode: nil, + shouldInterpolate: true, + intent: .defaultIntent + ) else { + return nil + } + + self.init(decorative: cgImage, scale: 1.0, orientation: .up) + } +} + +public struct Bitmap { + public private(set) var pixels: [Color] + public let width: Int + + public init(width: Int, pixels: [Color]) { + self.width = width + self.pixels = pixels + } + + var height: Int { + return pixels.count / width + } + + subscript(x: Int, y: Int) -> Color { + get { return pixels[y * width + x] } + set { pixels[y * width + x] = newValue } + } + + init(width: Int, height: Int, color: Color) { + self.pixels = Array(repeating: color, count: width * height) + self.width = width + } +} + +public struct Renderer { + public private(set) var bitmap: Bitmap + var audioUnit: sc55AU2ExtensionAudioUnit? + + public init(width: Int, height: Int) { + self.bitmap = Bitmap(width: width, height: height, color: Color.init( + r: 0, g: 0,b: 0, a: 0 + )) + } + + mutating func draw() { + if let audioUnitR = audioUnit { + let lcdResult = audioUnitR.lcd_Update(); + for x in 0...(741-1) { + for y in 0...(268-1) { + bitmap[x, y] = Color.init( + r: UInt8((lcdResult![x + y * 741] >> 0) & 0xff), + g: UInt8((lcdResult![x + y * 741] >> 8) & 0xff), + b: UInt8((lcdResult![x + y * 741] >> 16) & 0xff), + a: 255 + ) + } + } + } + } +} + +class Screen : ObservableObject { + @Published + var toggle: Bool = false + public var image: Image? { + didSet { + DispatchQueue.main.async { [weak self] in + self?.toggle.toggle() + } + } + } + + var renderer: Renderer + private var displayLink: CVDisplayLink? + + let displayCallback: CVDisplayLinkOutputCallback = { displayLink, inNow, inOutputTime, flagsIn, flagsOut, displayLinkContext in + let screen = unsafeBitCast(displayLinkContext, to: Screen.self) + screen.renderer.draw() + screen.image = Image(bitmap: screen.renderer.bitmap) + return kCVReturnSuccess + } + + init(width: Int, height: Int) { + self.renderer = Renderer(width: width, height: height) + + let error = CVDisplayLinkCreateWithActiveCGDisplays(&self.displayLink) + guard let link = self.displayLink, kCVReturnSuccess == error else { + NSLog("Display Link created with error: %d", error) + return + } + + CVDisplayLinkSetOutputCallback(link, displayCallback, UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())) + CVDisplayLinkStart(link) + } + + deinit { + CVDisplayLinkStop(self.displayLink!) + } +} + +struct SCButton: View { + let code: Int + let text: String + var audioUnit: sc55AU2ExtensionAudioUnit? + + var body: some View { + Button(action: { + audioUnit?.lcd_SendButton(UInt8(code), 1) + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { + audioUnit?.lcd_SendButton(UInt8(code), 0) + } + }){ + Text(text) + }.frame(maxWidth: .infinity) + } +} + +struct EmulatorView: View { + var audioUnit: sc55AU2ExtensionAudioUnit? + + @ObservedObject + var screen = Screen(width: 741, height: 268) + + var body: some View { + HStack { + screen.image? + .resizable() + .interpolation(.none) + .frame(width: 741/2, height: 268/2, alignment: .center) + .aspectRatio(contentMode: .fit) + .onAppear(perform: { screen.renderer.audioUnit = audioUnit }) + + VStack { + SCButton(code: MCU_BUTTON_INST_ALL, text: "ALL", audioUnit: audioUnit) + SCButton(code: MCU_BUTTON_INST_MUTE, text: "MUTE", audioUnit: audioUnit) + + SCButton(code: MCU_BUTTON_POWER, text: "POWER", audioUnit: audioUnit) + + Button(action: { + audioUnit?.lcd_SendButton(UInt8(MCU_BUTTON_PART_L), 1) + audioUnit?.lcd_SendButton(UInt8(MCU_BUTTON_PART_R), 1) + audioUnit?.lcd_SendButton(UInt8(MCU_BUTTON_POWER), 1) + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { + audioUnit?.lcd_SendButton(UInt8(MCU_BUTTON_PART_L), 0) + audioUnit?.lcd_SendButton(UInt8(MCU_BUTTON_PART_R), 0) + audioUnit?.lcd_SendButton(UInt8(MCU_BUTTON_POWER), 0) + } + }){ Text("DEMO") } + + Button(action: { + audioUnit?.lcd_SendButton(UInt8(MCU_BUTTON_INST_L), 1) + audioUnit?.lcd_SendButton(UInt8(MCU_BUTTON_INST_R), 1) + audioUnit?.lcd_SendButton(UInt8(MCU_BUTTON_POWER), 1) + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { + audioUnit?.lcd_SendButton(UInt8(MCU_BUTTON_INST_L), 0) + audioUnit?.lcd_SendButton(UInt8(MCU_BUTTON_INST_R), 0) + audioUnit?.lcd_SendButton(UInt8(MCU_BUTTON_POWER), 0) + } + }){ Text("INIT ALL") } + + Button(action: { + audioUnit?.lcd_SendButton(UInt8(MCU_BUTTON_INST_R), 1) + audioUnit?.lcd_SendButton(UInt8(MCU_BUTTON_POWER), 1) + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { + audioUnit?.lcd_SendButton(UInt8(MCU_BUTTON_INST_R), 0) + audioUnit?.lcd_SendButton(UInt8(MCU_BUTTON_POWER), 0) + } + }){ Text("GS RESET") } + + Button(action: { + audioUnit?.sc55_Reset() + }) { + Text("RESET") + } + }.frame(width: 100, alignment: .top) + + VStack { + Text("Part") + HStack { + SCButton(code: MCU_BUTTON_PART_L, text: "<", audioUnit: audioUnit) + SCButton(code: MCU_BUTTON_PART_R, text: ">", audioUnit: audioUnit) + } + Text("Level") + HStack { + SCButton(code: MCU_BUTTON_LEVEL_L, text: "<", audioUnit: audioUnit) + SCButton(code: MCU_BUTTON_LEVEL_R, text: ">", audioUnit: audioUnit) + } + Text("Reverb") + HStack { + SCButton(code: MCU_BUTTON_REVERB_L, text: "<", audioUnit: audioUnit) + SCButton(code: MCU_BUTTON_REVERB_R, text: ">", audioUnit: audioUnit) + } + Text("Key Shift") + HStack { + SCButton(code: MCU_BUTTON_KEY_SHIFT_L, text: "<", audioUnit: audioUnit) + SCButton(code: MCU_BUTTON_KEY_SHIFT_R, text: ">", audioUnit: audioUnit) + } + }.frame(width: 100, alignment: .center) + + VStack { + Text("Instrument") + HStack { + SCButton(code: MCU_BUTTON_INST_L, text: "<", audioUnit: audioUnit) + SCButton(code: MCU_BUTTON_INST_R, text: ">", audioUnit: audioUnit) + } + Text("Pan") + HStack { + SCButton(code: MCU_BUTTON_PAN_L, text: "<", audioUnit: audioUnit) + SCButton(code: MCU_BUTTON_PAN_R, text: ">", audioUnit: audioUnit) + } + Text("Chorus") + HStack { + SCButton(code: MCU_BUTTON_CHORUS_L, text: "<", audioUnit: audioUnit) + SCButton(code: MCU_BUTTON_CHORUS_R, text: ">", audioUnit: audioUnit) + } + Text("Midi CH") + HStack { + SCButton(code: MCU_BUTTON_MIDI_CH_L, text: "<", audioUnit: audioUnit) + SCButton(code: MCU_BUTTON_MIDI_CH_R, text: ">", audioUnit: audioUnit) + } + }.frame(width: 100, alignment: .center) + } + } +} + +#Preview { + EmulatorView() +} diff --git a/sc55AU2/sc55AU2/sc55AU2Extension/UI/ParameterSlider.swift b/sc55AU2/sc55AU2/sc55AU2Extension/UI/ParameterSlider.swift new file mode 100644 index 00000000..6474d9db --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2Extension/UI/ParameterSlider.swift @@ -0,0 +1,40 @@ +// +// ParameterSlider.swift +// sc55AU2Extension +// +// Created by Giulio Zausa on 02.04.24. +// + +import SwiftUI + +/// A SwiftUI Slider container which is bound to an ObservableAUParameter +/// +/// This view wraps a SwiftUI Slider, and provides it relevant data from the Parameter, like the minimum and maximum values. +struct ParameterSlider: View { + @ObservedObject var param: ObservableAUParameter + + var specifier: String { + switch param.unit { + case .midiNoteNumber: + return "%.0f" + default: + return "%.2f" + } + } + + var body: some View { + VStack { + Slider( + value: $param.value, + in: param.min...param.max, + onEditingChanged: param.onEditingChanged, + minimumValueLabel: Text("\(param.min, specifier: specifier)"), + maximumValueLabel: Text("\(param.max, specifier: specifier)") + ) { + EmptyView() + } + Text("\(param.displayName): \(param.value, specifier: specifier)") + } + .padding() + } +} diff --git a/sc55AU2/sc55AU2/sc55AU2Extension/UI/sc55AU2ExtensionMainView.swift b/sc55AU2/sc55AU2/sc55AU2Extension/UI/sc55AU2ExtensionMainView.swift new file mode 100644 index 00000000..d872b3f6 --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2Extension/UI/sc55AU2ExtensionMainView.swift @@ -0,0 +1,23 @@ +// +// sc55AU2ExtensionMainView.swift +// sc55AU2Extension +// +// Created by Giulio Zausa on 02.04.24. +// + +import SwiftUI + +struct sc55AU2ExtensionMainView: View { +// var parameterTree: ObservableAUParameterGroup + var audioUnit: sc55AU2ExtensionAudioUnit? + + var body: some View { + TabView { + EmulatorView(audioUnit: audioUnit).tabItem { Text("Emulator") } + } + } +} + +#Preview { + sc55AU2ExtensionMainView() +} diff --git a/sc55AU2/sc55AU2/sc55AU2Extension/sc55AU2Extension.entitlements b/sc55AU2/sc55AU2/sc55AU2Extension/sc55AU2Extension.entitlements new file mode 100644 index 00000000..11fa75eb --- /dev/null +++ b/sc55AU2/sc55AU2/sc55AU2Extension/sc55AU2Extension.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.files.downloads.read-write + + com.apple.security.files.user-selected.read-write + + + diff --git a/src/lcd.cpp b/src/lcd.cpp index 6690dd33..f95fbd8b 100644 --- a/src/lcd.cpp +++ b/src/lcd.cpp @@ -43,27 +43,17 @@ #include "submcu.h" #include "utils/files.h" - -static uint32_t LCD_DL, LCD_N, LCD_F, LCD_D, LCD_C, LCD_B, LCD_ID, LCD_S; -static uint32_t LCD_DD_RAM, LCD_AC, LCD_CG_RAM; -static uint32_t LCD_RAM_MODE = 0; -static uint8_t LCD_Data[80]; -static uint8_t LCD_CG[64]; - -static uint8_t lcd_enable = 1; -static bool lcd_quit_requested = false; - -void LCD_Enable(uint32_t enable) +void LCD::LCD_Enable(uint32_t enable) { lcd_enable = enable; } -bool LCD_QuitRequested() +bool LCD::LCD_QuitRequested() { return lcd_quit_requested; } -void LCD_Write(uint32_t address, uint8_t data) +void LCD::LCD_Write(uint32_t address, uint8_t data) { if (address == 0) { @@ -162,19 +152,6 @@ void LCD_Write(uint32_t address, uint8_t data) // printf("\n"); } -static const int lcd_width = 741; -static const int lcd_height = 268; -static SDL_Window *window; -static SDL_Renderer *renderer; -static SDL_Texture *texture; - -static std::string m_back_path = "back.data"; - -static uint32_t lcd_buffer[lcd_height][lcd_width]; -static uint32_t lcd_background[lcd_height][lcd_width]; - -static uint32_t lcd_init = 0; - const int button_map[][2] = { SDL_SCANCODE_Q, MCU_BUTTON_POWER, @@ -201,53 +178,29 @@ const int button_map[][2] = }; -void LCD_SetBackPath(const std::string &path) +void LCD::LCD_SetBackPath(const std::string &path) { m_back_path = path; } -void LCD_Init(void) +void LCD::LCD_Init(MCU *mcu) { + this->mcu = mcu; + FILE *raw; - if(lcd_init) - return; - - lcd_quit_requested = false; - - window = SDL_CreateWindow("SC-55mkII", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, lcd_width, lcd_height, SDL_WINDOW_SHOWN); - if (!window) - return; - - renderer = SDL_CreateRenderer(window, -1, 0); - if (!renderer) - return; - - texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_BGR888, SDL_TEXTUREACCESS_STREAMING, lcd_width, lcd_height); - - if (!texture) - return; - raw = Files::utf8_fopen(m_back_path.c_str(), "rb"); if (!raw) return; fread(lcd_background, 1, sizeof(lcd_background), raw); fclose(raw); - - lcd_init = 1; -} - -void LCD_UnInit(void) -{ - if(!lcd_init) - return; } -uint32_t lcd_col1 = 0x000000; -uint32_t lcd_col2 = 0x0050c8; +const uint32_t lcd_col1 = 0x000000; +const uint32_t lcd_col2 = 0x0050c8; -void LCD_FontRenderStandard(int32_t x, int32_t y, uint8_t ch) +void LCD::LCD_FontRenderStandard(int32_t x, int32_t y, uint8_t ch) { uint8_t* f; if (ch >= 16) @@ -280,7 +233,7 @@ void LCD_FontRenderStandard(int32_t x, int32_t y, uint8_t ch) } } -void LCD_FontRenderLevel(int32_t x, int32_t y, uint8_t ch, uint8_t width = 5) +void LCD::LCD_FontRenderLevel(int32_t x, int32_t y, uint8_t ch, uint8_t width) { uint8_t* f; if (ch >= 16) @@ -313,12 +266,10 @@ void LCD_FontRenderLevel(int32_t x, int32_t y, uint8_t ch, uint8_t width = 5) } } -void LCD_Update(void) +uint32_t* LCD::LCD_Update(void) { - if (!lcd_init) - return; - - MCU_WorkThread_Lock(); + // if (!lcd_init) + // return; if (!lcd_enable) { @@ -393,141 +344,17 @@ void LCD_Update(void) } } - MCU_WorkThread_Unlock(); - - SDL_UpdateTexture(texture, NULL, lcd_buffer, lcd_width * 4); - SDL_RenderCopy(renderer, texture, NULL, NULL); - SDL_RenderPresent(renderer); - - SDL_Event sdl_event; - while (SDL_PollEvent(&sdl_event)) - { - switch (sdl_event.type) - { - case SDL_QUIT: - lcd_quit_requested = true; - break; - - case SDL_KEYDOWN: - case SDL_KEYUP: - { - if (sdl_event.key.repeat) - continue; - - int mask = 0; - uint32_t button_pressed = (uint32_t)SDL_AtomicGet(&mcu_button_pressed); - - for (size_t i = 0; i < sizeof(button_map) / sizeof(button_map[0]); i++) - { - if (button_map[i][0] == sdl_event.key.keysym.scancode) - mask |= (1 << button_map[i][1]); - } - - if (sdl_event.type == SDL_KEYDOWN) - button_pressed |= mask; - else - button_pressed &= ~mask; - - SDL_AtomicSet(&mcu_button_pressed, (int)button_pressed); + return (uint32_t*)lcd_buffer; +} -#if 1 - if (sdl_event.key.keysym.scancode >= SDL_SCANCODE_1 && sdl_event.key.keysym.scancode < SDL_SCANCODE_0) - { -#if 0 - int kk = sdl_event.key.keysym.scancode - SDL_SCANCODE_1; - if (sdl_event.type == SDL_KEYDOWN) - { - SM_PostUART(0xc0); - SM_PostUART(118); - SM_PostUART(0x90); - SM_PostUART(0x30 + kk); - SM_PostUART(0x7f); - } - else - { - SM_PostUART(0x90); - SM_PostUART(0x30 + kk); - SM_PostUART(0); - } -#endif - int kk = sdl_event.key.keysym.scancode - SDL_SCANCODE_1; - const int patch = 47; - if (sdl_event.type == SDL_KEYDOWN) - { - static int bend = 0x2000; - if (kk == 4) - { - SM_PostUART(0x99); - SM_PostUART(0x32); - SM_PostUART(0x7f); - } - else if (kk == 3) - { - bend += 0x100; - if (bend > 0x3fff) - bend = 0x3fff; - SM_PostUART(0xe1); - SM_PostUART(bend & 127); - SM_PostUART((bend >> 7) & 127); - } - else if (kk == 2) - { - bend -= 0x100; - if (bend < 0) - bend = 0; - SM_PostUART(0xe1); - SM_PostUART(bend & 127); - SM_PostUART((bend >> 7) & 127); - } - else if (kk) - { - SM_PostUART(0xc1); - SM_PostUART(patch); - SM_PostUART(0xe1); - SM_PostUART(bend & 127); - SM_PostUART((bend >> 7) & 127); - SM_PostUART(0x91); - SM_PostUART(0x32); - SM_PostUART(0x7f); - } - else if (kk == 0) - { - //SM_PostUART(0xc0); - //SM_PostUART(patch); - SM_PostUART(0xe0); - SM_PostUART(0x00); - SM_PostUART(0x40); - SM_PostUART(0x99); - SM_PostUART(0x37); - SM_PostUART(0x7f); - } - } - else - { - if (kk == 1) - { - SM_PostUART(0x91); - SM_PostUART(0x32); - SM_PostUART(0); - } - else if (kk == 0) - { - SM_PostUART(0x99); - SM_PostUART(0x37); - SM_PostUART(0); - } - else if (kk == 4) - { - SM_PostUART(0x99); - SM_PostUART(0x32); - SM_PostUART(0); - } - } - } -#endif - break; - } - } +void LCD::LCD_SendButton(uint8_t button, int state) { + uint32_t button_pressed = (uint32_t)SDL_AtomicGet(&mcu->mcu_button_pressed); + int mask = (1 << button); + if (state) { + button_pressed |= mask; + } else { + button_pressed &= ~mask; } + SDL_AtomicSet(&mcu->mcu_button_pressed, (int)button_pressed); } diff --git a/src/lcd.h b/src/lcd.h index 173cf7b3..f9ed7893 100644 --- a/src/lcd.h +++ b/src/lcd.h @@ -36,11 +36,36 @@ #include #include -void LCD_SetBackPath(const std::string &path); -void LCD_Init(void); -void LCD_UnInit(void); -void LCD_Write(uint32_t address, uint8_t data); -void LCD_Enable(uint32_t enable); -bool LCD_QuitRequested(); -void LCD_Sync(void); -void LCD_Update(void); +struct MCU; + +static const int lcd_width = 741; +static const int lcd_height = 268; + +struct LCD { + MCU *mcu; + + uint32_t LCD_DL, LCD_N, LCD_F, LCD_D, LCD_C, LCD_B, LCD_ID, LCD_S; + uint32_t LCD_DD_RAM, LCD_AC, LCD_CG_RAM; + uint32_t LCD_RAM_MODE = 0; + uint8_t LCD_Data[80]; + uint8_t LCD_CG[64]; + + uint8_t lcd_enable = 1; + bool lcd_quit_requested = false; + + std::string m_back_path = "back.data"; + + uint32_t lcd_buffer[lcd_height][lcd_width]; + uint32_t lcd_background[lcd_height][lcd_width]; + + void LCD_SetBackPath(const std::string &path); + void LCD_FontRenderStandard(int32_t x, int32_t y, uint8_t ch); + void LCD_FontRenderLevel(int32_t x, int32_t y, uint8_t ch, uint8_t width = 5); + void LCD_Init(MCU *mcu); + void LCD_Write(uint32_t address, uint8_t data); + void LCD_Enable(uint32_t enable); + bool LCD_QuitRequested(); + uint32_t* LCD_Update(void); + void LCD_SendButton(uint8_t button, int state); +}; + diff --git a/src/mcu.cpp b/src/mcu.cpp index 066e33d5..303881ef 100644 --- a/src/mcu.cpp +++ b/src/mcu.cpp @@ -33,6 +33,7 @@ */ #include #include +#include #define SDL_MAIN_HANDLED #include "SDL.h" #include "mcu.h" @@ -42,7 +43,6 @@ #include "pcm.h" #include "lcd.h" #include "submcu.h" -#include "midi.h" #include "utf8main.h" #include "utils/files.h" @@ -51,59 +51,201 @@ #include #endif +void MCU::MCU_ErrorTrap(void) +{ + printf("trap %.2x %.4x\n", mcu.cp, mcu.pc); +} -static const int ROM1_SIZE = 0x8000; -static const int ROM2_SIZE = 0x80000; -static const int RAM_SIZE = 0x400; -static const int SRAM_SIZE = 0x8000; -static const int ROMSM_SIZE = 0x1000; - +uint8_t MCU::RCU_Read(void) +{ + return 0; +} -static const int audio_buffer_size = 16384; -static const int audio_page_size = 512; +enum { + ANALOG_LEVEL_RCU_LOW = 0, + ANALOG_LEVEL_RCU_HIGH = 0, + ANALOG_LEVEL_SW_0 = 0, + ANALOG_LEVEL_SW_1 = 0, + ANALOG_LEVEL_SW_2 = 0, + ANALOG_LEVEL_SW_3 = 0, + ANALOG_LEVEL_BATTERY = 0x3ff, +}; -static short sample_buffer[audio_buffer_size]; +uint32_t MCU::MCU_GetAddress(uint8_t page, uint16_t address) { + return (page << 16) + address; +} -static int sample_read_ptr; -static int sample_write_ptr; +uint8_t MCU::MCU_ReadCode(void) { + return MCU_Read(MCU_GetAddress(mcu.cp, mcu.pc)); +} -static SDL_AudioDeviceID sdl_audio; +uint8_t MCU::MCU_ReadCodeAdvance(void) { + uint8_t ret = MCU_ReadCode(); + mcu.pc++; + return ret; +} -void MCU_ErrorTrap(void) +void MCU::MCU_SetRegisterByte(uint8_t reg, uint8_t val) { - printf("%.2x %.4x\n", mcu.cp, mcu.pc); + mcu.r[reg] = val; } -int mcu_mk1 = 0; // 0 - SC-55mkII, SC-55ST. 1 - SC-55, CM-300/SCC-1 +uint32_t MCU::MCU_GetVectorAddress(uint32_t vector) +{ + return MCU_Read32(vector * 4); +} -static int ga_int[8]; -static int ga_int_enable = 0; -static int ga_int_trigger = 0; +uint32_t MCU::MCU_GetPageForRegister(uint32_t reg) +{ + if (reg >= 6) + return mcu.tp; + else if (reg >= 4) + return mcu.ep; + return mcu.dp; +} +void MCU::MCU_ControlRegisterWrite(uint32_t reg, uint32_t siz, uint32_t data) +{ + if (siz) + { + if (reg == 0) + { + mcu.sr = data; + mcu.sr &= sr_mask; + } + else if (reg == 5) // FIXME: undocumented + { + mcu.dp = data & 0xff; + } + else if (reg == 4) // FIXME: undocumented + { + mcu.ep = data & 0xff; + } + else if (reg == 3) // FIXME: undocumented + { + mcu.br = data & 0xff; + } + else + { + MCU_ErrorTrap(); + } + } + else + { + if (reg == 1) + { + mcu.sr &= ~0xff; + mcu.sr |= data & 0xff; + mcu.sr &= sr_mask; + } + else if (reg == 3) + { + mcu.br = data; + } + else if (reg == 4) + { + mcu.ep = data; + } + else if (reg == 5) + { + mcu.dp = data; + } + else if (reg == 7) + { + mcu.tp = data; + } + else + { + MCU_ErrorTrap(); + } + } +} -uint8_t dev_register[0x80]; +uint32_t MCU::MCU_ControlRegisterRead(uint32_t reg, uint32_t siz) +{ + uint32_t ret = 0; + if (siz) + { + if (reg == 0) + { + ret = mcu.sr & sr_mask; + } + else if (reg == 5) // FIXME: undocumented + { + ret = mcu.dp | (mcu.dp << 8); + } + else if (reg == 4) // FIXME: undocumented + { + ret = mcu.ep | (mcu.ep << 8); + } + else if (reg == 3) // FIXME: undocumented + { + ret = mcu.br | (mcu.br << 8);; + } + else + { + MCU_ErrorTrap(); + } + ret &= 0xffff; + } + else + { + if (reg == 1) + { + ret = mcu.sr & sr_mask; + } + else if (reg == 3) + { + ret = mcu.br; + } + else if (reg == 4) + { + ret = mcu.ep; + } + else if (reg == 5) + { + ret = mcu.dp; + } + else if (reg == 7) + { + ret = mcu.tp; + } + else + { + MCU_ErrorTrap(); + } + ret &= 0xff; + } + return ret; +} -static uint16_t ad_val[4]; -static uint8_t ad_nibble = 0x00; -static uint8_t sw_pos = 0; -static uint8_t io_sd = 0x00; +void MCU::MCU_SetStatus(uint32_t condition, uint32_t mask) +{ + if (condition) + mcu.sr |= mask; + else + mcu.sr &= ~mask; +} -uint8_t RCU_Read(void) +void MCU::MCU_PushStack(uint16_t data) { - return 0; + if (mcu.r[7] & 1) + MCU_Interrupt_Exception(this, EXCEPTION_SOURCE_ADDRESS_ERROR); + mcu.r[7] -= 2; + MCU_Write16(mcu.r[7], data); } -enum { - ANALOG_LEVEL_RCU_LOW = 0, - ANALOG_LEVEL_RCU_HIGH = 0, - ANALOG_LEVEL_SW_0 = 0, - ANALOG_LEVEL_SW_1 = 0, - ANALOG_LEVEL_SW_2 = 0, - ANALOG_LEVEL_SW_3 = 0, - ANALOG_LEVEL_BATTERY = 0x3ff, -}; +uint16_t MCU::MCU_PopStack(void) +{ + uint16_t ret; + if (mcu.r[7] & 1) + MCU_Interrupt_Exception(this, EXCEPTION_SOURCE_ADDRESS_ERROR); + ret = MCU_Read16(mcu.r[7]); + mcu.r[7] += 2; + return ret; +} -uint16_t MCU_AnalogReadPin(uint32_t pin) +uint16_t MCU::MCU_AnalogReadPin(uint32_t pin) { return 0x3ff; uint8_t rcu; @@ -139,7 +281,7 @@ uint16_t MCU_AnalogReadPin(uint32_t pin) return ANALOG_LEVEL_RCU_LOW; } -void MCU_AnalogSample(int channel) +void MCU::MCU_AnalogSample(int channel) { int value = MCU_AnalogReadPin(channel); int dest = (channel << 1) & 6; @@ -147,21 +289,17 @@ void MCU_AnalogSample(int channel) dev_register[DEV_ADDRAL + dest] = (value << 6) & 0xc0; } -int adf_rd = 0; - -uint64_t analog_end_time; - -void MCU_DeviceWrite(uint32_t address, uint8_t data) +void MCU::MCU_DeviceWrite(uint32_t address, uint8_t data) { address &= 0x7f; if (address >= 0x10 && address < 0x40) { - TIMER_Write(address, data); + mcu_timer.TIMER_Write(address, data); return; } if (address >= 0x50 && address < 0x55) { - TIMER2_Write(address, data); + mcu_timer.TIMER2_Write(address, data); return; } switch (address) @@ -233,10 +371,10 @@ void MCU_DeviceWrite(uint32_t address, uint8_t data) if ((data & 0x80) == 0 && adf_rd) { dev_register[address] &= ~0x80; - MCU_Interrupt_SetRequest(INTERRUPT_SOURCE_ANALOG, 0); + MCU_Interrupt_SetRequest(this, INTERRUPT_SOURCE_ANALOG, 0); } if ((data & 0x40) == 0) - MCU_Interrupt_SetRequest(INTERRUPT_SOURCE_ANALOG, 0); + MCU_Interrupt_SetRequest(this, INTERRUPT_SOURCE_ANALOG, 0); return; } default: @@ -246,16 +384,16 @@ void MCU_DeviceWrite(uint32_t address, uint8_t data) dev_register[address] = data; } -uint8_t MCU_DeviceRead(uint32_t address) +uint8_t MCU::MCU_DeviceRead(uint32_t address) { address &= 0x7f; if (address >= 0x10 && address < 0x40) { - return TIMER_Read(address); + return mcu_timer.TIMER_Read(address); } if (address >= 0x50 && address < 0x55) { - return TIMER_Read(address); + return mcu_timer.TIMER_Read(address); } switch (address) { @@ -294,14 +432,14 @@ uint8_t MCU_DeviceRead(uint32_t address) return dev_register[address]; } -void MCU_DeviceReset(void) +void MCU::MCU_DeviceReset(void) { // dev_register[0x00] = 0x03; // dev_register[0x7c] = 0x87; dev_register[DEV_RAME] = 0x80; } -void MCU_UpdateAnalog(uint64_t cycles) +void MCU::MCU_UpdateAnalog(uint64_t cycles) { int ctrl = dev_register[DEV_ADCSR]; int isscan = (ctrl & 16) != 0; @@ -327,23 +465,14 @@ void MCU_UpdateAnalog(uint64_t cycles) } dev_register[DEV_ADCSR] |= 0x80; if (ctrl & 0x40) - MCU_Interrupt_SetRequest(INTERRUPT_SOURCE_ANALOG, 1); + MCU_Interrupt_SetRequest(this, INTERRUPT_SOURCE_ANALOG, 1); } } else analog_end_time = 0; } -mcu_t mcu; - -uint8_t rom1[ROM1_SIZE]; -uint8_t rom2[ROM2_SIZE]; -uint8_t ram[RAM_SIZE]; -uint8_t sram[SRAM_SIZE]; - -int rom2_mask = ROM2_SIZE - 1; - -uint8_t MCU_Read(uint32_t address) +uint8_t MCU::MCU_Read(uint32_t address) { uint32_t address_rom = address & 0x3ffff; if (address & 0x80000) @@ -362,11 +491,11 @@ uint8_t MCU_Read(uint32_t address) { if (address >= 0xe000 && address < 0xe400) { - ret = PCM_Read(address & 0x3f); + ret = pcm.PCM_Read(address & 0x3f); } else if (address >= 0xec00 && address < 0xf000) { - ret = SM_SysRead(address & 0xff); + ret = sub_mcu.SM_SysRead(address & 0xff); } else if (address >= 0xff80) { @@ -383,7 +512,7 @@ uint8_t MCU_Read(uint32_t address) { ret = ga_int_trigger; ga_int_trigger = 0; - MCU_Interrupt_SetRequest(INTERRUPT_SOURCE_IRQ1, 0); + MCU_Interrupt_SetRequest(this, INTERRUPT_SOURCE_IRQ1, 0); } else { @@ -398,7 +527,7 @@ uint8_t MCU_Read(uint32_t address) { if (address >= 0xe000 && address < 0xe040) { - ret = PCM_Read(address & 0x3f); + ret = pcm.PCM_Read(address & 0x3f); } else if (address >= 0xff80) { @@ -462,7 +591,7 @@ uint8_t MCU_Read(uint32_t address) return ret; } -uint16_t MCU_Read16(uint32_t address) +uint16_t MCU::MCU_Read16(uint32_t address) { address &= ~1; uint8_t b0, b1; @@ -471,7 +600,7 @@ uint16_t MCU_Read16(uint32_t address) return (b0 << 8) + b1; } -uint32_t MCU_Read32(uint32_t address) +uint32_t MCU::MCU_Read32(uint32_t address) { address &= ~3; uint8_t b0, b1, b2, b3; @@ -482,7 +611,7 @@ uint32_t MCU_Read32(uint32_t address) return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; } -void MCU_Write(uint32_t address, uint8_t value) +void MCU::MCU_Write(uint32_t address, uint8_t value) { uint8_t page = (address >> 16) & 0xf; address &= 0xffff; @@ -495,11 +624,11 @@ void MCU_Write(uint32_t address, uint8_t value) if (address >= 0xe400 && address < 0xe800) { if (address == 0xe404 || address == 0xe405) - LCD_Write(address & 1, value); + lcd.LCD_Write(address & 1, value); else if (address == 0xe401) { io_sd = value; - LCD_Enable((value & 1) == 0); + lcd.LCD_Enable((value & 1) == 0); } else if (address == 0xe402) ga_int_enable = (value << 1); @@ -518,11 +647,11 @@ void MCU_Write(uint32_t address, uint8_t value) } else if (address >= 0xe000 && address < 0xe400) { - PCM_Write(address & 0x3f, value); + pcm.PCM_Write(address & 0x3f, value); } else if (!mcu_mk1 && address >= 0xec00 && address < 0xf000) { - SM_SysWrite(address & 0xff, value); + sub_mcu.SM_SysWrite(address & 0xff, value); } else if (address >= 0xff80) { @@ -544,7 +673,7 @@ void MCU_Write(uint32_t address, uint8_t value) { if (address >= 0xe000 && address < 0xe040) { - PCM_Write(address & 0x3f, value); + pcm.PCM_Write(address & 0x3f, value); } else if (address >= 0xff80) { @@ -582,14 +711,14 @@ void MCU_Write(uint32_t address, uint8_t value) } } -void MCU_Write16(uint32_t address, uint16_t value) +void MCU::MCU_Write16(uint32_t address, uint16_t value) { address &= ~1; MCU_Write(address, value >> 8); MCU_Write(address + 1, value & 0xff); } -void MCU_ReadInstruction(void) +void MCU::MCU_ReadInstruction(void) { uint8_t operand = MCU_ReadCodeAdvance(); @@ -598,20 +727,20 @@ void MCU_ReadInstruction(void) mcu.cycles += 0; } - MCU_Operand_Table[operand](operand); + MCU_Operand_Table[operand](this, operand); if (mcu.sr & STATUS_T) { - MCU_Interrupt_Exception(EXCEPTION_SOURCE_TRACE); + MCU_Interrupt_Exception(this, EXCEPTION_SOURCE_TRACE); } } -void MCU_Init(void) +void MCU::MCU_Init(void) { memset(&mcu, 0, sizeof(mcu_t)); } -void MCU_Reset(void) +void MCU::MCU_Reset(void) { mcu.r[0] = 0; mcu.r[1] = 0; @@ -632,7 +761,8 @@ void MCU_Reset(void) mcu.tp = 0; mcu.br = 0; - uint32_t reset_address = MCU_GetVectorAddress(VECTOR_RESET); + // uint32_t reset_address = MCU_GetVectorAddress(VECTOR_RESET); + uint32_t reset_address = 0x016C; mcu.cp = (reset_address >> 16) & 0xff; mcu.pc = reset_address & 0xffff; @@ -641,104 +771,19 @@ void MCU_Reset(void) MCU_DeviceReset(); } -static bool work_thread_run = false; - -static SDL_mutex *work_thread_lock; - -void MCU_WorkThread_Lock(void) -{ - SDL_LockMutex(work_thread_lock); -} - -void MCU_WorkThread_Unlock(void) -{ - SDL_UnlockMutex(work_thread_lock); -} - -int SDLCALL work_thread(void* data) -{ - work_thread_lock = SDL_CreateMutex(); - - MCU_WorkThread_Lock(); - while (work_thread_run) - { - if (sample_read_ptr == sample_write_ptr) - { - MCU_WorkThread_Unlock(); - while (sample_read_ptr == sample_write_ptr) - { - SDL_Delay(1); - } - MCU_WorkThread_Lock(); - } - - if (!mcu.ex_ignore) - MCU_Interrupt_Handle(); - else - mcu.ex_ignore = 0; - - if (!mcu.sleep) - MCU_ReadInstruction(); - - mcu.cycles += 12; // FIXME: assume 12 cycles per instruction - - // if (mcu.cycles % 24000000 == 0) - // printf("seconds: %i\n", (int)(mcu.cycles / 24000000)); - - PCM_Update(mcu.cycles); - - TIMER_Clock(mcu.cycles); - - if (!mcu_mk1) - SM_Update(mcu.cycles); - - MCU_UpdateAnalog(mcu.cycles); - } - MCU_WorkThread_Unlock(); - - SDL_DestroyMutex(work_thread_lock); - - return 0; -} - -static void MCU_Run() -{ - bool working = true; - - work_thread_run = true; - SDL_Thread *thread = SDL_CreateThread(work_thread, "work thread", 0); - - while (working) - { - if(LCD_QuitRequested()) - working = false; - - LCD_Update(); - SDL_Delay(15); - } - - work_thread_run = false; - SDL_WaitThread(thread, 0); -} - -void MCU_PatchROM(void) +void MCU::MCU_PatchROM(void) { //rom2[0x1333] = 0x11; //rom2[0x1334] = 0x19; //rom1[0x622d] = 0x19; } -SDL_atomic_t mcu_button_pressed = {0}; - -uint8_t mcu_p0_data = 0x00; -uint8_t mcu_p1_data = 0x00; - -uint8_t MCU_ReadP0(void) +uint8_t MCU::MCU_ReadP0(void) { return 0xff; } -uint8_t MCU_ReadP1(void) +uint8_t MCU::MCU_ReadP1(void) { uint8_t data = 0xff; uint32_t button_pressed = (uint32_t)SDL_AtomicGet(&mcu_button_pressed); @@ -753,18 +798,16 @@ uint8_t MCU_ReadP1(void) return data; } -void MCU_WriteP0(uint8_t data) +void MCU::MCU_WriteP0(uint8_t data) { mcu_p0_data = data; } -void MCU_WriteP1(uint8_t data) +void MCU::MCU_WriteP1(uint8_t data) { mcu_p1_data = data; } -uint8_t tempbuf[0x200000]; - void unscramble(uint8_t *src, uint8_t *dst, int len) { for (int i = 0; i < len; i++) @@ -792,87 +835,7 @@ void unscramble(uint8_t *src, uint8_t *dst, int len) } } -void audio_callback(void* /*userdata*/, Uint8* stream, int len) -{ - len /= 2; - memcpy(stream, &sample_buffer[sample_read_ptr], len * 2); - memset(&sample_buffer[sample_read_ptr], 0, len * 2); - sample_read_ptr += len; - sample_read_ptr %= audio_buffer_size; -} - -static const char* audio_format_to_str(int format) -{ - switch(format) - { - case AUDIO_S8: - return "S8"; - case AUDIO_U8: - return "U8"; - case AUDIO_S16MSB: - return "S16MSB"; - case AUDIO_S16LSB: - return "S16LSB"; - case AUDIO_U16MSB: - return "U16MSB"; - case AUDIO_U16LSB: - return "U16LSB"; - case AUDIO_S32MSB: - return "S32MSB"; - case AUDIO_S32LSB: - return "S32LSB"; - case AUDIO_F32MSB: - return "F32MSB"; - case AUDIO_F32LSB: - return "F32LSB"; - } - return "UNK"; -} - -int MCU_OpenAudio(void) -{ - SDL_AudioSpec spec = {}; - SDL_AudioSpec spec_actual = {}; - - spec.format = AUDIO_S16SYS; - spec.freq = mcu_mk1 ? 64000: 66207; - spec.channels = 2; - spec.callback = audio_callback; - spec.samples = audio_page_size / 4; - - sdl_audio = SDL_OpenAudioDevice(NULL, 0, &spec, &spec_actual, 0); - if (!sdl_audio) - { - return 0; - } - - printf("Audio Requested: F=%s, C=%d, R=%d, B=%d\n", - audio_format_to_str(spec.format), - spec.channels, - spec.freq, - spec.samples); - - printf("Audio Actual: F=%s, C=%d, R=%d, B=%d\n", - audio_format_to_str(spec_actual.format), - spec_actual.channels, - spec_actual.freq, - spec_actual.samples); - fflush(stdout); - - sample_read_ptr = 0; - sample_write_ptr = 0; - - SDL_PauseAudioDevice(sdl_audio, 0); - - return 1; -} - -void MCU_CloseAudio(void) -{ - SDL_CloseAudio(); -} - -void MCU_PostSample(int *sample) +void MCU::MCU_PostSample(int *sample) { sample[0] >>= 15; if (sample[0] > INT16_MAX) @@ -889,28 +852,17 @@ void MCU_PostSample(int *sample) sample_write_ptr = (sample_write_ptr + 2) % audio_buffer_size; } -void MCU_GA_SetGAInt(int line, int value) +void MCU::MCU_GA_SetGAInt(int line, int value) { // guesswork if (value && !ga_int[line] && (ga_int_enable & (1 << line)) != 0) ga_int_trigger = line; ga_int[line] = value; - MCU_Interrupt_SetRequest(INTERRUPT_SOURCE_IRQ1, ga_int_trigger != 0); + MCU_Interrupt_SetRequest(this, INTERRUPT_SOURCE_IRQ1, ga_int_trigger != 0); } - -static const size_t rf_num = 5; -static FILE *s_rf[rf_num] = -{ - nullptr, - nullptr, - nullptr, - nullptr, - nullptr -}; - -static void closeAllR() +void MCU::closeAllR() { for(size_t i = 0; i < rf_num; ++i) { @@ -920,49 +872,40 @@ static void closeAllR() } } -int main(int argc, char *argv[]) -{ - (void)argc; - std::string basePath; +MCU::MCU() : pcm(this), lcd(), sub_mcu(this), mcu_timer(this) {} -#if __linux__ - char self_path[PATH_MAX]; - memset(&self_path[0], 0, PATH_MAX); +int MCU::startSC55(std::string *basePath) +{ + if (init_lock == nullptr) + init_lock = SDL_CreateMutex(); - if(readlink("/proc/self/exe", self_path, PATH_MAX) == -1) - basePath = Files::real_dirname(argv[0]); - else - basePath = Files::dirname(self_path); -#else - basePath = Files::real_dirname(argv[0]); -#endif + SDL_LockMutex(init_lock); - printf("Base path is: %s\n", argv[0]); + uint8_t* tempbuf = (uint8_t*) malloc(0x200000); - if(Files::dirExists(basePath + "/../share/nuked-sc55")) - basePath += "/../share/nuked-sc55"; + printf("Base path is: %s\n", basePath->c_str()); std::string rpaths[5] = { - basePath + "/rom1.bin", - basePath + "/rom2.bin", - basePath + "/waverom1.bin", - basePath + "/waverom2.bin", - basePath + "/rom_sm.bin" + *basePath + "/rom1.bin", + *basePath + "/rom2.bin", + *basePath + "/waverom1.bin", + *basePath + "/waverom2.bin", + *basePath + "/rom_sm.bin" }; if (mcu_mk1) { - //rpaths[0] = basePath + "/sc55_rom1.bin"; - //rpaths[1] = basePath + "/sc55_rom2.bin"; - //rpaths[2] = basePath + "/sc55_waverom1.bin"; - //rpaths[3] = basePath + "/sc55_waverom2.bin"; - //rpaths[4] = basePath + "/sc55_waverom3.bin"; - rpaths[0] = basePath + "/cm300_rom1.bin"; - rpaths[1] = basePath + "/cm300_rom2.bin"; - rpaths[2] = basePath + "/cm300_waverom1.bin"; - rpaths[3] = basePath + "/cm300_waverom2.bin"; - rpaths[4] = basePath + "/cm300_waverom3.bin"; + //rpaths[0] = *basePath + "/sc55_rom1.bin"; + //rpaths[1] = *basePath + "/sc55_rom2.bin"; + //rpaths[2] = *basePath + "/sc55_waverom1.bin"; + //rpaths[3] = *basePath + "/sc55_waverom2.bin"; + //rpaths[4] = *basePath + "/sc55_waverom3.bin"; + rpaths[0] = *basePath + "/cm300_rom1.bin"; + rpaths[1] = *basePath + "/cm300_rom2.bin"; + rpaths[2] = *basePath + "/cm300_waverom1.bin"; + rpaths[3] = *basePath + "/cm300_waverom2.bin"; + rpaths[4] = *basePath + "/cm300_waverom3.bin"; } bool r_ok = true; @@ -989,7 +932,7 @@ int main(int argc, char *argv[]) return 1; } - LCD_SetBackPath(basePath + "/back.data"); + lcd.LCD_SetBackPath(*basePath + "/back.data"); memset(&mcu, 0, sizeof(mcu_t)); @@ -1026,7 +969,7 @@ int main(int argc, char *argv[]) return 1; } - unscramble(tempbuf, waverom1, 0x100000); + unscramble(tempbuf, pcm.waverom1, 0x100000); if (fread(tempbuf, 1, 0x100000, s_rf[3]) != 0x100000) { @@ -1036,7 +979,7 @@ int main(int argc, char *argv[]) return 1; } - unscramble(tempbuf, waverom2, 0x100000); + unscramble(tempbuf, pcm.waverom2, 0x100000); if (fread(tempbuf, 1, 0x100000, s_rf[4]) != 0x100000) { @@ -1046,7 +989,7 @@ int main(int argc, char *argv[]) return 1; } - unscramble(tempbuf, waverom2, 0x100000); + unscramble(tempbuf, pcm.waverom2, 0x100000); } else { @@ -1058,7 +1001,7 @@ int main(int argc, char *argv[]) return 1; } - unscramble(tempbuf, waverom1, 0x200000); + unscramble(tempbuf, pcm.waverom1, 0x200000); if (fread(tempbuf, 1, 0x100000, s_rf[3]) != 0x100000) { @@ -1068,9 +1011,9 @@ int main(int argc, char *argv[]) return 1; } - unscramble(tempbuf, waverom2, 0x100000); + unscramble(tempbuf, pcm.waverom2, 0x100000); - if (fread(sm_rom, 1, ROMSM_SIZE, s_rf[4]) != ROMSM_SIZE) + if (fread(sub_mcu.sm_rom, 1, ROMSM_SIZE, s_rf[4]) != ROMSM_SIZE) { fprintf(stderr, "FATAL ERROR: Failed to read the sub mcu ROM.\n"); fflush(stderr); @@ -1082,51 +1025,123 @@ int main(int argc, char *argv[]) // Close all files as they no longer needed being open closeAllR(); - if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) - { - fprintf(stderr, "FATAL ERROR: Failed to initialize the SDL2: %s.\n", SDL_GetError()); - fflush(stderr); - return 2; + lcd.LCD_Init(this); + MCU_Init(); + MCU_PatchROM(); + MCU_Reset(); + sub_mcu.SM_Reset(); + pcm.PCM_Reset(); + + for (int i = 0; i < 1024 * 4; i++) { + if (!mcu.ex_ignore) + MCU_Interrupt_Handle(this); + else + mcu.ex_ignore = 0; + + if (!mcu.sleep) + MCU_ReadInstruction(); + + mcu.cycles += 12; // FIXME: assume 12 cycles per instruction + + // if (mcu.cycles % 24000000 == 0) + // printf("seconds: %i\n", (int)(mcu.cycles / 24000000)); + + pcm.PCM_Update(mcu.cycles); + + mcu_timer.TIMER_Clock(mcu.cycles); + + if (!mcu_mk1) + sub_mcu.SM_Update(mcu.cycles); + + MCU_UpdateAnalog(mcu.cycles); } - if (!MCU_OpenAudio()) - { - fprintf(stderr, "FATAL ERROR: Failed to open the audio stream.\n"); - fflush(stderr); - return 2; + sample_write_ptr = 0; + + free(tempbuf); + SDL_UnlockMutex(init_lock); + + return 0; +} + +int MCU::updateSC55(int16_t *data, unsigned int dataSize) { + if (init_lock == nullptr) + init_lock = SDL_CreateMutex(); + + SDL_LockMutex(init_lock); + + // auto start = std::chrono::high_resolution_clock::now(); + + dataSize /= 2; + + if (audio_buffer_size < dataSize) { + printf("Audio buffer size is too small. (%d requested)\n", dataSize); + fflush(stdout); + return 0; } - int port = 0; - { - for (int i = 1; i < argc; i++) - { - if (!strncmp(argv[i], "-p:", 3)) - { - port = atoi(argv[i] + 3); - break; - } + sample_write_ptr = 0; + // memset(sample_buffer, 0, audio_buffer_size * 2); + + int maxCycles = dataSize * 256; + + for (int i = 0; sample_write_ptr < dataSize; i++) { + if (i > maxCycles) { + printf("Not enough samples!\n"); + fflush(stdout); + break; } - } - if(!MIDI_Init(port)) - { - fprintf(stderr, "ERROR: Failed to initialize the MIDI Input.\nWARNING: Continuing without MIDI Input...\n"); - fflush(stderr); + if (!mcu.ex_ignore) + MCU_Interrupt_Handle(this); + else + mcu.ex_ignore = 0; + + if (!mcu.sleep) + MCU_ReadInstruction(); + + mcu.cycles += 12; // FIXME: assume 12 cycles per instruction + + // if (mcu.cycles % 24000000 == 0) + // printf("seconds: %i\n", (int)(mcu.cycles / 24000000)); + + pcm.PCM_Update(mcu.cycles); + + mcu_timer.TIMER_Clock(mcu.cycles); + + if (!mcu_mk1) + sub_mcu.SM_Update(mcu.cycles); + + MCU_UpdateAnalog(mcu.cycles); } - LCD_Init(); + memcpy(data, sample_buffer, dataSize * 2); + + // auto stop = std::chrono::high_resolution_clock::now(); + // auto duration = std::chrono::duration_cast(stop - start).count(); + // if (duration > 8) { + // printf("updateSC55 took %lld ms\n", duration); + // fflush(stdout); + // } + + SDL_UnlockMutex(init_lock); + + return 0; +} + +void MCU::SC55_Reset() { + lcd.LCD_Init(this); MCU_Init(); MCU_PatchROM(); MCU_Reset(); - SM_Reset(); - PCM_Reset(); - - MCU_Run(); + sub_mcu.SM_Reset(); + pcm.PCM_Reset(); - MCU_CloseAudio(); - MIDI_Quit(); - LCD_UnInit(); - SDL_Quit(); + sample_write_ptr = 0; +} - return 0; +void MCU::postMidiSC55(uint8_t* message, int length) { + for (int i = 0; i < length; i++) { + sub_mcu.SM_PostUART(message[i]); + } } diff --git a/src/mcu.h b/src/mcu.h index 93c53db9..a5cce2c3 100644 --- a/src/mcu.h +++ b/src/mcu.h @@ -34,8 +34,19 @@ #pragma once #include +#include #include "mcu_interrupt.h" -#include "SDL_atomic.h" +#include +#include "SDL.h" +#include "pcm.h" +#include "lcd.h" +#include "mcu_timer.h" +#include "submcu.h" + +#ifdef __APPLE__ +#include // PATH_MAX +#include +#endif enum { DEV_P1DDR = 0x00, @@ -100,8 +111,6 @@ enum { DEV_P9DR = 0x7f, }; -extern uint8_t dev_register[0x80]; - const uint16_t sr_mask = 0x870f; enum { STATUS_T = 0x8000, @@ -186,190 +195,6 @@ struct mcu_t { uint64_t cycles; }; -extern mcu_t mcu; - -void MCU_ErrorTrap(void); - -uint8_t MCU_Read(uint32_t address); -uint16_t MCU_Read16(uint32_t address); -uint32_t MCU_Read32(uint32_t address); -void MCU_Write(uint32_t address, uint8_t value); -void MCU_Write16(uint32_t address, uint16_t value); - -inline uint32_t MCU_GetAddress(uint8_t page, uint16_t address) { - return (page << 16) + address; -} - -inline uint8_t MCU_ReadCode(void) { - return MCU_Read(MCU_GetAddress(mcu.cp, mcu.pc)); -} - -inline uint8_t MCU_ReadCodeAdvance(void) { - uint8_t ret = MCU_ReadCode(); - mcu.pc++; - return ret; -} - -inline void MCU_SetRegisterByte(uint8_t reg, uint8_t val) -{ - mcu.r[reg] = val; -} - -inline uint32_t MCU_GetVectorAddress(uint32_t vector) -{ - return MCU_Read32(vector * 4); -} - -inline uint32_t MCU_GetPageForRegister(uint32_t reg) -{ - if (reg >= 6) - return mcu.tp; - else if (reg >= 4) - return mcu.ep; - return mcu.dp; -} - -inline void MCU_ControlRegisterWrite(uint32_t reg, uint32_t siz, uint32_t data) -{ - if (siz) - { - if (reg == 0) - { - mcu.sr = data; - mcu.sr &= sr_mask; - } - else if (reg == 5) // FIXME: undocumented - { - mcu.dp = data & 0xff; - } - else if (reg == 4) // FIXME: undocumented - { - mcu.ep = data & 0xff; - } - else if (reg == 3) // FIXME: undocumented - { - mcu.br = data & 0xff; - } - else - { - MCU_ErrorTrap(); - } - } - else - { - if (reg == 1) - { - mcu.sr &= ~0xff; - mcu.sr |= data & 0xff; - mcu.sr &= sr_mask; - } - else if (reg == 3) - { - mcu.br = data; - } - else if (reg == 4) - { - mcu.ep = data; - } - else if (reg == 5) - { - mcu.dp = data; - } - else if (reg == 7) - { - mcu.tp = data; - } - else - { - MCU_ErrorTrap(); - } - } -} - -inline uint32_t MCU_ControlRegisterRead(uint32_t reg, uint32_t siz) -{ - uint32_t ret = 0; - if (siz) - { - if (reg == 0) - { - ret = mcu.sr & sr_mask; - } - else if (reg == 5) // FIXME: undocumented - { - ret = mcu.dp | (mcu.dp << 8); - } - else if (reg == 4) // FIXME: undocumented - { - ret = mcu.ep | (mcu.ep << 8); - } - else if (reg == 3) // FIXME: undocumented - { - ret = mcu.br | (mcu.br << 8);; - } - else - { - MCU_ErrorTrap(); - } - ret &= 0xffff; - } - else - { - if (reg == 1) - { - ret = mcu.sr & sr_mask; - } - else if (reg == 3) - { - ret = mcu.br; - } - else if (reg == 4) - { - ret = mcu.ep; - } - else if (reg == 5) - { - ret = mcu.dp; - } - else if (reg == 7) - { - ret = mcu.tp; - } - else - { - MCU_ErrorTrap(); - } - ret &= 0xff; - } - return ret; -} - -inline void MCU_SetStatus(uint32_t condition, uint32_t mask) -{ - if (condition) - mcu.sr |= mask; - else - mcu.sr &= ~mask; -} - -inline void MCU_PushStack(uint16_t data) -{ - if (mcu.r[7] & 1) - MCU_Interrupt_Exception(EXCEPTION_SOURCE_ADDRESS_ERROR); - mcu.r[7] -= 2; - MCU_Write16(mcu.r[7], data); -} - -inline uint16_t MCU_PopStack(void) -{ - uint16_t ret; - if (mcu.r[7] & 1) - MCU_Interrupt_Exception(EXCEPTION_SOURCE_ADDRESS_ERROR); - ret = MCU_Read16(mcu.r[7]); - mcu.r[7] += 2; - return ret; -} - enum { MCU_BUTTON_POWER = 0, MCU_BUTTON_INST_L = 3, @@ -392,17 +217,121 @@ enum { MCU_BUTTON_PART_L = 20 }; -extern int mcu_mk1; +static const int ROM1_SIZE = 0x8000; +static const int ROM2_SIZE = 0x80000; +static const int RAM_SIZE = 0x400; +static const int SRAM_SIZE = 0x8000; +static const int ROMSM_SIZE = 0x1000; + +static const int audio_buffer_size = 4096 * 8; +static const int audio_page_size = 512; + +const size_t rf_num = 5; + +struct MCU { + int mcu_mk1 = 0; // 0 - SC-55mkII, SC-55ST. 1 - SC-55, CM-300/SCC-1 + + SDL_atomic_t mcu_button_pressed = {0}; + + uint8_t mcu_p0_data = 0x00; + uint8_t mcu_p1_data = 0x00; + + mcu_t mcu; + + uint8_t rom1[ROM1_SIZE]; + uint8_t rom2[ROM2_SIZE]; + uint8_t ram[RAM_SIZE]; + uint8_t sram[SRAM_SIZE]; + + int rom2_mask = ROM2_SIZE - 1; -extern SDL_atomic_t mcu_button_pressed; + short sample_buffer[audio_buffer_size] = {0}; + int sample_write_ptr = 0; -uint8_t MCU_ReadP0(void); -uint8_t MCU_ReadP1(void); -void MCU_WriteP0(uint8_t data); -void MCU_WriteP1(uint8_t data); -void MCU_GA_SetGAInt(int line, int value); + int ga_int[8] = {0}; + int ga_int_enable = 0; + int ga_int_trigger = 0; -void MCU_PostSample(int *sample); + uint8_t dev_register[0x80] = {0}; -void MCU_WorkThread_Lock(void); -void MCU_WorkThread_Unlock(void); + uint16_t ad_val[4] = {0}; + uint8_t ad_nibble = 0x00; + uint8_t sw_pos = 0; + uint8_t io_sd = 0x00; + + int adf_rd = 0; + uint64_t analog_end_time = 0; + + uint32_t operand_type; + uint16_t operand_ea; + uint8_t operand_ep; + uint8_t operand_size; + uint8_t operand_reg; + uint8_t operand_status; + uint16_t operand_data; + uint8_t opcode_extended; + + SDL_mutex *init_lock; + + FILE *s_rf[rf_num] = + { + nullptr, + nullptr, + nullptr, + nullptr, + nullptr + }; + + Pcm pcm; + LCD lcd; + MCU_Timer mcu_timer; + SubMcu sub_mcu; + + MCU(); + + void MCU_ErrorTrap(void); + + uint8_t MCU_Read(uint32_t address); + uint16_t MCU_Read16(uint32_t address); + uint32_t MCU_Read32(uint32_t address); + void MCU_Write(uint32_t address, uint8_t value); + void MCU_Write16(uint32_t address, uint16_t value); + + uint8_t MCU_ReadP0(void); + uint8_t MCU_ReadP1(void); + void MCU_WriteP0(uint8_t data); + void MCU_WriteP1(uint8_t data); + void MCU_GA_SetGAInt(int line, int value); + + void MCU_PostSample(int *sample); + + int startSC55(std::string *basepath); + int updateSC55(int16_t *data, unsigned int dataSize); + void postMidiSC55(uint8_t* message, int length); + void SC55_Reset(); + + uint8_t RCU_Read(void); + uint16_t MCU_AnalogReadPin(uint32_t pin); + void MCU_AnalogSample(int channel); + void MCU_DeviceWrite(uint32_t address, uint8_t data); + uint8_t MCU_DeviceRead(uint32_t address); + void MCU_DeviceReset(void); + void MCU_UpdateAnalog(uint64_t cycles); + void MCU_ReadInstruction(void); + void MCU_Init(void); + void MCU_Reset(void); + void MCU_PatchROM(void); + void closeAllR(); + + uint32_t MCU_GetAddress(uint8_t page, uint16_t address); + uint8_t MCU_ReadCode(void); + uint8_t MCU_ReadCodeAdvance(void); + void MCU_SetRegisterByte(uint8_t reg, uint8_t val); + uint32_t MCU_GetVectorAddress(uint32_t vector); + uint32_t MCU_GetPageForRegister(uint32_t reg); + void MCU_ControlRegisterWrite(uint32_t reg, uint32_t siz, uint32_t data); + uint32_t MCU_ControlRegisterRead(uint32_t reg, uint32_t siz); + void MCU_SetStatus(uint32_t condition, uint32_t mask); + void MCU_PushStack(uint16_t data); + uint16_t MCU_PopStack(void); +}; diff --git a/src/mcu_interrupt.cpp b/src/mcu_interrupt.cpp index d4b17556..aed0ac18 100644 --- a/src/mcu_interrupt.cpp +++ b/src/mcu_interrupt.cpp @@ -35,174 +35,174 @@ #include "mcu.h" #include "mcu_interrupt.h" -void MCU_Interrupt_Start(int32_t mask) +void MCU_Interrupt_Start(MCU* mcu, int32_t mask) { - MCU_PushStack(mcu.pc); - MCU_PushStack(mcu.cp); - MCU_PushStack(mcu.sr); - mcu.sr &= ~STATUS_T; + mcu->MCU_PushStack(mcu->mcu.pc); + mcu->MCU_PushStack(mcu->mcu.cp); + mcu->MCU_PushStack(mcu->mcu.sr); + mcu->mcu.sr &= ~STATUS_T; if (mask >= 0) { - mcu.sr &= ~STATUS_INT_MASK; - mcu.sr |= mask << 8; + mcu->mcu.sr &= ~STATUS_INT_MASK; + mcu->mcu.sr |= mask << 8; } - mcu.sleep = 0; + mcu->mcu.sleep = 0; } -void MCU_Interrupt_SetRequest(uint32_t interrupt, uint32_t value) +void MCU_Interrupt_SetRequest(MCU* mcu, uint32_t interrupt, uint32_t value) { - mcu.interrupt_pending[interrupt] = value; + mcu->mcu.interrupt_pending[interrupt] = value; } -void MCU_Interrupt_Exception(uint32_t exception) +void MCU_Interrupt_Exception(MCU* mcu, uint32_t exception) { #if 0 - if (interrupt == INTERRUPT_SOURCE_IRQ0 && (dev_register[DEV_P1CR] & 0x20) == 0) + if (interrupt == INTERRUPT_SOURCE_IRQ0 && (mcu->dev_register[DEV_P1CR] & 0x20) == 0) return; - if (interrupt == INTERRUPT_SOURCE_IRQ1 && (dev_register[DEV_P1CR] & 0x40) == 0) + if (interrupt == INTERRUPT_SOURCE_IRQ1 && (mcu->dev_register[DEV_P1CR] & 0x40) == 0) return; #endif - mcu.exception_pending = exception; + mcu->mcu.exception_pending = exception; } -void MCU_Interrupt_TRAPA(uint32_t vector) +void MCU_Interrupt_TRAPA(MCU* mcu, uint32_t vector) { - mcu.trapa_pending[vector] = 1; + mcu->mcu.trapa_pending[vector] = 1; } -void MCU_Interrupt_StartVector(uint32_t vector, int32_t mask) +void MCU_Interrupt_StartVector(MCU* mcu, uint32_t vector, int32_t mask) { - uint32_t address = MCU_GetVectorAddress(vector); - MCU_Interrupt_Start(mask); - mcu.cp = address >> 16; - mcu.pc = address; + uint32_t address = mcu->MCU_GetVectorAddress(vector); + MCU_Interrupt_Start(mcu, mask); + mcu->mcu.cp = address >> 16; + mcu->mcu.pc = address; } -void MCU_Interrupt_Handle(void) +void MCU_Interrupt_Handle(MCU* mcu) { #if 0 - if (mcu.cycles % 2000 == 0 && mcu.sleep) + if (mcu->mcu.cycles % 2000 == 0 && mcu->mcu.sleep) { - MCU_Interrupt_StartVector(VECTOR_INTERNAL_INTERRUPT_94); + MCU_Interrupt_StartVector(mcu, VECTOR_INTERNAL_INTERRUPT_94); return; } - if (mcu.cycles % 2000 == 1000 && mcu.sleep) + if (mcu->mcu.cycles % 2000 == 1000 && mcu->mcu.sleep) { - MCU_Interrupt_StartVector(VECTOR_INTERNAL_INTERRUPT_A4); + MCU_Interrupt_StartVector(mcu, VECTOR_INTERNAL_INTERRUPT_A4); return; } - if (mcu.cycles % 2000 == 1500 && mcu.sleep) + if (mcu->mcu.cycles % 2000 == 1500 && mcu->mcu.sleep) { - MCU_Interrupt_StartVector(VECTOR_INTERNAL_INTERRUPT_B4); + MCU_Interrupt_StartVector(mcu, VECTOR_INTERNAL_INTERRUPT_B4); return; } #endif uint32_t i; for (i = 0; i < 16; i++) { - if (mcu.trapa_pending[i]) + if (mcu->mcu.trapa_pending[i]) { - mcu.trapa_pending[i] = 0; - MCU_Interrupt_StartVector(VECTOR_TRAPA_0 + i, -1); + mcu->mcu.trapa_pending[i] = 0; + MCU_Interrupt_StartVector(mcu, VECTOR_TRAPA_0 + i, -1); return; } } - if (mcu.exception_pending >= 0) + if (mcu->mcu.exception_pending >= 0) { - switch (mcu.exception_pending) + switch (mcu->mcu.exception_pending) { case EXCEPTION_SOURCE_ADDRESS_ERROR: - MCU_Interrupt_StartVector(VECTOR_ADDRESS_ERROR, -1); + MCU_Interrupt_StartVector(mcu, VECTOR_ADDRESS_ERROR, -1); break; case EXCEPTION_SOURCE_INVALID_INSTRUCTION: - MCU_Interrupt_StartVector(VECTOR_INVALID_INSTRUCTION, -1); + MCU_Interrupt_StartVector(mcu, VECTOR_INVALID_INSTRUCTION, -1); break; case EXCEPTION_SOURCE_TRACE: - MCU_Interrupt_StartVector(VECTOR_TRACE, -1); + MCU_Interrupt_StartVector(mcu, VECTOR_TRACE, -1); break; } - mcu.exception_pending = -1; + mcu->mcu.exception_pending = -1; return; } - if (mcu.interrupt_pending[INTERRUPT_SOURCE_NMI]) + if (mcu->mcu.interrupt_pending[INTERRUPT_SOURCE_NMI]) { - // mcu.interrupt_pending[INTERRUPT_SOURCE_NMI] = 0; - MCU_Interrupt_StartVector(VECTOR_NMI, 7); + // mcu->mcu.interrupt_pending[INTERRUPT_SOURCE_NMI] = 0; + MCU_Interrupt_StartVector(mcu, VECTOR_NMI, 7); return; } - uint32_t mask = (mcu.sr >> 8) & 7; + uint32_t mask = (mcu->mcu.sr >> 8) & 7; for (i = INTERRUPT_SOURCE_NMI + 1; i < INTERRUPT_SOURCE_MAX; i++) { int32_t vector = -1; int32_t level = 0; - if (!mcu.interrupt_pending[i]) + if (!mcu->mcu.interrupt_pending[i]) continue; switch (i) { case INTERRUPT_SOURCE_IRQ0: - if ((dev_register[DEV_P1CR] & 0x20) == 0) + if ((mcu->dev_register[DEV_P1CR] & 0x20) == 0) continue; vector = VECTOR_IRQ0; - level = (dev_register[DEV_IPRA] >> 4) & 7; + level = (mcu->dev_register[DEV_IPRA] >> 4) & 7; break; case INTERRUPT_SOURCE_IRQ1: - if ((dev_register[DEV_P1CR] & 0x40) == 0) + if ((mcu->dev_register[DEV_P1CR] & 0x40) == 0) continue; vector = VECTOR_IRQ1; - level = (dev_register[DEV_IPRA] >> 0) & 7; + level = (mcu->dev_register[DEV_IPRA] >> 0) & 7; break; case INTERRUPT_SOURCE_FRT0_OCIA: vector = VECTOR_INTERNAL_INTERRUPT_94; - level = (dev_register[DEV_IPRB] >> 4) & 7; + level = (mcu->dev_register[DEV_IPRB] >> 4) & 7; break; case INTERRUPT_SOURCE_FRT0_OCIB: vector = VECTOR_INTERNAL_INTERRUPT_98; - level = (dev_register[DEV_IPRB] >> 4) & 7; + level = (mcu->dev_register[DEV_IPRB] >> 4) & 7; break; case INTERRUPT_SOURCE_FRT0_FOVI: vector = VECTOR_INTERNAL_INTERRUPT_9C; - level = (dev_register[DEV_IPRB] >> 4) & 7; + level = (mcu->dev_register[DEV_IPRB] >> 4) & 7; break; case INTERRUPT_SOURCE_FRT1_OCIA: vector = VECTOR_INTERNAL_INTERRUPT_A4; - level = (dev_register[DEV_IPRB] >> 0) & 7; + level = (mcu->dev_register[DEV_IPRB] >> 0) & 7; break; case INTERRUPT_SOURCE_FRT1_OCIB: vector = VECTOR_INTERNAL_INTERRUPT_A8; - level = (dev_register[DEV_IPRB] >> 0) & 7; + level = (mcu->dev_register[DEV_IPRB] >> 0) & 7; break; case INTERRUPT_SOURCE_FRT1_FOVI: vector = VECTOR_INTERNAL_INTERRUPT_AC; - level = (dev_register[DEV_IPRB] >> 0) & 7; + level = (mcu->dev_register[DEV_IPRB] >> 0) & 7; break; case INTERRUPT_SOURCE_FRT2_OCIA: vector = VECTOR_INTERNAL_INTERRUPT_B4; - level = (dev_register[DEV_IPRC] >> 4) & 7; + level = (mcu->dev_register[DEV_IPRC] >> 4) & 7; break; case INTERRUPT_SOURCE_FRT2_OCIB: vector = VECTOR_INTERNAL_INTERRUPT_B8; - level = (dev_register[DEV_IPRC] >> 4) & 7; + level = (mcu->dev_register[DEV_IPRC] >> 4) & 7; break; case INTERRUPT_SOURCE_FRT2_FOVI: vector = VECTOR_INTERNAL_INTERRUPT_BC; - level = (dev_register[DEV_IPRC] >> 4) & 7; + level = (mcu->dev_register[DEV_IPRC] >> 4) & 7; break; case INTERRUPT_SOURCE_TIMER_CMIA: vector = VECTOR_INTERNAL_INTERRUPT_C0; - level = (dev_register[DEV_IPRC] >> 0) & 7; + level = (mcu->dev_register[DEV_IPRC] >> 0) & 7; break; case INTERRUPT_SOURCE_TIMER_CMIB: vector = VECTOR_INTERNAL_INTERRUPT_C4; - level = (dev_register[DEV_IPRC] >> 0) & 7; + level = (mcu->dev_register[DEV_IPRC] >> 0) & 7; break; case INTERRUPT_SOURCE_TIMER_OVI: vector = VECTOR_INTERNAL_INTERRUPT_C8; - level = (dev_register[DEV_IPRC] >> 0) & 7; + level = (mcu->dev_register[DEV_IPRC] >> 0) & 7; break; case INTERRUPT_SOURCE_ANALOG: vector = VECTOR_INTERNAL_INTERRUPT_E0; - level = (dev_register[DEV_IPRD] >> 0) & 7; + level = (mcu->dev_register[DEV_IPRD] >> 0) & 7; break; default: break; @@ -210,8 +210,8 @@ void MCU_Interrupt_Handle(void) if ((int32_t)mask < level) { - // mcu.interrupt_pending[INTERRUPT_SOURCE_NMI] = 0; - MCU_Interrupt_StartVector(vector, level); + // mcu->mcu.interrupt_pending[INTERRUPT_SOURCE_NMI] = 0; + MCU_Interrupt_StartVector(mcu, vector, level); return; } } diff --git a/src/mcu_interrupt.h b/src/mcu_interrupt.h index d63d21e2..20424feb 100644 --- a/src/mcu_interrupt.h +++ b/src/mcu_interrupt.h @@ -35,10 +35,12 @@ #include -void MCU_Interrupt_SetRequest(uint32_t interrupt, uint32_t value); -void MCU_Interrupt_Exception(uint32_t exception); -void MCU_Interrupt_TRAPA(uint32_t vector); -void MCU_Interrupt_Handle(void); +struct MCU; + +void MCU_Interrupt_SetRequest(MCU* mcu, uint32_t interrupt, uint32_t value); +void MCU_Interrupt_Exception(MCU* mcu, uint32_t exception); +void MCU_Interrupt_TRAPA(MCU* mcu, uint32_t vector); +void MCU_Interrupt_Handle(MCU* mcu); enum { INTERRUPT_SOURCE_NMI = 0, diff --git a/src/mcu_opcodes.cpp b/src/mcu_opcodes.cpp index 131755ec..0e0083f8 100644 --- a/src/mcu_opcodes.cpp +++ b/src/mcu_opcodes.cpp @@ -36,7 +36,7 @@ #include "mcu_opcodes.h" #include "mcu_interrupt.h" -int32_t MCU_SUB_Common(int32_t t1, int32_t t2, int32_t c_bit, uint32_t siz) +int32_t MCU_SUB_Common(MCU *mcu, int32_t t1, int32_t t2, int32_t c_bit, uint32_t siz) { int32_t st1, st2; int32_t N, Z, C, V = 0; @@ -78,15 +78,15 @@ int32_t MCU_SUB_Common(int32_t t1, int32_t t2, int32_t c_bit, uint32_t siz) if (st1 < INT8_MIN || st1 > INT8_MAX) V = 1; } - MCU_SetStatus(N, STATUS_N); - MCU_SetStatus(Z, STATUS_Z); - MCU_SetStatus(C, STATUS_C); - MCU_SetStatus(V, STATUS_V); + mcu->MCU_SetStatus(N, STATUS_N); + mcu->MCU_SetStatus(Z, STATUS_Z); + mcu->MCU_SetStatus(C, STATUS_C); + mcu->MCU_SetStatus(V, STATUS_V); return t1; } -int32_t MCU_ADD_Common(int32_t t1, int32_t t2, int32_t c_bit, uint32_t siz) +int32_t MCU_ADD_Common(MCU *mcu, int32_t t1, int32_t t2, int32_t c_bit, uint32_t siz) { int32_t st1, st2; int32_t N, Z, C, V = 0; @@ -128,26 +128,26 @@ int32_t MCU_ADD_Common(int32_t t1, int32_t t2, int32_t c_bit, uint32_t siz) if (st1 < INT8_MIN || st1 > INT8_MAX) V = 1; } - MCU_SetStatus(N, STATUS_N); - MCU_SetStatus(Z, STATUS_Z); - MCU_SetStatus(C, STATUS_C); - MCU_SetStatus(V, STATUS_V); + mcu->MCU_SetStatus(N, STATUS_N); + mcu->MCU_SetStatus(Z, STATUS_Z); + mcu->MCU_SetStatus(C, STATUS_C); + mcu->MCU_SetStatus(V, STATUS_V); return t1; } -void MCU_Operand_Nop(uint8_t operand) +void MCU_Operand_Nop(MCU *mcu, uint8_t operand) { } -void MCU_Operand_Sleep(uint8_t operand) +void MCU_Operand_Sleep(MCU *mcu, uint8_t operand) { - mcu.sleep = 1; + mcu->mcu.sleep = 1; } -void MCU_Operand_NotImplemented(uint8_t operand) +void MCU_Operand_NotImplemented(MCU *mcu, uint8_t operand) { - MCU_ErrorTrap(); + mcu->MCU_ErrorTrap(); } enum { @@ -168,84 +168,84 @@ enum { INCREASE_INCREASE }; -void MCU_LDM(uint8_t operand) +void MCU_LDM(MCU *mcu, uint8_t operand) { - uint8_t rlist = MCU_ReadCodeAdvance(); + uint8_t rlist = mcu->MCU_ReadCodeAdvance(); int32_t i; for (i = 0; i < 8; i++) { if (rlist & (1 << i)) { - uint16_t data = MCU_PopStack(); + uint16_t data = mcu->MCU_PopStack(); if (i != 7) - mcu.r[i] = data; + mcu->mcu.r[i] = data; } } } -void MCU_STM(uint8_t operand) +void MCU_STM(MCU *mcu, uint8_t operand) { - uint8_t rlist = MCU_ReadCodeAdvance(); + uint8_t rlist = mcu->MCU_ReadCodeAdvance(); int32_t i; for (i = 7; i >= 0; i--) { if (rlist & (1 << i)) { - uint16_t data = mcu.r[i]; + uint16_t data = mcu->mcu.r[i]; if (i == 7) data -= 2; - MCU_PushStack(data); + mcu->MCU_PushStack(data); } } } -void MCU_TRAPA(uint8_t operand) +void MCU_TRAPA(MCU *mcu, uint8_t operand) { - uint32_t opcode = MCU_ReadCodeAdvance(); + uint32_t opcode = mcu->MCU_ReadCodeAdvance(); if ((opcode & 0xf0) == 0x10) { - MCU_Interrupt_TRAPA(opcode & 0x0f); + MCU_Interrupt_TRAPA(mcu, opcode & 0x0f); } else { - MCU_ErrorTrap(); + mcu->MCU_ErrorTrap(); } } -void MCU_Jump_PJSR(uint8_t operand) +void MCU_Jump_PJSR(MCU *mcu, uint8_t operand) { - uint32_t ocp = mcu.cp; - uint32_t opc = mcu.pc; - uint8_t page = MCU_ReadCodeAdvance(); + uint32_t ocp = mcu->mcu.cp; + uint32_t opc = mcu->mcu.pc; + uint8_t page = mcu->MCU_ReadCodeAdvance(); uint16_t address; - address = MCU_ReadCodeAdvance() << 8; - address |= MCU_ReadCodeAdvance(); - MCU_PushStack(mcu.pc); - MCU_PushStack(mcu.cp); - mcu.cp = page; - if (mcu.cp == 0x27) - mcu.cp += 0; - mcu.pc = address; + address = mcu->MCU_ReadCodeAdvance() << 8; + address |= mcu->MCU_ReadCodeAdvance(); + mcu->MCU_PushStack(mcu->mcu.pc); + mcu->MCU_PushStack(mcu->mcu.cp); + mcu->mcu.cp = page; + if (mcu->mcu.cp == 0x27) + mcu->mcu.cp += 0; + mcu->mcu.pc = address; } -void MCU_Jump_JSR(uint8_t operand) +void MCU_Jump_JSR(MCU *mcu, uint8_t operand) { uint16_t address; - address = MCU_ReadCodeAdvance() << 8; - address |= MCU_ReadCodeAdvance(); - MCU_PushStack(mcu.pc); - mcu.pc = address; + address = mcu->MCU_ReadCodeAdvance() << 8; + address |= mcu->MCU_ReadCodeAdvance(); + mcu->MCU_PushStack(mcu->mcu.pc); + mcu->mcu.pc = address; } -void MCU_Jump_RTE(uint8_t operand) +void MCU_Jump_RTE(MCU *mcu, uint8_t operand) { - mcu.sr = MCU_PopStack(); - mcu.cp = (uint8_t)MCU_PopStack(); - mcu.pc = MCU_PopStack(); - mcu.ex_ignore = 1; + mcu->mcu.sr = mcu->MCU_PopStack(); + mcu->mcu.cp = (uint8_t)mcu->MCU_PopStack(); + mcu->mcu.pc = mcu->MCU_PopStack(); + mcu->mcu.ex_ignore = 1; } -void MCU_Jump_Bcc(uint8_t operand) +void MCU_Jump_Bcc(MCU *mcu, uint8_t operand) { uint16_t disp; uint32_t cond; @@ -253,19 +253,19 @@ void MCU_Jump_Bcc(uint8_t operand) uint32_t N, C, Z, V; if (operand & 0x10) { - disp = MCU_ReadCodeAdvance() << 8; - disp |= MCU_ReadCodeAdvance(); + disp = mcu->MCU_ReadCodeAdvance() << 8; + disp |= mcu->MCU_ReadCodeAdvance(); } else { - disp = (int8_t)MCU_ReadCodeAdvance(); + disp = (int8_t)mcu->MCU_ReadCodeAdvance(); } cond = operand & 0x0f; - N = (mcu.sr & STATUS_N) != 0; - C = (mcu.sr & STATUS_C) != 0; - Z = (mcu.sr & STATUS_Z) != 0; - V = (mcu.sr & STATUS_V) != 0; + N = (mcu->mcu.sr & STATUS_N) != 0; + C = (mcu->mcu.sr & STATUS_C) != 0; + Z = (mcu->mcu.sr & STATUS_Z) != 0; + V = (mcu->mcu.sr & STATUS_V) != 0; switch (cond) { @@ -321,213 +321,204 @@ void MCU_Jump_Bcc(uint8_t operand) if (branch) { - mcu.pc += disp; + mcu->mcu.pc += disp; } } -void MCU_Jump_RTS(uint8_t operand) +void MCU_Jump_RTS(MCU *mcu, uint8_t operand) { - mcu.pc = MCU_PopStack(); + mcu->mcu.pc = mcu->MCU_PopStack(); } -void MCU_Jump_JMP(uint8_t operand) +void MCU_Jump_JMP(MCU *mcu, uint8_t operand) { if (operand == 0x11) { - uint8_t opcode = MCU_ReadCodeAdvance(); + uint8_t opcode = mcu->MCU_ReadCodeAdvance(); uint8_t opcode_h = opcode >> 3; uint8_t opcode_l = opcode & 0x07; if (opcode == 0x19) { - mcu.cp = (uint8_t)MCU_PopStack(); - mcu.pc = MCU_PopStack(); + mcu->mcu.cp = (uint8_t)mcu->MCU_PopStack(); + mcu->mcu.pc = mcu->MCU_PopStack(); } else if (opcode_h == 0x1a) { - mcu.pc = mcu.r[opcode_l]; + mcu->mcu.pc = mcu->mcu.r[opcode_l]; } else if (opcode_h == 0x1b) { - MCU_PushStack(mcu.pc); - mcu.pc = mcu.r[opcode_l]; + mcu->MCU_PushStack(mcu->mcu.pc); + mcu->mcu.pc = mcu->mcu.r[opcode_l]; } else { - MCU_ErrorTrap(); + mcu->MCU_ErrorTrap(); } } else if (operand == 0x01) { - uint8_t opcode = MCU_ReadCodeAdvance(); + uint8_t opcode = mcu->MCU_ReadCodeAdvance(); uint8_t reg = opcode & 0x07; opcode >>= 3; if (opcode == 0x17) { - uint16_t disp = (int8_t)MCU_ReadCodeAdvance(); - mcu.r[reg]--; - if (mcu.r[reg] != 0xffff) + uint16_t disp = (int8_t)mcu->MCU_ReadCodeAdvance(); + mcu->mcu.r[reg]--; + if (mcu->mcu.r[reg] != 0xffff) { - mcu.pc += disp; + mcu->mcu.pc += disp; } } else { - MCU_ErrorTrap(); + mcu->MCU_ErrorTrap(); } } else if (operand == 0x10) { uint32_t addr; - addr = MCU_ReadCodeAdvance() << 8; - addr |= MCU_ReadCodeAdvance(); - mcu.pc = addr; + addr = mcu->MCU_ReadCodeAdvance() << 8; + addr |= mcu->MCU_ReadCodeAdvance(); + mcu->mcu.pc = addr; } else if (operand == 0x06) { - uint8_t opcode = MCU_ReadCodeAdvance(); + uint8_t opcode = mcu->MCU_ReadCodeAdvance(); uint8_t reg = opcode & 0x07; opcode >>= 3; if (opcode == 0x17) { - uint16_t disp = (int8_t)MCU_ReadCodeAdvance(); - uint32_t Z = (mcu.sr & STATUS_Z) != 0; + uint16_t disp = (int8_t)mcu->MCU_ReadCodeAdvance(); + uint32_t Z = (mcu->mcu.sr & STATUS_Z) != 0; if (Z) { - mcu.r[reg]--; - if (mcu.r[reg] != 0xffff) + mcu->mcu.r[reg]--; + if (mcu->mcu.r[reg] != 0xffff) { - mcu.pc += disp; + mcu->mcu.pc += disp; } } } else { - MCU_ErrorTrap(); + mcu->MCU_ErrorTrap(); } } else if (operand == 0x07) { - uint8_t opcode = MCU_ReadCodeAdvance(); + uint8_t opcode = mcu->MCU_ReadCodeAdvance(); uint8_t reg = opcode & 0x07; opcode >>= 3; if (opcode == 0x17) { - uint16_t disp = (int8_t)MCU_ReadCodeAdvance(); - uint32_t Z = (mcu.sr & STATUS_Z) != 0; + uint16_t disp = (int8_t)mcu->MCU_ReadCodeAdvance(); + uint32_t Z = (mcu->mcu.sr & STATUS_Z) != 0; if (!Z) { - mcu.r[reg]--; - if (mcu.r[reg] != 0xffff) + mcu->mcu.r[reg]--; + if (mcu->mcu.r[reg] != 0xffff) { - mcu.pc += disp; + mcu->mcu.pc += disp; } } } else { - MCU_ErrorTrap(); + mcu->MCU_ErrorTrap(); } } else { - MCU_ErrorTrap(); + mcu->MCU_ErrorTrap(); } } -void MCU_Jump_BSR(uint8_t operand) +void MCU_Jump_BSR(MCU *mcu, uint8_t operand) { uint16_t disp; if (operand == 0x0e) { - disp = (int8_t)MCU_ReadCodeAdvance(); + disp = (int8_t)mcu->MCU_ReadCodeAdvance(); } else { - disp = MCU_ReadCodeAdvance() << 8; - disp |= MCU_ReadCodeAdvance(); + disp = mcu->MCU_ReadCodeAdvance() << 8; + disp |= mcu->MCU_ReadCodeAdvance(); } - MCU_PushStack(mcu.pc); - mcu.pc += disp; + mcu->MCU_PushStack(mcu->mcu.pc); + mcu->mcu.pc += disp; } -void MCU_Jump_PJMP(uint8_t operand) +void MCU_Jump_PJMP(MCU *mcu, uint8_t operand) { uint8_t page; uint16_t address; - page = MCU_ReadCodeAdvance(); - address = MCU_ReadCodeAdvance() << 8; - address |= MCU_ReadCodeAdvance(); - mcu.cp = page; - mcu.pc = address; + page = mcu->MCU_ReadCodeAdvance(); + address = mcu->MCU_ReadCodeAdvance() << 8; + address |= mcu->MCU_ReadCodeAdvance(); + mcu->mcu.cp = page; + mcu->mcu.pc = address; } -uint32_t operand_type; -uint16_t operand_ea; -uint8_t operand_ep; -uint8_t operand_size; -uint8_t operand_reg; -uint8_t operand_status; -uint16_t operand_data; -uint8_t opcode_extended; - -uint32_t MCU_Operand_Read(void) +uint32_t MCU_Operand_Read(MCU *mcu) { - switch (operand_type) + switch (mcu->operand_type) { case GENERAL_DIRECT: - if (operand_size) - return mcu.r[operand_reg]; - return mcu.r[operand_reg] & 0xff; + if (mcu->operand_size) + return mcu->mcu.r[mcu->operand_reg]; + return mcu->mcu.r[mcu->operand_reg] & 0xff; case GENERAL_INDIRECT: case GENERAL_ABSOLUTE: - if (operand_size) + if (mcu->operand_size) { - if (operand_ea & 1) + if (mcu->operand_ea & 1) { - MCU_Interrupt_Exception(EXCEPTION_SOURCE_ADDRESS_ERROR); + MCU_Interrupt_Exception(mcu, EXCEPTION_SOURCE_ADDRESS_ERROR); } - return MCU_Read16(MCU_GetAddress(operand_ep, operand_ea)); + return mcu->MCU_Read16(mcu->MCU_GetAddress(mcu->operand_ep, mcu->operand_ea)); } - return MCU_Read(MCU_GetAddress(operand_ep, operand_ea)); + return mcu->MCU_Read(mcu->MCU_GetAddress(mcu->operand_ep, mcu->operand_ea)); case GENERAL_IMMEDIATE: - return operand_data; + return mcu->operand_data; } return 0; } -void MCU_Operand_Write(uint32_t data) +void MCU_Operand_Write(MCU *mcu, uint32_t data) { - switch (operand_type) + switch (mcu->operand_type) { case GENERAL_DIRECT: - if (operand_size) - mcu.r[operand_reg] = data; + if (mcu->operand_size) + mcu->mcu.r[mcu->operand_reg] = data; else { - mcu.r[operand_reg] &= ~0xff; - mcu.r[operand_reg] |= data & 0xff; + mcu->mcu.r[mcu->operand_reg] &= ~0xff; + mcu->mcu.r[mcu->operand_reg] |= data & 0xff; } break; case GENERAL_INDIRECT: case GENERAL_ABSOLUTE: - if (operand_size) + if (mcu->operand_size) { - if (operand_ea & 1) + if (mcu->operand_ea & 1) { - MCU_Interrupt_Exception(EXCEPTION_SOURCE_ADDRESS_ERROR); + MCU_Interrupt_Exception(mcu, EXCEPTION_SOURCE_ADDRESS_ERROR); } - MCU_Write16(MCU_GetAddress(operand_ep, operand_ea), data); + mcu->MCU_Write16(mcu->MCU_GetAddress(mcu->operand_ep, mcu->operand_ea), data); } else - MCU_Write(MCU_GetAddress(operand_ep, operand_ea), data); + mcu->MCU_Write(mcu->MCU_GetAddress(mcu->operand_ep, mcu->operand_ea), data); break; case GENERAL_IMMEDIATE: - MCU_Interrupt_Exception(EXCEPTION_SOURCE_INVALID_INSTRUCTION); + MCU_Interrupt_Exception(mcu, EXCEPTION_SOURCE_INVALID_INSTRUCTION); break; } } -void MCU_Operand_General(uint8_t operand) +void MCU_Operand_General(MCU *mcu, uint8_t operand) { uint32_t type = GENERAL_DIRECT; uint32_t disp = 0; @@ -557,13 +548,13 @@ void MCU_Operand_General(uint8_t operand) break; case 0xe0: type = GENERAL_INDIRECT; - disp = (int8_t)MCU_ReadCodeAdvance(); + disp = (int8_t)mcu->MCU_ReadCodeAdvance(); break; case 0xf0: type = GENERAL_INDIRECT; - disp = MCU_ReadCodeAdvance(); + disp = mcu->MCU_ReadCodeAdvance(); disp <<= 8; - disp |= MCU_ReadCodeAdvance(); + disp |= mcu->MCU_ReadCodeAdvance(); break; case 0xb0: type = GENERAL_INDIRECT; @@ -577,18 +568,18 @@ void MCU_Operand_General(uint8_t operand) if (reg == 5) { type = GENERAL_ABSOLUTE; - addr = mcu.br << 8; - addr |= MCU_ReadCodeAdvance(); + addr = mcu->mcu.br << 8; + addr |= mcu->MCU_ReadCodeAdvance(); addrpage = 0; } else if (reg == 4) { type = GENERAL_IMMEDIATE; - data = MCU_ReadCodeAdvance(); + data = mcu->MCU_ReadCodeAdvance(); if (siz) { data <<= 8; - data |= MCU_ReadCodeAdvance(); + data |= mcu->MCU_ReadCodeAdvance(); } } break; @@ -596,9 +587,9 @@ void MCU_Operand_General(uint8_t operand) if (reg == 5) { type = GENERAL_ABSOLUTE; - addr = MCU_ReadCodeAdvance() << 8; - addr |= MCU_ReadCodeAdvance(); - addrpage = mcu.dp; + addr = mcu->MCU_ReadCodeAdvance() << 8; + addr |= mcu->MCU_ReadCodeAdvance(); + addrpage = mcu->mcu.dp; } break; } @@ -608,29 +599,29 @@ void MCU_Operand_General(uint8_t operand) { if (siz || reg == 7) { - mcu.r[reg] -= 2; + mcu->mcu.r[reg] -= 2; } else { - mcu.r[reg] -= 1; + mcu->mcu.r[reg] -= 1; } } - ea = mcu.r[reg] + disp; + ea = mcu->mcu.r[reg] + disp; if (increase == INCREASE_INCREASE) { if (siz || reg == 7) { - mcu.r[reg] += 2; + mcu->mcu.r[reg] += 2; } else { - mcu.r[reg] += 1; + mcu->mcu.r[reg] += 1; } } ea &= 0xffff; - ep = MCU_GetPageForRegister(reg) & 0xff; + ep = mcu->MCU_GetPageForRegister(reg) & 0xff; } else if (type == GENERAL_ABSOLUTE) { @@ -639,363 +630,363 @@ void MCU_Operand_General(uint8_t operand) ep = addrpage & 0xff; } - opcode = MCU_ReadCodeAdvance(); - opcode_extended = opcode == 0x00; - if (opcode_extended) + opcode = mcu->MCU_ReadCodeAdvance(); + mcu->opcode_extended = opcode == 0x00; + if (mcu->opcode_extended) { - opcode = MCU_ReadCodeAdvance(); + opcode = mcu->MCU_ReadCodeAdvance(); } opcode_reg = opcode & 0x07; opcode >>= 3; - operand_type = type; - operand_ea = ea; - operand_ep = ep; - operand_size = siz; - operand_reg = reg; - operand_data = data; - operand_status = 0; + mcu->operand_type = type; + mcu->operand_ea = ea; + mcu->operand_ep = ep; + mcu->operand_size = siz; + mcu->operand_reg = reg; + mcu->operand_data = data; + mcu->operand_status = 0; - MCU_Opcode_Table[opcode](opcode, opcode_reg); + MCU_Opcode_Table[opcode](mcu, opcode, opcode_reg); } -void MCU_SetStatusCommon(uint32_t val, uint32_t siz) +void MCU_SetStatusCommon(MCU *mcu, uint32_t val, uint32_t siz) { if (siz) val &= 0xffff; else val &= 0xff; if (siz) - MCU_SetStatus(val & 0x8000, STATUS_N); + mcu->MCU_SetStatus(val & 0x8000, STATUS_N); else - MCU_SetStatus(val & 0x80, STATUS_N); - MCU_SetStatus(val == 0, STATUS_Z); - MCU_SetStatus(0, STATUS_V); + mcu->MCU_SetStatus(val & 0x80, STATUS_N); + mcu->MCU_SetStatus(val == 0, STATUS_Z); + mcu->MCU_SetStatus(0, STATUS_V); } -void MCU_Opcode_Short_NotImplemented(uint8_t opcode) +void MCU_Opcode_Short_NotImplemented(MCU *mcu, uint8_t opcode) { - MCU_ErrorTrap(); + mcu->MCU_ErrorTrap(); } -void MCU_Opcode_Short_MOVE(uint8_t opcode) +void MCU_Opcode_Short_MOVE(MCU *mcu, uint8_t opcode) { uint32_t reg = opcode & 0x07; - uint8_t data = MCU_ReadCodeAdvance(); - mcu.r[reg] &= ~0xff; - mcu.r[reg] |= data; - MCU_SetStatusCommon(data, 0); + uint8_t data = mcu->MCU_ReadCodeAdvance(); + mcu->mcu.r[reg] &= ~0xff; + mcu->mcu.r[reg] |= data; + MCU_SetStatusCommon(mcu, data, 0); } -void MCU_Opcode_Short_MOVI(uint8_t opcode) +void MCU_Opcode_Short_MOVI(MCU *mcu, uint8_t opcode) { uint32_t reg = opcode & 0x07; uint16_t data; - data = MCU_ReadCodeAdvance() << 8; - data |= MCU_ReadCodeAdvance(); - mcu.r[reg] = data; - MCU_SetStatusCommon(data, 1); + data = mcu->MCU_ReadCodeAdvance() << 8; + data |= mcu->MCU_ReadCodeAdvance(); + mcu->mcu.r[reg] = data; + MCU_SetStatusCommon(mcu, data, 1); } -void MCU_Opcode_Short_MOVL(uint8_t opcode) +void MCU_Opcode_Short_MOVL(MCU *mcu, uint8_t opcode) { uint32_t reg = opcode & 0x07; uint32_t siz = (opcode & 0x08) != 0; - uint16_t addr = mcu.br << 8; + uint16_t addr = mcu->mcu.br << 8; uint32_t data; - addr |= MCU_ReadCodeAdvance(); + addr |= mcu->MCU_ReadCodeAdvance(); if (siz) { if (addr & 1) - MCU_Interrupt_Exception(EXCEPTION_SOURCE_ADDRESS_ERROR); - data = MCU_Read16(addr); - mcu.r[reg] = data; - MCU_SetStatusCommon(data, 1); + MCU_Interrupt_Exception(mcu, EXCEPTION_SOURCE_ADDRESS_ERROR); + data = mcu->MCU_Read16(addr); + mcu->mcu.r[reg] = data; + MCU_SetStatusCommon(mcu, data, 1); } else { - data = MCU_Read(addr); - mcu.r[reg] &= ~0xff; - mcu.r[reg] |= data; - MCU_SetStatusCommon(data, 0); + data = mcu->MCU_Read(addr); + mcu->mcu.r[reg] &= ~0xff; + mcu->mcu.r[reg] |= data; + MCU_SetStatusCommon(mcu, data, 0); } } -void MCU_Opcode_Short_MOVS(uint8_t opcode) +void MCU_Opcode_Short_MOVS(MCU *mcu, uint8_t opcode) { uint32_t reg = opcode & 0x07; uint32_t siz = (opcode & 0x08) != 0; - uint16_t addr = mcu.br << 8; + uint16_t addr = mcu->mcu.br << 8; uint32_t data; - addr |= MCU_ReadCodeAdvance(); + addr |= mcu->MCU_ReadCodeAdvance(); if (siz) { if (addr & 1) - MCU_Interrupt_Exception(EXCEPTION_SOURCE_ADDRESS_ERROR); - data = mcu.r[reg]; - MCU_Write16(addr, data); - MCU_SetStatusCommon(data, 1); + MCU_Interrupt_Exception(mcu, EXCEPTION_SOURCE_ADDRESS_ERROR); + data = mcu->mcu.r[reg]; + mcu->MCU_Write16(addr, data); + MCU_SetStatusCommon(mcu, data, 1); } else { - data = mcu.r[reg] & 0xff; - MCU_Write(addr, data); - MCU_SetStatusCommon(data, 0); + data = mcu->mcu.r[reg] & 0xff; + mcu->MCU_Write(addr, data); + MCU_SetStatusCommon(mcu, data, 0); } } -void MCU_Opcode_Short_CMP(uint8_t opcode) +void MCU_Opcode_Short_CMP(MCU *mcu, uint8_t opcode) { uint32_t reg = opcode & 0x07; uint32_t siz = (opcode & 0x08) != 0; int32_t t1, t2; if (siz) { - t2 = MCU_ReadCodeAdvance() << 8; - t2 |= MCU_ReadCodeAdvance(); + t2 = mcu->MCU_ReadCodeAdvance() << 8; + t2 |= mcu->MCU_ReadCodeAdvance(); } else { - t2 = MCU_ReadCodeAdvance(); + t2 = mcu->MCU_ReadCodeAdvance(); } - t1 = mcu.r[reg]; - MCU_SUB_Common(t1, t2, 0, siz); + t1 = mcu->mcu.r[reg]; + MCU_SUB_Common(mcu, t1, t2, 0, siz); } -void MCU_Opcode_NotImplemented(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_NotImplemented(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - MCU_ErrorTrap(); + mcu->MCU_ErrorTrap(); } -void MCU_Opcode_MOVG_Immediate(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_MOVG_Immediate(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { uint32_t data; - if (opcode_reg == 6 && (operand_type == GENERAL_INDIRECT || operand_type == GENERAL_ABSOLUTE)) + if (opcode_reg == 6 && (mcu->operand_type == GENERAL_INDIRECT || mcu->operand_type == GENERAL_ABSOLUTE)) { - data = (int8_t)MCU_ReadCodeAdvance(); - MCU_Operand_Write(data); - MCU_SetStatusCommon(data, operand_size); + data = (int8_t)mcu->MCU_ReadCodeAdvance(); + MCU_Operand_Write(mcu, data); + MCU_SetStatusCommon(mcu, data, mcu->operand_size); } - else if (opcode_reg == 7 && (operand_type == GENERAL_INDIRECT || operand_type == GENERAL_ABSOLUTE)) + else if (opcode_reg == 7 && (mcu->operand_type == GENERAL_INDIRECT || mcu->operand_type == GENERAL_ABSOLUTE)) { - data = MCU_ReadCodeAdvance() << 8; - data |= MCU_ReadCodeAdvance(); - MCU_Operand_Write(data); - MCU_SetStatusCommon(data, operand_size); + data = mcu->MCU_ReadCodeAdvance() << 8; + data |= mcu->MCU_ReadCodeAdvance(); + MCU_Operand_Write(mcu, data); + MCU_SetStatusCommon(mcu, data, mcu->operand_size); } - else if (opcode_reg == 4 && (operand_type == GENERAL_INDIRECT || operand_type == GENERAL_ABSOLUTE) && operand_size == OPERAND_BYTE) + else if (opcode_reg == 4 && (mcu->operand_type == GENERAL_INDIRECT || mcu->operand_type == GENERAL_ABSOLUTE) && mcu->operand_size == OPERAND_BYTE) { - uint32_t t1 = MCU_Operand_Read(); - uint32_t t2 = MCU_ReadCodeAdvance(); - MCU_SUB_Common(t1, t2, 0, OPERAND_BYTE); + uint32_t t1 = MCU_Operand_Read(mcu); + uint32_t t2 = mcu->MCU_ReadCodeAdvance(); + MCU_SUB_Common(mcu, t1, t2, 0, OPERAND_BYTE); } - else if (opcode_reg == 4 && (operand_type == GENERAL_INDIRECT || operand_type == GENERAL_ABSOLUTE) && operand_size == OPERAND_WORD) // FIXME + else if (opcode_reg == 4 && (mcu->operand_type == GENERAL_INDIRECT || mcu->operand_type == GENERAL_ABSOLUTE) && mcu->operand_size == OPERAND_WORD) // FIXME { - uint32_t t1 = MCU_Operand_Read(); - uint32_t t2 = MCU_ReadCodeAdvance(); - MCU_SUB_Common(t1, t2, 0, OPERAND_WORD); + uint32_t t1 = MCU_Operand_Read(mcu); + uint32_t t2 = mcu->MCU_ReadCodeAdvance(); + MCU_SUB_Common(mcu, t1, t2, 0, OPERAND_WORD); } - else if (opcode_reg == 5 && (operand_type == GENERAL_INDIRECT || operand_type == GENERAL_ABSOLUTE) && operand_size == OPERAND_WORD) + else if (opcode_reg == 5 && (mcu->operand_type == GENERAL_INDIRECT || mcu->operand_type == GENERAL_ABSOLUTE) && mcu->operand_size == OPERAND_WORD) { uint32_t t1, t2; - t1 = MCU_Operand_Read(); - t2 = MCU_ReadCodeAdvance() << 8; - t2 |= MCU_ReadCodeAdvance(); - MCU_SUB_Common(t1, t2, 0, OPERAND_WORD); + t1 = MCU_Operand_Read(mcu); + t2 = mcu->MCU_ReadCodeAdvance() << 8; + t2 |= mcu->MCU_ReadCodeAdvance(); + MCU_SUB_Common(mcu, t1, t2, 0, OPERAND_WORD); } - else if (opcode_reg == 5 && (operand_type == GENERAL_INDIRECT || operand_type == GENERAL_ABSOLUTE) && operand_size == OPERAND_BYTE) // FIXME + else if (opcode_reg == 5 && (mcu->operand_type == GENERAL_INDIRECT || mcu->operand_type == GENERAL_ABSOLUTE) && mcu->operand_size == OPERAND_BYTE) // FIXME { uint32_t t1, t2; - t1 = MCU_Operand_Read(); - t2 = MCU_ReadCodeAdvance() << 8; - t2 |= MCU_ReadCodeAdvance(); - MCU_SUB_Common(t1, t2, 0, OPERAND_BYTE); + t1 = MCU_Operand_Read(mcu); + t2 = mcu->MCU_ReadCodeAdvance() << 8; + t2 |= mcu->MCU_ReadCodeAdvance(); + MCU_SUB_Common(mcu, t1, t2, 0, OPERAND_BYTE); } else { - MCU_ErrorTrap(); + mcu->MCU_ErrorTrap(); } } -void MCU_Opcode_BSET_ORC(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_BSET_ORC(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - if (operand_type == GENERAL_IMMEDIATE) // ORC + if (mcu->operand_type == GENERAL_IMMEDIATE) // ORC { - uint32_t data = MCU_Operand_Read(); - uint32_t val = MCU_ControlRegisterRead(opcode_reg, operand_size); + uint32_t data = MCU_Operand_Read(mcu); + uint32_t val = mcu->MCU_ControlRegisterRead(opcode_reg, mcu->operand_size); val |= data; - MCU_ControlRegisterWrite(opcode_reg, operand_size, val); + mcu->MCU_ControlRegisterWrite(opcode_reg, mcu->operand_size, val); if (opcode_reg >= 2) { - MCU_SetStatusCommon(val, operand_size); + MCU_SetStatusCommon(mcu, val, mcu->operand_size); } - mcu.ex_ignore = 1; + mcu->mcu.ex_ignore = 1; } else // BSET { - uint32_t data = MCU_Operand_Read(); - uint32_t bit = mcu.r[opcode_reg] & 0x0f; - MCU_SetStatus((data & (1 << bit)) == 0, STATUS_Z); + uint32_t data = MCU_Operand_Read(mcu); + uint32_t bit = mcu->mcu.r[opcode_reg] & 0x0f; + mcu->MCU_SetStatus((data & (1 << bit)) == 0, STATUS_Z); data |= 1 << bit; - MCU_Operand_Write(data); + MCU_Operand_Write(mcu, data); } } -void MCU_Opcode_BCLR_ANDC(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_BCLR_ANDC(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - if (operand_type == GENERAL_IMMEDIATE) // ANDC + if (mcu->operand_type == GENERAL_IMMEDIATE) // ANDC { - uint32_t data = MCU_Operand_Read(); - uint32_t val = MCU_ControlRegisterRead(opcode_reg, operand_size); + uint32_t data = MCU_Operand_Read(mcu); + uint32_t val = mcu->MCU_ControlRegisterRead(opcode_reg, mcu->operand_size); val &= data; - MCU_ControlRegisterWrite(opcode_reg, operand_size, val); + mcu->MCU_ControlRegisterWrite(opcode_reg, mcu->operand_size, val); if (opcode_reg >= 2) { - MCU_SetStatusCommon(val, operand_size); + MCU_SetStatusCommon(mcu, val, mcu->operand_size); } - mcu.ex_ignore = 1; + mcu->mcu.ex_ignore = 1; } else // BCLR { - uint32_t data = MCU_Operand_Read(); - uint32_t bit = mcu.r[opcode_reg] & 0x0f; - MCU_SetStatus((data & (1 << bit)) == 0, STATUS_Z); + uint32_t data = MCU_Operand_Read(mcu); + uint32_t bit = mcu->mcu.r[opcode_reg] & 0x0f; + mcu->MCU_SetStatus((data & (1 << bit)) == 0, STATUS_Z); data &= ~(1 << bit); - MCU_Operand_Write(data); + MCU_Operand_Write(mcu, data); } } -void MCU_Opcode_BTST(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_BTST(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - if (operand_type != GENERAL_IMMEDIATE) + if (mcu->operand_type != GENERAL_IMMEDIATE) { - uint32_t data = MCU_Operand_Read(); - uint32_t bit = mcu.r[opcode_reg] & 0x0f; - MCU_SetStatus((data & (1 << bit)) == 0, STATUS_Z); + uint32_t data = MCU_Operand_Read(mcu); + uint32_t bit = mcu->mcu.r[opcode_reg] & 0x0f; + mcu->MCU_SetStatus((data & (1 << bit)) == 0, STATUS_Z); } else { - MCU_ErrorTrap(); + mcu->MCU_ErrorTrap(); } } -void MCU_Opcode_CLR(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_CLR(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - if (opcode_reg == 3 && operand_type != GENERAL_IMMEDIATE) // CLR + if (opcode_reg == 3 && mcu->operand_type != GENERAL_IMMEDIATE) // CLR { - MCU_Operand_Write(0); - MCU_SetStatus(0, STATUS_N); - MCU_SetStatus(1, STATUS_Z); - MCU_SetStatus(0, STATUS_V); - MCU_SetStatus(0, STATUS_C); + MCU_Operand_Write(mcu, 0); + mcu->MCU_SetStatus(0, STATUS_N); + mcu->MCU_SetStatus(1, STATUS_Z); + mcu->MCU_SetStatus(0, STATUS_V); + mcu->MCU_SetStatus(0, STATUS_C); } - else if (opcode_reg == 6 && operand_type != GENERAL_IMMEDIATE) // TST + else if (opcode_reg == 6 && mcu->operand_type != GENERAL_IMMEDIATE) // TST { - uint32_t data = MCU_Operand_Read(); - MCU_SetStatusCommon(data, operand_size); - MCU_SetStatus(0, STATUS_C); + uint32_t data = MCU_Operand_Read(mcu); + MCU_SetStatusCommon(mcu, data, mcu->operand_size); + mcu->MCU_SetStatus(0, STATUS_C); } - else if (opcode_reg == 2 && operand_type == GENERAL_DIRECT && operand_size == 0) // EXTU + else if (opcode_reg == 2 && mcu->operand_type == GENERAL_DIRECT && mcu->operand_size == 0) // EXTU { - uint32_t data = (uint8_t)mcu.r[operand_reg]; - mcu.r[operand_reg] = data; - MCU_SetStatus(0, STATUS_N); - MCU_SetStatus(data == 0, STATUS_Z); - MCU_SetStatus(0, STATUS_V); - MCU_SetStatus(0, STATUS_C); + uint32_t data = (uint8_t)mcu->mcu.r[mcu->operand_reg]; + mcu->mcu.r[mcu->operand_reg] = data; + mcu->MCU_SetStatus(0, STATUS_N); + mcu->MCU_SetStatus(data == 0, STATUS_Z); + mcu->MCU_SetStatus(0, STATUS_V); + mcu->MCU_SetStatus(0, STATUS_C); } - else if (opcode_reg == 0 && operand_type == GENERAL_DIRECT && operand_size == 0) // SWAP + else if (opcode_reg == 0 && mcu->operand_type == GENERAL_DIRECT && mcu->operand_size == 0) // SWAP { - uint32_t data = mcu.r[operand_reg]; + uint32_t data = mcu->mcu.r[mcu->operand_reg]; uint32_t data_h = data >> 8; uint32_t data_l = data & 0xff; data = (data_l << 8) | data_h; - mcu.r[operand_reg] = data; - MCU_SetStatusCommon(data, OPERAND_BYTE); // FIXME: might be WORD??? - //MCU_SetStatusCommon(data, OPERAND_WORD); + mcu->mcu.r[mcu->operand_reg] = data; + MCU_SetStatusCommon(mcu, data, OPERAND_BYTE); // FIXME: might be WORD??? + //MCU_SetStatusCommon(mcu, data, OPERAND_WORD); } - else if (opcode_reg == 5 && operand_type != GENERAL_IMMEDIATE) // NOT + else if (opcode_reg == 5 && mcu->operand_type != GENERAL_IMMEDIATE) // NOT { - uint32_t data = MCU_Operand_Read(); + uint32_t data = MCU_Operand_Read(mcu); data = ~data; - MCU_Operand_Write(data); - MCU_SetStatusCommon(data, operand_size); + MCU_Operand_Write(mcu, data); + MCU_SetStatusCommon(mcu, data, mcu->operand_size); } - else if (opcode_reg == 4 && operand_type != GENERAL_IMMEDIATE) // NEG + else if (opcode_reg == 4 && mcu->operand_type != GENERAL_IMMEDIATE) // NEG { - uint32_t data = MCU_Operand_Read(); - data = MCU_SUB_Common(0, data, 0, operand_size); - MCU_Operand_Write(data); + uint32_t data = MCU_Operand_Read(mcu); + data = MCU_SUB_Common(mcu, 0, data, 0, mcu->operand_size); + MCU_Operand_Write(mcu, data); } - else if (opcode_reg == 1 && operand_type == GENERAL_DIRECT && operand_size == 0) // EXTS + else if (opcode_reg == 1 && mcu->operand_type == GENERAL_DIRECT && mcu->operand_size == 0) // EXTS { - uint32_t data = mcu.r[operand_reg]; - mcu.r[operand_reg] = (int8_t)data; - MCU_SetStatusCommon(data, OPERAND_WORD); + uint32_t data = mcu->mcu.r[mcu->operand_reg]; + mcu->mcu.r[mcu->operand_reg] = (int8_t)data; + MCU_SetStatusCommon(mcu, data, OPERAND_WORD); } else { - MCU_ErrorTrap(); + mcu->MCU_ErrorTrap(); } } -void MCU_Opcode_LDC(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_LDC(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - uint32_t data = MCU_Operand_Read(); - MCU_ControlRegisterWrite(opcode_reg, operand_size, data); - mcu.ex_ignore = 1; + uint32_t data = MCU_Operand_Read(mcu); + mcu->MCU_ControlRegisterWrite(opcode_reg, mcu->operand_size, data); + mcu->mcu.ex_ignore = 1; } -void MCU_Opcode_STC(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_STC(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - uint32_t data = MCU_ControlRegisterRead(opcode_reg, operand_size); - MCU_Operand_Write(data); + uint32_t data = mcu->MCU_ControlRegisterRead(opcode_reg, mcu->operand_size); + MCU_Operand_Write(mcu, data); } -void MCU_Opcode_BSET(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_BSET(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - if (operand_type != GENERAL_IMMEDIATE) + if (mcu->operand_type != GENERAL_IMMEDIATE) { - uint32_t data = MCU_Operand_Read(); + uint32_t data = MCU_Operand_Read(mcu); uint32_t bit = opcode_reg | ((opcode & 1) << 3); - MCU_SetStatus((data & (1 << bit)) == 0, STATUS_Z); + mcu->MCU_SetStatus((data & (1 << bit)) == 0, STATUS_Z); data |= 1 << bit; - MCU_Operand_Write(data); + MCU_Operand_Write(mcu, data); } else { - MCU_ErrorTrap(); + mcu->MCU_ErrorTrap(); } } -void MCU_Opcode_BCLR(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_BCLR(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - if (operand_type != GENERAL_IMMEDIATE) + if (mcu->operand_type != GENERAL_IMMEDIATE) { - uint32_t data = MCU_Operand_Read(); + uint32_t data = MCU_Operand_Read(mcu); uint32_t bit = opcode_reg | ((opcode & 1) << 3); - MCU_SetStatus((data & (1 << bit)) == 0, STATUS_Z); + mcu->MCU_SetStatus((data & (1 << bit)) == 0, STATUS_Z); data &= ~(1 << bit); - MCU_Operand_Write(data); + MCU_Operand_Write(mcu, data); } else { - MCU_ErrorTrap(); + mcu->MCU_ErrorTrap(); } } -void MCU_Opcode_MOVG(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_MOVG(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - if (opcode_extended) + if (mcu->opcode_extended) { if (opcode == 0x12) { // FIXME - MCU_ErrorTrap(); + mcu->MCU_ErrorTrap(); } else { - MCU_ErrorTrap(); + mcu->MCU_ErrorTrap(); } } else @@ -1004,73 +995,73 @@ void MCU_Opcode_MOVG(uint8_t opcode, uint8_t opcode_reg) uint32_t data; if (d) { - if (operand_type == GENERAL_DIRECT) // XCH + if (mcu->operand_type == GENERAL_DIRECT) // XCH { - if (operand_size) + if (mcu->operand_size) { - uint32_t r1 = mcu.r[opcode_reg]; - uint32_t r2 = mcu.r[operand_reg]; - mcu.r[opcode_reg] = r2; - mcu.r[operand_reg] = r1; + uint32_t r1 = mcu->mcu.r[opcode_reg]; + uint32_t r2 = mcu->mcu.r[mcu->operand_reg]; + mcu->mcu.r[opcode_reg] = r2; + mcu->mcu.r[mcu->operand_reg] = r1; } else { - MCU_ErrorTrap(); + mcu->MCU_ErrorTrap(); } } else { - data = mcu.r[opcode_reg]; - MCU_Operand_Write(data); - MCU_SetStatusCommon(data, operand_size); + data = mcu->mcu.r[opcode_reg]; + MCU_Operand_Write(mcu, data); + MCU_SetStatusCommon(mcu, data, mcu->operand_size); } } else { - data = MCU_Operand_Read(); - if (operand_size) - mcu.r[opcode_reg] = data; + data = MCU_Operand_Read(mcu); + if (mcu->operand_size) + mcu->mcu.r[opcode_reg] = data; else { - mcu.r[opcode_reg] &= ~0xff; - mcu.r[opcode_reg] |= data & 0xff; + mcu->mcu.r[opcode_reg] &= ~0xff; + mcu->mcu.r[opcode_reg] |= data & 0xff; } - MCU_SetStatusCommon(data, operand_size); + MCU_SetStatusCommon(mcu, data, mcu->operand_size); } } } -void MCU_Opcode_BTSTI(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_BTSTI(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - if (operand_type != GENERAL_IMMEDIATE) + if (mcu->operand_type != GENERAL_IMMEDIATE) { - uint32_t data = MCU_Operand_Read(); + uint32_t data = MCU_Operand_Read(mcu); uint32_t bit = opcode_reg | ((opcode & 1) << 3); - MCU_SetStatus((data & (1 << bit)) == 0, STATUS_Z); + mcu->MCU_SetStatus((data & (1 << bit)) == 0, STATUS_Z); } else { - MCU_ErrorTrap(); + mcu->MCU_ErrorTrap(); } } -void MCU_Opcode_OR(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_OR(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - uint32_t data = MCU_Operand_Read(); - mcu.r[opcode_reg] |= data; - MCU_SetStatusCommon(mcu.r[opcode_reg], operand_size); + uint32_t data = MCU_Operand_Read(mcu); + mcu->mcu.r[opcode_reg] |= data; + MCU_SetStatusCommon(mcu, mcu->mcu.r[opcode_reg], mcu->operand_size); } -void MCU_Opcode_CMP(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_CMP(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - int32_t t1 = mcu.r[opcode_reg]; - int32_t t2 = MCU_Operand_Read(); - MCU_SUB_Common(t1, t2, 0, operand_size); + int32_t t1 = mcu->mcu.r[opcode_reg]; + int32_t t2 = MCU_Operand_Read(mcu); + MCU_SUB_Common(mcu, t1, t2, 0, mcu->operand_size); } -void MCU_Opcode_ADDQ(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_ADDQ(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - int32_t t1 = MCU_Operand_Read(); + int32_t t1 = MCU_Operand_Read(mcu); int32_t t2 = 0; switch (opcode_reg) { @@ -1087,281 +1078,281 @@ void MCU_Opcode_ADDQ(uint8_t opcode, uint8_t opcode_reg) t2 = -2; break; default: - MCU_ErrorTrap(); + mcu->MCU_ErrorTrap(); break; } - t1 = MCU_ADD_Common(t1, t2, 0, operand_size); - MCU_Operand_Write(t1); + t1 = MCU_ADD_Common(mcu, t1, t2, 0, mcu->operand_size); + MCU_Operand_Write(mcu, t1); } -void MCU_Opcode_ADD(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_ADD(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - int32_t t1 = mcu.r[opcode_reg]; - int32_t t2 = MCU_Operand_Read(); - t1 = MCU_ADD_Common(t1, t2, 0, operand_size); - if (operand_size) - mcu.r[opcode_reg] = t1; + int32_t t1 = mcu->mcu.r[opcode_reg]; + int32_t t2 = MCU_Operand_Read(mcu); + t1 = MCU_ADD_Common(mcu, t1, t2, 0, mcu->operand_size); + if (mcu->operand_size) + mcu->mcu.r[opcode_reg] = t1; else { - mcu.r[opcode_reg] &= ~0xff; - mcu.r[opcode_reg] |= t1 & 0xff; + mcu->mcu.r[opcode_reg] &= ~0xff; + mcu->mcu.r[opcode_reg] |= t1 & 0xff; } } -void MCU_Opcode_SUB(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_SUB(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - int32_t t1 = mcu.r[opcode_reg]; - int32_t t2 = MCU_Operand_Read(); - t1 = MCU_SUB_Common(t1, t2, 0, operand_size); - if (operand_size) - mcu.r[opcode_reg] = t1; + int32_t t1 = mcu->mcu.r[opcode_reg]; + int32_t t2 = MCU_Operand_Read(mcu); + t1 = MCU_SUB_Common(mcu, t1, t2, 0, mcu->operand_size); + if (mcu->operand_size) + mcu->mcu.r[opcode_reg] = t1; else { - mcu.r[opcode_reg] &= ~0xff; - mcu.r[opcode_reg] |= t1 & 0xff; + mcu->mcu.r[opcode_reg] &= ~0xff; + mcu->mcu.r[opcode_reg] |= t1 & 0xff; } } -void MCU_Opcode_SUBS(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_SUBS(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - int32_t t1 = mcu.r[opcode_reg]; - int32_t t2 = MCU_Operand_Read(); - if (operand_size) - mcu.r[opcode_reg] = t1 - t2; + int32_t t1 = mcu->mcu.r[opcode_reg]; + int32_t t2 = MCU_Operand_Read(mcu); + if (mcu->operand_size) + mcu->mcu.r[opcode_reg] = t1 - t2; else - mcu.r[opcode_reg] = t1 - (int8_t)t2; + mcu->mcu.r[opcode_reg] = t1 - (int8_t)t2; } -void MCU_Opcode_AND(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_AND(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - uint32_t data = mcu.r[opcode_reg]; - data &= MCU_Operand_Read(); - if (operand_size) - mcu.r[opcode_reg] = data; + uint32_t data = mcu->mcu.r[opcode_reg]; + data &= MCU_Operand_Read(mcu); + if (mcu->operand_size) + mcu->mcu.r[opcode_reg] = data; else { - mcu.r[opcode_reg] &= ~0xff; - mcu.r[opcode_reg] |= data & 0xff; + mcu->mcu.r[opcode_reg] &= ~0xff; + mcu->mcu.r[opcode_reg] |= data & 0xff; } - MCU_SetStatusCommon(mcu.r[opcode_reg], operand_size); + MCU_SetStatusCommon(mcu, mcu->mcu.r[opcode_reg], mcu->operand_size); } -void MCU_Opcode_SHLR(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_SHLR(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - if (opcode_reg == 0x03 && operand_type != GENERAL_IMMEDIATE) // SHLR + if (opcode_reg == 0x03 && mcu->operand_type != GENERAL_IMMEDIATE) // SHLR { - uint32_t data = MCU_Operand_Read(); + uint32_t data = MCU_Operand_Read(mcu); uint32_t C = data & 1; data >>= 1; - MCU_Operand_Write(data); - MCU_SetStatus(C, STATUS_C); - MCU_SetStatusCommon(data, operand_size); + MCU_Operand_Write(mcu, data); + mcu->MCU_SetStatus(C, STATUS_C); + MCU_SetStatusCommon(mcu, data, mcu->operand_size); } - else if (opcode_reg == 0x02 && operand_type != GENERAL_IMMEDIATE) // SHLL + else if (opcode_reg == 0x02 && mcu->operand_type != GENERAL_IMMEDIATE) // SHLL { - uint32_t data = MCU_Operand_Read(); + uint32_t data = MCU_Operand_Read(mcu); uint32_t C; - if (operand_size) + if (mcu->operand_size) C = (data & 0x8000) != 0; else C = (data & 0x80) != 0; data <<= 1; - MCU_Operand_Write(data); - MCU_SetStatus(C, STATUS_C); - MCU_SetStatusCommon(data, operand_size); + MCU_Operand_Write(mcu, data); + mcu->MCU_SetStatus(C, STATUS_C); + MCU_SetStatusCommon(mcu, data, mcu->operand_size); } - else if (opcode_reg == 0x06 && operand_type != GENERAL_IMMEDIATE) // ROTXL + else if (opcode_reg == 0x06 && mcu->operand_type != GENERAL_IMMEDIATE) // ROTXL { - uint32_t data = MCU_Operand_Read(); - uint32_t bit = (mcu.sr & STATUS_C) != 0; + uint32_t data = MCU_Operand_Read(mcu); + uint32_t bit = (mcu->mcu.sr & STATUS_C) != 0; uint32_t C; - if (operand_size) + if (mcu->operand_size) C = (data & 0x8000) != 0; else C = (data & 0x80) != 0; data <<= 1; data |= bit; - MCU_Operand_Write(data); - MCU_SetStatus(C, STATUS_C); - MCU_SetStatusCommon(data, operand_size); + MCU_Operand_Write(mcu, data); + mcu->MCU_SetStatus(C, STATUS_C); + MCU_SetStatusCommon(mcu, data, mcu->operand_size); } - else if (opcode_reg == 0x04 && operand_type != GENERAL_IMMEDIATE) // ROTL + else if (opcode_reg == 0x04 && mcu->operand_type != GENERAL_IMMEDIATE) // ROTL { - uint32_t data = MCU_Operand_Read(); + uint32_t data = MCU_Operand_Read(mcu); uint32_t C; - if (operand_size) + if (mcu->operand_size) C = (data & 0x8000) != 0; else C = (data & 0x80) != 0; data <<= 1; data |= C; - MCU_Operand_Write(data); - MCU_SetStatus(C, STATUS_C); - MCU_SetStatusCommon(data, operand_size); + MCU_Operand_Write(mcu, data); + mcu->MCU_SetStatus(C, STATUS_C); + MCU_SetStatusCommon(mcu, data, mcu->operand_size); } - else if (opcode_reg == 0x00 && operand_type != GENERAL_IMMEDIATE) // SHAL + else if (opcode_reg == 0x00 && mcu->operand_type != GENERAL_IMMEDIATE) // SHAL { - uint32_t data = MCU_Operand_Read(); + uint32_t data = MCU_Operand_Read(mcu); uint32_t C; - if (operand_size) + if (mcu->operand_size) C = (data & 0x8000) != 0; else C = (data & 0x80) != 0; data <<= 1; - MCU_Operand_Write(data); - MCU_SetStatus(C, STATUS_C); - MCU_SetStatusCommon(data, operand_size); + MCU_Operand_Write(mcu, data); + mcu->MCU_SetStatus(C, STATUS_C); + MCU_SetStatusCommon(mcu, data, mcu->operand_size); } else { - MCU_ErrorTrap(); + mcu->MCU_ErrorTrap(); } } -void MCU_Opcode_MULXU(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_MULXU(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - uint32_t t1 = MCU_Operand_Read(); - uint32_t t2 = mcu.r[opcode_reg]; + uint32_t t1 = MCU_Operand_Read(mcu); + uint32_t t2 = mcu->mcu.r[opcode_reg]; uint32_t N, Z; - if (!operand_size) + if (!mcu->operand_size) t2 &= 0xff; t1 *= t2; - if (operand_size) + if (mcu->operand_size) { opcode_reg &= ~1; - mcu.r[opcode_reg | 0] = t1 >> 16; - mcu.r[opcode_reg | 1] = t1; + mcu->mcu.r[opcode_reg | 0] = t1 >> 16; + mcu->mcu.r[opcode_reg | 1] = t1; N = (t1 & 0x80000000UL) != 0; // FIXME } else { t1 &= 0xffff; - mcu.r[opcode_reg] = t1; + mcu->mcu.r[opcode_reg] = t1; N = (t1 & 0x8000UL) != 0; // FIXME } Z = t1 == 0; - MCU_SetStatus(N, STATUS_N); - MCU_SetStatus(Z, STATUS_Z); - MCU_SetStatus(0, STATUS_V); - MCU_SetStatus(0, STATUS_C); + mcu->MCU_SetStatus(N, STATUS_N); + mcu->MCU_SetStatus(Z, STATUS_Z); + mcu->MCU_SetStatus(0, STATUS_V); + mcu->MCU_SetStatus(0, STATUS_C); } -void MCU_Opcode_DIVXU(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_DIVXU(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - uint32_t t1 = MCU_Operand_Read(); + uint32_t t1 = MCU_Operand_Read(mcu); uint32_t t2; uint32_t R, Q; if (!t1) { - MCU_ErrorTrap(); // FIXME: implement proper exception - MCU_SetStatus(0, STATUS_N); - MCU_SetStatus(1, STATUS_Z); - MCU_SetStatus(0, STATUS_V); - MCU_SetStatus(0, STATUS_C); + mcu->MCU_ErrorTrap(); // FIXME: implement proper exception + mcu->MCU_SetStatus(0, STATUS_N); + mcu->MCU_SetStatus(1, STATUS_Z); + mcu->MCU_SetStatus(0, STATUS_V); + mcu->MCU_SetStatus(0, STATUS_C); return; } - if (operand_size) + if (mcu->operand_size) { opcode_reg &= ~1; - t2 = mcu.r[opcode_reg | 0] << 16; - t2 |= mcu.r[opcode_reg | 1]; + t2 = mcu->mcu.r[opcode_reg | 0] << 16; + t2 |= mcu->mcu.r[opcode_reg | 1]; R = t2 % t1; Q = t2 / t1; if (Q > UINT16_MAX) { - MCU_SetStatus(0, STATUS_N); - MCU_SetStatus(0, STATUS_Z); - MCU_SetStatus(1, STATUS_V); - MCU_SetStatus(0, STATUS_C); + mcu->MCU_SetStatus(0, STATUS_N); + mcu->MCU_SetStatus(0, STATUS_Z); + mcu->MCU_SetStatus(1, STATUS_V); + mcu->MCU_SetStatus(0, STATUS_C); } else { - mcu.r[opcode_reg | 0] = R; - mcu.r[opcode_reg | 1] = Q; - MCU_SetStatusCommon(Q, OPERAND_WORD); - MCU_SetStatus(0, STATUS_C); + mcu->mcu.r[opcode_reg | 0] = R; + mcu->mcu.r[opcode_reg | 1] = Q; + MCU_SetStatusCommon(mcu, Q, OPERAND_WORD); + mcu->MCU_SetStatus(0, STATUS_C); } } else { - t2 = mcu.r[opcode_reg]; + t2 = mcu->mcu.r[opcode_reg]; R = t2 % t1; Q = t2 / t1; if (Q > UINT8_MAX) { - MCU_SetStatus(0, STATUS_N); - MCU_SetStatus(0, STATUS_Z); - MCU_SetStatus(1, STATUS_V); - MCU_SetStatus(0, STATUS_C); + mcu->MCU_SetStatus(0, STATUS_N); + mcu->MCU_SetStatus(0, STATUS_Z); + mcu->MCU_SetStatus(1, STATUS_V); + mcu->MCU_SetStatus(0, STATUS_C); } else { R &= 0xff; Q &= 0xff; - mcu.r[opcode_reg] = (R << 8) | Q; - MCU_SetStatusCommon(Q, OPERAND_BYTE); - MCU_SetStatus(0, STATUS_C); + mcu->mcu.r[opcode_reg] = (R << 8) | Q; + MCU_SetStatusCommon(mcu, Q, OPERAND_BYTE); + mcu->MCU_SetStatus(0, STATUS_C); } } } -void MCU_Opcode_ADDS(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_ADDS(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - uint32_t data = MCU_Operand_Read(); - if (!operand_size) + uint32_t data = MCU_Operand_Read(mcu); + if (!mcu->operand_size) data = (int8_t)data; - mcu.r[opcode_reg] += data; + mcu->mcu.r[opcode_reg] += data; } -void MCU_Opcode_XOR(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_XOR(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - uint32_t data = MCU_Operand_Read(); - mcu.r[opcode_reg] ^= data; - MCU_SetStatusCommon(mcu.r[opcode_reg], operand_size); + uint32_t data = MCU_Operand_Read(mcu); + mcu->mcu.r[opcode_reg] ^= data; + MCU_SetStatusCommon(mcu, mcu->mcu.r[opcode_reg], mcu->operand_size); } -void MCU_Opcode_ADDX(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_ADDX(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - int32_t t1 = mcu.r[opcode_reg]; - int32_t t2 = MCU_Operand_Read(); - int32_t C = (mcu.sr & STATUS_C) != 0; - int32_t Z = (mcu.sr & STATUS_Z) != 0; - t1 = MCU_ADD_Common(t1, t2, C, operand_size); + int32_t t1 = mcu->mcu.r[opcode_reg]; + int32_t t2 = MCU_Operand_Read(mcu); + int32_t C = (mcu->mcu.sr & STATUS_C) != 0; + int32_t Z = (mcu->mcu.sr & STATUS_Z) != 0; + t1 = MCU_ADD_Common(mcu, t1, t2, C, mcu->operand_size); if (!Z) - MCU_SetStatus(0, STATUS_Z); + mcu->MCU_SetStatus(0, STATUS_Z); - if (operand_size) - mcu.r[opcode_reg] = t1; + if (mcu->operand_size) + mcu->mcu.r[opcode_reg] = t1; else { - mcu.r[opcode_reg] &= ~0xff; - mcu.r[opcode_reg] |= t1 & 0xff; + mcu->mcu.r[opcode_reg] &= ~0xff; + mcu->mcu.r[opcode_reg] |= t1 & 0xff; } } -void MCU_Opcode_SUBX(uint8_t opcode, uint8_t opcode_reg) +void MCU_Opcode_SUBX(MCU *mcu, uint8_t opcode, uint8_t opcode_reg) { - int32_t t1 = mcu.r[opcode_reg]; - int32_t t2 = MCU_Operand_Read(); - int32_t C = (mcu.sr & STATUS_C) != 0; - t1 = MCU_SUB_Common(t1, t2, C, operand_size); - if (operand_size) - mcu.r[opcode_reg] = t1; + int32_t t1 = mcu->mcu.r[opcode_reg]; + int32_t t2 = MCU_Operand_Read(mcu); + int32_t C = (mcu->mcu.sr & STATUS_C) != 0; + t1 = MCU_SUB_Common(mcu, t1, t2, C, mcu->operand_size); + if (mcu->operand_size) + mcu->mcu.r[opcode_reg] = t1; else { - mcu.r[opcode_reg] &= ~0xff; - mcu.r[opcode_reg] |= t1 & 0xff; + mcu->mcu.r[opcode_reg] &= ~0xff; + mcu->mcu.r[opcode_reg] |= t1 & 0xff; } } -void (*MCU_Operand_Table[256])(uint8_t operand) = { +void (*MCU_Operand_Table[256])(MCU *_this, uint8_t operand) = { MCU_Operand_Nop, // 00 MCU_Jump_JMP, // 01 MCU_LDM, // 02 @@ -1620,7 +1611,7 @@ void (*MCU_Operand_Table[256])(uint8_t operand) = { MCU_Operand_General, // FF }; -void (*MCU_Opcode_Table[32])(uint8_t opcode, uint8_t opcode_reg) = { +void (*MCU_Opcode_Table[32])(MCU *_this, uint8_t opcode, uint8_t opcode_reg) = { MCU_Opcode_MOVG_Immediate, // 00 MCU_Opcode_ADDQ, // 01 MCU_Opcode_CLR, // 02 diff --git a/src/mcu_opcodes.h b/src/mcu_opcodes.h index 5b703002..1d06c76e 100644 --- a/src/mcu_opcodes.h +++ b/src/mcu_opcodes.h @@ -35,5 +35,7 @@ #include -extern void (*MCU_Operand_Table[256])(uint8_t operand); -extern void (*MCU_Opcode_Table[32])(uint8_t opcode, uint8_t opcode_reg); +struct MCU; + +extern void (*MCU_Operand_Table[256])(MCU *_this, uint8_t operand); +extern void (*MCU_Opcode_Table[32])(MCU *_this, uint8_t opcode, uint8_t opcode_reg); diff --git a/src/mcu_timer.cpp b/src/mcu_timer.cpp index d6f51f53..6db9bc09 100644 --- a/src/mcu_timer.cpp +++ b/src/mcu_timer.cpp @@ -36,12 +36,6 @@ #include "mcu.h" #include "mcu_timer.h" -uint64_t timer_cycles; -uint8_t timer_tempreg; - -frt_t frt[3]; -mcu_timer_t timer; - enum { REG_TCR = 0x00, REG_TCSR = 0x01, @@ -55,7 +49,7 @@ enum { REG_ICRL = 0x09, }; -void TIMER_Reset(void) +void MCU_Timer::TIMER_Reset(void) { timer_cycles = 0; timer_tempreg = 0; @@ -63,7 +57,7 @@ void TIMER_Reset(void) memset(&timer, 0, sizeof(timer)); } -void TIMER_Write(uint32_t address, uint8_t data) +void MCU_Timer::TIMER_Write(uint32_t address, uint8_t data) { uint32_t t = (address >> 4) - 1; if (t > 2) @@ -82,19 +76,19 @@ void TIMER_Write(uint32_t address, uint8_t data) { timer->tcsr &= ~0x10; timer->status_rd &= ~0x10; - MCU_Interrupt_SetRequest(INTERRUPT_SOURCE_FRT0_FOVI + t * 4, 0); + MCU_Interrupt_SetRequest(mcu, INTERRUPT_SOURCE_FRT0_FOVI + t * 4, 0); } if ((data & 0x20) == 0 && (timer->status_rd & 0x20) != 0) { timer->tcsr &= ~0x20; timer->status_rd &= ~0x20; - MCU_Interrupt_SetRequest(INTERRUPT_SOURCE_FRT0_OCIA + t * 4, 0); + MCU_Interrupt_SetRequest(mcu, INTERRUPT_SOURCE_FRT0_OCIA + t * 4, 0); } if ((data & 0x40) == 0 && (timer->status_rd & 0x40) != 0) { timer->tcsr &= ~0x40; timer->status_rd &= ~0x40; - MCU_Interrupt_SetRequest(INTERRUPT_SOURCE_FRT0_OCIB + t * 4, 0); + MCU_Interrupt_SetRequest(mcu, INTERRUPT_SOURCE_FRT0_OCIB + t * 4, 0); } break; case REG_FRCH: @@ -118,7 +112,7 @@ void TIMER_Write(uint32_t address, uint8_t data) } } -uint8_t TIMER_Read(uint32_t address) +uint8_t MCU_Timer::TIMER_Read(uint32_t address) { uint32_t t = (address >> 4) - 1; if (t > 2) @@ -157,7 +151,7 @@ uint8_t TIMER_Read(uint32_t address) return 0xff; } -void TIMER2_Write(uint32_t address, uint8_t data) +void MCU_Timer::TIMER2_Write(uint32_t address, uint8_t data) { switch (address) { @@ -171,19 +165,19 @@ void TIMER2_Write(uint32_t address, uint8_t data) { timer.tcsr &= ~0x20; timer.status_rd &= ~0x20; - MCU_Interrupt_SetRequest(INTERRUPT_SOURCE_TIMER_OVI, 0); + MCU_Interrupt_SetRequest(mcu, INTERRUPT_SOURCE_TIMER_OVI, 0); } if ((data & 0x40) == 0 && (timer.status_rd & 0x40) != 0) { timer.tcsr &= ~0x40; timer.status_rd &= ~0x40; - MCU_Interrupt_SetRequest(INTERRUPT_SOURCE_TIMER_CMIA, 0); + MCU_Interrupt_SetRequest(mcu, INTERRUPT_SOURCE_TIMER_CMIA, 0); } if ((data & 0x80) == 0 && (timer.status_rd & 0x80) != 0) { timer.tcsr &= ~0x80; timer.status_rd &= ~0x80; - MCU_Interrupt_SetRequest(INTERRUPT_SOURCE_TIMER_CMIB, 0); + MCU_Interrupt_SetRequest(mcu, INTERRUPT_SOURCE_TIMER_CMIB, 0); } break; case DEV_TMR_TCORA: @@ -197,7 +191,7 @@ void TIMER2_Write(uint32_t address, uint8_t data) break; } } -uint8_t TIMER_Read2(uint32_t address) +uint8_t MCU_Timer::TIMER_Read2(uint32_t address) { switch (address) { @@ -219,7 +213,7 @@ uint8_t TIMER_Read2(uint32_t address) return 0xff; } -void TIMER_Clock(uint64_t cycles) +void MCU_Timer::TIMER_Clock(uint64_t cycles) { uint32_t i; while (timer_cycles*2 < cycles) // FIXME @@ -268,11 +262,11 @@ void TIMER_Clock(uint64_t cycles) if (matchb) timer->tcsr |= 0x40; if ((timer->tcr & 0x10) != 0 && (timer->tcsr & 0x10) != 0) - MCU_Interrupt_SetRequest(INTERRUPT_SOURCE_FRT0_FOVI + i * 4, 1); + MCU_Interrupt_SetRequest(mcu, INTERRUPT_SOURCE_FRT0_FOVI + i * 4, 1); if ((timer->tcr & 0x20) != 0 && (timer->tcsr & 0x20) != 0) - MCU_Interrupt_SetRequest(INTERRUPT_SOURCE_FRT0_OCIA + i * 4, 1); + MCU_Interrupt_SetRequest(mcu, INTERRUPT_SOURCE_FRT0_OCIA + i * 4, 1); if ((timer->tcr & 0x40) != 0 && (timer->tcsr & 0x40) != 0) - MCU_Interrupt_SetRequest(INTERRUPT_SOURCE_FRT0_OCIB + i * 4, 1); + MCU_Interrupt_SetRequest(mcu, INTERRUPT_SOURCE_FRT0_OCIB + i * 4, 1); } int32_t timer_step = 0; @@ -324,11 +318,11 @@ void TIMER_Clock(uint64_t cycles) if (matchb) timer.tcsr |= 0x80; if ((timer.tcr & 0x20) != 0 && (timer.tcsr & 0x20) != 0) - MCU_Interrupt_SetRequest(INTERRUPT_SOURCE_TIMER_OVI, 1); + MCU_Interrupt_SetRequest(mcu, INTERRUPT_SOURCE_TIMER_OVI, 1); if ((timer.tcr & 0x40) != 0 && (timer.tcsr & 0x40) != 0) - MCU_Interrupt_SetRequest(INTERRUPT_SOURCE_TIMER_CMIA, 1); + MCU_Interrupt_SetRequest(mcu, INTERRUPT_SOURCE_TIMER_CMIA, 1); if ((timer.tcr & 0x80) != 0 && (timer.tcsr & 0x80) != 0) - MCU_Interrupt_SetRequest(INTERRUPT_SOURCE_TIMER_CMIB, 1); + MCU_Interrupt_SetRequest(mcu, INTERRUPT_SOURCE_TIMER_CMIB, 1); } timer_cycles++; diff --git a/src/mcu_timer.h b/src/mcu_timer.h index 41e0eb1d..02560d92 100644 --- a/src/mcu_timer.h +++ b/src/mcu_timer.h @@ -53,10 +53,24 @@ struct mcu_timer_t { uint8_t status_rd; }; -void TIMER_Write(uint32_t address, uint8_t data); -uint8_t TIMER_Read(uint32_t address); -void TIMER_Clock(uint64_t cycles); +struct MCU; -void TIMER2_Write(uint32_t address, uint8_t data); -uint8_t TIMER_Read2(uint32_t address); +struct MCU_Timer { + MCU *mcu; + MCU_Timer(MCU *mcu): mcu(mcu) {} + + uint64_t timer_cycles; + uint8_t timer_tempreg; + + frt_t frt[3]; + mcu_timer_t timer; + + void TIMER_Reset(void); + void TIMER_Write(uint32_t address, uint8_t data); + uint8_t TIMER_Read(uint32_t address); + void TIMER_Clock(uint64_t cycles); + + void TIMER2_Write(uint32_t address, uint8_t data); + uint8_t TIMER_Read2(uint32_t address); +}; diff --git a/src/midi.h b/src/midi.h deleted file mode 100644 index 94366205..00000000 --- a/src/midi.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2021, 2024 nukeykt - * - * Redistribution and use of this code or any derivative works are permitted - * provided that the following conditions are met: - * - * - Redistributions may not be sold, nor may they be used in a commercial - * product or activity. - * - * - Redistributions that are modified from the original source must include the - * complete source code, including the source code for all components used by a - * binary built from the modified sources. However, as a special exception, the - * source code distributed need not include anything that is normally distributed - * (in either source or binary form) with the major components (compiler, kernel, - * and so on) of the operating system on which the executable runs, unless that - * component itself accompanies the executable. - * - * - Redistributions must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#pragma once - -int MIDI_Init(int port); -void MIDI_Quit(void); - diff --git a/src/midi_rtmidi.cpp b/src/midi_rtmidi.cpp deleted file mode 100644 index 9a28afc5..00000000 --- a/src/midi_rtmidi.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include "mcu.h" -#include "submcu.h" -#include "midi.h" -#include - -static RtMidiIn *s_midi_in = nullptr; - - -static void MidiOnReceive(double, std::vector *message, void *) -{ - uint8_t *beg = message->data(); - uint8_t *end = message->data() + message->size(); - - while(beg < end) - SM_PostUART(*beg++); -} - -static void MidiOnError(RtMidiError::Type, const std::string &errorText, void *) -{ - fprintf(stderr, "RtMidi: Error has occured: %s\n", errorText.c_str()); - fflush(stderr); -} - -int MIDI_Init(int port) -{ - if (s_midi_in) - { - printf("MIDI already running\n"); - return 0; // Already running - } - - s_midi_in = new RtMidiIn(RtMidi::UNSPECIFIED, "Nuked SC55", 1024); - s_midi_in->setCallback(&MidiOnReceive, nullptr); // FIXME: (local bug) Fix the linking error - s_midi_in->setErrorCallback(&MidiOnError, nullptr); - - unsigned count = s_midi_in->getPortCount(); - - if (count == 0) - { - printf("No midi input\n"); - delete s_midi_in; - s_midi_in = nullptr; - return 0; - } - - if (port < 0 || port >= count) - { - printf("Out of range midi port is requested. Defaulting to port 0\n"); - port = 0; - } - - s_midi_in->openPort(port, "Nuked SC55"); - - return 1; -} - -void MIDI_Quit() -{ - if (s_midi_in) - { - s_midi_in->closePort(); - delete s_midi_in; - s_midi_in = nullptr; - } -} diff --git a/src/midi_win32.cpp b/src/midi_win32.cpp deleted file mode 100644 index 1a0d1459..00000000 --- a/src/midi_win32.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2021, 2024 nukeykt - * - * Redistribution and use of this code or any derivative works are permitted - * provided that the following conditions are met: - * - * - Redistributions may not be sold, nor may they be used in a commercial - * product or activity. - * - * - Redistributions that are modified from the original source must include the - * complete source code, including the source code for all components used by a - * binary built from the modified sources. However, as a special exception, the - * source code distributed need not include anything that is normally distributed - * (in either source or binary form) with the major components (compiler, kernel, - * and so on) of the operating system on which the executable runs, unless that - * component itself accompanies the executable. - * - * - Redistributions must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#include -#define WIN32_LEAN_AND_MEAN -#include -#include -#include "mcu.h" -#include "submcu.h" -#include "midi.h" - -static HMIDIIN midi_handle; -static MIDIHDR midi_buffer; - -static char midi_in_buffer[1024]; - -void CALLBACK MIDI_Callback( - HMIDIIN hMidiIn, - UINT wMsg, - DWORD_PTR dwInstance, - DWORD_PTR dwParam1, - DWORD_PTR dwParam2 -) -{ - switch (wMsg) - { - case MIM_OPEN: - break; - case MIM_DATA: - { - int b1 = dwParam1 & 0xff; - switch (b1 & 0xf0) - { - case 0x80: - case 0x90: - case 0xa0: - case 0xb0: - case 0xe0: - SM_PostUART(b1); - SM_PostUART((dwParam1 >> 8) & 0xff); - SM_PostUART((dwParam1 >> 16) & 0xff); - break; - case 0xc0: - case 0xd0: - SM_PostUART(b1); - SM_PostUART((dwParam1 >> 8) & 0xff); - break; - } - break; - } - case MIM_LONGDATA: - case MIM_LONGERROR: - { - midiInUnprepareHeader(midi_handle, &midi_buffer, sizeof(MIDIHDR)); - - if (wMsg == MIM_LONGDATA) - { - for (int i = 0; i < midi_buffer.dwBytesRecorded; i++) - { - SM_PostUART(midi_in_buffer[i]); - } - } - - midiInPrepareHeader(midi_handle, &midi_buffer, sizeof(MIDIHDR)); - midiInAddBuffer(midi_handle, &midi_buffer, sizeof(MIDIHDR)); - - break; - } - default: - printf("hmm"); - break; - } -} - -int MIDI_Init(int port) -{ - int num = midiInGetNumDevs(); - - if (num == 0) - { - printf("No midi input\n"); - return 0; - } - - if (port < 0 || port >= num) - { - printf("Out of range midi port is requested. Defaulting to port 0\n"); - port = 0; - } - - MIDIINCAPSA caps; - - midiInGetDevCapsA(0, &caps, sizeof(MIDIINCAPSA)); - - auto res = midiInOpen(&midi_handle, port, (DWORD_PTR)MIDI_Callback, 0, CALLBACK_FUNCTION); - - if (res != MMSYSERR_NOERROR) - { - printf("Can't open midi input\n"); - return 0; - } - - printf("Opened midi port: %s\n", caps.szPname); - - midi_buffer.lpData = midi_in_buffer; - midi_buffer.dwBufferLength = sizeof(midi_in_buffer); - - auto r1 = midiInPrepareHeader(midi_handle, &midi_buffer, sizeof(MIDIHDR)); - auto r2 = midiInAddBuffer(midi_handle, &midi_buffer, sizeof(MIDIHDR)); - auto r3 = midiInStart(midi_handle); - - return 1; -} - -void MIDI_Quit() -{ - if (midi_handle) - { - midiInStop(midi_handle); - midiInClose(midi_handle); - midi_handle = 0; - } -} diff --git a/src/pcm.cpp b/src/pcm.cpp index 213d78c3..49b7e7d2 100644 --- a/src/pcm.cpp +++ b/src/pcm.cpp @@ -38,12 +38,9 @@ #include "mcu_interrupt.h" #include "pcm.h" -pcm_t pcm; -uint8_t waverom1[0x200000]; -uint8_t waverom2[0x100000]; -uint8_t waverom3[0x100000]; +Pcm::Pcm(MCU *mcu): mcu(mcu) {} -uint8_t PCM_ReadROM(uint32_t address) +uint8_t Pcm::PCM_ReadROM(uint32_t address) { int bank; if (pcm.config_reg_3d & 0x20) @@ -53,7 +50,7 @@ uint8_t PCM_ReadROM(uint32_t address) switch (bank) { case 0: - if (mcu_mk1) + if (mcu->mcu_mk1) return waverom1[address & 0xfffff]; else return waverom1[address & 0x1fffff]; @@ -67,7 +64,7 @@ uint8_t PCM_ReadROM(uint32_t address) return 0; } -void PCM_Write(uint32_t address, uint8_t data) +void Pcm::PCM_Write(uint32_t address, uint8_t data) { address &= 0x3f; if (address < 0x4) // voice enable @@ -181,7 +178,7 @@ void PCM_Write(uint32_t address, uint8_t data) // rv: [30][2], [30][3] // ch: [31][2], [31][5] -uint8_t PCM_Read(uint32_t address) +uint8_t Pcm::PCM_Read(uint32_t address) { address &= 0x3f; //printf("PCM Read: %.2x\n", address); @@ -198,7 +195,7 @@ uint8_t PCM_Read(uint32_t address) if (address == 0x3e && pcm.irq_assert) { pcm.irq_assert = 0; - MCU_Interrupt_SetRequest(INTERRUPT_SOURCE_IRQ0, 0); + MCU_Interrupt_SetRequest(mcu, INTERRUPT_SOURCE_IRQ0, 0); } status |= pcm.irq_channel; @@ -253,7 +250,7 @@ uint8_t PCM_Read(uint32_t address) return 0; } -void PCM_Reset(void) +void Pcm::PCM_Reset(void) { memset(&pcm, 0, sizeof(pcm)); } @@ -312,7 +309,7 @@ static const int interp_lut[3][128] = { 484, 497, 510, 523, 536, 549, 563, 577, 591, 605, 619, 634, 648, 663, 679, 694, }; -inline void calc_tv(int e, int adjust, uint16_t *levelcur, int active, int *volmul) +inline void calc_tv(pcm_t *pcm, int e, int adjust, uint16_t *levelcur, int active, int *volmul) { // int adjust = ram2[3+e]; // int levelcur = ram2[9+e] & 0x7fff; @@ -323,7 +320,7 @@ inline void calc_tv(int e, int adjust, uint16_t *levelcur, int active, int *volm int w1 = (speed & 0xf0) == 0; int w2 = w1 || (speed & 0x10) != 0; - int w3 = pcm.nfs && + int w3 = pcm->nfs && ((speed & 0x80) == 0 || ((speed & 0x40) == 0 && (!w2 || (speed & 0x20) == 0))); int type = w2 | (w3 << 3); @@ -337,13 +334,13 @@ inline void calc_tv(int e, int adjust, uint16_t *levelcur, int active, int *volm int addlow = 0; if (type & 4) { - if (pcm.tv_counter & 8) + if (pcm->tv_counter & 8) addlow |= 1; - if (pcm.tv_counter & 4) + if (pcm->tv_counter & 4) addlow |= 2; - if (pcm.tv_counter & 2) + if (pcm->tv_counter & 2) addlow |= 4; - if (pcm.tv_counter & 1) + if (pcm->tv_counter & 1) addlow |= 8; write |= 1; } @@ -352,48 +349,48 @@ inline void calc_tv(int e, int adjust, uint16_t *levelcur, int active, int *volm switch (type & 3) { case 0: - if (pcm.tv_counter & 0x20) + if (pcm->tv_counter & 0x20) addlow |= 1; - if (pcm.tv_counter & 0x10) + if (pcm->tv_counter & 0x10) addlow |= 2; - if (pcm.tv_counter & 8) + if (pcm->tv_counter & 8) addlow |= 4; - if (pcm.tv_counter & 4) + if (pcm->tv_counter & 4) addlow |= 8; - write |= (pcm.tv_counter & 3) == 0; + write |= (pcm->tv_counter & 3) == 0; break; case 1: - if (pcm.tv_counter & 0x80) + if (pcm->tv_counter & 0x80) addlow |= 1; - if (pcm.tv_counter & 0x40) + if (pcm->tv_counter & 0x40) addlow |= 2; - if (pcm.tv_counter & 0x20) + if (pcm->tv_counter & 0x20) addlow |= 4; - if (pcm.tv_counter & 0x10) + if (pcm->tv_counter & 0x10) addlow |= 8; - write |= (pcm.tv_counter & 15) == 0; + write |= (pcm->tv_counter & 15) == 0; break; case 2: - if (pcm.tv_counter & 0x200) + if (pcm->tv_counter & 0x200) addlow |= 1; - if (pcm.tv_counter & 0x100) + if (pcm->tv_counter & 0x100) addlow |= 2; - if (pcm.tv_counter & 0x80) + if (pcm->tv_counter & 0x80) addlow |= 4; - if (pcm.tv_counter & 0x40) + if (pcm->tv_counter & 0x40) addlow |= 8; - write |= (pcm.tv_counter & 63) == 0; + write |= (pcm->tv_counter & 63) == 0; break; case 3: - if (pcm.tv_counter & 0x800) + if (pcm->tv_counter & 0x800) addlow |= 1; - if (pcm.tv_counter & 0x400) + if (pcm->tv_counter & 0x400) addlow |= 2; - if (pcm.tv_counter & 0x200) + if (pcm->tv_counter & 0x200) addlow |= 4; - if (pcm.tv_counter & 0x100) + if (pcm->tv_counter & 0x100) addlow |= 8; - write |= (pcm.tv_counter & 127) == 0; + write |= (pcm->tv_counter & 127) == 0; break; } } @@ -414,7 +411,7 @@ inline void calc_tv(int e, int adjust, uint16_t *levelcur, int active, int *volm shifted -= sum1; int sum2 = (target << 11) + addlow + shifted; - if (write && pcm.nfs) + if (write && pcm->nfs) *levelcur = (sum2 >> 4) & 0x7fff; if (e == 0) @@ -454,7 +451,7 @@ inline void calc_tv(int e, int adjust, uint16_t *levelcur, int active, int *volm int neg2 = (sum3 & 0x80000) != 0; int xnor = !(neg2 ^ neg); - if (write && pcm.nfs) + if (write && pcm->nfs) { if (xnor) *levelcur = sum2_l & 0x7fff; @@ -476,10 +473,10 @@ inline void calc_tv(int e, int adjust, uint16_t *levelcur, int active, int *volm } } -inline int eram_unpack(int addr, int type = 0) +inline int eram_unpack(pcm_t *pcm, int addr, int type = 0) { addr &= 0x3fff; - int data = pcm.eram[addr]; + int data = pcm->eram[addr]; int val = data & 0x3fff; int sh = (data >> 14) & 3; @@ -487,7 +484,7 @@ inline int eram_unpack(int addr, int type = 0) return val >> (18 - sh * 2 + type); } -inline void eram_pack(int addr, int val) +inline void eram_pack(pcm_t *pcm, int addr, int val) { addr &= 0x3fff; int sh = 0; @@ -505,10 +502,10 @@ inline void eram_pack(int addr, int val) int data = (val >> (sh * 2)) & 0x3fff; data |= sh << 14; - pcm.eram[addr] = data; + pcm->eram[addr] = data; } -void PCM_Update(uint64_t cycles) +void Pcm::PCM_Update(uint64_t cycles) { int reg_slots = (pcm.config_reg_3d & 31) + 1; int voice_active = pcm.voice_mask & pcm.voice_mask_pending; @@ -597,7 +594,7 @@ void PCM_Update(uint64_t cycles) tt[0] = (int)((pcm.ram1[30][2] & ~write_mask) << 12); tt[1] = (int)((pcm.ram1[30][4] & ~write_mask) << 12); - MCU_PostSample(tt); + mcu->MCU_PostSample(tt); xr = ((shifter >> 0) ^ (shifter >> 1) ^ (shifter >> 7) ^ (shifter >> 12)) & 1; shifter = (shifter >> 1) | (xr << 15); @@ -622,7 +619,7 @@ void PCM_Update(uint64_t cycles) tt[0] = (int)((pcm.ram1[30][3] & ~write_mask) << 12); tt[1] = (int)((pcm.ram1[30][5] & ~write_mask) << 12); - MCU_PostSample(tt); + mcu->MCU_PostSample(tt); } } @@ -663,7 +660,7 @@ void PCM_Update(uint64_t cycles) int key = 1; int active = okey && key; int u = 0; - calc_tv(1, pcm.ram2[30][0], &pcm.ram2[30][9], active, &u); + calc_tv(&pcm, 1, pcm.ram2[30][0], &pcm.ram2[30][9], active, &u); } { @@ -683,8 +680,8 @@ void PCM_Update(uint64_t cycles) int v1 = pcm.ram2[30][4]; int m1 = multi(pcm.ram1[29][0], (v1 >> 8)) >> 6; int v2 = 0; - int s1 = eram_unpack(pcm.ram2[28][1] + pcm.tv_counter, 1); - int s2 = eram_unpack(pcm.ram2[28][1] + pcm.tv_counter); + int s1 = eram_unpack(&pcm, pcm.ram2[28][1] + pcm.tv_counter, 1); + int s2 = eram_unpack(&pcm, pcm.ram2[28][1] + pcm.tv_counter); if ((v1 & 0x30) != 0) { v2 = s1; @@ -698,8 +695,8 @@ void PCM_Update(uint64_t cycles) // 2 int v1 = pcm.ram2[30][4]; int v2 = 0; - int s1 = eram_unpack(pcm.ram2[28][2] + pcm.tv_counter, 1); - int s2 = eram_unpack(pcm.ram2[28][2] + pcm.tv_counter); + int s1 = eram_unpack(&pcm, pcm.ram2[28][2] + pcm.tv_counter, 1); + int s2 = eram_unpack(&pcm, pcm.ram2[28][2] + pcm.tv_counter); if ((v1 & 0x30) != 0) { v2 = s1; @@ -713,8 +710,8 @@ void PCM_Update(uint64_t cycles) // 3 int v1 = pcm.ram2[30][4]; int v2 = 0; - int s1 = eram_unpack(pcm.ram2[28][3] + pcm.tv_counter, 1); - int s2 = eram_unpack(pcm.ram2[28][3] + pcm.tv_counter); + int s1 = eram_unpack(&pcm, pcm.ram2[28][3] + pcm.tv_counter, 1); + int s2 = eram_unpack(&pcm, pcm.ram2[28][3] + pcm.tv_counter); if ((v1 & 0x30) != 0) { v2 = s1; @@ -725,14 +722,14 @@ void PCM_Update(uint64_t cycles) pcm.ram1[28][1] = addclip20(m2 >> 1, s2, m2 & 1); - pcm.ram1[28][2] = eram_unpack(pcm.ram2[28][5] + pcm.tv_counter); + pcm.ram1[28][2] = eram_unpack(&pcm, pcm.ram2[28][5] + pcm.tv_counter); } { // 4 int v1 = pcm.ram2[30][5]; int v2 = 0; - int s1 = eram_unpack(pcm.ram2[28][4] + pcm.tv_counter, 1); - int s2 = eram_unpack(pcm.ram2[28][4] + pcm.tv_counter); + int s1 = eram_unpack(&pcm, pcm.ram2[28][4] + pcm.tv_counter, 1); + int s2 = eram_unpack(&pcm, pcm.ram2[28][4] + pcm.tv_counter); if ((v1 & 0x30) != 0) { v2 = s1; @@ -743,31 +740,31 @@ void PCM_Update(uint64_t cycles) pcm.ram1[28][3] = addclip20(m2 >> 1, s2, m2 & 1); - pcm.ram1[28][4] = eram_unpack(pcm.ram2[29][1] + pcm.tv_counter); + pcm.ram1[28][4] = eram_unpack(&pcm, pcm.ram2[29][1] + pcm.tv_counter); } { // 5 int v1 = pcm.ram2[30][7]; int m1 = multi(pcm.ram1[29][2], (v1 >> 8)) >> 5; - int s1 = eram_unpack(pcm.ram2[29][0] + pcm.tv_counter); + int s1 = eram_unpack(&pcm, pcm.ram2[29][0] + pcm.tv_counter); int m2 = multi(s1, v1 & 255) >> 5; pcm.ram1[29][2] = addclip20(m1 >> 1, m2 >> 1, (m1 | m2) & 1); - eram_pack(pcm.ram2[28][0] + pcm.tv_counter, pcm.ram1[29][4]); + eram_pack(&pcm, pcm.ram2[28][0] + pcm.tv_counter, pcm.ram1[29][4]); } { // 6 int v1 = pcm.ram2[30][8]; int m1 = multi(pcm.ram1[29][3], (v1 >> 8)) >> 5; - int s1 = eram_unpack(pcm.ram2[29][8] + pcm.tv_counter); + int s1 = eram_unpack(&pcm, pcm.ram2[29][8] + pcm.tv_counter); int m2 = multi(s1, v1 & 255) >> 5; pcm.ram1[29][3] = addclip20(m1 >> 1, m2 >> 1, (m1 | m2) & 1); - eram_pack(pcm.ram2[28][1] + pcm.tv_counter, pcm.ram1[29][5]); + eram_pack(&pcm, pcm.ram2[28][1] + pcm.tv_counter, pcm.ram1[29][5]); - eram_pack(pcm.ram2[28][2] + pcm.tv_counter, pcm.ram1[28][0]); + eram_pack(&pcm, pcm.ram2[28][2] + pcm.tv_counter, pcm.ram1[28][0]); } { // 7 @@ -779,7 +776,7 @@ void PCM_Update(uint64_t cycles) pcm.ram1[28][3] = addclip20(v2, m1 >> 1, m1 & 1); pcm.ram1[28][5] = addclip20(v2, m2 >> 1, m2 & 1); - eram_pack(pcm.ram2[28][3] + pcm.tv_counter, pcm.ram1[28][1]); + eram_pack(&pcm, pcm.ram2[28][3] + pcm.tv_counter, pcm.ram1[28][1]); } { // 8 @@ -793,7 +790,7 @@ void PCM_Update(uint64_t cycles) pcm.ram1[28][2] = addclip20(pcm.ram1[28][2], m2 >> 1, m2 & 1); - pcm.ram1[28][1] = eram_unpack(pcm.ram2[28][9] + pcm.tv_counter); + pcm.ram1[28][1] = eram_unpack(&pcm, pcm.ram2[28][9] + pcm.tv_counter); } { // 9 @@ -807,7 +804,7 @@ void PCM_Update(uint64_t cycles) pcm.ram1[28][4] = addclip20(pcm.ram1[28][4], m2 >> 1, m2 & 1); - pcm.ram1[29][4] = eram_unpack(pcm.ram2[29][5] + pcm.tv_counter); + pcm.ram1[29][4] = eram_unpack(&pcm, pcm.ram2[29][5] + pcm.tv_counter); } { // 10 @@ -815,13 +812,13 @@ void PCM_Update(uint64_t cycles) int v1 = pcm.ram2[30][6]; int v2 = pcm.ram1[28][1]; int m1 = multi(v2, v1 >> 8) >> 5; - int s1 = eram_unpack(pcm.ram2[28][8] + pcm.tv_counter); + int s1 = eram_unpack(&pcm, pcm.ram2[28][8] + pcm.tv_counter); int v3 = addclip20(m1 >> 1, s1, m1 & 1); pcm.ram1[28][1] = v3; int m2 = multi(v3, v1 & 255) >> 5; pcm.ram1[29][5] = addclip20(m2 >> 1, v2, m2 & 1); - eram_pack(pcm.ram2[28][4] + pcm.tv_counter, pcm.ram1[28][3]); + eram_pack(&pcm, pcm.ram2[28][4] + pcm.tv_counter, pcm.ram1[28][3]); } { // 11 @@ -829,63 +826,63 @@ void PCM_Update(uint64_t cycles) int v1 = pcm.ram2[30][6]; int v2 = pcm.ram1[29][4]; int m1 = multi(v2, v1 >> 8) >> 5; - int s1 = eram_unpack(pcm.ram2[29][4] + pcm.tv_counter); + int s1 = eram_unpack(&pcm, pcm.ram2[29][4] + pcm.tv_counter); int v3 = addclip20(m1 >> 1, s1, m1 & 1); pcm.ram1[29][4] = v3; int m2 = multi(v3, v1 & 255) >> 5; pcm.ram1[28][0] = addclip20(m2 >> 1, v2, m2 & 1); - eram_pack(pcm.ram2[28][5] + pcm.tv_counter, pcm.ram1[28][2]); + eram_pack(&pcm, pcm.ram2[28][5] + pcm.tv_counter, pcm.ram1[28][2]); - eram_pack(pcm.ram2[29][0] + pcm.tv_counter, pcm.ram1[28][5]); + eram_pack(&pcm, pcm.ram2[29][0] + pcm.tv_counter, pcm.ram1[28][5]); } { // 12 - pcm.ram1[28][5] = eram_unpack(pcm.ram2[28][6] + pcm.tv_counter); + pcm.ram1[28][5] = eram_unpack(&pcm, pcm.ram2[28][6] + pcm.tv_counter); } { // 13 - int s1 = eram_unpack(pcm.ram2[28][10] + pcm.tv_counter); + int s1 = eram_unpack(&pcm, pcm.ram2[28][10] + pcm.tv_counter); pcm.ram1[28][5] = addclip20(pcm.ram1[28][5], s1, 0); - pcm.ram1[28][2] = eram_unpack(pcm.ram2[29][2] + pcm.tv_counter); + pcm.ram1[28][2] = eram_unpack(&pcm, pcm.ram2[29][2] + pcm.tv_counter); } { // 14 - int s1 = eram_unpack(pcm.ram2[29][6] + pcm.tv_counter); + int s1 = eram_unpack(&pcm, pcm.ram2[29][6] + pcm.tv_counter); int t1 = addclip20(s1, pcm.ram1[28][2], 0); // 6 pcm.ram1[28][5] = addclip20(t1, pcm.ram1[28][5], 0); - pcm.ram1[28][2] = eram_unpack(pcm.ram2[28][7] + pcm.tv_counter); + pcm.ram1[28][2] = eram_unpack(&pcm, pcm.ram2[28][7] + pcm.tv_counter); } { // 15 - int s1 = eram_unpack(pcm.ram2[28][11] + pcm.tv_counter); + int s1 = eram_unpack(&pcm, pcm.ram2[28][11] + pcm.tv_counter); pcm.ram1[28][2] = addclip20(pcm.ram1[28][2], s1, 0); - pcm.ram1[28][3] = eram_unpack(pcm.ram2[29][3] + pcm.tv_counter); + pcm.ram1[28][3] = eram_unpack(&pcm, pcm.ram2[29][3] + pcm.tv_counter); } { // 16 - int s1 = eram_unpack(pcm.ram2[29][7] + pcm.tv_counter); + int s1 = eram_unpack(&pcm, pcm.ram2[29][7] + pcm.tv_counter); int t1 = addclip20(s1, pcm.ram1[28][2], 0); pcm.ram1[28][2] = addclip20(t1, pcm.ram1[28][3], 0); - eram_pack(pcm.ram2[29][1] + pcm.tv_counter, pcm.ram1[28][4]); + eram_pack(&pcm, pcm.ram2[29][1] + pcm.tv_counter, pcm.ram1[28][4]); - eram_pack(pcm.ram2[28][8] + pcm.tv_counter, pcm.ram1[28][1]); + eram_pack(&pcm, pcm.ram2[28][8] + pcm.tv_counter, pcm.ram1[28][1]); } { @@ -899,8 +896,8 @@ void PCM_Update(uint64_t cycles) rcadd2[0] = multi(v2, v1 & 255) >> 5; - int t1 = eram_unpack(pcm.ram2[29][10] + pcm.tv_counter + 1); //? 3a6e - eram_pack(pcm.ram2[28][9] + pcm.tv_counter, pcm.ram1[29][5]); + int t1 = eram_unpack(&pcm, pcm.ram2[29][10] + pcm.tv_counter + 1); //? 3a6e + eram_pack(&pcm, pcm.ram2[28][9] + pcm.tv_counter, pcm.ram1[29][5]); pcm.ram1[29][5] = t1; } @@ -915,16 +912,16 @@ void PCM_Update(uint64_t cycles) rcadd2[1] = multi(v2, v1 & 255) >> 5; - pcm.ram1[28][1] = eram_unpack(pcm.ram2[29][11] + pcm.tv_counter + 1); //? 3a1e + pcm.ram1[28][1] = eram_unpack(&pcm, pcm.ram2[29][11] + pcm.tv_counter + 1); //? 3a1e } { // 19 int v1 = pcm.ram2[31][9]; - int s1 = eram_unpack(pcm.ram2[29][10] + pcm.tv_counter); //? 3a6d + int s1 = eram_unpack(&pcm, pcm.ram2[29][10] + pcm.tv_counter); //? 3a6d - eram_pack(pcm.ram2[29][4] + pcm.tv_counter, pcm.ram1[29][4]); + eram_pack(&pcm, pcm.ram2[29][4] + pcm.tv_counter, pcm.ram1[29][4]); int m1 = multi(s1, v1 >> 8) >> 5; int m2 = multi(pcm.ram1[29][5], v1 >> 8) >> 5; @@ -938,9 +935,9 @@ void PCM_Update(uint64_t cycles) int v1 = pcm.ram2[31][10]; - int s1 = eram_unpack(pcm.ram2[29][11] + pcm.tv_counter); //? 3a1d + int s1 = eram_unpack(&pcm, pcm.ram2[29][11] + pcm.tv_counter); //? 3a1d - eram_pack(pcm.ram2[29][5] + pcm.tv_counter, pcm.ram1[28][0]); + eram_pack(&pcm, pcm.ram2[29][5] + pcm.tv_counter, pcm.ram1[28][0]); int m1 = multi(s1, v1 >> 8) >> 5; int m2 = multi(pcm.ram1[28][1], v1 >> 8) >> 5; @@ -949,7 +946,7 @@ void PCM_Update(uint64_t cycles) pcm.ram1[28][1] = addclip20(t2, m2 >> 1, m2 & 1); - eram_pack(pcm.ram2[29][9] + pcm.tv_counter, pcm.ram1[29][1]); + eram_pack(&pcm, pcm.ram2[29][9] + pcm.tv_counter, pcm.ram1[29][1]); } { // 21 @@ -1384,15 +1381,15 @@ void PCM_Update(uint64_t cycles) ram2[8] |= 0x4000; pcm.irq_assert = 1; pcm.irq_channel = slot; - MCU_Interrupt_SetRequest(INTERRUPT_SOURCE_IRQ0, 1); + MCU_Interrupt_SetRequest(mcu, INTERRUPT_SOURCE_IRQ0, 1); } int volmul1 = 0; int volmul2 = 0; - calc_tv(0, ram2[3], &ram2[9], active, &volmul1); - calc_tv(1, ram2[4], &ram2[10], active, &volmul2); - calc_tv(2, ram2[5], &ram2[11], active, NULL); + calc_tv(&pcm, 0, ram2[3], &ram2[9], active, &volmul1); + calc_tv(&pcm, 1, ram2[4], &ram2[10], active, &volmul2); + calc_tv(&pcm, 2, ram2[5], &ram2[11], active, NULL); // if (volmul1 && volmul2) // volmul1 += 0; diff --git a/src/pcm.h b/src/pcm.h index e2bdbdca..709b6074 100644 --- a/src/pcm.h +++ b/src/pcm.h @@ -63,10 +63,20 @@ struct pcm_t { int rcsum[2]; }; -extern uint8_t waverom1[]; -extern uint8_t waverom2[]; +struct MCU; -void PCM_Write(uint32_t address, uint8_t data); -uint8_t PCM_Read(uint32_t address); -void PCM_Reset(void); -void PCM_Update(uint64_t cycles); +struct Pcm { + MCU *mcu; + Pcm(MCU *mcu); + + pcm_t pcm = {0}; + uint8_t waverom1[0x200000]; + uint8_t waverom2[0x100000]; + uint8_t waverom3[0x100000]; + + void PCM_Write(uint32_t address, uint8_t data); + uint8_t PCM_Read(uint32_t address); + void PCM_Reset(void); + void PCM_Update(uint64_t cycles); + uint8_t PCM_ReadROM(uint32_t address); +}; diff --git a/src/submcu.cpp b/src/submcu.cpp index 5a53a5ce..07585d3a 100644 --- a/src/submcu.cpp +++ b/src/submcu.cpp @@ -33,7 +33,7 @@ */ #include #include -#include "SDL_audio.h" +// #include "SDL_audio.h" #include "mcu.h" #include "submcu.h" @@ -78,38 +78,12 @@ enum { SM_DEV_TIMER_CTRL = 0x1f }; -uint8_t sm_rom[4096]; -uint8_t sm_ram[128]; -uint8_t sm_shared_ram[192]; -uint8_t sm_access[0x18]; - -uint8_t sm_p0_dir; -uint8_t sm_p1_dir; - -uint8_t sm_device_mode[32]; -uint8_t sm_cts; - -uint64_t sm_timer_cycles; -uint8_t sm_timer_prescaler; -uint8_t sm_timer_counter; - -submcu_t sm; - -static const uint32_t uart_buffer_size = 8192; -uint32_t uart_write_ptr; -uint32_t uart_read_ptr; -uint8_t uart_buffer[uart_buffer_size]; - -uint8_t uart_rx_gotbyte; -uint8_t uart_rx_byte; -uint64_t uart_rx_delay; - -void SM_ErrorTrap(void) +void SubMcu::SM_ErrorTrap(void) { - printf("%.4x\n", sm.pc); + printf("smtrap %.4x\n", sm.pc); } -uint8_t SM_Read(uint16_t address) +uint8_t SubMcu::SM_Read(uint16_t address) { address &= 0x1fff; if (address & 0x1000) @@ -153,7 +127,7 @@ uint8_t SM_Read(uint16_t address) return ret; } case SM_DEV_P1_DATA: - return MCU_ReadP1(); + return mcu->MCU_ReadP1(); case SM_DEV_P1_DIR: return sm_p1_dir; case SM_DEV_PRESCALER: @@ -177,7 +151,7 @@ uint8_t SM_Read(uint16_t address) } } -void SM_Write(uint16_t address, uint8_t data) +void SubMcu::SM_Write(uint16_t address, uint8_t data) { address &= 0x1fff; if (address < 0x80) @@ -190,7 +164,7 @@ void SM_Write(uint16_t address, uint8_t data) switch (address) { case SM_DEV_P1_DATA: - MCU_WriteP1(data); + mcu->MCU_WriteP1(data); break; case SM_DEV_P1_DIR: sm_p1_dir = data; @@ -221,7 +195,7 @@ void SM_Write(uint16_t address, uint8_t data) break; } if (address == SM_DEV_UART3_MODE_STATUS || address == SM_DEV_UART3_CTRL) - MCU_GA_SetGAInt(5, (sm_device_mode[SM_DEV_UART3_MODE_STATUS] & 0x80) != 0 + mcu->MCU_GA_SetGAInt(5, (sm_device_mode[SM_DEV_UART3_MODE_STATUS] & 0x80) != 0 && (sm_device_mode[SM_DEV_UART3_CTRL] & 0x20) == 0); } else if (address >= 0x200 && address < 0x2c0) @@ -236,7 +210,7 @@ void SM_Write(uint16_t address, uint8_t data) } } -void SM_SysWrite(uint32_t address, uint8_t data) +void SubMcu::SM_SysWrite(uint32_t address, uint8_t data) { address &= 0xff; if (address < 0xc0) @@ -261,11 +235,11 @@ void SM_SysWrite(uint32_t address, uint8_t data) } else if (address == 0xf5) { - MCU_WriteP1(data); + mcu->MCU_WriteP1(data); } else if (address == 0xf6) { - MCU_WriteP0(data); + mcu->MCU_WriteP0(data); } else if (address == 0xf7) { @@ -277,7 +251,7 @@ void SM_SysWrite(uint32_t address, uint8_t data) } } -uint8_t SM_SysRead(uint32_t address) +uint8_t SubMcu::SM_SysRead(uint32_t address) { address &= 0xff; if (address < 0xc0) @@ -302,11 +276,11 @@ uint8_t SM_SysRead(uint32_t address) } else if (address == 0xf5) { - return MCU_ReadP1(); + return mcu->MCU_ReadP1(); } else if (address == 0xf6) { - return MCU_ReadP0(); + return mcu->MCU_ReadP0(); } else if (address == 0xf7) { @@ -319,14 +293,14 @@ uint8_t SM_SysRead(uint32_t address) } } -uint16_t SM_GetVectorAddress(uint32_t vector) +uint16_t SubMcu::SM_GetVectorAddress(uint32_t vector) { uint16_t pc = SM_Read(0x1fec + vector * 2); pc |= SM_Read(0x1fec + vector * 2 + 1) << 8; return pc; } -void SM_SetStatus(uint32_t condition, uint32_t mask) +void SubMcu::SM_SetStatus(uint32_t condition, uint32_t mask) { if (condition) sm.sr |= mask; @@ -334,145 +308,145 @@ void SM_SetStatus(uint32_t condition, uint32_t mask) sm.sr &= ~mask; } -void SM_Reset(void) +void SubMcu::SM_Reset(void) { memset(&sm, 0, sizeof(sm)); - sm.pc = SM_GetVectorAddress(SM_VECTOR_RESET); + this->sm.pc = SM_GetVectorAddress(SM_VECTOR_RESET); } -uint8_t SM_ReadAdvance(void) +uint8_t SubMcu::SM_ReadAdvance(void) { - uint8_t byte = SM_Read(sm.pc); - sm.pc++; + uint8_t byte = SM_Read(this->sm.pc); + this->sm.pc++; return byte; } -uint16_t SM_ReadAdvance16(void) +uint16_t SubMcu::SM_ReadAdvance16(void) { uint16_t word = SM_ReadAdvance(); word |= SM_ReadAdvance() << 8; return word; } -uint16_t SM_Read16(uint16_t address) +uint16_t SubMcu::SM_Read16(uint16_t address) { uint16_t word = SM_Read(address); word |= SM_Read(address) << 8; return word; } -void SM_Update_NZ(uint8_t val) +void SubMcu::SM_Update_NZ(uint8_t val) { SM_SetStatus(val == 0, SM_STATUS_Z); SM_SetStatus(val & 0x80, SM_STATUS_N); } -void SM_PushStack(uint8_t data) +void SubMcu::SM_PushStack(uint8_t data) { SM_Write(sm.s, data); sm.s--; } -uint8_t SM_PopStack(void) +uint8_t SubMcu::SM_PopStack(void) { sm.s++; return SM_Read(sm.s); } -void SM_Opcode_NotImplemented(uint8_t opcode) +void SM_Opcode_NotImplemented(SubMcu* _this, uint8_t opcode) { - SM_ErrorTrap(); + _this->SM_ErrorTrap(); } -void SM_Opcode_SEI(uint8_t opcode) // 78 +void SM_Opcode_SEI(SubMcu* _this, uint8_t opcode) // 78 { - SM_SetStatus(1, SM_STATUS_I); + _this->SM_SetStatus(1, SM_STATUS_I); } -void SM_Opcode_CLD(uint8_t opcode) // d8 +void SM_Opcode_CLD(SubMcu* _this, uint8_t opcode) // d8 { - SM_SetStatus(0, SM_STATUS_D); + _this->SM_SetStatus(0, SM_STATUS_D); } -void SM_Opcode_CLT(uint8_t opcode) // 12 +void SM_Opcode_CLT(SubMcu* _this, uint8_t opcode) // 12 { - SM_SetStatus(0, SM_STATUS_T); + _this->SM_SetStatus(0, SM_STATUS_T); } -void SM_Opcode_LDX(uint8_t opcode) // a2, a6, ae, b6, be +void SM_Opcode_LDX(SubMcu* _this, uint8_t opcode) // a2, a6, ae, b6, be { uint8_t val = 0; switch (opcode) { case 0xa2: - val = SM_ReadAdvance(); + val = _this->SM_ReadAdvance(); break; case 0xa6: - val = SM_Read(SM_ReadAdvance()); + val = _this->SM_Read(_this->SM_ReadAdvance()); break; case 0xb6: - val = SM_Read((SM_ReadAdvance() + sm.y) & 0xff); + val = _this->SM_Read((_this->SM_ReadAdvance() + _this->sm.y) & 0xff); break; case 0xae: - val = SM_Read(SM_ReadAdvance16()); + val = _this->SM_Read(_this->SM_ReadAdvance16()); break; case 0xbe: - val = SM_Read(SM_ReadAdvance16() + sm.y); + val = _this->SM_Read(_this->SM_ReadAdvance16() + _this->sm.y); break; } - sm.x = val; - SM_Update_NZ(sm.x); + _this->sm.x = val; + _this->SM_Update_NZ(_this->sm.x); } -void SM_Opcode_TXS(uint8_t opcode) // 9a +void SM_Opcode_TXS(SubMcu* _this, uint8_t opcode) // 9a { - sm.s = sm.x; + _this->sm.s = _this->sm.x; } -void SM_Opcode_TXA(uint8_t opcode) // 8a +void SM_Opcode_TXA(SubMcu* _this, uint8_t opcode) // 8a { - sm.a = sm.x; - SM_Update_NZ(sm.a); + _this->sm.a = _this->sm.x; + _this->SM_Update_NZ(_this->sm.a); } -void SM_Opcode_STA(uint8_t opcode) // 85, 95, 8d, 9d, 99, 81, 91 +void SM_Opcode_STA(SubMcu* _this, uint8_t opcode) // 85, 95, 8d, 9d, 99, 81, 91 { uint16_t dest = 0; switch (opcode) { case 0x85: - dest = SM_ReadAdvance(); + dest = _this->SM_ReadAdvance(); break; case 0x95: - dest = SM_ReadAdvance() + sm.x; + dest = _this->SM_ReadAdvance() + _this->sm.x; break; case 0x8d: - dest = SM_ReadAdvance16(); + dest = _this->SM_ReadAdvance16(); break; case 0x9d: - dest = SM_ReadAdvance16() + sm.x; + dest = _this->SM_ReadAdvance16() + _this->sm.x; break; case 0x99: - dest = SM_ReadAdvance16() + sm.y; + dest = _this->SM_ReadAdvance16() + _this->sm.y; break; case 0x81: - dest = SM_Read16((SM_ReadAdvance() + sm.x) & 0xff); + dest = _this->SM_Read16((_this->SM_ReadAdvance() + _this->sm.x) & 0xff); break; case 0x91: - dest = SM_Read16(SM_ReadAdvance()) + sm.y; + dest = _this->SM_Read16(_this->SM_ReadAdvance()) + _this->sm.y; break; } - SM_Write(dest, sm.a); + _this->SM_Write(dest, _this->sm.a); } -void SM_Opcode_INX(uint8_t opcode) // e8 +void SM_Opcode_INX(SubMcu* _this, uint8_t opcode) // e8 { - sm.x++; - SM_Update_NZ(sm.x); + _this->sm.x++; + _this->SM_Update_NZ(_this->sm.x); } -void SM_Opcode_BBC_BBS(uint8_t opcode) +void SM_Opcode_BBC_BBS(SubMcu* _this, uint8_t opcode) { int32_t zp = (opcode & 4) != 0; int32_t bit = (opcode >> 5) & 7; @@ -481,127 +455,127 @@ void SM_Opcode_BBC_BBS(uint8_t opcode) if (!zp) { - val = sm.a; + val = _this->sm.a; } else { - val = SM_Read(SM_ReadAdvance()); + val = _this->SM_Read(_this->SM_ReadAdvance()); } - int8_t diff = SM_ReadAdvance(); + int8_t diff = _this->SM_ReadAdvance(); int32_t set = (val >> bit) & 1; if (set != type) - sm.pc += diff; + _this->sm.pc += diff; } -void SM_Opcode_CPX(uint8_t opcode) // e0, e4, ec +void SM_Opcode_CPX(SubMcu* _this, uint8_t opcode) // e0, e4, ec { uint8_t operand = 0; switch (opcode) { case 0xe0: - operand = SM_ReadAdvance(); + operand = _this->SM_ReadAdvance(); break; case 0xe4: - operand = SM_Read(SM_ReadAdvance()); + operand = _this->SM_Read(_this->SM_ReadAdvance()); break; case 0xec: - operand = SM_Read(SM_ReadAdvance16()); + operand = _this->SM_Read(_this->SM_ReadAdvance16()); break; } - int diff = sm.x - operand; - SM_SetStatus((diff & 0x100) == 0, SM_STATUS_C); - SM_Update_NZ(diff & 0xff); + int diff = _this->sm.x - operand; + _this->SM_SetStatus((diff & 0x100) == 0, SM_STATUS_C); + _this->SM_Update_NZ(diff & 0xff); } -void SM_Opcode_BEQ(uint8_t opcode) // f0 +void SM_Opcode_BEQ(SubMcu* _this, uint8_t opcode) // f0 { - int8_t diff = SM_ReadAdvance(); - if ((sm.sr & SM_STATUS_Z) != 0) - sm.pc += diff; + int8_t diff = _this->SM_ReadAdvance(); + if ((_this->sm.sr & SM_STATUS_Z) != 0) + _this->sm.pc += diff; } -void SM_Opcode_BCC(uint8_t opcode) // 90 +void SM_Opcode_BCC(SubMcu* _this, uint8_t opcode) // 90 { - int8_t diff = SM_ReadAdvance(); - if ((sm.sr & SM_STATUS_C) == 0) - sm.pc += diff; + int8_t diff = _this->SM_ReadAdvance(); + if ((_this->sm.sr & SM_STATUS_C) == 0) + _this->sm.pc += diff; } -void SM_Opcode_BCS(uint8_t opcode) // b0 +void SM_Opcode_BCS(SubMcu* _this, uint8_t opcode) // b0 { - int8_t diff = SM_ReadAdvance(); - if ((sm.sr & SM_STATUS_C) != 0) - sm.pc += diff; + int8_t diff = _this->SM_ReadAdvance(); + if ((_this->sm.sr & SM_STATUS_C) != 0) + _this->sm.pc += diff; } -void SM_Opcode_LDM(uint8_t opcode) // 3c +void SM_Opcode_LDM(SubMcu* _this, uint8_t opcode) // 3c { - uint8_t val = SM_ReadAdvance(); - SM_Write(SM_ReadAdvance(), val); + uint8_t val = _this->SM_ReadAdvance(); + _this->SM_Write(_this->SM_ReadAdvance(), val); } -void SM_Opcode_LDA(uint8_t opcode) // a9, a5, b5, ad, bd, b9, a1, b1 +void SM_Opcode_LDA(SubMcu* _this, uint8_t opcode) // a9, a5, b5, ad, bd, b9, a1, b1 { uint8_t val = 0; switch (opcode) { case 0xa9: - val = SM_ReadAdvance(); + val = _this->SM_ReadAdvance(); break; case 0xa5: - val = SM_Read(SM_ReadAdvance()); + val = _this->SM_Read(_this->SM_ReadAdvance()); break; case 0xb5: - val = SM_Read((SM_ReadAdvance() + sm.x) & 0xff); + val = _this->SM_Read((_this->SM_ReadAdvance() + _this->sm.x) & 0xff); break; case 0xad: - val = SM_Read(SM_ReadAdvance16()); + val = _this->SM_Read(_this->SM_ReadAdvance16()); break; case 0xbd: - val = SM_Read(SM_ReadAdvance16() + sm.x); + val = _this->SM_Read(_this->SM_ReadAdvance16() + _this->sm.x); break; case 0xb9: - val = SM_Read(SM_ReadAdvance16() + sm.y); + val = _this->SM_Read(_this->SM_ReadAdvance16() + _this->sm.y); break; case 0xa1: - val = SM_Read(SM_Read16((SM_ReadAdvance() + sm.x) & 0xff)); + val = _this->SM_Read(_this->SM_Read16((_this->SM_ReadAdvance() + _this->sm.x) & 0xff)); break; case 0xb1: - val = SM_Read(SM_Read16(SM_ReadAdvance()) + sm.y); + val = _this->SM_Read(_this->SM_Read16(_this->SM_ReadAdvance()) + _this->sm.y); break; } - if ((sm.sr & SM_STATUS_T) == 0) + if ((_this->sm.sr & SM_STATUS_T) == 0) { - sm.a = val; - SM_Update_NZ(val); + _this->sm.a = val; + _this->SM_Update_NZ(val); } else { // FIXME - SM_Write(sm.x, val); + _this->SM_Write(_this->sm.x, val); } } -void SM_Opcode_CLI(uint8_t opcode) // 58 +void SM_Opcode_CLI(SubMcu* _this, uint8_t opcode) // 58 { - SM_SetStatus(0, SM_STATUS_I); + _this->SM_SetStatus(0, SM_STATUS_I); } -void SM_Opcode_STP(uint8_t opcode) // 42 +void SM_Opcode_STP(SubMcu* _this, uint8_t opcode) // 42 { - sm.sleep = 1; + _this->sm.sleep = 1; } -void SM_Opcode_PHA(uint8_t opcode) // 48 +void SM_Opcode_PHA(SubMcu* _this, uint8_t opcode) // 48 { - SM_PushStack(sm.a); + _this->SM_PushStack(_this->sm.a); } -void SM_Opcode_SEB_CLB(uint8_t opcode) +void SM_Opcode_SEB_CLB(SubMcu* _this, uint8_t opcode) { int32_t zp = (opcode & 4) != 0; int32_t bit = (opcode >> 5) & 7; @@ -611,12 +585,12 @@ void SM_Opcode_SEB_CLB(uint8_t opcode) if (!zp) { - val = sm.a; + val = _this->sm.a; } else { - dest = SM_ReadAdvance(); - val = SM_Read(dest); + dest = _this->SM_ReadAdvance(); + val = _this->SM_Read(dest); } if (type) @@ -626,339 +600,339 @@ void SM_Opcode_SEB_CLB(uint8_t opcode) if (!zp) { - sm.a = val; + _this->sm.a = val; } else { - SM_Write(dest, val); + _this->SM_Write(dest, val); } } -void SM_Opcode_RTI(uint8_t opcode) // 40 +void SM_Opcode_RTI(SubMcu* _this, uint8_t opcode) // 40 { - sm.sr = SM_PopStack(); - sm.pc = SM_PopStack(); - sm.pc |= SM_PopStack() << 8; + _this->sm.sr = _this->SM_PopStack(); + _this->sm.pc = _this->SM_PopStack(); + _this->sm.pc |= _this->SM_PopStack() << 8; } -void SM_Opcode_PLA(uint8_t opcode) // 68 +void SM_Opcode_PLA(SubMcu* _this, uint8_t opcode) // 68 { - sm.a = SM_PopStack(); - SM_Update_NZ(sm.a); + _this->sm.a = _this->SM_PopStack(); + _this->SM_Update_NZ(_this->sm.a); } -void SM_Opcode_BRA(uint8_t opcode) // 80 +void SM_Opcode_BRA(SubMcu* _this, uint8_t opcode) // 80 { - int8_t disp = SM_ReadAdvance(); - sm.pc += disp; + int8_t disp = _this->SM_ReadAdvance(); + _this->sm.pc += disp; } -void SM_Opcode_JSR(uint8_t opcode) // 20, 02, 22 +void SM_Opcode_JSR(SubMcu* _this, uint8_t opcode) // 20, 02, 22 { uint16_t newpc = 0; switch (opcode) { case 0x20: - newpc = SM_ReadAdvance16(); + newpc = _this->SM_ReadAdvance16(); break; case 0x02: - newpc = SM_Read16(SM_ReadAdvance()); + newpc = _this->SM_Read16(_this->SM_ReadAdvance()); break; case 0x22: - newpc = 0xff00 | SM_ReadAdvance(); + newpc = 0xff00 | _this->SM_ReadAdvance(); break; } - SM_PushStack(sm.pc >> 8); - SM_PushStack(sm.pc & 0xff); - sm.pc = newpc; + _this->SM_PushStack(_this->sm.pc >> 8); + _this->SM_PushStack(_this->sm.pc & 0xff); + _this->sm.pc = newpc; } -void SM_Opcode_CMP(uint8_t opcode) // c9, c5, d5, cd, dd, d9, c1, d1 +void SM_Opcode_CMP(SubMcu* _this, uint8_t opcode) // c9, c5, d5, cd, dd, d9, c1, d1 { uint8_t operand = 0; switch (opcode) { case 0xc9: - operand = SM_ReadAdvance(); + operand = _this->SM_ReadAdvance(); break; case 0xc5: - operand = SM_Read(SM_ReadAdvance()); + operand = _this->SM_Read(_this->SM_ReadAdvance()); break; case 0xd5: - operand = SM_Read((SM_ReadAdvance()+sm.x)&0xff); + operand = _this->SM_Read((_this->SM_ReadAdvance()+_this->sm.x)&0xff); break; case 0xcd: - operand = SM_Read(SM_ReadAdvance16()); + operand = _this->SM_Read(_this->SM_ReadAdvance16()); break; case 0xdd: - operand = SM_Read(SM_ReadAdvance16() + sm.x); + operand = _this->SM_Read(_this->SM_ReadAdvance16() + _this->sm.x); break; case 0xd9: - operand = SM_Read(SM_ReadAdvance16() + sm.y); + operand = _this->SM_Read(_this->SM_ReadAdvance16() + _this->sm.y); break; case 0xc1: - operand = SM_Read(SM_Read16((SM_ReadAdvance() + sm.x) & 0xff)); + operand = _this->SM_Read(_this->SM_Read16((_this->SM_ReadAdvance() + _this->sm.x) & 0xff)); break; case 0xd1: - operand = SM_Read(SM_Read16(SM_ReadAdvance()) + sm.y); + operand = _this->SM_Read(_this->SM_Read16(_this->SM_ReadAdvance()) + _this->sm.y); break; } - int diff = sm.a - operand; - SM_SetStatus((diff & 0x100) == 0, SM_STATUS_C); - SM_Update_NZ(diff & 0xff); + int diff = _this->sm.a - operand; + _this->SM_SetStatus((diff & 0x100) == 0, SM_STATUS_C); + _this->SM_Update_NZ(diff & 0xff); } -void SM_Opcode_BNE(uint8_t opcode) // d0 +void SM_Opcode_BNE(SubMcu* _this, uint8_t opcode) // d0 { - int8_t diff = SM_ReadAdvance(); - if ((sm.sr & SM_STATUS_Z) == 0) - sm.pc += diff; + int8_t diff = _this->SM_ReadAdvance(); + if ((_this->sm.sr & SM_STATUS_Z) == 0) + _this->sm.pc += diff; } -void SM_Opcode_RTS(uint8_t opcode) // 60 +void SM_Opcode_RTS(SubMcu* _this, uint8_t opcode) // 60 { - sm.pc = SM_PopStack(); - sm.pc |= SM_PopStack() << 8; + _this->sm.pc = _this->SM_PopStack(); + _this->sm.pc |= _this->SM_PopStack() << 8; } -void SM_Opcode_JMP(uint8_t opcode) // 4c, 6c, b2 +void SM_Opcode_JMP(SubMcu* _this, uint8_t opcode) // 4c, 6c, b2 { switch (opcode) { case 0x4c: - sm.pc = SM_ReadAdvance16(); + _this->sm.pc = _this->SM_ReadAdvance16(); break; case 0x6c: - sm.pc = SM_Read16(SM_ReadAdvance16()); + _this->sm.pc = _this->SM_Read16(_this->SM_ReadAdvance16()); break; case 0xb2: - sm.pc = SM_Read16(SM_ReadAdvance()); + _this->sm.pc = _this->SM_Read16(_this->SM_ReadAdvance()); break; } } -void SM_Opcode_ORA(uint8_t opcode) // 09, 05, 15, 0d, 1d, 01, 11 +void SM_Opcode_ORA(SubMcu* _this, uint8_t opcode) // 09, 05, 15, 0d, 1d, 01, 11 { uint8_t val = 0; uint8_t val2 = 0; - if ((sm.sr & SM_STATUS_T) == 0) + if ((_this->sm.sr & SM_STATUS_T) == 0) { - val = sm.a; + val = _this->sm.a; } else { // FIXME - val = SM_Read(sm.x); + val = _this->SM_Read(_this->sm.x); } switch (opcode) { case 0x09: - val2 = SM_ReadAdvance(); + val2 = _this->SM_ReadAdvance(); break; case 0x05: - val2 = SM_Read(SM_ReadAdvance()); + val2 = _this->SM_Read(_this->SM_ReadAdvance()); break; case 0x15: - val2 = SM_Read((SM_ReadAdvance() + sm.x) & 0xff); + val2 = _this->SM_Read((_this->SM_ReadAdvance() + _this->sm.x) & 0xff); break; case 0x0d: - val2 = SM_Read(SM_ReadAdvance16()); + val2 = _this->SM_Read(_this->SM_ReadAdvance16()); break; case 0x1d: - val2 = SM_Read(SM_ReadAdvance16() + sm.x); + val2 = _this->SM_Read(_this->SM_ReadAdvance16() + _this->sm.x); break; case 0x19: - val2 = SM_Read(SM_ReadAdvance16() + sm.y); + val2 = _this->SM_Read(_this->SM_ReadAdvance16() + _this->sm.y); break; case 0x01: - val2 = SM_Read(SM_Read16((SM_ReadAdvance() + sm.x) & 0xff)); + val2 = _this->SM_Read(_this->SM_Read16((_this->SM_ReadAdvance() + _this->sm.x) & 0xff)); break; case 0x11: - val2 = SM_Read(SM_Read16(SM_ReadAdvance()) + sm.y); + val2 = _this->SM_Read(_this->SM_Read16(_this->SM_ReadAdvance()) + _this->sm.y); break; } val |= val2; - if ((sm.sr & SM_STATUS_T) == 0) + if ((_this->sm.sr & SM_STATUS_T) == 0) { - sm.a = val; + _this->sm.a = val; - SM_Update_NZ(val); + _this->SM_Update_NZ(val); } else { // FIXME - SM_Write(sm.x, val); + _this->SM_Write(_this->sm.x, val); } } -void SM_Opcode_DEC(uint8_t opcode) // 1a, c6, d6, ce, de +void SM_Opcode_DEC(SubMcu* _this, uint8_t opcode) // 1a, c6, d6, ce, de { uint8_t val = 0; uint16_t dest = 0; switch (opcode) { case 0x1a: - sm.a--; - SM_Update_NZ(sm.a); + _this->sm.a--; + _this->SM_Update_NZ(_this->sm.a); return; case 0xc6: - dest = SM_ReadAdvance(); + dest = _this->SM_ReadAdvance(); break; case 0xd6: - dest = (SM_ReadAdvance() + sm.x) & 0xff; + dest = (_this->SM_ReadAdvance() + _this->sm.x) & 0xff; break; case 0xce: - dest = SM_ReadAdvance16(); + dest = _this->SM_ReadAdvance16(); break; case 0xde: - dest = SM_ReadAdvance16() + sm.x; + dest = _this->SM_ReadAdvance16() + _this->sm.x; break; } - val = SM_Read(dest); + val = _this->SM_Read(dest); val--; - SM_Write(dest, val); - SM_Update_NZ(val); + _this->SM_Write(dest, val); + _this->SM_Update_NZ(val); } -void SM_Opcode_TAX(uint8_t opcode) // aa +void SM_Opcode_TAX(SubMcu* _this, uint8_t opcode) // aa { - sm.x = sm.a; - SM_Update_NZ(sm.x); + _this->sm.x = _this->sm.a; + _this->SM_Update_NZ(_this->sm.x); } -void SM_Opcode_STX(uint8_t opcode) // 86 96 8e +void SM_Opcode_STX(SubMcu* _this, uint8_t opcode) // 86 96 8e { uint16_t dest = 0; switch (opcode) { case 0x86: - dest = SM_ReadAdvance(); + dest = _this->SM_ReadAdvance(); break; case 0x96: - dest = SM_ReadAdvance() + sm.x; + dest = _this->SM_ReadAdvance() + _this->sm.x; break; case 0x8e: - dest = SM_ReadAdvance16(); + dest = _this->SM_ReadAdvance16(); break; } - SM_Write(dest, sm.x); + _this->SM_Write(dest, _this->sm.x); } -void SM_Opcode_SEC(uint8_t opcode) // 38 +void SM_Opcode_SEC(SubMcu* _this, uint8_t opcode) // 38 { - SM_SetStatus(1, SM_STATUS_C); + _this->SM_SetStatus(1, SM_STATUS_C); } -void SM_Opcode_NOP(uint8_t opcode) // EA +void SM_Opcode_NOP(SubMcu* _this, uint8_t opcode) // EA { } -void SM_Opcode_BPL(uint8_t opcode) // 10 +void SM_Opcode_BPL(SubMcu* _this, uint8_t opcode) // 10 { - int8_t diff = SM_ReadAdvance(); - if ((sm.sr & SM_STATUS_N) == 0) - sm.pc += diff; + int8_t diff = _this->SM_ReadAdvance(); + if ((_this->sm.sr & SM_STATUS_N) == 0) + _this->sm.pc += diff; } -void SM_Opcode_CLC(uint8_t opcode) // 18 +void SM_Opcode_CLC(SubMcu* _this, uint8_t opcode) // 18 { - SM_SetStatus(0, SM_STATUS_C); + _this->SM_SetStatus(0, SM_STATUS_C); } -void SM_Opcode_AND(uint8_t opcode) // 29, 25, 35, 2d, 3d, 21, 31 +void SM_Opcode_AND(SubMcu* _this, uint8_t opcode) // 29, 25, 35, 2d, 3d, 21, 31 { uint8_t val = 0; uint8_t val2 = 0; - if ((sm.sr & SM_STATUS_T) == 0) + if ((_this->sm.sr & SM_STATUS_T) == 0) { - val = sm.a; + val = _this->sm.a; } else { // FIXME - val = SM_Read(sm.x); + val = _this->SM_Read(_this->sm.x); } switch (opcode) { case 0x29: - val2 = SM_ReadAdvance(); + val2 = _this->SM_ReadAdvance(); break; case 0x25: - val2 = SM_Read(SM_ReadAdvance()); + val2 = _this->SM_Read(_this->SM_ReadAdvance()); break; case 0x35: - val2 = SM_Read((SM_ReadAdvance() + sm.x) & 0xff); + val2 = _this->SM_Read((_this->SM_ReadAdvance() + _this->sm.x) & 0xff); break; case 0x2d: - val2 = SM_Read(SM_ReadAdvance16()); + val2 = _this->SM_Read(_this->SM_ReadAdvance16()); break; case 0x3d: - val2 = SM_Read(SM_ReadAdvance16() + sm.x); + val2 = _this->SM_Read(_this->SM_ReadAdvance16() + _this->sm.x); break; case 0x39: - val2 = SM_Read(SM_ReadAdvance16() + sm.y); + val2 = _this->SM_Read(_this->SM_ReadAdvance16() + _this->sm.y); break; case 0x21: - val2 = SM_Read(SM_Read16((SM_ReadAdvance() + sm.x) & 0xff)); + val2 = _this->SM_Read(_this->SM_Read16((_this->SM_ReadAdvance() + _this->sm.x) & 0xff)); break; case 0x31: - val2 = SM_Read(SM_Read16(SM_ReadAdvance()) + sm.y); + val2 = _this->SM_Read(_this->SM_Read16(_this->SM_ReadAdvance()) + _this->sm.y); break; } val &= val2; - if ((sm.sr & SM_STATUS_T) == 0) + if ((_this->sm.sr & SM_STATUS_T) == 0) { - sm.a = val; + _this->sm.a = val; - SM_Update_NZ(val); + _this->SM_Update_NZ(val); } else { // FIXME - SM_Write(sm.x, val); + _this->SM_Write(_this->sm.x, val); } } -void SM_Opcode_INC(uint8_t opcode) // 3a, e6, f6, ee, fe +void SM_Opcode_INC(SubMcu* _this, uint8_t opcode) // 3a, e6, f6, ee, fe { uint8_t val = 0; uint16_t dest = 0; switch (opcode) { case 0x3a: - sm.a++; - SM_Update_NZ(sm.a); + _this->sm.a++; + _this->SM_Update_NZ(_this->sm.a); return; case 0xe6: - dest = SM_ReadAdvance(); + dest = _this->SM_ReadAdvance(); break; case 0xf6: - dest = (SM_ReadAdvance() + sm.x) & 0xff; + dest = (_this->SM_ReadAdvance() + _this->sm.x) & 0xff; break; case 0xee: - dest = SM_ReadAdvance16(); + dest = _this->SM_ReadAdvance16(); break; case 0xfe: - dest = SM_ReadAdvance16() + sm.x; + dest = _this->SM_ReadAdvance16() + _this->sm.x; break; } - val = SM_Read(dest); + val = _this->SM_Read(dest); val++; - SM_Write(dest, val); - SM_Update_NZ(val); + _this->SM_Write(dest, val); + _this->SM_Update_NZ(val); } -void (*SM_Opcode_Table[256])(uint8_t opcode) +void (*SM_Opcode_Table[256])(SubMcu *_this, uint8_t opcode) { SM_Opcode_NotImplemented, // 00 SM_Opcode_ORA, // 01 @@ -1218,21 +1192,21 @@ void (*SM_Opcode_Table[256])(uint8_t opcode) SM_Opcode_SEB_CLB, // ff }; -void SM_StartVector(uint32_t vector) +void SubMcu::SM_StartVector(uint32_t vector) { SM_PushStack(sm.pc >> 8); SM_PushStack(sm.pc & 0xff); - SM_PushStack(sm.sr); + SM_PushStack(this->sm.sr); - sm.sr |= SM_STATUS_I; - sm.sleep = 0; + this->sm.sr |= SM_STATUS_I; + this->sm.sleep = 0; sm.pc = SM_GetVectorAddress(vector); } -void SM_HandleInterrupt(void) +void SubMcu::SM_HandleInterrupt(void) { - if (sm.sr & SM_STATUS_I) + if (this->sm.sr & SM_STATUS_I) return; if ((sm_device_mode[SM_DEV_UART1_CTRL] & 0x8) != 0 @@ -1310,11 +1284,11 @@ void SM_HandleInterrupt(void) } } -void SM_UpdateTimer(void) +void SubMcu::SM_UpdateTimer(void) { while (sm_timer_cycles < sm.cycles) { - if ((sm_device_mode[SM_DEV_TIMER_CTRL] & 0x20) == 0 && !sm.sleep) + if ((sm_device_mode[SM_DEV_TIMER_CTRL] & 0x20) == 0 && !this->sm.sleep) { if (sm_timer_prescaler == 0) { @@ -1335,7 +1309,7 @@ void SM_UpdateTimer(void) } } -void SM_PostUART(uint8_t data) +void SubMcu::SM_PostUART(uint8_t data) { //MCU_WorkThread_Lock(); uart_buffer[uart_write_ptr] = data; @@ -1343,7 +1317,7 @@ void SM_PostUART(uint8_t data) //MCU_WorkThread_Unlock(); } -void SM_UpdateUART(void) +void SubMcu::SM_UpdateUART(void) { if ((sm_device_mode[SM_DEV_UART1_CTRL] & 4) == 0) // RX disabled return; @@ -1364,17 +1338,17 @@ void SM_UpdateUART(void) uart_rx_delay = sm.cycles + 3000 * 4; } -void SM_Update(uint64_t cycles) +void SubMcu::SM_Update(uint64_t cycles) { while (sm.cycles < cycles * 5) { SM_HandleInterrupt(); - if (!sm.sleep) + if (!this->sm.sleep) { uint8_t opcode = SM_ReadAdvance(); - SM_Opcode_Table[opcode](opcode); + SM_Opcode_Table[opcode](this, opcode); } sm.cycles += 12 * 4; // FIXME diff --git a/src/submcu.h b/src/submcu.h index d6c7feeb..8e94423a 100644 --- a/src/submcu.h +++ b/src/submcu.h @@ -56,12 +56,58 @@ struct submcu_t { uint8_t sleep; }; -extern submcu_t sm; +static const uint32_t uart_buffer_size = 8192; -extern uint8_t sm_rom[4096]; +struct MCU; -void SM_Reset(void); -void SM_Update(uint64_t cycles); -void SM_SysWrite(uint32_t address, uint8_t data); -uint8_t SM_SysRead(uint32_t address); -void SM_PostUART(uint8_t data); +struct SubMcu { + MCU *mcu; + SubMcu(MCU *mcu) : mcu(mcu) {} + + uint8_t sm_rom[4096]; + uint8_t sm_ram[128]; + uint8_t sm_shared_ram[192]; + uint8_t sm_access[0x18]; + + uint8_t sm_p0_dir; + uint8_t sm_p1_dir; + + uint8_t sm_device_mode[32]; + uint8_t sm_cts; + + uint64_t sm_timer_cycles; + uint8_t sm_timer_prescaler; + uint8_t sm_timer_counter; + + submcu_t sm; + + uint32_t uart_write_ptr; + uint32_t uart_read_ptr; + uint8_t uart_buffer[uart_buffer_size]; + + uint8_t uart_rx_gotbyte; + uint8_t uart_rx_byte; + uint64_t uart_rx_delay; + + void SM_ErrorTrap(void); + uint8_t SM_Read(uint16_t address); + void SM_Write(uint16_t address, uint8_t data); + void SM_SysWrite(uint32_t address, uint8_t data); + uint8_t SM_SysRead(uint32_t address); + uint16_t SM_GetVectorAddress(uint32_t vector); + void SM_SetStatus(uint32_t condition, uint32_t mask); + void SM_Reset(void); + uint8_t SM_ReadAdvance(void); + uint16_t SM_ReadAdvance16(void); + uint16_t SM_Read16(uint16_t address); + void SM_Update_NZ(uint8_t val); + void SM_PushStack(uint8_t data); + uint8_t SM_PopStack(void); + + void SM_StartVector(uint32_t vector); + void SM_HandleInterrupt(void); + void SM_UpdateTimer(void); + void SM_PostUART(uint8_t data); + void SM_UpdateUART(void); + void SM_Update(uint64_t cycles); +};