├── .github └── workflows │ ├── autorelease.yml │ ├── build_test_only.yml │ └── continuous.yml ├── .gitignore ├── LICENSE ├── command.md ├── diskimage ├── 2017_FM7DEMO_CaptainYS_V3.T77 ├── 2018_FM7DEMO_CaptainYS_V1.T77 ├── 2019_FM77AVDEMO_CaptainYS_V2.D77 └── readme.txt ├── eventLog ├── DEATHFORCETEST.evt ├── FB33TEST.evt ├── FB34TEST.evt ├── LAPTICKTEST.evt ├── LAYDOCKTEST.evt ├── LOADM.evt ├── LOSTPOWERTEST.evt ├── MAGUSTEST.evt ├── PROFANTEST.evt ├── RUN.evt ├── SPACECRUISERTEST.evt ├── SPACEHARRIERTEST.evt ├── THEXDER.evt ├── VALISTEST.evt ├── WAIT_AND_BANG_RETURN.evt ├── WORLDGOLF2TEST.evt ├── XANADU1TEST.evt └── YS1TEST.evt ├── gui ├── .gitignore ├── sampleProfiles │ ├── Laydock.Mutsu │ ├── YS2.Mutsu │ └── readme.txt └── src │ ├── .gitignore │ ├── CMakeLists.txt │ └── main_gui │ ├── CMakeLists.txt │ ├── fsguiapp.cpp │ ├── fsguiapp.h │ ├── fsguimain.cpp │ ├── profiledlg.cpp │ ├── profiledlg.h │ ├── readme.txt │ ├── runvm.cpp │ ├── runvm.h │ └── singleton.cpp ├── readme.md ├── scripts ├── build.py ├── buildgui.py ├── run.py ├── run7.py ├── runGUI.py └── runav.py ├── src ├── CMakeLists.txt ├── ay38910 │ ├── CMakeLists.txt │ ├── ay38910.cpp │ └── ay38910.h ├── exas_compiler │ ├── CMakeLists.txt │ ├── exas_compiler.cpp │ └── exas_compiler.h ├── externals │ ├── CMakeLists.txt │ ├── connect_fssimplewindow │ │ ├── CMakeLists.txt │ │ ├── fssimplewindow_connection.cpp │ │ └── fssimplewindow_connection.h │ └── ysbitmapfont │ │ ├── CMakeLists.txt │ │ ├── ysglfontdata.c │ │ └── ysglfontdata.h ├── fm77av │ ├── CMakeLists.txt │ ├── crtc │ │ ├── CMakeLists.txt │ │ ├── fm77avcrtc.cpp │ │ └── fm77avcrtc.h │ ├── datarecorder │ │ ├── CMakeLists.txt │ │ ├── fm77avtape.cpp │ │ └── fm77avtape.h │ ├── dma │ │ ├── CMakeLists.txt │ │ ├── fm77av40dmac.cpp │ │ └── fm77av40dmac.h │ ├── eventlog │ │ ├── CMakeLists.txt │ │ ├── fm77aveventlog.cpp │ │ └── fm77aveventlog.h │ ├── fdc │ │ ├── CMakeLists.txt │ │ ├── fm77avfdc.cpp │ │ └── fm77avfdc.h │ ├── fm77av.cpp │ ├── fm77av.h │ ├── fm77avdef.cpp │ ├── fm77avdef.h │ ├── fm77avint.cpp │ ├── fm77avio.cpp │ ├── fm77avkey.cpp │ ├── fm77avkey.h │ ├── fm77avparam.cpp │ ├── fm77avparam.h │ ├── fm77avrender.cpp │ ├── fm77avrender.h │ ├── fm77avstate.cpp │ ├── fm77avthread.cpp │ ├── fm77avthread.h │ ├── gameport │ │ ├── CMakeLists.txt │ │ ├── fm77avgameport.cpp │ │ └── fm77avgameport.h │ ├── keyboard │ │ ├── CMakeLists.txt │ │ ├── fm77avkeyboard.cpp │ │ ├── fm77avkeyboard.h │ │ ├── fm77avrkana.cpp │ │ └── fm77avrkana.h │ ├── serialport │ │ ├── CMakeLists.txt │ │ ├── fm77avserialport.cpp │ │ └── fm77avserialport.h │ └── sound │ │ ├── CMakeLists.txt │ │ ├── fm77avsound.cpp │ │ └── fm77avsound.h ├── fm7lib │ ├── CMakeLists.txt │ ├── cpplib.cpp │ ├── cpplib.h │ ├── fm7lib.cpp │ └── fm7lib.h ├── main_cui │ ├── CMakeLists.txt │ ├── argv │ │ ├── CMakeLists.txt │ │ ├── fm77avargv.cpp │ │ └── fm77avargv.h │ ├── command │ │ ├── CMakeLists.txt │ │ ├── fm77avcommand.cpp │ │ ├── fm77avcommand.h │ │ ├── fm77avlineparser.cpp │ │ └── fm77avlineparser.h │ ├── cuithread │ │ ├── CMakeLists.txt │ │ ├── fm77avcuithread.cpp │ │ └── fm77avcuithread.h │ └── main.cpp ├── mc6809 │ ├── CMakeLists.txt │ ├── mc6809.cpp │ ├── mc6809.h │ ├── mc6809debugger.cpp │ ├── mc6809symtable.cpp │ └── mc6809symtable.h ├── mc6809util │ ├── CMakeLists.txt │ ├── mc6809util.cpp │ └── mc6809util.h ├── memory │ ├── CMakeLists.txt │ ├── fm77avmemory.cpp │ ├── fm77avmemory.h │ ├── memory.cpp │ ├── memory.h │ ├── plainmemory.cpp │ └── plainmemory.h ├── miscutil │ ├── CMakeLists.txt │ ├── miscutil.cpp │ └── miscutil.h ├── outside_world │ ├── CMakeLists.txt │ ├── icons.cpp │ ├── icons.h │ ├── outside_world.cpp │ └── outside_world.h ├── resources │ ├── CAPS.png │ ├── CMakeLists.txt │ ├── FD_BUSY.png │ ├── FD_IDLE.png │ ├── INS.png │ ├── KANA.png │ ├── MENU.png │ ├── PAUSE.png │ ├── TAPE_IDLE.png │ ├── TAPE_LOADING.png │ ├── TAPE_SAVING.png │ └── png2cpp.cpp ├── t77lib │ ├── CMakeLists.txt │ ├── t77.cpp │ └── t77.h ├── tests │ ├── CMakeLists.txt │ ├── adc_daa.cpp │ ├── disasmtest.cpp │ ├── divisiontest.cpp │ └── memeval.cpp ├── vgmrecorder │ └── CMakeLists.txt └── ym2203c │ └── CMakeLists.txt └── testasm ├── MAGUSBug.asm ├── cmp_inc.asm ├── cmpx_inc.asm ├── disasmtest.asm ├── div16.asm ├── divtest.asm ├── encoder_get.asm ├── encoder_get.lst ├── encoder_init.asm ├── fdc_headload.asm ├── indexhole.asm ├── ldu_inc.asm ├── ldx_inc.asm ├── multiPage_hwDraw.asm ├── puls.asm ├── stx_inc.asm ├── subhalt.asm └── tfr_u_a.asm /.github/workflows/autorelease.yml: -------------------------------------------------------------------------------- 1 | name: Auto Release with Tag 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' # Run if tagged as v*. 7 | 8 | jobs: 9 | build-windows: 10 | 11 | runs-on: windows-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: checkout_Tsugaru 16 | run: git clone https://github.com/captainys/TOWNSEMU.git 17 | - name: mkdir 18 | run: mkdir ci_windows 19 | - name: build 20 | run: | 21 | cmake ../src 22 | cmake --build . --config Release 23 | working-directory: ./ci_windows 24 | - name: mkdir_gui 25 | run: mkdir build 26 | working-directory: ./gui 27 | - name: checkout_gui 28 | run: git clone https://github.com/captainys/public.git 29 | working-directory: ./gui/src 30 | - name: build_gui 31 | run: | 32 | cmake ../src 33 | cmake --build . --config Release --target Mutsu_GUI 34 | working-directory: ./gui/build 35 | - name: make_zip 36 | run: | 37 | cmake -E copy ./main_cui/Release/Mutsu_CUI.exe . 38 | cmake -E copy ../gui/build/main_gui/Release/Mutsu_GUI.exe . 39 | cmake -E copy ../readme.md . 40 | cmake -E copy ../command.md . 41 | # cmake -E copy ../util/MutsuUtil.D77 . 42 | cmake -E tar cvf windows_binary_latest.zip --format=zip Mutsu_CUI.exe Mutsu_GUI.exe readme.md command.md 43 | working-directory: ./ci_windows 44 | - name: upload_to_artifact 45 | uses: actions/upload-artifact@v4 46 | with: 47 | name: Windows-Binary 48 | path: ci_windows/windows_binary_latest.zip 49 | 50 | 51 | 52 | build-linux: 53 | 54 | runs-on: ubuntu-latest 55 | 56 | steps: 57 | - uses: actions/checkout@v2 58 | - name: checkout_Tsugaru 59 | run: git clone https://github.com/captainys/TOWNSEMU.git 60 | - name: mkdir 61 | run: mkdir ci_ubuntu 62 | - name: install-OpenGL 63 | run: | 64 | sudo apt-get update 65 | sudo apt-get install libglu1-mesa-dev mesa-common-dev 66 | - name: install-ALSA 67 | run: sudo apt-get install libasound2-dev 68 | - name: cmake 69 | run: cmake ../src -DCMAKE_BUILD_TYPE=Release 70 | working-directory: ./ci_ubuntu 71 | - name: build 72 | run: cmake --build . --config Release --target Mutsu_CUI 73 | working-directory: ./ci_ubuntu 74 | 75 | - name: mkdir_gui 76 | run: mkdir build 77 | working-directory: ./gui 78 | - name: checkout_gui 79 | run: git clone https://github.com/captainys/public.git 80 | working-directory: ./gui/src 81 | - name: build_gui 82 | run: | 83 | cmake ../src -DCMAKE_BUILD_TYPE=Release 84 | cmake --build main_gui --config Release --target Mutsu_GUI 85 | working-directory: ./gui/build 86 | 87 | - name: make_zip 88 | run: | 89 | cmake -E copy ./main_cui/Mutsu_CUI . 90 | cmake -E copy ../gui/build/main_gui/Mutsu_GUI . 91 | cmake -E copy ../readme.md . 92 | cmake -E copy ../command.md . 93 | # cmake -E copy ../util/MutsuUtil.D77 . 94 | cmake -E tar cvf ubuntu_binary_latest.zip --format=zip Mutsu_CUI Mutsu_GUI readme.md command.md 95 | working-directory: ./ci_ubuntu 96 | - name: upload_to_artifact 97 | uses: actions/upload-artifact@v4 98 | with: 99 | name: Ubuntu-Binary 100 | path: ci_ubuntu/ubuntu_binary_latest.zip 101 | 102 | 103 | 104 | build-macos: 105 | 106 | runs-on: macos-latest 107 | 108 | steps: 109 | - uses: actions/checkout@v2 110 | - name: checkout_Tsugaru 111 | run: git clone https://github.com/captainys/TOWNSEMU.git 112 | - name: mkdir 113 | run: mkdir ci_macos 114 | - name: cmake 115 | run: cmake ../src -DCMAKE_BUILD_TYPE=Release 116 | working-directory: ./ci_macos 117 | - name: build 118 | run: cmake --build . 119 | working-directory: ./ci_macos 120 | 121 | - name: mkdir_gui 122 | run: mkdir build 123 | working-directory: ./gui 124 | - name: checkout_gui 125 | run: git clone https://github.com/captainys/public.git 126 | working-directory: ./gui/src 127 | - name: build_gui 128 | run: | 129 | cmake ../src -DCMAKE_BUILD_TYPE=Release 130 | cmake --build main_gui --config Release --target Mutsu_GUI 131 | working-directory: ./gui/build 132 | 133 | - name: make_zip 134 | run: | 135 | cmake -E copy_directory ../gui/build/main_gui/Mutsu_GUI.app ./Mutsu_GUI.app 136 | # cmake -E copy main_cui/Mutsu_CUI.app/Contents/MacOS/Mutsu_CUI Mutsu_GUI.app/Contents/MacOS/. 137 | cmake -E copy ../readme.md . 138 | cmake -E copy ../command.md . 139 | # cmake -E copy ../util/MutsuUtil.D77 . 140 | cmake -E tar cvf macos_binary_latest.zip --format=zip Mutsu_GUI.app readme.md command.md 141 | working-directory: ./ci_macos 142 | - name: upload_to_artifact 143 | uses: actions/upload-artifact@v4 144 | with: 145 | name: Macos-Binary 146 | path: ci_macos/macos_binary_latest.zip 147 | 148 | 149 | after-build: 150 | needs: [build-windows, build-linux, build-macos] 151 | 152 | runs-on: ubuntu-latest 153 | 154 | steps: 155 | - uses: actions/download-artifact@v4 156 | with: 157 | name: Windows-Binary 158 | 159 | - uses: actions/download-artifact@v4 160 | with: 161 | name: Ubuntu-Binary 162 | 163 | - uses: actions/download-artifact@v4 164 | with: 165 | name: Macos-Binary 166 | 167 | - name: Verify files 168 | run: ls -l 169 | 170 | # https://github.com/actions/upload-release-asset 171 | - name: Create Release 172 | id: create_release 173 | uses: actions/create-release@v1 174 | env: 175 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 176 | with: 177 | tag_name: ${{ github.ref }} 178 | release_name: Auto Release ${{ github.ref }} 179 | draft: false 180 | prerelease: true 181 | - name: Upload Windows Binary 182 | id: upload-windows-binary 183 | uses: actions/upload-release-asset@v1 184 | env: 185 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 186 | with: 187 | upload_url: ${{ steps.create_release.outputs.upload_url }} 188 | asset_path: ./windows_binary_latest.zip 189 | asset_name: windows_binary_latest.zip 190 | asset_content_type: application/zip 191 | 192 | - name: Upload Ubuntu Binary 193 | id: upload-ubuntu-binary 194 | uses: actions/upload-release-asset@v1 195 | env: 196 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 197 | with: 198 | upload_url: ${{ steps.create_release.outputs.upload_url }} 199 | asset_path: ./ubuntu_binary_latest.zip 200 | asset_name: ubuntu_binary_latest.zip 201 | asset_content_type: application/zip 202 | 203 | - name: Upload macOS Binary 204 | id: upload-macOS-binary 205 | uses: actions/upload-release-asset@v1 206 | env: 207 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 208 | with: 209 | upload_url: ${{ steps.create_release.outputs.upload_url }} 210 | asset_path: ./macos_binary_latest.zip 211 | asset_name: macos_binary_latest.zip 212 | asset_content_type: application/zip 213 | 214 | -------------------------------------------------------------------------------- /.github/workflows/build_test_only.yml: -------------------------------------------------------------------------------- 1 | name: Build Test on Pull-Request 2 | 3 | on: 4 | pull_request: 5 | branches: [ master ] 6 | 7 | jobs: 8 | build: 9 | 10 | runs-on: windows-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: checkout_Tsugaru 15 | run: git clone https://github.com/captainys/TOWNSEMU.git 16 | - name: mkdir 17 | run: mkdir ci 18 | - name: cmake 19 | run: cmake ../src 20 | working-directory: ./ci 21 | - name: build 22 | run: cmake --build . --config Release 23 | working-directory: ./ci 24 | - name: make_zip 25 | run: | 26 | cmake -E copy ./main_cui/Release/Mutsu_CUI.exe . 27 | cmake -E copy ../readme.md . 28 | cmake -E copy ../command.md . 29 | cmake -E tar cvf windows_binary_latest.zip --format=zip Mutsu_CUI.exe readme.md command.md 30 | working-directory: ./ci 31 | 32 | 33 | 34 | build-linux: 35 | 36 | runs-on: ubuntu-latest 37 | 38 | steps: 39 | - uses: actions/checkout@v2 40 | - name: checkout_Tsugaru 41 | run: git clone https://github.com/captainys/TOWNSEMU.git 42 | - name: mkdir 43 | run: mkdir ci_ubuntu 44 | - name: install-OpenGL 45 | run: sudo apt-get install libglu1-mesa-dev mesa-common-dev 46 | - name: cmake 47 | run: cmake ../src -DCMAKE_BUILD_TYPE=Release 48 | working-directory: ./ci_ubuntu 49 | - name: build 50 | run: cmake --build . 51 | working-directory: ./ci_ubuntu 52 | 53 | 54 | 55 | build-macos: 56 | 57 | runs-on: macos-latest 58 | 59 | steps: 60 | - uses: actions/checkout@v2 61 | - name: checkout_Tsugaru 62 | run: git clone https://github.com/captainys/TOWNSEMU.git 63 | - name: mkdir 64 | run: mkdir ci_macos 65 | - name: cmake 66 | run: cmake ../src -DCMAKE_BUILD_TYPE=Release 67 | working-directory: ./ci_macos 68 | - name: build 69 | run: cmake --build . 70 | working-directory: ./ci_macos 71 | -------------------------------------------------------------------------------- /.github/workflows/continuous.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | tags-ignore: 7 | - 'v*' # Don't run if tagged as v*. 8 | 9 | jobs: 10 | build-windows: 11 | 12 | runs-on: windows-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: checkout_Tsugaru 17 | run: git clone https://github.com/captainys/TOWNSEMU.git 18 | - name: mkdir 19 | run: mkdir ci_windows 20 | - name: build 21 | run: | 22 | cmake ../src 23 | cmake --build . --config Release 24 | working-directory: ./ci_windows 25 | - name: mkdir_gui 26 | run: mkdir build 27 | working-directory: ./gui 28 | - name: checkout_gui 29 | run: git clone https://github.com/captainys/public.git 30 | working-directory: ./gui/src 31 | - name: build_gui 32 | run: | 33 | cmake ../src 34 | cmake --build . --config Release --target Mutsu_GUI 35 | working-directory: ./gui/build 36 | - name: make_zip 37 | run: | 38 | cmake -E copy ./main_cui/Release/Mutsu_CUI.exe . 39 | cmake -E copy ../gui/build/main_gui/Release/Mutsu_GUI.exe . 40 | cmake -E copy ../readme.md . 41 | cmake -E copy ../command.md . 42 | cmake -E tar cvf windows_binary_latest.zip --format=zip Mutsu_CUI.exe Mutsu_GUI.exe readme.md command.md 43 | working-directory: ./ci_windows 44 | 45 | 46 | 47 | build-linux: 48 | 49 | runs-on: ubuntu-latest 50 | 51 | steps: 52 | - uses: actions/checkout@v2 53 | - name: checkout_Tsugaru 54 | run: git clone https://github.com/captainys/TOWNSEMU.git 55 | - name: mkdir 56 | run: mkdir ci_ubuntu 57 | - name: install-OpenGL 58 | run: | 59 | sudo apt-get update 60 | sudo apt-get install libglu1-mesa-dev mesa-common-dev 61 | - name: install-ALSA 62 | run: sudo apt-get install libasound2-dev 63 | - name: cmake 64 | run: cmake ../src -DCMAKE_BUILD_TYPE=Release 65 | working-directory: ./ci_ubuntu 66 | - name: build 67 | run: cmake --build . --config Release --target Mutsu_CUI 68 | working-directory: ./ci_ubuntu 69 | 70 | - name: mkdir_gui 71 | run: mkdir build 72 | working-directory: ./gui 73 | - name: checkout_gui 74 | run: git clone https://github.com/captainys/public.git 75 | working-directory: ./gui/src 76 | - name: build_gui 77 | run: | 78 | cmake ../src -DCMAKE_BUILD_TYPE=Release 79 | cmake --build main_gui --config Release --target Mutsu_GUI 80 | working-directory: ./gui/build 81 | 82 | - name: make_zip 83 | run: | 84 | cmake -E copy ./main_cui/Mutsu_CUI . 85 | cmake -E copy ../gui/build/main_gui/Mutsu_GUI . 86 | cmake -E copy ../readme.md . 87 | cmake -E copy ../command.md . 88 | cmake -E tar cvf ubuntu_binary_latest.zip --format=zip Mutsu_CUI Mutsu_GUI readme.md command.md 89 | working-directory: ./ci_ubuntu 90 | 91 | 92 | 93 | build-macos: 94 | 95 | runs-on: macos-latest 96 | 97 | steps: 98 | - uses: actions/checkout@v2 99 | - name: checkout_Tsugaru 100 | run: git clone https://github.com/captainys/TOWNSEMU.git 101 | - name: mkdir 102 | run: mkdir ci_macos 103 | - name: cmake 104 | run: cmake ../src -DCMAKE_BUILD_TYPE=Release 105 | working-directory: ./ci_macos 106 | - name: build 107 | run: cmake --build . 108 | working-directory: ./ci_macos 109 | 110 | - name: mkdir_gui 111 | run: mkdir build 112 | working-directory: ./gui 113 | - name: checkout_gui 114 | run: git clone https://github.com/captainys/public.git 115 | working-directory: ./gui/src 116 | - name: build_gui 117 | run: | 118 | cmake ../src -DCMAKE_BUILD_TYPE=Release 119 | cmake --build main_gui --config Release --target Mutsu_GUI 120 | working-directory: ./gui/build 121 | 122 | - name: make_zip 123 | run: | 124 | cmake -E copy_directory ../gui/build/main_gui/Mutsu_GUI.app ./Mutsu_GUI.app 125 | cmake -E copy main_cui/Mutsu_CUI.app/Contents/MacOS/Mutsu_CUI Mutsu_GUI.app/Contents/MacOS/. 126 | cmake -E copy ../readme.md . 127 | cmake -E copy ../command.md . 128 | cmake -E tar cvf macos_binary_latest.zip --format=zip Mutsu_GUI.app readme.md command.md 129 | working-directory: ./ci_macos 130 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | __pycache__ 3 | scripts 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022 Soji Yamakawa (CaptainYS, http://www.ysflight.com) 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form 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. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | 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 HOLDER 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. 12 | -------------------------------------------------------------------------------- /command.md: -------------------------------------------------------------------------------- 1 | To be written.... 2 | -------------------------------------------------------------------------------- /diskimage/2017_FM7DEMO_CaptainYS_V3.T77: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainys/77AVEMU/b5e69050ba4e5fd5c98fe93820fc1588b5bd65b5/diskimage/2017_FM7DEMO_CaptainYS_V3.T77 -------------------------------------------------------------------------------- /diskimage/2018_FM7DEMO_CaptainYS_V1.T77: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainys/77AVEMU/b5e69050ba4e5fd5c98fe93820fc1588b5bd65b5/diskimage/2018_FM7DEMO_CaptainYS_V1.T77 -------------------------------------------------------------------------------- /diskimage/2019_FM77AVDEMO_CaptainYS_V2.D77: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainys/77AVEMU/b5e69050ba4e5fd5c98fe93820fc1588b5bd65b5/diskimage/2019_FM77AVDEMO_CaptainYS_V2.D77 -------------------------------------------------------------------------------- /diskimage/readme.txt: -------------------------------------------------------------------------------- 1 | These demos are submitted to Demosplash 2017, 2018, and 2019 respectively. Copyright CaptainYS. 2 | 3 | 2017_FM7DEMO_CaptainYS_V3.T77 4 | 2018_FM7DEMO_CaptainYS_V1.T77 5 | 2019_FM77AVDEMO_CaptainYS_V2.D77 6 | -------------------------------------------------------------------------------- /eventLog/DEATHFORCETEST.evt: -------------------------------------------------------------------------------- 1 | EVENT 30000ms 2 | KEYPRESS MID_SPACE 3 | 4 | EVENT 30500ms 5 | KEYRELEASE MID_SPACE 6 | 7 | 8 | EVENT 55000ms 9 | KEYPRESS NUM_2 10 | 11 | EVENT 65000ms 12 | KEYRELEASE NUM_2 13 | 14 | EVENT 66000ms 15 | KEYPRESS NUM_4 16 | 17 | EVENT 76000ms 18 | KEYRELEASE NUM_4 19 | 20 | EVENT 77000ms 21 | KEYPRESS NUM_2 22 | 23 | EVENT 87000ms 24 | KEYRELEASE NUM_2 25 | -------------------------------------------------------------------------------- /eventLog/FB33TEST.evt: -------------------------------------------------------------------------------- 1 | EVENT 10000ms 2 | TYPECOMMAND 3 | 4 | EVENT 10500ms 5 | TYPECOMMAND 6 | -------------------------------------------------------------------------------- /eventLog/FB34TEST.evt: -------------------------------------------------------------------------------- 1 | EVENT 20000ms 2 | TYPECOMMAND 3 | -------------------------------------------------------------------------------- /eventLog/LAPTICKTEST.evt: -------------------------------------------------------------------------------- 1 | EVENT 50000ms 2 | KEYPRESS MID_SPACE 3 | 4 | EVENT 50500ms 5 | KEYRELEASE MID_SPACE 6 | -------------------------------------------------------------------------------- /eventLog/LAYDOCKTEST.evt: -------------------------------------------------------------------------------- 1 | # Title Screen 2 | EVENT 50000ms 3 | PAD0ADOWN 4 | 5 | EVENT +500ms 6 | PAD0AUP 7 | 8 | 9 | 10 | # PLAYER A SET 11 | EVENT +5000ms 12 | PAD0ADOWN 13 | 14 | EVENT +500ms 15 | PAD0AUP 16 | 17 | EVENT +2000ms 18 | PAD0ADOWN 19 | 20 | EVENT +500ms 21 | PAD0AUP 22 | 23 | 24 | # PLAYER B SET 25 | EVENT +2000ms 26 | PAD0ADOWN 27 | 28 | EVENT +500ms 29 | PAD0AUP 30 | 31 | EVENT +2000ms 32 | PAD0BCKDOWN 33 | 34 | EVENT +500ms 35 | PAD0BCKUP 36 | 37 | EVENT +2000ms 38 | PAD0ADOWN 39 | 40 | EVENT +500ms 41 | PAD0AUP 42 | 43 | 44 | 45 | # HIT RETURN 46 | EVENT +2000ms 47 | PAD0ADOWN 48 | 49 | EVENT +500ms 50 | PAD0AUP 51 | 52 | 53 | 54 | # GAME START 55 | EVENT +2000ms 56 | PAD0ADOWN 57 | 58 | EVENT +500ms 59 | PAD0AUP 60 | 61 | 62 | 63 | # HOW MANY PLAYERS? 64 | EVENT +2000ms 65 | PAD0ADOWN 66 | 67 | EVENT +500ms 68 | PAD0AUP 69 | 70 | 71 | 72 | # WHO IS PILOT? 73 | EVENT +2000ms 74 | PAD0ADOWN 75 | 76 | EVENT +500ms 77 | PAD0AUP 78 | 79 | 80 | 81 | # KEYBOARD, JOYSTICK1, or JOYSTICK2 82 | EVENT +2000ms 83 | PAD0ADOWN 84 | 85 | EVENT +500ms 86 | PAD0AUP 87 | 88 | 89 | 90 | # SCENE NUMBER 91 | EVENT +2000ms 92 | PAD0FWDDOWN 93 | 94 | EVENT +500ms 95 | PAD0FWDUP 96 | 97 | EVENT +2000ms 98 | PAD0ADOWN 99 | 100 | EVENT +500ms 101 | PAD0AUP 102 | 103 | 104 | 105 | # OPTION 106 | EVENT +2000ms 107 | PAD0BCKDOWN 108 | 109 | EVENT +500ms 110 | PAD0BCKUP 111 | 112 | EVENT +2000ms 113 | PAD0BCKDOWN 114 | 115 | EVENT +500ms 116 | PAD0BCKUP 117 | 118 | EVENT +2000ms 119 | PAD0ADOWN 120 | 121 | EVENT +500ms 122 | PAD0AUP 123 | 124 | EVENT +500ms 125 | PAD0ADOWN 126 | 127 | EVENT +500ms 128 | PAD0AUP 129 | 130 | EVENT +500ms 131 | PAD0ADOWN 132 | 133 | EVENT +500ms 134 | PAD0AUP 135 | -------------------------------------------------------------------------------- /eventLog/LOADM.evt: -------------------------------------------------------------------------------- 1 | EVENT 5000ms 2 | TYPECOMMAND LOADM"",,R 3 | -------------------------------------------------------------------------------- /eventLog/LOSTPOWERTEST.evt: -------------------------------------------------------------------------------- 1 | EVENT 30000ms 2 | KEYPRESS RETURN 3 | 4 | EVENT 30500ms 5 | KEYRELEASE RETURN 6 | -------------------------------------------------------------------------------- /eventLog/MAGUSTEST.evt: -------------------------------------------------------------------------------- 1 | EVENT 40000ms 2 | KEYPRESS RETURN 3 | 4 | EVENT 40500ms 5 | KEYRELEASE RETURN 6 | -------------------------------------------------------------------------------- /eventLog/PROFANTEST.evt: -------------------------------------------------------------------------------- 1 | EVENT 40000ms 2 | KEYPRESS MID_SPACE 3 | 4 | EVENT 40500ms 5 | KEYRELEASE MID_SPACE 6 | -------------------------------------------------------------------------------- /eventLog/RUN.evt: -------------------------------------------------------------------------------- 1 | EVENT 5000ms 2 | TYPECOMMAND RUN"" 3 | -------------------------------------------------------------------------------- /eventLog/SPACECRUISERTEST.evt: -------------------------------------------------------------------------------- 1 | EVENT 240000ms 2 | KEYPRESS MID_SPACE 3 | 4 | EVENT 240500ms 5 | KEYRELEASE MID_SPACE 6 | -------------------------------------------------------------------------------- /eventLog/SPACEHARRIERTEST.evt: -------------------------------------------------------------------------------- 1 | EVENT 40000ms 2 | KEYPRESS MID_SPACE 3 | 4 | EVENT 40500ms 5 | KEYRELEASE MID_SPACE 6 | -------------------------------------------------------------------------------- /eventLog/THEXDER.evt: -------------------------------------------------------------------------------- 1 | EVENT 20000ms 2 | KEYPRESS BREAK 3 | -------------------------------------------------------------------------------- /eventLog/VALISTEST.evt: -------------------------------------------------------------------------------- 1 | EVENT 20000ms 2 | KEYPRESS MID_SPACE 3 | 4 | EVENT 20500ms 5 | KEYRELEASE MID_SPACE 6 | -------------------------------------------------------------------------------- /eventLog/WAIT_AND_BANG_RETURN.evt: -------------------------------------------------------------------------------- 1 | EVENT 30000ms 2 | KEYPRESS RETURN 3 | 4 | EVENT 30500ms 5 | KEYRELEASE RETURN 6 | 7 | EVENT 31000ms 8 | LABEL LOOP 9 | KEYPRESS RETURN 10 | 11 | EVENT 31500ms 12 | KEYRELEASE RETURN 13 | 14 | EVENT 32000ms 15 | GOTO LOOP 16 | -------------------------------------------------------------------------------- /eventLog/WORLDGOLF2TEST.evt: -------------------------------------------------------------------------------- 1 | EVENT 20000ms 2 | KEYPRESS MID_SPACE 3 | 4 | EVENT 20500ms 5 | KEYRELEASE MID_SPACE 6 | -------------------------------------------------------------------------------- /eventLog/XANADU1TEST.evt: -------------------------------------------------------------------------------- 1 | EVENT 17000ms 2 | KEYPRESS MID_SPACE 3 | 4 | EVENT 17500ms 5 | KEYRELEASE MID_SPACE 6 | 7 | 8 | 9 | EVENT 30000ms 10 | KEYPRESS S 11 | 12 | EVENT 30500ms 13 | KEYRELEASE S 14 | -------------------------------------------------------------------------------- /eventLog/YS1TEST.evt: -------------------------------------------------------------------------------- 1 | EVENT 20000ms 2 | KEYPRESS RETURN 3 | 4 | EVENT 20500ms 5 | KEYRELEASE RETURN 6 | 7 | 8 | 9 | EVENT 30000ms 10 | KEYPRESS I 11 | 12 | EVENT 30500ms 13 | KEYRELEASE I 14 | -------------------------------------------------------------------------------- /gui/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /gui/sampleProfiles/Laydock.Mutsu: -------------------------------------------------------------------------------- 1 | ROMDIR__ "ROMS/AV" 2 | TAPEIMG_ "" 3 | TAPESAVE "" 4 | FDIMG___ 0 0 "DISK/LAYDOCK1.D77" 5 | FDWPROT_ 0 0 0 6 | FDIMG___ 1 0 "DISK/LAYDOCK2.D77" 7 | FDWPROT_ 1 0 0 8 | FDIMG___ 2 0 "" 9 | FDWPROT_ 2 0 0 10 | FDIMG___ 3 0 "" 11 | FDWPROT_ 3 0 0 12 | GAMEPORT 0 PHYS0 13 | GAMEPORT 1 PHYS1 14 | BTNHOLDT 0 0 0 15 | BTNHOLDT 0 1 0 16 | BTNHOLDT 1 0 0 17 | BTNHOLDT 1 1 0 18 | AUTOSTAR 0 19 | SCALING_ 100 20 | AUTOSCAL 1 21 | WNDWMODE MAXIMIZE 22 | APPSPEC_ NONE 23 | KYBDMODE DIRECT 24 | VIRTUKEY LEFT_SPACE 0 2 25 | QSSDIREC "" 26 | PAUSEKEY SCROLLLOCK 27 | AUTOTAPE 0 28 | FM77AVTYP FM77AV 29 | -------------------------------------------------------------------------------- /gui/sampleProfiles/YS2.Mutsu: -------------------------------------------------------------------------------- 1 | ROMDIR__ "ROMS/AV/" 2 | TAPEIMG_ "" 3 | TAPESAVE "" 4 | FDIMG___ 0 0 "DISKP" 5 | FDWPROT_ 0 0 0 6 | FDIMG___ 1 0 "USERDISK" 7 | FDWPROT_ 1 0 0 8 | FDIMG___ 2 0 "" 9 | FDWPROT_ 2 0 0 10 | FDIMG___ 3 0 "" 11 | FDWPROT_ 3 0 0 12 | GAMEPORT 0 PHYS0 13 | GAMEPORT 1 PHYS1 14 | BTNHOLDT 0 0 0 15 | BTNHOLDT 0 1 0 16 | BTNHOLDT 1 0 0 17 | BTNHOLDT 1 1 0 18 | AUTOSTAR 0 19 | SCALING_ 100 20 | AUTOSCAL 1 21 | WNDWMODE MAXIMIZE 22 | APPSPEC_ NONE 23 | KYBDMODE DIRECT 24 | QSSDIREC "" 25 | PAUSEKEY SCROLLLOCK 26 | AUTOTAPE 0 27 | FM77AVTYP FM77AV 28 | IMGALIAS USERDISK "DISK/YS2_USER.D77" 29 | IMGALIAS DISKA "DISK/YS2_A.D77" 30 | IMGALIAS DISKB "DISK/YS2_B.D77" 31 | IMGALIAS DISKP "DISK/YS2_PROG.D77" 32 | -------------------------------------------------------------------------------- /gui/sampleProfiles/readme.txt: -------------------------------------------------------------------------------- 1 | Sample Profiles 2 | 3 | [LAYDOCK (T&E)] 4 | Mutsu Profile allows relative-path from the location of the profile. If you have Laydock disk images, and FM77AV40 ROM files, organize files as: 5 | 6 | Laydock.Mutsu (in this folder) 7 | ROMS/AV 8 | BOOT_BAS.ROM 9 | BOOT_DOS.ROM 10 | FBASIC30.ROM 11 | INITIATE.ROM 12 | KANJI.ROM 13 | SUBSYSCG.ROM 14 | SUBSYS_A.ROM 15 | SUBSYS_B.ROM 16 | SUBSYS_C.ROM 17 | DISK 18 | LAYDOCK1.D77 19 | LAYDOCK2.D77 20 | 21 | Then, you can open Laydock.Mutsu, and start LAYDOCK by clicking on "START" button. 22 | 23 | Also, this game really required two players, but many Laydock players (I believe) played by oneself with a game pad and a keyboard. In fact, player 2 only had a role of shooting gun or a missile and was pretty boring. 24 | 25 | How I did was holding gamepad to control the fighter 1, dock with fighter 2 as soon as the game starts, and then pressed the left space with side of my left hand while still controlling fighter 1 with the game pad. 26 | 27 | What a pain! 28 | 29 | But, with virtual keys, you don't have to use both a game pad and a keyboard. You can assign LEFT_SPACE to your game pad in Keyboard 2 or Keyboard 3 tab. Make sure to assign your USB or Bluetooth game pad to Gameport 0 of the VM. Then, 30 | 31 | (1) Start Laydock and load up players. 32 | (2) Start the game with: 33 | Player 1 JOYSTICK 1 34 | Player 2 KEYBOARD 35 | (3) Dock fighter 1 to fighter 2, and then you can do all the controls with your game pad. 36 | 37 | 38 | 39 | 40 | 41 | [YS2 (Falcom)] 42 | Back in late 1980s, games were released in multiple floppy disks, and very often we had to change disk as the game progresses. 43 | 44 | It would be very inconvenient if you need to open file-selector and select a disk-image all the time. 45 | 46 | To solve this problem, you can set up image-file aliases, like DISKA for DISK/YS2_A.D77, and DISKB for DISK/YS2_B.D77 etc. 47 | 48 | This profile is an example of how to use aliases. You can start YS2 by putting this profile and disk and ROM images as follows. 49 | 50 | YS2.Mutsu (in this folder) 51 | ROMS/AV 52 | BOOT_BAS.ROM 53 | BOOT_DOS.ROM 54 | FBASIC30.ROM 55 | INITIATE.ROM 56 | KANJI.ROM 57 | SUBSYSCG.ROM 58 | SUBSYS_A.ROM 59 | SUBSYS_B.ROM 60 | SUBSYS_C.ROM 61 | DISK 62 | YS2_A.D77 63 | YS2_B.D77 64 | YS2_P.D77 65 | YS2_USER.D77 66 | 67 | -------------------------------------------------------------------------------- /gui/src/.gitignore: -------------------------------------------------------------------------------- 1 | public 2 | -------------------------------------------------------------------------------- /gui/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | project(MUTSU_GUI) 4 | 5 | enable_testing() 6 | 7 | set(CMAKE_CXX_STANDARD 11) 8 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 9 | 10 | add_compile_definitions(MUTSU_FM77AV) 11 | 12 | add_compile_definitions(YS_LITTLE_ENDIAN) 13 | add_compile_definitions(YS_TWOS_COMPLEMENT) 14 | # Believe or not, C/C++ does not assume 2's complement. 15 | # C/C++ does not guarantee that 0xFFFF is interpreted as 16-bit signed negative one. 16 | # In practice, pretty much all CPUs uses 2's complement, and safe to assume it is. 17 | # This flag will skip a little bit of computation. 18 | 19 | add_subdirectory(public/src) 20 | 21 | 22 | if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../../TOWNSEMU) 23 | set(TSUGARU_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../TOWNSEMU/src) 24 | else() 25 | set(TSUGARU_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../TOWNSEMU/src) 26 | endif() 27 | 28 | add_subdirectory(${TSUGARU_SOURCE_DIR}/cpputil ${CMAKE_BINARY_DIR}/cpputil) 29 | add_subdirectory(${TSUGARU_SOURCE_DIR}/cheapmath ${CMAKE_BINARY_DIR}/cheapmath) 30 | add_subdirectory(${TSUGARU_SOURCE_DIR}/device ${CMAKE_BINARY_DIR}/device) 31 | add_subdirectory(${TSUGARU_SOURCE_DIR}/vmbase ${CMAKE_BINARY_DIR}/vmbase) 32 | add_subdirectory(${TSUGARU_SOURCE_DIR}/lineparser ${CMAKE_BINARY_DIR}/lineparser) 33 | # add_subdirectory(${TSUGARU_SOURCE_DIR}/ym2612 ${CMAKE_BINARY_DIR}/ym2612) Should be included from ym2203c library. 34 | add_subdirectory(${TSUGARU_SOURCE_DIR}/i8251 ${CMAKE_BINARY_DIR}/i8251) 35 | add_subdirectory(${TSUGARU_SOURCE_DIR}/diskdrive ${CMAKE_BINARY_DIR}/diskdrive) 36 | add_subdirectory(${TSUGARU_SOURCE_DIR}/osdependent/gamepad ${CMAKE_BINARY_DIR}/gamepad) 37 | add_subdirectory(${TSUGARU_SOURCE_DIR}/externals/d77 ${CMAKE_BINARY_DIR}/d77) 38 | add_subdirectory(${TSUGARU_SOURCE_DIR}/externals/yspng ${CMAKE_BINARY_DIR}/yspng) 39 | 40 | set(MUTSU_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../src) 41 | 42 | add_subdirectory(${MUTSU_SOURCE_DIR}/mc6809 mc6809) 43 | add_subdirectory(${MUTSU_SOURCE_DIR}/mc6809util mc6809util) 44 | add_subdirectory(${MUTSU_SOURCE_DIR}/memory memory) 45 | add_subdirectory(${MUTSU_SOURCE_DIR}/fm77av fm77av) 46 | add_subdirectory(${MUTSU_SOURCE_DIR}/main_cui main_cui) 47 | add_subdirectory(${MUTSU_SOURCE_DIR}/miscutil miscutil) 48 | add_subdirectory(${MUTSU_SOURCE_DIR}/ay38910 ay38910) 49 | add_subdirectory(${MUTSU_SOURCE_DIR}/t77lib t77lib) 50 | add_subdirectory(${MUTSU_SOURCE_DIR}/fm7lib fm7lib) 51 | add_subdirectory(${MUTSU_SOURCE_DIR}/ym2203c ym2203c) 52 | add_subdirectory(${MUTSU_SOURCE_DIR}/vgmrecorder vgmrecorder) 53 | add_subdirectory(${MUTSU_SOURCE_DIR}/tests tests) 54 | add_subdirectory(${MUTSU_SOURCE_DIR}/resources resources) 55 | add_subdirectory(${MUTSU_SOURCE_DIR}/outside_world outside_world) 56 | add_subdirectory(${MUTSU_SOURCE_DIR}/externals externals) 57 | 58 | add_subdirectory(main_gui) 59 | -------------------------------------------------------------------------------- /gui/src/main_gui/fsguimain.cpp: -------------------------------------------------------------------------------- 1 | /* //////////////////////////////////////////////////////////// 2 | 3 | File Name: fsguimain.cpp 4 | Copyright (c) 2017 Soji Yamakawa. All rights reserved. 5 | http://www.ysflight.com 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, 11 | this list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 19 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 21 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | //////////////////////////////////////////////////////////// */ 29 | 30 | #include 31 | #include 32 | 33 | // Comment out FSGUI_USE_SYSTEM_FONT to remove depencency on YsSystemFont library. 34 | #define FSGUI_USE_SYSTEM_FONT 35 | 36 | // Comment out FSGUI_USE_MODERN_UI to use primitive graphics, which may be faster. 37 | #define FSGUI_USE_MODERN_UI 38 | 39 | 40 | 41 | #ifdef FSGUI_USE_SYSTEM_FONT 42 | #include 43 | #endif 44 | 45 | #include "fsguiapp.h" 46 | 47 | 48 | 49 | class FsLazyWindowApplication : public FsLazyWindowApplicationBase 50 | { 51 | public: 52 | static FsLazyWindowApplication *currentApplication; 53 | YsSystemFontRenderer *sysFont; 54 | 55 | FsLazyWindowApplication(); 56 | ~FsLazyWindowApplication(); 57 | 58 | virtual void BeforeEverything(int ac,char *av[]); 59 | virtual void GetOpenWindowOption(FsOpenWindowOption &opt) const; 60 | virtual void Initialize(int ac,char *av[]); 61 | virtual void Interval(void); 62 | virtual void BeforeTerminate(void); 63 | virtual void Draw(void); 64 | virtual bool NeedRedraw(void) const; 65 | virtual bool MustTerminate(void) const; 66 | virtual long long int GetMinimumSleepPerInterval(void) const; 67 | }; 68 | 69 | FsLazyWindowApplication::FsLazyWindowApplication() 70 | { 71 | sysFont=nullptr; 72 | } 73 | FsLazyWindowApplication::~FsLazyWindowApplication() 74 | { 75 | if(nullptr!=sysFont) 76 | { 77 | delete sysFont; 78 | sysFont=nullptr; 79 | } 80 | } 81 | 82 | /* virtual */ void FsLazyWindowApplication::BeforeEverything(int,char *[]) 83 | { 84 | } 85 | 86 | /* virtual */ void FsLazyWindowApplication::GetOpenWindowOption(FsOpenWindowOption &opt) const 87 | { 88 | opt.x0=0; 89 | opt.y0=0; 90 | opt.wid=1024; 91 | opt.hei=768; 92 | } 93 | 94 | /* virtual */ void FsLazyWindowApplication::Initialize(int ac,char *av[]) 95 | { 96 | #ifdef FSGUI_USE_SYSTEM_FONT 97 | sysFont=new YsSystemFontRenderer; 98 | FsGuiObject::defUnicodeRenderer=sysFont; 99 | #endif 100 | 101 | #ifdef FSGUI_USE_MODERN_UI 102 | FsGuiObject::scheme=FsGuiObject::MODERN; 103 | FsGuiObject::defRoundRadius=8.0; 104 | FsGuiObject::defHScrollBar=20; 105 | FsGuiObject::defHAnnotation=14; 106 | FsGuiObject::defVSpaceUnit=12; 107 | 108 | FsGuiObject::defDialogBgCol.SetDoubleRGB(0.75,0.75,0.75); 109 | 110 | FsGuiObject::defTabBgCol.SetDoubleRGB(0.82,0.82,0.82); 111 | FsGuiObject::defTabClosedFgCol.SetDoubleRGB(0.8,0.8,0.8); 112 | FsGuiObject::defTabClosedBgCol.SetDoubleRGB(0.2,0.2,0.2); 113 | 114 | FsGuiObject::defBgCol.SetDoubleRGB(0.85,0.85,0.85); 115 | FsGuiObject::defFgCol.SetDoubleRGB(0.0,0.0,0.0); 116 | FsGuiObject::defActiveBgCol.SetDoubleRGB(0.3,0.3,0.7); 117 | FsGuiObject::defActiveFgCol.SetDoubleRGB(1.0,1.0,1.0); 118 | FsGuiObject::defFrameCol.SetDoubleRGB(0.0,0.0,0.0); 119 | 120 | FsGuiObject::defListFgCol.SetDoubleRGB(0.0,0.0,0.0); 121 | FsGuiObject::defListBgCol.SetDoubleRGB(0.8,0.8,0.8); 122 | FsGuiObject::defListActiveFgCol.SetDoubleRGB(1.0,1.0,1.0); 123 | FsGuiObject::defListActiveBgCol.SetDoubleRGB(0.3,0.3,0.7); 124 | #endif 125 | 126 | FsGuiObject::defUnicodeRenderer->RequestDefaultFontWithPixelHeight(16); 127 | FsGuiObject::defAsciiRenderer->RequestDefaultFontWithPixelHeight(16); 128 | 129 | YsCoordSysModel=YSOPENGL; 130 | 131 | // This should be the first call of FsGuiMainCanvas::GetMainCanvas(), 132 | // in which the application is created. 133 | FsGuiMainCanvas::GetMainCanvas()->Initialize(ac,av); 134 | } 135 | 136 | /* virtual */ void FsLazyWindowApplication::Interval(void) 137 | { 138 | FsGuiMainCanvas::GetMainCanvas()->OnInterval(); 139 | } 140 | 141 | /* virtual */ void FsLazyWindowApplication::BeforeTerminate(void) 142 | { 143 | YsGLSLDeleteSharedRenderer(); 144 | FsGuiMainCanvas::DeleteMainCanvas(); 145 | } 146 | 147 | /* virtual */ void FsLazyWindowApplication::Draw(void) 148 | { 149 | FsGuiMainCanvas::GetMainCanvas()->Draw(); 150 | } 151 | 152 | /* virtual */ bool FsLazyWindowApplication::NeedRedraw(void) const 153 | { 154 | return (bool)FsGuiMainCanvas::GetMainCanvas()->NeedRedraw(); 155 | } 156 | 157 | /* virtual */ bool FsLazyWindowApplication::MustTerminate(void) const 158 | { 159 | return (bool)FsGuiMainCanvas::GetMainCanvas()->appMustTerminate; 160 | } 161 | 162 | 163 | 164 | FsLazyWindowApplication *FsLazyWindowApplication::currentApplication=nullptr; 165 | 166 | /* static */ FsLazyWindowApplicationBase *FsLazyWindowApplicationBase::GetApplication(void) 167 | { 168 | if(nullptr==FsLazyWindowApplication::currentApplication) 169 | { 170 | FsLazyWindowApplication::currentApplication=new FsLazyWindowApplication; 171 | } 172 | return FsLazyWindowApplication::currentApplication; 173 | } 174 | 175 | /* virtual */ long long int FsLazyWindowApplication::GetMinimumSleepPerInterval(void) const 176 | { 177 | return 60; 178 | } 179 | -------------------------------------------------------------------------------- /gui/src/main_gui/profiledlg.h: -------------------------------------------------------------------------------- 1 | #ifndef PROFILEDLG_IS_INCLUDED 2 | #define PROFILEDLG_IS_INCLUDED 3 | /* { */ 4 | 5 | #include 6 | 7 | #include "fsgui.h" 8 | #include "fsguifiledialog.h" 9 | 10 | #include "fm77avparam.h" 11 | 12 | class ProfileDialog : public FsGuiDialog 13 | { 14 | public: 15 | typedef class ProfileDialog THISCLASS; 16 | 17 | enum 18 | { 19 | PATH_LENGTH=1024, 20 | PATH_SHOW=64, 21 | MAX_NUM_HOST_SHORTCUT=8, 22 | MAX_NUM_SHARED_DIR=4, 23 | MAX_NUM_ALIASES=8, 24 | }; 25 | 26 | 27 | class FsGuiMainCanvas *canvasPtr; 28 | 29 | FsGuiTabControl *tab; 30 | 31 | FsGuiStatic *profileFNameTxt; 32 | 33 | FsGuiButton *ROMDirBtn,*TapeImgBtn,*TapeSaveImgBtn,*FDImgBtn[FM77AVProfile::NUM_FDDRIVES]; 34 | FsGuiButton *AutoStartTapeBtn; 35 | FsGuiButton *FDWriteProtBtn[FM77AVProfile::NUM_FDDRIVES]; 36 | FsGuiTextBox *ROMDirTxt,*TapeImgTxt,*TapeSaveImgTxt,*FDImgTxt[FM77AVProfile::NUM_FDDRIVES]; 37 | FsGuiDropList *gamePortDrp[2]; // None, Pad0, Pad1, Keybord Emulation, Mouse, 38 | //FsGuiSlider *mouseIntegSpdSlider; 39 | //FsGuiButton *mouseIntegConsiderVRAMOffsetBtn; 40 | //FsGuiTextBox *mouseMinXTxt,*mouseMinYTxt,*mouseMaxXTxt,*mouseMaxYTxt; 41 | FsGuiTextBox *maxButtonHoldTimeTxt[2][2]; 42 | 43 | FsGuiTextBox *scrnScaleTxt; 44 | FsGuiButton *scrnAutoScaleBtn; 45 | FsGuiDropList *scrnModeDrp; 46 | FsGuiButton *autoStartBtn; 47 | FsGuiButton *runBtn; 48 | FsGuiDropList *machineTypeDrp; 49 | FsGuiButton *startUpStateFNameBtn; 50 | FsGuiTextBox *startUpStateFNameTxt; 51 | 52 | 53 | FsGuiTextBox *aliasNameTxt[MAX_NUM_ALIASES],*aliasFileTxt[MAX_NUM_ALIASES]; 54 | FsGuiButton *aliasBrowseBtn[MAX_NUM_ALIASES]; 55 | 56 | 57 | FsGuiDropList *keyboardModeDrp; 58 | FsGuiDropList *virtualKeyFM77AVKeyDrp[FM77AVProfile::MAX_NUM_VIRTUALKEYS]; 59 | FsGuiDropList *virtualKeyPhysIdDrp[FM77AVProfile::MAX_NUM_VIRTUALKEYS]; 60 | FsGuiDropList *virtualKeyButtonDrp[FM77AVProfile::MAX_NUM_VIRTUALKEYS]; 61 | FsGuiDropList *autoStopTypeDrp; 62 | FsGuiDropList *autoStopKeyDrp; 63 | 64 | 65 | FsGuiTextBox *scrnShotCropTxt[4]; 66 | FsGuiTextBox *mapXYExpressionTxt[2]; 67 | 68 | 69 | FsGuiDropList *hostShortCutKeyLabelDrp[MAX_NUM_HOST_SHORTCUT]; 70 | FsGuiButton *hostShortCutKeyCtrlBtn[MAX_NUM_HOST_SHORTCUT]; 71 | FsGuiButton *hostShortCutKeyShiftBtn[MAX_NUM_HOST_SHORTCUT]; 72 | FsGuiDropList *hostShortCutFunctionDrp[MAX_NUM_HOST_SHORTCUT]; 73 | FsGuiButton *quickSsDirBtn; 74 | FsGuiTextBox *quickSsDirTxt; 75 | 76 | FsGuiButton *quickStateSaveFNameBtn; 77 | FsGuiTextBox *quickStateSaveFNameTxt; 78 | 79 | FsGuiDropList *pauseResumeKeyDrp; 80 | 81 | FsGuiDropList *appSpecificAugDrp; 82 | FsGuiStatic *appSpecificExplanation; 83 | 84 | FsGuiButton *browseShareDirBtn[MAX_NUM_SHARED_DIR]; 85 | FsGuiTextBox *shareDirTxt[MAX_NUM_SHARED_DIR]; 86 | 87 | ProfileDialog(FsGuiMainCanvas *canvasPtr); 88 | 89 | void Make(void); 90 | 91 | void OnSliderPositionChange(FsGuiSlider *slider,const double &prevPos,const double &prevValue); 92 | 93 | virtual void OnDropListSelChange(FsGuiDropList *drp,int prevSel); 94 | 95 | virtual void OnButtonClick(FsGuiButton *btn); 96 | void OnSelectROMFile(FsGuiDialog *dlg,int returnCode); 97 | 98 | FsGuiTextBox *nowBrowsingTxt=nullptr; 99 | void Browse(const wchar_t label[],FsGuiTextBox *txt,std::vector extList,YsString defFileName); 100 | void OnSelectFile(FsGuiDialog *dlg,int returnCode); 101 | 102 | void BrowseDir(const wchar_t label[],FsGuiTextBox *txt,std::vector extList); 103 | void OnSelectDir(FsGuiDialog *dlg,int returnCode); 104 | 105 | void BrowseSaveAs(const wchar_t label[],FsGuiTextBox *txt,std::vector extList); 106 | void OnSelectFileSaveAs(FsGuiDialog *dlg,int returnCode); 107 | 108 | FM77AVProfile GetProfile(void) const; 109 | void SetProfile(const FM77AVProfile &profile); 110 | 111 | /* 1: Same drive same image file. 112 | 2: The other drive, same extension. 113 | 3: Any known directory, *.D77 114 | 4: Empty (Browse function will come up with default) 115 | */ 116 | YsString GetDefaultFloppyImageFile(unsigned int drive) const; 117 | 118 | /* 1: Currently-selected image file. 119 | 2: Any known directory, *.T77 120 | 3: Empty (Browse function will come up with default) 121 | */ 122 | YsString GetDefaultTapeImageFile(void) const; 123 | 124 | /* 1: Currently-selected state file. 125 | 2: Any known directory, *.7state 126 | 3: Empty (Browse function will come up with default) 127 | */ 128 | YsString GetDefaultVMStateFile(void) const; 129 | 130 | YsString GetAnyKnownDirectory(void) const; 131 | 132 | YsString GetDirectoryFromTextBox(FsGuiTextBox *txtBox) const; 133 | }; 134 | 135 | 136 | /* } */ 137 | #endif 138 | -------------------------------------------------------------------------------- /gui/src/main_gui/readme.txt: -------------------------------------------------------------------------------- 1 | 2 | This template demonstrates a standard-way of using FS GUI library. 3 | 4 | Some APIs takes over main loop and never gives control to the application. I don't think it is right. The programmer should be able to choose whether the application takes control of the main loop. 5 | 6 | However, at least iOS doesn't give control of the main loop, and if you look at the OpenGL ES template, everything needs to be driven from event-handling functions. Probably the easiest way is to drive the application from the interval function. 7 | 8 | fsgui3dmain.cpp mimics the framework of the iOS OpenGL ES application template. The application needs to be driven from FsGui3DAppIntervalCallBack function in fsgui3dapp.cpp. This call-back function shouldn't block and give back control to the application framework, unfortunately. 9 | 10 | But, by following this style, the program should be easily ported to iOS. 11 | 12 | 13 | 14 | As of 03/04/2013, fsgui3d library is yet to be ready for OpenGL ES 2.0. So, this framework is yet to be ready for iOS. But, it will be done soon. 15 | -------------------------------------------------------------------------------- /gui/src/main_gui/runvm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "runvm.h" 4 | #include "fssimplewindow_connection.h" 5 | 6 | #ifdef _WIN32 7 | #include 8 | #else 9 | static void timeBeginPeriod(int) 10 | { 11 | } 12 | static void timeEndPeriod(int) 13 | { 14 | } 15 | #endif 16 | 17 | /* virtual */ void FM77AVCommandQueue::Main(FM77AVThread &,FM77AV &,const FM77AVParam &,Outside_World &) 18 | { 19 | } 20 | /* virtual */ void FM77AVCommandQueue::ExecCommandQueue(FM77AVThread &vmThread,FM77AV &fm77av,Outside_World *outside_world) 21 | { 22 | for(int i=0; i<2; ++i) 23 | { 24 | auto &cmdqueue=(i==0 ? this->cmdqueue : outside_world->commandQueue); 25 | while(true!=cmdqueue.empty()) 26 | { 27 | auto cmdline=cmdqueue.front(); 28 | cmdqueue.pop(); 29 | 30 | std::cout << cmdline << std::endl; 31 | 32 | auto cmd=cmdInterpreter.Interpret(cmdline); 33 | cmdInterpreter.Execute(vmThread,fm77av,outside_world,cmd); 34 | if(FM77AVCommandInterpreter::CMD_QUIT==cmd.primaryCmd) 35 | { 36 | } 37 | } 38 | } 39 | } 40 | 41 | void FM77AVCommandQueue::SendCommand(std::string cmd) 42 | { 43 | uiLock.lock(); 44 | this->cmdqueue.push(cmd); 45 | uiLock.unlock(); 46 | } 47 | 48 | FM77AVVM::FM77AVVM() 49 | { 50 | } 51 | FM77AVVM::~FM77AVVM() 52 | { 53 | Free(); 54 | } 55 | 56 | void FM77AVVM::Alloc(void) 57 | { 58 | fm77avPtr=new FM77AV; 59 | fm77avThreadPtr=new FM77AVThread; 60 | cmdQueuePtr=new FM77AVCommandQueue; 61 | outsideWorldPtr=new FsSimpleWindowConnection; 62 | outsideWorldPtr->lowerRightIcon=Outside_World::LOWER_RIGHT_MENU; 63 | soundPtr=outsideWorldPtr->CreateSound(); 64 | windowPtr=outsideWorldPtr->CreateWindowInterface(); 65 | fm77avThreadPtr->SetRunMode(FM77AVThread::RUNMODE_RUN); 66 | fm77avThreadPtr->SetReturnOnPause(true); 67 | } 68 | void FM77AVVM::Free(void) 69 | { 70 | if(nullptr!=outsideWorldPtr) 71 | { 72 | outsideWorldPtr->DeleteSound(soundPtr); 73 | soundPtr=nullptr; 74 | outsideWorldPtr->DeleteWindowInterface(windowPtr); 75 | windowPtr=nullptr; 76 | } 77 | delete fm77avThreadPtr; 78 | delete fm77avPtr; 79 | delete cmdQueuePtr; 80 | delete outsideWorldPtr; 81 | fm77avPtr=nullptr; 82 | fm77avThreadPtr=nullptr; 83 | cmdQueuePtr=nullptr; 84 | outsideWorldPtr=nullptr; 85 | } 86 | 87 | std::vector FM77AVVM::GetMissingROMFiles(void) const 88 | { 89 | return fm77avPtr->CheckMissingROMFiles(profile); 90 | } 91 | 92 | void FM77AVVM::Run(void) 93 | { 94 | bool freshStart=false; 95 | if(nullptr==fm77avPtr || 96 | FM77AVThread::RUNMODE_EXIT==fm77avThreadPtr->GetRunMode()) 97 | { 98 | Free(); 99 | Alloc(); 100 | 101 | fm77avPtr->SetUp(profile,outsideWorldPtr,windowPtr); 102 | windowPtr->Start(); 103 | freshStart=true; 104 | } 105 | 106 | windowPtr->ClearVMClosedFlag(); 107 | 108 | std::thread VMThr([&] 109 | { 110 | if(true==freshStart) 111 | { 112 | fm77avThreadPtr->VMStart(fm77avPtr,outsideWorldPtr,windowPtr,cmdQueuePtr); 113 | } 114 | fm77avThreadPtr->SetRunMode(FM77AVThread::RUNMODE_RUN); 115 | fm77avThreadPtr->VMMainLoop(fm77avPtr,outsideWorldPtr,windowPtr,soundPtr,cmdQueuePtr); 116 | if(FM77AVThread::RUNMODE_EXIT==fm77avThreadPtr->GetRunMode()) 117 | { 118 | fm77avThreadPtr->VMEnd(fm77avPtr,outsideWorldPtr,windowPtr,cmdQueuePtr); 119 | } 120 | }); 121 | 122 | auto t0=std::chrono::high_resolution_clock::now(); 123 | while(true!=windowPtr->CheckVMClosed()) 124 | { 125 | windowPtr->Interval(); 126 | auto t=std::chrono::high_resolution_clock::now(); 127 | auto dt=t-t0; 128 | if(50<=std::chrono::duration_cast(dt).count() || true==windowPtr->winThr.newImageRendered) 129 | { 130 | windowPtr->Render(true); 131 | t0=t; 132 | windowPtr->winThr.newImageRendered=false; 133 | } 134 | else 135 | { 136 | timeBeginPeriod(1); 137 | std::this_thread::sleep_for(std::chrono::milliseconds(8)); 138 | timeEndPeriod(1); 139 | } 140 | } 141 | 142 | VMThr.join(); 143 | 144 | if(FM77AVThread::RUNMODE_EXIT==fm77avThreadPtr->GetRunMode()) 145 | { 146 | windowPtr->Stop(); 147 | Free(); 148 | } 149 | } 150 | bool FM77AVVM::IsRunning(void) const 151 | { 152 | return 153 | (nullptr!=fm77avThreadPtr && 154 | FM77AVThread::RUNMODE_EXIT!=fm77avThreadPtr->GetRunMode()); 155 | } 156 | void FM77AVVM::SendCommand(std::string cmd) 157 | { 158 | if(nullptr!=cmdQueuePtr) 159 | { 160 | cmdQueuePtr->SendCommand(cmd); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /gui/src/main_gui/runvm.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNVM_IS_INCLUDED 2 | #define RUNVM_IS_INCLUDED 3 | /* { */ 4 | 5 | 6 | 7 | #ifdef OUT 8 | #undef OUT 9 | #endif 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "fm77av.h" 16 | #include "fm77avthread.h" 17 | #include "outside_world.h" 18 | #include "fm77avcommand.h" 19 | #include "fm77avparam.h" 20 | #include "fssimplewindow_connection.h" 21 | 22 | class FM77AVCommandQueue : public FM77AVUIThread 23 | { 24 | public: 25 | using FM77AVUIThread::uiLock; 26 | std::queue cmdqueue; 27 | FM77AVCommandInterpreter cmdInterpreter; 28 | 29 | virtual void Main(FM77AVThread &vmThread,FM77AV &fm77av,const FM77AVParam &argv,Outside_World &outside_world); 30 | virtual void ExecCommandQueue(FM77AVThread &vmThread,FM77AV &fm77av,Outside_World *outside_world); 31 | 32 | void SendCommand(std::string cmd); 33 | }; 34 | 35 | class FM77AVVM 36 | { 37 | public: 38 | FM77AVProfile profile; 39 | FM77AVRender lastImage; 40 | FM77AV *fm77avPtr=nullptr; 41 | FM77AVThread *fm77avThreadPtr=nullptr; 42 | FM77AVCommandQueue *cmdQueuePtr=nullptr; 43 | FsSimpleWindowConnection *outsideWorldPtr=nullptr; 44 | Outside_World::WindowInterface *windowPtr=nullptr; 45 | Outside_World::Sound *soundPtr=nullptr; 46 | 47 | FM77AVVM(); 48 | ~FM77AVVM(); 49 | 50 | void Alloc(void); 51 | void Free(void); 52 | 53 | std::vector GetMissingROMFiles(void) const; 54 | void Run(void); 55 | bool IsRunning(void) const; 56 | void SendCommand(std::string cmd); 57 | }; 58 | 59 | 60 | 61 | /* } */ 62 | #endif 63 | -------------------------------------------------------------------------------- /gui/src/main_gui/singleton.cpp: -------------------------------------------------------------------------------- 1 | /* //////////////////////////////////////////////////////////// 2 | 3 | File Name: singleton.cpp 4 | Copyright (c) 2017 Soji Yamakawa. All rights reserved. 5 | http://www.ysflight.com 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, 11 | this list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 19 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 21 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | //////////////////////////////////////////////////////////// */ 29 | 30 | #include "fsguiapp.h" 31 | 32 | static FsGuiMainCanvas *appPtr=nullptr; 33 | 34 | /* static */ FsGuiMainCanvas *FsGuiMainCanvas::GetMainCanvas() 35 | { 36 | if(nullptr==appPtr) 37 | { 38 | appPtr=new FsGuiMainCanvas; 39 | } 40 | return appPtr; 41 | } 42 | 43 | /* static */ void FsGuiMainCanvas::DeleteMainCanvas(void) 44 | { 45 | if(nullptr!=appPtr) 46 | { 47 | delete appPtr; 48 | appPtr=nullptr; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /scripts/build.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | import shutil 4 | import sys 5 | 6 | THISFILE=os.path.realpath(__file__) 7 | THISDIR=os.path.dirname(THISFILE) 8 | BUILDDIR=os.path.join(THISDIR,"..","build") 9 | SRCDIR=os.path.join(THISDIR,"..","src") 10 | 11 | 12 | 13 | def Run(): 14 | cwd=os.getcwd() 15 | 16 | os.chdir(BUILDDIR) 17 | 18 | cmd=[ 19 | "cmake", 20 | "--build", 21 | ".", 22 | "--config", 23 | "Release", 24 | "--parallel", 25 | ] 26 | 27 | proc=subprocess.Popen(cmd) 28 | proc.communicate(); 29 | 30 | print(cmd) 31 | 32 | os.chdir(cwd) 33 | 34 | if proc.returncode!=0: 35 | print("Build Error!") 36 | quit() 37 | 38 | 39 | 40 | if __name__=="__main__": 41 | Run() 42 | 43 | 44 | -------------------------------------------------------------------------------- /scripts/buildgui.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | import shutil 4 | import sys 5 | 6 | THISFILE=os.path.realpath(__file__) 7 | THISDIR=os.path.dirname(THISFILE) 8 | BUILDDIR=os.path.join(THISDIR,"..","gui","build") 9 | 10 | 11 | 12 | def Run(): 13 | cwd=os.getcwd() 14 | 15 | os.chdir(BUILDDIR) 16 | 17 | cmd=[ 18 | "cmake", 19 | "--build", 20 | ".", 21 | "--config", 22 | "Release", 23 | "--parallel", 24 | ] 25 | 26 | proc=subprocess.Popen(cmd) 27 | proc.communicate(); 28 | 29 | print(cmd) 30 | 31 | os.chdir(cwd) 32 | 33 | if proc.returncode!=0: 34 | print("Build Error!") 35 | quit() 36 | 37 | 38 | 39 | if __name__=="__main__": 40 | Run() 41 | 42 | 43 | -------------------------------------------------------------------------------- /scripts/run.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | import shutil 4 | import sys 5 | import sys 6 | 7 | import build 8 | 9 | MACHINETYPE="7" 10 | 11 | THISFILE=os.path.realpath(__file__) 12 | THISDIR=os.path.dirname(THISFILE) 13 | MUTSUDIR=os.path.join(THISDIR,"..") 14 | 15 | BUILDDIR=os.path.join(MUTSUDIR,"build") 16 | SRCDIR=os.path.join(MUTSUDIR,"src") 17 | ROMDIR=os.path.join(MUTSUDIR,"..","77AVTEST","ROMS",MACHINETYPE) 18 | DISKDIR=os.path.join(MUTSUDIR,"..","77AVTEST","DISK") 19 | TAPEDIR=os.path.join(MUTSUDIR,"..","77AVTEST","TAPE") 20 | 21 | 22 | 23 | def ExeExtension(): 24 | if sys.platform.startswith('win'): 25 | return ".exe" 26 | else: 27 | return "" 28 | 29 | 30 | 31 | def MutsuExe(): 32 | fName=os.path.join(MUTSUDIR,"build","main_cui","Mutsu_CUI"+ExeExtension()) 33 | if os.path.isfile(fName): 34 | return fName 35 | fName=os.path.join(MUTSUDIR,"build","main_cui","Release","Mutsu_CUI"+ExeExtension()) 36 | if os.path.isfile(fName): 37 | return fName 38 | fName=os.path.join(MUTSUDIR,"build","main_cui","Mutsu_CUI.app","Contents","MacOS","Mutsu_CUI"+ExeExtension()) 39 | if os.path.isfile(fName): 40 | return fName 41 | throw 42 | 43 | 44 | 45 | def Run(argv): 46 | subprocess.Popen([ 47 | MutsuExe(), 48 | ]+argv).wait() 49 | 50 | 51 | 52 | if __name__=="__main__": 53 | build.Run() 54 | Run(sys.argv[1:]) 55 | -------------------------------------------------------------------------------- /scripts/run7.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | import shutil 4 | import sys 5 | import sys 6 | 7 | import build 8 | 9 | MACHINETYPE="7" 10 | 11 | THISFILE=os.path.realpath(__file__) 12 | THISDIR=os.path.dirname(THISFILE) 13 | MUTSUDIR=os.path.join(THISDIR,"..") 14 | 15 | BUILDDIR=os.path.join(MUTSUDIR,"build") 16 | SRCDIR=os.path.join(MUTSUDIR,"src") 17 | ROMDIR=os.path.join(MUTSUDIR,"..","77AVTEST","ROMS",MACHINETYPE) 18 | DISKDIR=os.path.join(MUTSUDIR,"..","77AVTEST","DISK") 19 | TAPEDIR=os.path.join(MUTSUDIR,"..","77AVTEST","TAPE") 20 | SYMTABLEDIR=os.path.join(MUTSUDIR,"..","77AVTEST","SYMTABLE") 21 | 22 | 23 | def ExeExtension(): 24 | if sys.platform.startswith('win'): 25 | return ".exe" 26 | else: 27 | return "" 28 | 29 | 30 | 31 | def MutsuExe(): 32 | fName=os.path.join(MUTSUDIR,"build","main_cui","Mutsu_CUI"+ExeExtension()) 33 | if os.path.isfile(fName): 34 | return fName 35 | fName=os.path.join(MUTSUDIR,"build","main_cui","Release","Mutsu_CUI"+ExeExtension()) 36 | if os.path.isfile(fName): 37 | return fName 38 | fName=os.path.join(MUTSUDIR,"build","main_cui","Mutsu_CUI.app","Contents","MacOS","Mutsu_CUI"+ExeExtension()) 39 | if os.path.isfile(fName): 40 | return fName 41 | throw 42 | 43 | 44 | 45 | def Run(argv): 46 | subprocess.Popen([ 47 | MutsuExe(), 48 | ROMDIR, 49 | "-SYM", 50 | os.path.join(SYMTABLEDIR,"RUN"+MACHINETYPE+".txt"), 51 | #"-DEBUG", 52 | #"-PAUSE", 53 | "-AUTOSCALE", 54 | "-INITCMD","ena cst", 55 | "-INITCMD","mute sub", 56 | ]+argv).wait() 57 | 58 | 59 | 60 | if __name__=="__main__": 61 | build.Run() 62 | Run(sys.argv[1:]) 63 | -------------------------------------------------------------------------------- /scripts/runGUI.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | import shutil 4 | import sys 5 | import sys 6 | 7 | import buildgui 8 | 9 | MACHINETYPE="AV" 10 | 11 | THISFILE=os.path.realpath(__file__) 12 | THISDIR=os.path.dirname(THISFILE) 13 | MUTSUDIR=os.path.join(THISDIR,"..") 14 | 15 | BUILDDIR=os.path.join(MUTSUDIR,"gui","build") 16 | SRCDIR=os.path.join(MUTSUDIR,"gui","src") 17 | ROMDIR=os.path.join(MUTSUDIR,"..","77AVTEST","ROMS",MACHINETYPE) 18 | DISKDIR=os.path.join(MUTSUDIR,"..","77AVTEST","DISK") 19 | TAPEDIR=os.path.join(MUTSUDIR,"..","77AVTEST","TAPE") 20 | 21 | 22 | 23 | def ExeExtension(): 24 | if sys.platform.startswith('win'): 25 | return ".exe" 26 | else: 27 | return "" 28 | 29 | 30 | 31 | def MutsuExe(): 32 | fName=os.path.join(BUILDDIR,"main_gui","Mutsu_GUI"+ExeExtension()) 33 | if os.path.isfile(fName): 34 | return fName 35 | fName=os.path.join(BUILDDIR,"main_gui","Release","Mutsu_GUI"+ExeExtension()) 36 | if os.path.isfile(fName): 37 | return fName 38 | fName=os.path.join(BUILDDIR,"main_gui","Mutsu_GUI.app","Contents","MacOS","Mutsu_GUI"+ExeExtension()) 39 | if os.path.isfile(fName): 40 | return fName 41 | throw 42 | 43 | 44 | 45 | def Run(argv): 46 | subprocess.Popen([ 47 | MutsuExe(), 48 | ROMDIR, 49 | "-AUTOSCALE", 50 | #"-SYM", 51 | #os.path.join(MUTSUDIR,"symtables","RUN"+MACHINETYPE+".txt"), 52 | #"-DEBUG", 53 | #"-PAUSE", 54 | ]+argv).wait() 55 | 56 | 57 | 58 | def GitPull(): 59 | cwd=os.getcwd(); 60 | os.chdir(SRCDIR) 61 | if os.path.isdir("public"): 62 | proc=subprocess.Popen(["git","pull"]) 63 | proc.communicate(); 64 | if 0!=proc.returncode: 65 | print("Failed to update public libraries.") 66 | throw 67 | else: 68 | proc=subprocess.Popen(["git","clone","https://github.com/captainys/public.git"]) 69 | proc.communicate() 70 | if 0!=proc.returncode: 71 | print("Failed to checkout public libraries.") 72 | throw 73 | if True!=os.path.isdir(BUILDDIR): 74 | os.mkdir(BUILDDIR) 75 | os.chdir(BUILDDIR) 76 | proc=subprocess.Popen(["cmake","../src"]) 77 | proc.communicate() 78 | if 0!=proc.returncode: 79 | print("Failed to set up CMake projects.") 80 | throw 81 | os.chdir(cwd); 82 | 83 | 84 | 85 | if __name__=="__main__": 86 | GitPull() 87 | buildgui.Run() 88 | Run(sys.argv[1:]) 89 | -------------------------------------------------------------------------------- /scripts/runav.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | import shutil 4 | import sys 5 | import sys 6 | 7 | import build 8 | 9 | MACHINETYPE="AV" 10 | 11 | THISFILE=os.path.realpath(__file__) 12 | THISDIR=os.path.dirname(THISFILE) 13 | MUTSUDIR=os.path.join(THISDIR,"..") 14 | 15 | BUILDDIR=os.path.join(MUTSUDIR,"build") 16 | SRCDIR=os.path.join(MUTSUDIR,"src") 17 | ROMDIR=os.path.join(MUTSUDIR,"..","77AVTEST","ROMS",MACHINETYPE) 18 | DISKDIR=os.path.join(MUTSUDIR,"..","77AVTEST","DISK") 19 | TAPEDIR=os.path.join(MUTSUDIR,"..","77AVTEST","TAPE") 20 | 21 | 22 | 23 | def ExeExtension(): 24 | if sys.platform.startswith('win'): 25 | return ".exe" 26 | else: 27 | return "" 28 | 29 | 30 | 31 | def MutsuExe(): 32 | fName=os.path.join(MUTSUDIR,"build","main_cui","Mutsu_CUI"+ExeExtension()) 33 | if os.path.isfile(fName): 34 | return fName 35 | fName=os.path.join(MUTSUDIR,"build","main_cui","Release","Mutsu_CUI"+ExeExtension()) 36 | if os.path.isfile(fName): 37 | return fName 38 | fName=os.path.join(MUTSUDIR,"build","main_cui","Mutsu_CUI.app","Contents","MacOS","Mutsu_CUI"+ExeExtension()) 39 | if os.path.isfile(fName): 40 | return fName 41 | throw 42 | 43 | 44 | 45 | def Run(argv): 46 | subprocess.Popen([ 47 | MutsuExe(), 48 | ROMDIR, 49 | "-AUTOSCALE", 50 | "-INITCMD", "mute sub", 51 | "-INITCMD", "ena cst", 52 | #"-SYM", 53 | #os.path.join(MUTSUDIR,"symtables","RUN"+MACHINETYPE+".txt"), 54 | #"-DEBUG", 55 | #"-PAUSE", 56 | ]+argv).wait() 57 | 58 | 59 | 60 | if __name__=="__main__": 61 | build.Run() 62 | Run(sys.argv[1:]) 63 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | project(MUTSU) 3 | 4 | enable_testing() 5 | 6 | set(CMAKE_CXX_STANDARD 17) 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | 9 | add_compile_definitions(MUTSU_FM77AV) 10 | 11 | if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../TOWNSEMU) 12 | set(TSUGARU_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../TOWNSEMU/src) 13 | else() 14 | set(TSUGARU_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../TOWNSEMU/src) 15 | endif() 16 | 17 | add_subdirectory(${TSUGARU_SOURCE_DIR}/cpputil ${CMAKE_BINARY_DIR}/cpputil) 18 | add_subdirectory(${TSUGARU_SOURCE_DIR}/cheapmath ${CMAKE_BINARY_DIR}/cheapmath) 19 | add_subdirectory(${TSUGARU_SOURCE_DIR}/device ${CMAKE_BINARY_DIR}/device) 20 | add_subdirectory(${TSUGARU_SOURCE_DIR}/vmbase ${CMAKE_BINARY_DIR}/vmbase) 21 | add_subdirectory(${TSUGARU_SOURCE_DIR}/lineparser ${CMAKE_BINARY_DIR}/lineparser) 22 | # add_subdirectory(${TSUGARU_SOURCE_DIR}/ym2612 ${CMAKE_BINARY_DIR}/ym2612) Should be included from ym2203c 23 | add_subdirectory(${TSUGARU_SOURCE_DIR}/i8251 ${CMAKE_BINARY_DIR}/i8251) 24 | add_subdirectory(${TSUGARU_SOURCE_DIR}/diskdrive ${CMAKE_BINARY_DIR}/diskdrive) 25 | add_subdirectory(${TSUGARU_SOURCE_DIR}/osdependent/gamepad ${CMAKE_BINARY_DIR}/gamepad) 26 | add_subdirectory(${TSUGARU_SOURCE_DIR}/externals/yssimplesound/src ${CMAKE_BINARY_DIR}/yssimplesound) 27 | add_subdirectory(${TSUGARU_SOURCE_DIR}/externals/fssimplewindow/src ${CMAKE_BINARY_DIR}/fssimplewindow) 28 | add_subdirectory(${TSUGARU_SOURCE_DIR}/externals/yspng ${CMAKE_BINARY_DIR}/yspng) 29 | add_subdirectory(${TSUGARU_SOURCE_DIR}/externals/d77 ${CMAKE_BINARY_DIR}/d77) 30 | 31 | add_subdirectory(mc6809) 32 | add_subdirectory(mc6809util) 33 | add_subdirectory(memory) 34 | add_subdirectory(fm77av) 35 | add_subdirectory(main_cui) 36 | add_subdirectory(miscutil) 37 | add_subdirectory(ay38910) 38 | add_subdirectory(ym2203c) 39 | add_subdirectory(vgmrecorder) 40 | add_subdirectory(tests) 41 | add_subdirectory(resources) 42 | add_subdirectory(outside_world) 43 | add_subdirectory(externals) 44 | add_subdirectory(t77lib) 45 | add_subdirectory(fm7lib) 46 | 47 | add_subdirectory(exas_compiler) 48 | -------------------------------------------------------------------------------- /src/ay38910/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TARGET_NAME ay38910) 2 | add_library(${TARGET_NAME} ay38910.h ay38910.cpp) 3 | target_link_libraries(${TARGET_NAME} cpputil) 4 | target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 5 | -------------------------------------------------------------------------------- /src/ay38910/ay38910.h: -------------------------------------------------------------------------------- 1 | #ifndef AY38910_IS_INCLUDED 2 | #define AY38910_IS_INCLUDED 3 | /* { */ 4 | 5 | 6 | 7 | #include 8 | #include 9 | 10 | class AY38910 11 | { 12 | public: 13 | enum 14 | { 15 | PRESCALING_DEFAULT=2, 16 | 17 | NUM_CHANNELS=3, 18 | NUM_REGS=16, 19 | REG_MASK=NUM_REGS-1, 20 | FREQ_CONST=1228800, // FM-Techknow pp.230, 200000 for PC88? 21 | MAX_AMPLITUDE=4096, 22 | 23 | ENV_OUT_MAX=256, 24 | LFSR_CYCLE=255, 25 | 26 | WAVE_SAMPLING_RATE=44100, // Must be equal from ym2612.h 27 | 28 | REG_CH0_FREQ_LOW=0, 29 | REG_CH0_FEEQ_HIGH=1, 30 | REG_CH1_FREQ_LOW=2, 31 | REG_CH1_FEEQ_HIGH=3, 32 | REG_CH2_FREQ_LOW=4, 33 | REG_CH2_FEEQ_HIGH=5, 34 | REG_NOISE_FREQ=6, 35 | REG_MIXER=7, 36 | REG_CH0_VOL=8, 37 | REG_CH1_VOL=9, 38 | REG_CH2_VOL=10, 39 | REG_ENV_FREQ_LOW=11, 40 | REG_ENV_FREQ_HIGH=12, 41 | REG_ENV_PATTERN=13, 42 | REG_PORTA=14, 43 | REG_PORTB=15, 44 | }; 45 | enum 46 | { 47 | ENV_UP, 48 | ENV_DOWN, 49 | ENV_ZERO, 50 | ENV_ONE, 51 | ENV_REPT, 52 | ENV_KEEP 53 | }; 54 | 55 | class RegWriteLog 56 | { 57 | public: 58 | uint64_t t; 59 | uint8_t reg,value; 60 | }; 61 | 62 | class Channel 63 | { 64 | public: 65 | unsigned int toneSign=0; 66 | unsigned int tonePeriodBalance=0; 67 | }; 68 | class State 69 | { 70 | public: 71 | uint8_t regs[NUM_REGS]; 72 | Channel ch[NUM_CHANNELS]; 73 | unsigned int envPhase=0; 74 | unsigned int envOut=0; 75 | unsigned int envPeriodBalance=0; 76 | unsigned int envPatternSeg=0; // 0 to 3. Index to envPtn[PTN]. 77 | 78 | unsigned int preScaler=2; 79 | 80 | uint32_t LFSR=1; 81 | unsigned int noisePeriodBalance=0; 82 | }; 83 | State state; 84 | 85 | bool channelMute[NUM_CHANNELS]={false,false,false}; 86 | 87 | static const uint8_t envPtn[16][4]; 88 | static const unsigned int DAConvOut[16]; 89 | 90 | bool takeRegisterLog=false; 91 | std::vector registerLog; 92 | 93 | AY38910(); 94 | void Reset(void); 95 | uint8_t ReadRegister(uint8_t reg) const; 96 | void WriteRegister(uint8_t reg,uint8_t value,uint64_t vmTime); 97 | private: 98 | void ReallyWriteRegister(uint8_t reg,uint8_t value,uint64_t vmTime); 99 | void WriteRegisterSchedule(unsigned int reg,unsigned int value,uint64_t vmTime); 100 | public: 101 | inline bool IsPlaying(void) const 102 | { 103 | return ((state.regs[REG_MIXER]&0x3F)!=0x3F || 0 MakeWaveAllChannels(unsigned long long int millisec,uint64_t lastWaveGentime); 117 | void AddWaveAllChannelsForNumSamples(unsigned char data[],unsigned long long int numSamples,uint64_t lastWaveGentime); 118 | private: 119 | class PlaybackParam; 120 | class WithScheduler; 121 | class WithoutScheduler; 122 | template 123 | void AddWaveAllChannelsForNumSamplesTemplate(unsigned char data[],unsigned long long int numSamples,uint64_t lastWaveGentime); 124 | void RecalculatePlaybackParam(PlaybackParam &pp); 125 | 126 | public: 127 | std::vector GetStatusText(void) const; 128 | 129 | std::vector FormatRegisterLog(void) const; 130 | 131 | 132 | 133 | /* Some PSG magicians bangs registers faster than the wave-generation interval. In such situation, 134 | AY38910 class needs to remember register-write log, and update as it generates wave. 135 | 136 | Schedule must be flushed: 137 | After every wave generation, 138 | Before saving state. 139 | 140 | To enable scheduling, 141 | (1) useScheduling=true; 142 | (2) VM needs to remember when the wave was generated for the last time, and pass it to MakeWaveForNSamples. 143 | (3) VM needs to copy regs to regCache on state load. 144 | */ 145 | bool useScheduling=false; 146 | uint8_t regCache[NUM_REGS]; 147 | // AY registers are readable. Some may be using register read to identify FM-7 and FM-8. 148 | // Therefore, register values need to be written to the registers immediately, but to 149 | // delay writing, it needs to remember the state of the registers at the end of last wave generation. 150 | std::vector regWriteSched; 151 | void FlushRegisterSchedule(void); 152 | }; 153 | 154 | /* } */ 155 | #endif 156 | -------------------------------------------------------------------------------- /src/exas_compiler/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TARGET_NAME exas_compiler) 2 | add_library(${TARGET_NAME} exas_compiler.cpp exas_compiler.h) 3 | #target_link_libraries(${TARGET_NAME} cpputil) 4 | target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 5 | -------------------------------------------------------------------------------- /src/exas_compiler/exas_compiler.cpp: -------------------------------------------------------------------------------- 1 | #include "exas_compiler.h" 2 | -------------------------------------------------------------------------------- /src/exas_compiler/exas_compiler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define ENABLE_EXAS_COMPILER 11 | 12 | class ExasCompiler { 13 | protected: 14 | size_t exasAddr; 15 | bool ready; 16 | std::vector rom0; 17 | std::vector rom12x; 18 | public: 19 | ExasCompiler() : exasAddr(0), ready(false) {}; 20 | 21 | void LoadROMFiles(std::string ROMPath) { 22 | { 23 | std::ifstream ifs(ROMPath + "EXAS-0.ROM", std::ios::binary); 24 | if (!ifs.is_open()) return; 25 | rom0.resize(64); 26 | ifs.read(reinterpret_cast(rom0.data()), 64); 27 | } 28 | 29 | std::vector RomNames = { "EXAS-1.ROM", "EXAS-2.ROM", "EXAS-X.ROM" }; 30 | constexpr size_t RomSize = 0x2000; 31 | rom12x.clear(); 32 | for (auto it = RomNames.begin(); it != RomNames.end(); ++it) 33 | { 34 | std::ifstream ifs(ROMPath + (*it), std::ios::binary); 35 | if (!ifs.is_open()) return; 36 | std::vector buf; 37 | buf.resize(RomSize); 38 | ifs.read(reinterpret_cast(buf.data()), RomSize); 39 | rom12x.insert(rom12x.end(), buf.begin(), buf.end()); 40 | } 41 | ready = true; 42 | } 43 | 44 | void IncrementAddress(void) { 45 | exasAddr ++; 46 | if (exasAddr >= rom12x.size()) 47 | { 48 | exasAddr = 0; 49 | } 50 | } 51 | 52 | void Reset(void) { 53 | exasAddr = 0; 54 | } 55 | 56 | uint8_t ReadROM_12X(void) const { 57 | return rom12x[exasAddr]; 58 | } 59 | 60 | uint8_t ReadROM_0(const size_t addr) const { 61 | return rom0[addr]; 62 | } 63 | 64 | bool isReady(void) const { 65 | return ready; 66 | } 67 | 68 | }; 69 | -------------------------------------------------------------------------------- /src/externals/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(connect_fssimplewindow) 2 | add_subdirectory(ysbitmapfont) 3 | -------------------------------------------------------------------------------- /src/externals/connect_fssimplewindow/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TARGET_NAME fssimplewindow_connection) 2 | 3 | add_library(${TARGET_NAME} fssimplewindow_connection.h fssimplewindow_connection.cpp) 4 | target_link_libraries(${TARGET_NAME} outside_world fm77av fm77avkeyboard fssimplewindow fontdata yssimplesound cpputil ysgamepad) 5 | target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 6 | 7 | if(MSVC) 8 | target_link_libraries(${TARGET_NAME} yssimplesound_dsound) 9 | elseif(APPLE) 10 | find_library(COCOA_LIB Cocoa) 11 | mark_as_advanced(COCOA_LIB) 12 | target_link_libraries(${TARGET_NAME} yssimplesound_macosx ${COCOA_LIB}) 13 | elseif(UNIX) 14 | target_link_libraries(${TARGET_NAME} yssimplesound_linux_alsa) 15 | endif() 16 | -------------------------------------------------------------------------------- /src/externals/connect_fssimplewindow/fssimplewindow_connection.h: -------------------------------------------------------------------------------- 1 | /* LICENSE>> 2 | Copyright 2020 Soji Yamakawa (CaptainYS, http://www.ysflight.com) 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. Redistributions in binary form 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. 9 | 10 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | 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 HOLDER 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. 13 | 14 | << LICENSE */ 15 | #ifndef FSSIMPLEWINDOW_CONNECTION_IS_INCLUDED 16 | #define FSSIMPLEWINDOW_CONNECTION_IS_INCLUDED 17 | /* { */ 18 | 19 | 20 | 21 | /* 22 | The original plan was entirely transition to the streaming mode. However, it turned out DirectSound gives an shameful 60ms latency (practically 80ms), and ALSA apalling 80ms latency. 23 | macOS's AVAudioEngine easily gave a 40ms latency. 24 | 25 | DirectSound does better job if I poll play-back state every 1ms and start new 20ms segment, which yields maximum 40ms latency. The draw back is when you move window or click on 26 | the window frame, you may hear zapping noise, but I believe latency is more important for games. 27 | 28 | ALSA has no choice. Behind the scenes ALSA code does streaming. 29 | 30 | So, my best decision is to use streaming mode in macOS, which should work perfectly. I have no choice with ALSA. But, for Windows, I keep it polling-based playback. 31 | */ 32 | 33 | #define AUDIO_USE_STREAMING 34 | 35 | 36 | 37 | #include "outside_world.h" 38 | #include "yssimplesound.h" 39 | #include "ysgamepad.h" 40 | #include "fssimplewindow.h" 41 | #include 42 | #include 43 | 44 | class FsSimpleWindowConnection : public Outside_World 45 | { 46 | public: 47 | class MouseEvent 48 | { 49 | public: 50 | int evt=0,lb=0,mb=0,rb=0,mx=0,my=0; 51 | inline void Read(void) 52 | { 53 | evt=FsGetMouseEvent(lb,mb,rb,mx,my); 54 | } 55 | }; 56 | class DeviceAndEvent 57 | { 58 | public: 59 | std::vector keyCode,charCode; 60 | std::vector mouseEvents; 61 | unsigned char keyState[FSKEY_NUM_KEYCODE]; 62 | MouseEvent lastKnownMouse; 63 | 64 | std::vector gamePads; 65 | 66 | int winWid=640,winHei=480; 67 | 68 | DeviceAndEvent() 69 | { 70 | for(auto &s : keyState) 71 | { 72 | s=0; 73 | } 74 | } 75 | 76 | bool EventEmpty(void) const 77 | { 78 | return keyCode.empty() && charCode.empty() && mouseEvents.empty(); 79 | } 80 | void CleanUpEvents(void) 81 | { 82 | keyCode.clear(); 83 | charCode.clear(); 84 | mouseEvents.clear(); 85 | } 86 | }; 87 | 88 | class HostShortCut 89 | { 90 | public: 91 | bool inUse=false; 92 | bool ctrl=false,shift=false,graph=false; 93 | std::string cmdStr; 94 | }; 95 | 96 | #define DEFAULT_PAUSE_KEY_CODE FSKEY_SCROLLLOCK 97 | 98 | enum 99 | { 100 | STATUS_TAPEPOS_X=320, 101 | }; 102 | 103 | DeviceAndEvent windowEvent; 104 | 105 | HostShortCut hostShortCut[FSKEY_NUM_KEYCODE]; 106 | unsigned int PAUSE_KEY_CODE=DEFAULT_PAUSE_KEY_CODE; 107 | unsigned int GRAPH_KEY_CODE=FSKEY_NULL; 108 | 109 | unsigned int *FSKEYtoFM77AVKEY=nullptr; 110 | unsigned int *FSKEYState=nullptr; 111 | FsSimpleWindowConnection(); 112 | ~FsSimpleWindowConnection(); 113 | 114 | std::vector prevGamePads; 115 | 116 | // For mouse emulation by pad digital axes. 117 | int mouseDX=0,mouseDY=0; 118 | 119 | unsigned int lastPressedFsKey=0; 120 | uint64_t nextKeyRepeatTime=0; 121 | 122 | int winWid=640,winHei=480; 123 | 124 | 125 | virtual std::vector MakeKeyMappingText(void) const; 126 | virtual void LoadKeyMappingFromText(const std::vector &text); 127 | 128 | virtual void Start(void); 129 | virtual void Stop(void); 130 | virtual void DevicePolling(class FM77AV &fm77av); 131 | unsigned int KeyFlagsFilter(unsigned int keyFlags,unsigned int fsKey); 132 | 133 | virtual void SetKeyboardLayout(unsigned int layout); 134 | 135 | virtual void RegisterHostShortCut(std::string hostKeyLabel,bool ctrl,bool shift,std::string cmdStr); 136 | virtual void RegisterPauseResume(std::string hostKeyLabel); 137 | 138 | 139 | class WindowConnection : public WindowInterface 140 | { 141 | public: 142 | class SharedVariables 143 | { 144 | public: 145 | // Locked by deviceStateLock 146 | DeviceAndEvent readyToSend; 147 | }; 148 | class VMThreadVariables 149 | { 150 | }; 151 | class WindowThreadVariables 152 | { 153 | public: 154 | unsigned int sinceLastResize=0; 155 | unsigned int prevTapePosition=0; 156 | DeviceAndEvent primary; 157 | 158 | GLuint mainTexId,statusTexId,pauseIconTexId,menuIconTexId; 159 | std::vector PAUSEicon,MENUicon,FD_IDLEicon,FD_BUSYicon,TAPE_IDLEicon,TAPE_LOADINGicon,TAPE_SAVINGicon,CAPSicon,KANAicon,INSicon; 160 | 161 | bool gamePadInitialized=false; 162 | }; 163 | SharedVariables sharedEx; 164 | VMThreadVariables vmThrEx; 165 | WindowThreadVariables winThrEx; 166 | 167 | 168 | 169 | void Start(void) override; 170 | void Stop(void) override; 171 | 172 | /*! Called in the window thread. 173 | */ 174 | void Interval(void) override; 175 | 176 | /*! Called in the VM thread. 177 | */ 178 | void Communicate(Outside_World *outside_world) override; 179 | 180 | void Render(bool swapBuffers) override; 181 | 182 | void UpdateStatusBitmap(void); 183 | 184 | void Render(const FM77AVRender::Image &img,const class FM77AV &fm77av) override; 185 | 186 | bool ImageNeedsFlip(void) override; 187 | 188 | GLuint GenTexture(void); 189 | void UpdateTexture(GLuint texId,int wid,int hei,const unsigned char *rgba) const; 190 | void DrawTextureRect(int x0,int y0,int x1,int y1) const; 191 | 192 | void PollGamePads(void); 193 | }; 194 | WindowInterface *CreateWindowInterface(void) const override; 195 | void DeleteWindowInterface(WindowInterface *) const override; 196 | 197 | 198 | class SoundConnection : public Sound 199 | { 200 | public: 201 | YsSoundPlayer soundPlayer; 202 | 203 | #ifdef AUDIO_USE_STREAMING 204 | YsSoundPlayer::Stream FMPSGStream; 205 | #else 206 | YsSoundPlayer::SoundData FMPSGChannel; 207 | #endif 208 | 209 | virtual void Start(void) override; 210 | virtual void Stop(void) override; 211 | 212 | virtual void Polling(void) override; 213 | 214 | virtual void FMPSGPlay(std::vector &wave) override; 215 | virtual void FMPSGPlayStop(void) override; 216 | virtual bool FMPSGChannelPlaying(void) override; 217 | }; 218 | virtual Sound *CreateSound(void) const override; 219 | virtual void DeleteSound(Sound *) const override; 220 | }; 221 | 222 | /* } */ 223 | #endif 224 | -------------------------------------------------------------------------------- /src/externals/ysbitmapfont/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(fontdata ysglfontdata.c ysglfontdata.h) 2 | target_include_directories(fontdata PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 3 | -------------------------------------------------------------------------------- /src/externals/ysbitmapfont/ysglfontdata.h: -------------------------------------------------------------------------------- 1 | /* //////////////////////////////////////////////////////////// 2 | 3 | File Name: ysglfontdata.h 4 | Copyright (c) 2017 Soji Yamakawa. All rights reserved. 5 | http://www.ysflight.com 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, 11 | this list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 19 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 21 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | //////////////////////////////////////////////////////////// */ 29 | 30 | #ifndef YSGLFONTDATA_IS_INCLUDED 31 | #define YSGLFONTDATA_IS_INCLUDED 32 | /* { */ 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | extern unsigned char *YsFont6x7[256]; 39 | extern unsigned char *YsFont6x8[256]; 40 | extern unsigned char *YsFont6x10[256]; 41 | extern unsigned char *YsFont7x10[256]; 42 | extern unsigned char *YsFont8x8[256]; 43 | extern unsigned char *YsFont8x12[256]; 44 | extern unsigned char *YsFont10x14[256]; 45 | extern unsigned char *YsFont12x16[256]; 46 | extern unsigned char *YsFont16x20[256]; 47 | extern unsigned char *YsFont16x24[256]; 48 | extern unsigned char *YsFont20x28[256]; 49 | extern unsigned char *YsFont20x32[256]; 50 | extern unsigned char *YsFont24x40[256]; 51 | extern unsigned char *YsFont28x44[256]; 52 | extern unsigned char *YsFont32x48[256]; 53 | 54 | extern unsigned char *YsFont12P_Ptn[256]; 55 | extern int YsFont12P_Wid[256]; 56 | extern unsigned char *YsFont14P_Ptn[256]; 57 | extern int YsFont14P_Wid[256]; 58 | extern unsigned char *YsFont16P_Ptn[256]; 59 | extern int YsFont16P_Wid[256]; 60 | 61 | void YsGlMakeFontBitmapDisplayList(int listBase,const unsigned char *const fontPtr[],int wid,int hei); 62 | void YsGlDrawFontBitmapDirect(const char str[],const unsigned char *const fontPtr[],int wid,int hei); 63 | void YsGlDrawFontBitmapDirectWithLength(int nChar,const char str[],const unsigned char *const fontPtr[],int wid,int hei); 64 | 65 | void YsGlUseFontBitmap6x7(int listBase); 66 | void YsGlDrawFontBitmap6x7(const char str[]); 67 | void YsGlUseFontBitmap6x8(int listBase); 68 | void YsGlDrawFontBitmap6x8(const char str[]); 69 | void YsGlUseFontBitmap6x10(int listBase); 70 | void YsGlDrawFontBitmap6x10(const char str[]); 71 | void YsGlUseFontBitmap7x10(int listBase); 72 | void YsGlDrawFontBitmap7x10(const char str[]); 73 | void YsGlUseFontBitmap8x8(int listBase); 74 | void YsGlDrawFontBitmap8x8(const char str[]); 75 | void YsGlUseFontBitmap8x12(int listBase); 76 | void YsGlDrawFontBitmap8x12(const char str[]); 77 | void YsGlUseFontBitmap10x14(int listBase); 78 | void YsGlDrawFontBitmap10x14(const char str[]); 79 | void YsGlUseFontBitmap12x16(int listBase); 80 | void YsGlDrawFontBitmap12x16(const char str[]); 81 | void YsGlUseFontBitmap16x20(int listBase); 82 | void YsGlDrawFontBitmap16x20(const char str[]); 83 | void YsGlUseFontBitmap16x24(int listBase); 84 | void YsGlDrawFontBitmap16x24(const char str[]); 85 | void YsGlUseFontBitmap20x28(int listBase); 86 | void YsGlDrawFontBitmap20x28(const char str[]); 87 | void YsGlUseFontBitmap20x32(int listBase); 88 | void YsGlDrawFontBitmap20x32(const char str[]); 89 | void YsGlUseFontBitmap24x40(int listBase); 90 | void YsGlDrawFontBitmap24x40(const char str[]); 91 | void YsGlUseFontBitmap28x44(int listBase); 92 | void YsGlDrawFontBitmap28x44(const char str[]); 93 | void YsGlUseFontBitmap32x48(int listBase); 94 | void YsGlDrawFontBitmap32x48(const char str[]); 95 | 96 | void YsGlSelectAndUseFontBitmapByHeight(int *selectedWidth,int *selectedHeight,int listBase,int fontHeight); 97 | const unsigned char * const *YsGlSelectFontBitmapPointerByHeight(int *selectedWidth,int *selectedHeight,int fontHeight); 98 | 99 | int YsGlWriteStringToSingleBitBitmap( 100 | const char str[], 101 | unsigned char bmpPtr[],unsigned int bmpWid,unsigned int bmpHei, 102 | int bottomLeftX,int bottomLeftY, 103 | const unsigned char *const fontPtr[],int fontWid,int fontHei); 104 | 105 | int YsGlWriteStringToRGBA8Bitmap( 106 | const char str[],unsigned int c0,unsigned int c1,unsigned int c2,unsigned int c3, 107 | unsigned char bmpPtr[],unsigned int bmpWid,unsigned int bmpHei, 108 | int bottomLeftX,int bottomLeftY, 109 | const unsigned char *const fontPtr[],int fontWid,int fontHei); 110 | /* In OpenGL: c0=r c1=g c2=b c3=a 111 | In Direct3D: c0=a c1=r c2=g c3=b */ 112 | 113 | int YsGlWriteStringToRGBA8BitmapPropFont( 114 | const char str[],unsigned int c0,unsigned int c1,unsigned int c2,unsigned int c3, 115 | unsigned char bmpPtr[],unsigned int bmpWid,unsigned int bmpHei, 116 | int bottomLeftX,int bottomLeftY, 117 | const unsigned char *const fontPtr[],const int fontWid[],int fontHei); 118 | 119 | 120 | #ifdef __cplusplus 121 | } 122 | #endif 123 | 124 | 125 | /* } */ 126 | #endif 127 | -------------------------------------------------------------------------------- /src/fm77av/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(crtc) 2 | add_subdirectory(fdc) 3 | add_subdirectory(datarecorder) 4 | add_subdirectory(keyboard) 5 | add_subdirectory(sound) 6 | add_subdirectory(gameport) 7 | add_subdirectory(eventlog) 8 | add_subdirectory(serialport) 9 | add_subdirectory(dma) 10 | 11 | 12 | 13 | set(TARGET_NAME fm77av) 14 | add_library(${TARGET_NAME} fm77av.h fm77av.cpp fm77avint.cpp fm77avio.cpp fm77avstate.cpp) 15 | target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 16 | target_link_libraries(${TARGET_NAME} outside_world fm77aveventlog fm77avdef fm77avmemory fm77avrender fm77avcrtc fm77avfdc fm77avsound fm77avkeyboard fm77avkey fm77avgameport fm77avdatarecorder fm77avserialport fm77av40dmac vgmrecorder ym2203c device cpputil mc6809 mc6809util vmbase lineParser) 17 | # lineparser is for MemoryEvaluation class. 18 | 19 | 20 | 21 | add_library(fm77avdef fm77avdef.cpp fm77avdef.h) 22 | target_include_directories(fm77avdef PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 23 | 24 | 25 | 26 | add_library(fm77avthread fm77avthread.cpp fm77avthread.h) 27 | target_link_libraries(fm77avthread fm77avdef fm77av fm77avcommand outside_world) 28 | target_include_directories(fm77avthread PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 29 | if(UNIX) 30 | target_link_libraries(fm77avthread pthread) 31 | endif() 32 | 33 | 34 | 35 | add_library(fm77avparam fm77avparam.cpp fm77avparam.h) 36 | target_link_libraries(fm77avparam fm77avdef fm77avkey fm77av cpputil) 37 | target_include_directories(fm77avparam PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 38 | 39 | 40 | 41 | add_library(fm77avrender fm77avrender.h fm77avrender.cpp) 42 | target_link_libraries(fm77avrender fm77av fm77avcrtc memory cpputil fm77avdef) 43 | target_include_directories(fm77avrender PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 44 | 45 | 46 | 47 | add_library(fm77avkey fm77avkey.h fm77avkey.cpp) 48 | target_link_libraries(fm77avkey cpputil) 49 | -------------------------------------------------------------------------------- /src/fm77av/crtc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(fm77avcrtc fm77avcrtc.h fm77avcrtc.cpp) 2 | target_link_libraries(fm77avcrtc fm77av memory cpputil fm77avdef) 3 | target_include_directories(fm77avcrtc PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 4 | -------------------------------------------------------------------------------- /src/fm77av/datarecorder/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(fm77avdatarecorder fm77avtape.h fm77avtape.cpp) 2 | target_link_libraries(fm77avdatarecorder device t77lib fm77avdef cpputil outside_world) 3 | target_include_directories(fm77avdatarecorder PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 4 | -------------------------------------------------------------------------------- /src/fm77av/datarecorder/fm77avtape.h: -------------------------------------------------------------------------------- 1 | #ifndef FM77AVTAPE_IS_INCLUDED 2 | #define FM77AVTAPE_IS_INCLUDED 3 | /* { */ 4 | 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "device.h" 12 | #include "t77.h" 13 | #include "fm7lib.h" 14 | 15 | class FM77AVTape 16 | { 17 | public: 18 | std::string fName; 19 | char header[18]; 20 | std::vector data; 21 | bool writeProtect=false; 22 | 23 | mutable bool modified=false; 24 | uint64_t lastModifiedTime=0; 25 | 26 | bool Load(std::string fName); 27 | bool Save(void) const; 28 | bool SaveAs(std::string fName) const; 29 | 30 | enum 31 | { 32 | NANOSEC_PER_T77_ONE=9000 33 | }; 34 | 35 | class 36 | { 37 | }; 38 | 39 | class TapeFile 40 | { 41 | public: 42 | std::string fName; 43 | unsigned int fType; 44 | uint64_t ptr; 45 | }; 46 | 47 | class TapePointer 48 | { 49 | public: 50 | unsigned int dataPtr=0; 51 | uint64_t fm77avTime=0; // In nano sec. 52 | bool eot=false; 53 | }; 54 | 55 | void Eject(void); 56 | // T77 format that I remembered from my utility: 57 | // - Data contains two-byte pairs. 58 | // Level Duration(ms) 59 | // - For long silence, it can be 60 | // 0x7F 0xFF 61 | void Rewind(TapePointer &ptr) const; 62 | void Dniwer(TapePointer &ptr) const; 63 | void Seek(TapePointer &ptr,unsigned int dataPtr) const; 64 | void MotorOn(TapePointer &pointer,uint64_t fm77avTimeNanoSec) const; // First byte=16 65 | void MoveTapePointer(TapePointer &pointer,uint64_t fm77avTimeNanoSec) const; 66 | uint8_t GetLevel(TapePointer tracker) const; 67 | 68 | std::vector Files(void) const; 69 | }; 70 | 71 | class FM77AVDataRecorder : public Device 72 | { 73 | public: 74 | virtual const char *DeviceName(void) const{return "FMDataRecorder";} 75 | 76 | enum 77 | { 78 | HEAD_SILENT_TIME=1000000000, // 1.0sec 79 | }; 80 | 81 | class TapePointerPair 82 | { 83 | public: 84 | FM77AVTape t77; 85 | FM77AVTape::TapePointer ptr; 86 | 87 | void Rewind(void); 88 | void Dniwer(void); 89 | }; 90 | 91 | class State 92 | { 93 | public: 94 | TapePointerPair primary,toSave; 95 | bool motor; 96 | bool recButton=false; 97 | bool writeData=false; 98 | 99 | uint64_t motorOnTime=0; 100 | uint64_t lastBitFlipTime=0; 101 | }; 102 | State state; 103 | class Outside_World *outside_world=nullptr; 104 | 105 | FM77AVDataRecorder(VMBase *vmPtr) : Device(vmPtr){} 106 | 107 | void Reset(void); // Don't rewind 108 | bool LoadT77(std::string fName); 109 | bool LoadAutoSaveT77(std::string fName); 110 | void Eject(void); 111 | void MotorOn(uint64_t fm77avTime); 112 | void MotorOff(uint64_t fm77avTime); 113 | void Move(uint64_t fm77avTime); 114 | bool Read(void) const; 115 | 116 | void Rewind(void); 117 | void FastForwardAllTheWay(void); 118 | 119 | void WriteBit(TapePointerPair &tape,uint64_t fm77avTime); 120 | 121 | void WriteFD00(uint64_t fm77avTime,uint8_t data); 122 | 123 | void SaveModifiedTapeImagesAfterOneSecond(uint64_t fm77avTime); 124 | void SaveModifiedTapeImages(void); 125 | 126 | std::vector GetStatusText(uint64_t fm77avTime) const; 127 | 128 | /* virtual */ uint32_t SerializeVersion(void) const; 129 | /* virtual */ void SpecificSerialize(std::vector &data,std::string stateFName) const; 130 | /* virtual */ bool SpecificDeserialize(const unsigned char *&data,std::string stateFName,uint32_t version); 131 | }; 132 | 133 | 134 | 135 | /* } */ 136 | #endif 137 | -------------------------------------------------------------------------------- /src/fm77av/dma/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(fm77av40dmac fm77av40dmac.cpp fm77av40dmac.h) 2 | target_include_directories(fm77av40dmac PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 3 | target_link_libraries(fm77av40dmac fm77av fm77avdef device memory) 4 | -------------------------------------------------------------------------------- /src/fm77av/dma/fm77av40dmac.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "cpputil.h" 3 | #include "fm77av40dmac.h" 4 | 5 | FM77AV40DMAC::FM77AV40DMAC(VMBase *vmBase) : Device(vmBase) 6 | { 7 | Reset(); 8 | } 9 | 10 | void FM77AV40DMAC::Reset(void) 11 | { 12 | for(auto &d: state.regs) 13 | { 14 | d=0; 15 | } 16 | } 17 | 18 | bool FM77AV40DMAC::TxRQ(void) const 19 | { 20 | return (0!=(state.regs[0x14]&1)); 21 | } 22 | uint16_t FM77AV40DMAC::Address(void) const 23 | { 24 | uint16_t data=state.regs[0]; 25 | data<<=8; 26 | data|=state.regs[1]; 27 | return data; 28 | } 29 | uint16_t FM77AV40DMAC::NumBytes(void) const 30 | { 31 | uint16_t data=state.regs[2]; 32 | data<<=8; 33 | data|=state.regs[3]; 34 | return data; 35 | } 36 | bool FM77AV40DMAC::AddressGoUp(void) const 37 | { 38 | return 0!=(state.regs[0x10]&8); 39 | } 40 | bool FM77AV40DMAC::FDCtoMEM(void) const 41 | { 42 | return 0==(state.regs[0x10]&1); 43 | } 44 | bool FM77AV40DMAC::MEMtoFDC(void) const 45 | { 46 | return 0!=(state.regs[0x10]&1); 47 | } 48 | void FM77AV40DMAC::SetDMAEnd(bool ended) 49 | { 50 | state.regs[0x10]&=0x7F; 51 | if(true==ended) 52 | { 53 | state.regs[0x10]|=0x80; 54 | } 55 | } 56 | void FM77AV40DMAC::SetBusy(bool busy) 57 | { 58 | state.regs[0x10]&=0xBF; 59 | if(true==busy) 60 | { 61 | state.regs[0x10]|=0x40; 62 | } 63 | } 64 | bool FM77AV40DMAC::IRQEnabled(void) const 65 | { 66 | return 0!=(state.regs[0x15]&1); 67 | } 68 | void FM77AV40DMAC::SetIRQ(bool IRQ) 69 | { 70 | state.regs[0x15]&0x7F; 71 | if(true==IRQ) 72 | { 73 | state.regs[0x15]|=0x80; 74 | } 75 | } 76 | 77 | void FM77AV40DMAC::WriteFD98(uint8_t data) 78 | { 79 | state.addrLatch=(data&0x1F); 80 | } 81 | void FM77AV40DMAC::WriteFD99(uint8_t data) 82 | { 83 | std::cout << "DMAC Write Reg=" << cpputil::Ubtox(state.addrLatch) << " Value=" << cpputil::Ubtox(data) << std::endl; 84 | state.regs[state.addrLatch]=data; 85 | } 86 | void FM77AV40DMAC::ReadFD99(void) 87 | { 88 | std::cout << "DMAC Read Reg=" << cpputil::Ubtox(state.addrLatch) << " Value=" << cpputil::Ubtox(state.regs[state.addrLatch]) << std::endl; 89 | if(0x15==state.addrLatch) 90 | { 91 | state.regs[0x15]&=0x7F; 92 | } 93 | } 94 | uint8_t FM77AV40DMAC::NonDestructiveReadFD99(void) const 95 | { 96 | return state.regs[state.addrLatch]; 97 | } 98 | 99 | 100 | 101 | /* virtual */ uint32_t FM77AV40DMAC::SerializeVersion(void) const 102 | { 103 | return 0; 104 | } 105 | /* virtual */ void FM77AV40DMAC::SpecificSerialize(std::vector &data,std::string stateFName) const 106 | { 107 | PushUint16(data,state.addrLatch); 108 | PushUcharArray(data,NUM_REGS,state.regs); 109 | } 110 | /* virtual */ bool FM77AV40DMAC::SpecificDeserialize(const unsigned char *&data,std::string stateFName,uint32_t version) 111 | { 112 | state.addrLatch=ReadUint16(data); 113 | ReadUcharArray(data,NUM_REGS,state.regs); 114 | return true; 115 | } 116 | -------------------------------------------------------------------------------- /src/fm77av/dma/fm77av40dmac.h: -------------------------------------------------------------------------------- 1 | #ifndef FM77AV40DMA_IS_INCLUDED 2 | #define FM77AV40DMA_IS_INCLUDED 3 | /* { */ 4 | 5 | 6 | 7 | #include "device.h" 8 | #include "memory.h" 9 | 10 | class FM77AV40DMAC : public Device, public CanAccessMemory 11 | { 12 | public: 13 | virtual const char *DeviceName(void) const{return "DMAC";} 14 | FM77AV40DMAC(VMBase *vmBase); 15 | 16 | enum 17 | { 18 | NUM_REGS=32, 19 | }; 20 | 21 | class State 22 | { 23 | public: 24 | uint8_t addrLatch=0; 25 | uint8_t regs[NUM_REGS]; 26 | }; 27 | State state; 28 | 29 | void Reset(void); 30 | 31 | /*! If true, DMA enabled. 32 | */ 33 | bool TxRQ(void) const; 34 | 35 | uint16_t Address(void) const; 36 | uint16_t NumBytes(void) const; 37 | bool AddressGoUp(void) const; 38 | bool FDCtoMEM(void) const; 39 | bool MEMtoFDC(void) const; 40 | void SetDMAEnd(bool ended); 41 | void SetBusy(bool busy); 42 | 43 | bool IRQEnabled(void) const; 44 | void SetIRQ(bool IRQ); 45 | 46 | void WriteFD98(uint8_t data); 47 | void WriteFD99(uint8_t data); 48 | void ReadFD99(void); 49 | uint8_t NonDestructiveReadFD99(void) const; 50 | 51 | virtual uint32_t SerializeVersion(void) const; 52 | virtual void SpecificSerialize(std::vector &data,std::string stateFName) const; 53 | virtual bool SpecificDeserialize(const unsigned char *&data,std::string stateFName,uint32_t version); 54 | }; 55 | 56 | /* } */ 57 | #endif 58 | -------------------------------------------------------------------------------- /src/fm77av/eventlog/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TARGET_NAME fm77aveventlog) 2 | add_library(${TARGET_NAME} fm77aveventlog.h fm77aveventlog.cpp) 3 | target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 4 | target_link_libraries(${TARGET_NAME} fm77av fm77avkey fm77avkeyboard cpputil) 5 | -------------------------------------------------------------------------------- /src/fm77av/eventlog/fm77aveventlog.h: -------------------------------------------------------------------------------- 1 | #ifndef FM77AVEVENTLOG_IS_INCLUDED 2 | #define FM77AVEVENTLOG_IS_INCLUDED 3 | /* { */ 4 | 5 | #include 6 | #include 7 | 8 | class FM77AVEventLog 9 | { 10 | public: 11 | enum 12 | { 13 | STATE_IDLE, 14 | STATE_RECORDING, 15 | STATE_PLAYBACK, 16 | }; 17 | 18 | enum 19 | { 20 | EVT_NULL, 21 | EVT_KEYPRESS, 22 | EVT_KEYRELEASE, 23 | EVT_PAD0_A_DOWN, 24 | EVT_PAD0_A_UP, 25 | EVT_PAD0_B_DOWN, 26 | EVT_PAD0_B_UP, 27 | EVT_PAD0_FWD_DOWN, 28 | EVT_PAD0_FWD_UP, 29 | EVT_PAD0_BACK_DOWN, 30 | EVT_PAD0_BACK_UP, 31 | EVT_PAD0_LEFT_DOWN, 32 | EVT_PAD0_LEFT_UP, 33 | EVT_PAD0_RIGHT_DOWN, 34 | EVT_PAD0_RIGHT_UP, 35 | EVT_GOTO, 36 | EVEYTTYPE_TYPE_COMMAND, 37 | }; 38 | static std::string EventTypeToStr(unsigned int eventType); 39 | static unsigned int StrToEventType(std::string str); 40 | 41 | class Event 42 | { 43 | public: 44 | unsigned int type=EVT_NULL; 45 | std::string label; // For GOTO 46 | uint64_t time=0; 47 | 48 | unsigned int code=0; 49 | // AVKEY_? for KEYPRESS and KEYRELEASE 50 | // |0|0||B|A|Right|Left|Down|Up| for PADPRESS and PADRELEASE 51 | 52 | std::string str; 53 | // Label for GOTO 54 | }; 55 | 56 | unsigned int state=STATE_IDLE; 57 | std::vector eventLog; 58 | uint64_t timeOrigin=0; 59 | unsigned int playbackPointer=0; 60 | 61 | 62 | void CleanUp(void); 63 | 64 | bool LoadEventLog(std::string fName); 65 | 66 | static uint64_t GetTime(std::string timeStr,uint64_t prevTime); 67 | 68 | void BeginPlayback(uint64_t fm77avTime); 69 | 70 | void RunOneStep(class FM77AV &fm77av); 71 | void Playback(class FM77AV &fm77av); 72 | 73 | void StopPlayback(void); 74 | }; 75 | 76 | /* } */ 77 | #endif 78 | -------------------------------------------------------------------------------- /src/fm77av/fdc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(fm77avfdc fm77avfdc.h fm77avfdc.cpp) 2 | target_link_libraries(fm77avfdc fm77av diskdrive memory cpputil fm77avdef) 3 | target_include_directories(fm77avfdc PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 4 | -------------------------------------------------------------------------------- /src/fm77av/fdc/fm77avfdc.h: -------------------------------------------------------------------------------- 1 | #ifndef FM77AVFDC_IS_INCLUDED 2 | #define FM77AVFDC_IS_INCLUDED 3 | /* { */ 4 | 5 | #include "diskdrive.h" 6 | 7 | class FM77AVFDC : public DiskDrive 8 | { 9 | public: 10 | enum 11 | { 12 | // 2D/2DD 300rpm. Confirmed on actual FM77AV. (300 index-hole detection for 60.95 seconds) 13 | // 5 rotation per seconds. 14 | // 200 ms per rotation. 15 | // Track Read returns 0x17BB bytes (6075 bytes) on actual hardwarre. 16 | // 200 ms/6075=32 microseconds per byte. 17 | NANOSEC_PER_BYTE=32000, 18 | NANOSEC_BETWEEN_MULTI_SECTOR_READ=3200000, // Just multiplied by 100. Let's see how it works. 19 | 20 | FORMAT_WRITE_LENGTH_2D_2DD=6144, 21 | FORMAT_WRITE_LENGTH_2HD_1232KB=10416, 22 | FORMAT_WRITE_LENFTH_2HD_1440KB=12934, 23 | 24 | INDEXHOLE_INTERVAL=200000000, // 300rpm. 5 rotations per second. 200ms per index hole. 25 | INDEXHOLE_DURATION=20000, 26 | }; 27 | class FM77AV *fm77avPtr; 28 | 29 | bool debugBreakOnCommandWrite=false; 30 | bool debugBreakOnFDCIRQ=false; 31 | bool monitorFDC=false; 32 | 33 | class DebugCondition 34 | { 35 | public: 36 | bool monitorOnly=false; 37 | bool anyTrack=false; 38 | uint8_t cmd; 39 | uint8_t C,H,R; 40 | 41 | bool MatchCHR(uint8_t C,uint8_t H,uint8_t R) const 42 | { 43 | return (true!=anyTrack && C==this->C && H==this->H && R==this->R) || 44 | (true==anyTrack && R==this->R); 45 | } 46 | }; 47 | std::vector debugCond; 48 | 49 | enum 50 | { 51 | FDD_DRIVE_TYPE_2DD=0, 52 | FDD_DRIVE_TYPE_2D=1 53 | }; 54 | 55 | class FM7SpecificState 56 | { 57 | public: 58 | uint8_t driveMode=FDD_DRIVE_TYPE_2DD; 59 | bool enableDriveMap=false; 60 | uint8_t driveMapping[4] {0,1,2,3}; 61 | uint8_t currentDS=0; 62 | uint8_t lastLogicalDriveWritten=0; 63 | 64 | // For Albatross. 65 | bool needIncrementSector=false; 66 | 67 | // C H R cache. 68 | uint8_t CCache=0,HCache=0,RCache=0; 69 | }; 70 | FM7SpecificState state7; 71 | 72 | virtual const char *DeviceName(void) const{return "FDC";} 73 | 74 | FM77AVFDC(class FM77AV *fm77avPtr); 75 | 76 | void SendCommand(unsigned int cmd); 77 | 78 | /*! Turns off BUSY flag. Also if IRQ is not masked it raises IRR flag of PIC. 79 | */ 80 | void MakeReady(void); 81 | 82 | virtual void RunScheduledTask(unsigned long long int fm77avTime); 83 | void IOWrite(unsigned int ioport,unsigned int data); 84 | unsigned int IORead(unsigned int ioport); 85 | 86 | unsigned int NonDestructiveIORead(unsigned int ioport) const; 87 | 88 | bool IndexHole(unsigned long long fm77avTime) const; 89 | 90 | void Reset(void) override; 91 | void WriteTrack(const std::vector &data); 92 | inline bool has2DD(void) const; 93 | unsigned int compensateTrackNumber(unsigned int trackPos); 94 | inline unsigned int mapDrive(unsigned int logicalDrive) const; 95 | 96 | void BreakOnSectorRead(uint8_t C,uint8_t H,uint8_t R,bool monitorOnly); 97 | void BreakOnSectorRead(uint8_t R,bool monitorOnly); 98 | void ClearBreakOnSectorRead(uint8_t C,uint8_t H,uint8_t R); 99 | void ClearBreakOnSectorRead(uint8_t R); 100 | void ClearBreakOnAllSectorRead(void); 101 | 102 | 103 | uint32_t SerializeVersion(void) const override; 104 | void SpecificSerialize(std::vector &data,std::string stateFName) const override; 105 | bool SpecificDeserialize(const unsigned char *&data,std::string stateFName,uint32_t version) override; 106 | }; 107 | 108 | /* } */ 109 | #endif 110 | -------------------------------------------------------------------------------- /src/fm77av/fm77avint.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "fm77av.h" 4 | #include "fm77avdef.h" 5 | #include "outside_world.h" 6 | 7 | 8 | 9 | bool FM77AV::KeyIRQFlagSet(void) const 10 | { 11 | if(CPU_SUB==state.keyboardIRQHandler) 12 | { 13 | return 0!=(state.sub.firqSource&SystemState::SUB_FIRQ_SOURCE_KEY); 14 | } 15 | else 16 | { 17 | return 0!=(state.main.irqSource&SystemState::MAIN_IRQ_SOURCE_KEY); 18 | } 19 | } 20 | void FM77AV::SetKeyIRQFlag(void) 21 | { 22 | if(CPU_SUB==state.keyboardIRQHandler) 23 | { 24 | state.sub.firqSource|=SystemState::SUB_FIRQ_SOURCE_KEY; 25 | } 26 | else 27 | { 28 | state.main.irqSource|=SystemState::MAIN_IRQ_SOURCE_KEY; 29 | } 30 | } 31 | void FM77AV::ClearKeyIRQFlag(void) 32 | { 33 | state.sub.firqSource&=~SystemState::SUB_FIRQ_SOURCE_KEY; 34 | state.main.irqSource&=~SystemState::MAIN_IRQ_SOURCE_KEY; 35 | } 36 | void FM77AV::SetBreakKeyFIRQFlag(void) 37 | { 38 | state.main.firqSource|=SystemState::MAIN_FIRQ_SOURCE_BREAK_KEY; 39 | } 40 | void FM77AV::ClearBreakKeyFIRQFlag(void) 41 | { 42 | state.main.firqSource&=~SystemState::MAIN_FIRQ_SOURCE_BREAK_KEY; 43 | } 44 | 45 | void FM77AV::SetSubToMainFIRQFlag(void) 46 | { 47 | state.main.firqSource|=SystemState::MAIN_FIRQ_SOURCE_ATTENTION; 48 | } 49 | void FM77AV::ClearSubToMainFIRQFlag(void) 50 | { 51 | state.main.firqSource&=~SystemState::MAIN_FIRQ_SOURCE_ATTENTION; 52 | } 53 | 54 | void FM77AV::ClearMainToSubIRQFlag(void) 55 | { 56 | state.sub.irqSource&=~SystemState::SUB_IRQ_SOURCE_CANCEL_REQ; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/fm77av/fm77avkey.h: -------------------------------------------------------------------------------- 1 | #ifndef FM77AVKEY_IS_INCLUDED 2 | #define FM77AVKEY_IS_INCLUDED 3 | /* { */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | enum 10 | { 11 | AVKEY_NULL, 12 | 13 | AVKEY_BREAK, 14 | AVKEY_PF1, 15 | AVKEY_PF2, 16 | AVKEY_PF3, 17 | AVKEY_PF4, 18 | AVKEY_PF5, 19 | AVKEY_PF6, 20 | AVKEY_PF7, 21 | AVKEY_PF8, 22 | AVKEY_PF9, 23 | AVKEY_PF10, 24 | AVKEY_EL, 25 | AVKEY_CLS, 26 | AVKEY_DUP, 27 | AVKEY_HOME, 28 | AVKEY_INS, 29 | AVKEY_DEL, 30 | AVKEY_LEFT, 31 | AVKEY_RIGHT, 32 | AVKEY_UP, 33 | AVKEY_DOWN, 34 | 35 | AVKEY_ESC, 36 | AVKEY_0, 37 | AVKEY_1, 38 | AVKEY_2, 39 | AVKEY_3, 40 | AVKEY_4, 41 | AVKEY_5, 42 | AVKEY_6, 43 | AVKEY_7, 44 | AVKEY_8, 45 | AVKEY_9, 46 | AVKEY_MINUS, 47 | AVKEY_HAT, 48 | AVKEY_YEN, 49 | AVKEY_BACKSPACE, 50 | 51 | AVKEY_TAB, 52 | AVKEY_Q, 53 | AVKEY_W, 54 | AVKEY_E, 55 | AVKEY_R, 56 | AVKEY_T, 57 | AVKEY_Y, 58 | AVKEY_U, 59 | AVKEY_I, 60 | AVKEY_O, 61 | AVKEY_P, 62 | AVKEY_AT, 63 | AVKEY_LEFT_SQUARE_BRACKET, 64 | AVKEY_RETURN, 65 | 66 | AVKEY_CTRL, 67 | AVKEY_A, 68 | AVKEY_S, 69 | AVKEY_D, 70 | AVKEY_F, 71 | AVKEY_G, 72 | AVKEY_H, 73 | AVKEY_J, 74 | AVKEY_K, 75 | AVKEY_L, 76 | AVKEY_SEMICOLON, 77 | AVKEY_COLON, 78 | AVKEY_RIGHT_SQUARE_BRACKET, 79 | 80 | AVKEY_LEFT_SHIFT, 81 | AVKEY_Z, 82 | AVKEY_X, 83 | AVKEY_C, 84 | AVKEY_V, 85 | AVKEY_B, 86 | AVKEY_N, 87 | AVKEY_M, 88 | AVKEY_COMMA, 89 | AVKEY_DOT, 90 | AVKEY_SLASH, 91 | AVKEY_DOUBLE_QUOTE, 92 | AVKEY_RIGHT_SHIFT, 93 | 94 | AVKEY_CAPS, 95 | AVKEY_GRAPH, 96 | AVKEY_LEFT_SPACE, 97 | AVKEY_MID_SPACE, 98 | AVKEY_RIGHT_SPACE, 99 | AVKEY_KANA, 100 | 101 | AVKEY_NUM_STAR, 102 | AVKEY_NUM_SLASH, 103 | AVKEY_NUM_PLUS, 104 | AVKEY_NUM_MINUS, 105 | AVKEY_NUM_EQUAL, 106 | AVKEY_NUM_COMMA, 107 | AVKEY_NUM_RETURN, 108 | AVKEY_NUM_DOT, 109 | AVKEY_NUM_0, 110 | AVKEY_NUM_1, 111 | AVKEY_NUM_2, 112 | AVKEY_NUM_3, 113 | AVKEY_NUM_4, 114 | AVKEY_NUM_5, 115 | AVKEY_NUM_6, 116 | AVKEY_NUM_7, 117 | AVKEY_NUM_8, 118 | AVKEY_NUM_9, 119 | 120 | AVKEY_NUM_KEYCODE 121 | }; 122 | 123 | typedef struct 124 | { 125 | int keyCode; 126 | bool shift,ctrl,graph; 127 | } FM77AVKeyCombination; 128 | 129 | class FM77AVKeyEvent 130 | { 131 | public: 132 | bool pressEvent; // If false, it is a release event. 133 | int keyCode; 134 | 135 | FM77AVKeyEvent(){}; 136 | FM77AVKeyEvent(bool pressEvent,int keyCode) 137 | { 138 | this->pressEvent=pressEvent; 139 | this->keyCode=keyCode; 140 | } 141 | }; 142 | 143 | /*! Translates a label to key code. For auto-typing, str[] can be terminated with 0, 0x0d, 0x0a, or '\\'. 144 | */ 145 | int FM77AVKeyLabelToKeyCode(std::string str); 146 | 147 | std::string FM77AVKeyCodeToKeyLabel(int fm77avkey); 148 | 149 | FM77AVKeyCombination FM77AVTranslateCharToCode(unsigned char c); 150 | 151 | uint16_t FM77AVTranslateKeyCombinationToChar(FM77AVKeyCombination keyComb); 152 | 153 | const char *FM77AVGetKeyPress30BitPattern(int fm77avkey); 154 | std::string FM77AVGetKeyRelease30BitPattern(int fm77avkey); 155 | 156 | std::string FM77AVMake30BitPattern(const FM77AVKeyEvent keyEvent); 157 | 158 | unsigned int FM77AVGet1stByteIn30bitEncoding(const char code30[]); 159 | void FM77AVPut1stByteIn30bitEncoding(char code30[],unsigned int byteData); 160 | 161 | void FM77AV30bitTo40bit(char code40[41],const char code30[]); 162 | 163 | /* } */ 164 | #endif 165 | -------------------------------------------------------------------------------- /src/fm77av/fm77avparam.h: -------------------------------------------------------------------------------- 1 | #ifndef FM77AVPARAM_IS_INCLUDED 2 | #define FM77AVPARAM_IS_INCLUDED 3 | /* { */ 4 | 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include "fm77avdef.h" 11 | #include "fm77avkey.h" 12 | 13 | class FM77AVParam 14 | { 15 | public: 16 | void CleanUp(void); 17 | 18 | enum 19 | { 20 | WINDOW_NORMAL, 21 | WINDOW_MAXIMIZE, 22 | WINDOW_FULLSCREEN 23 | }; 24 | 25 | enum 26 | { 27 | NUM_GAMEPORTS=2, 28 | NUM_FDDRIVES=4, 29 | MAX_NUM_SCSI_DEVICES=7, 30 | }; 31 | 32 | enum 33 | { 34 | SCALING_DEFAULT=100, 35 | SCALING_MIN=50, 36 | SCALING_MAX=1000, 37 | }; 38 | 39 | class VirtualKey 40 | { 41 | public: 42 | std::string fm77avKey; 43 | int physicalId; 44 | unsigned int button; 45 | }; 46 | 47 | class HostShortCut 48 | { 49 | public: 50 | std::string hostKey; 51 | bool ctrl,shift; 52 | std::string cmdStr; 53 | }; 54 | 55 | unsigned int scaling=100; 56 | bool autoScaling=false; 57 | unsigned int windowModeOnStartUp=WINDOW_NORMAL; 58 | bool windowShift=false; 59 | 60 | std::string startUpStateFName; 61 | 62 | std::string pauseResumeKeyLabel="SCROLLLOCK"; 63 | 64 | unsigned int machineType=MACHINETYPE_AUTO; 65 | std::string ROMPath; 66 | std::string quickStateSaveFName; 67 | 68 | std::string symTableFName; 69 | 70 | bool pauseOnStart=false; 71 | unsigned int keyboardMode=FM77AV_KEYBOARD_MODE_DIRECT; 72 | 73 | unsigned int gamePort[NUM_GAMEPORTS]={FM77AV_GAMEPORTEMU_PHYSICAL0,FM77AV_GAMEPORTEMU_PHYSICAL1}; 74 | long long int maxButtonHoldTime[2][2]={{0,0},{0,0}}; 75 | 76 | bool noWait=false; 77 | 78 | std::vector imgSearchPaths; 79 | std::vector hostShortCutKeys; 80 | std::vector initialCmd; 81 | 82 | std::vector virtualKeys; 83 | 84 | std::unordered_map fileNameAlias; 85 | 86 | std::string quickScrnShotDir; 87 | unsigned int scrnShotX0=0,scrnShotY0=0,scrnShotWid=0,scrnShotHei=0; 88 | 89 | std::string playbackEventLogFName; 90 | 91 | std::string t77Path,t77SavePath; 92 | bool t77WriteProtect=false; 93 | std::string fdImgFName[NUM_FDDRIVES]; 94 | bool fdImgWriteProtect[NUM_FDDRIVES]={false,false,false,false}; 95 | 96 | bool unitTest=false; // If true, CUI will not be attached. Implies termination condition. 97 | 98 | bool enableCOM[FM7_MAX_NUM_COMPORTS]={false,false,false,false}; 99 | 100 | unsigned int appSpecificSetting=FM77AV_APPSPECIFIC_NONE; 101 | 102 | bool autoLoadTapeFile=false; 103 | 104 | unsigned int autoStopType=0; 105 | unsigned int autoStopKey=AVKEY_NUM_5; 106 | 107 | bool DOSMode=false; 108 | 109 | uint8_t powerOffAtCPUType=CPU_UNKNOWN; 110 | uint16_t powerOffAtAddr=0; 111 | class TestCondMem 112 | { 113 | public: 114 | uint8_t addrType; 115 | uint32_t addr; 116 | uint8_t data; 117 | }; 118 | std::vector testCondMem; 119 | 120 | 121 | // Toward semi-automated 1X RPG map generation. 122 | std::string mapXYExpression[2]; 123 | }; 124 | 125 | 126 | 127 | class FM77AVProfile : public FM77AVParam 128 | { 129 | public: 130 | // MAX_NUM_VIRTUALKEYS is limitation for GUI environment only. 131 | enum 132 | { 133 | MAX_NUM_VIRTUALKEYS=20, 134 | }; 135 | 136 | 137 | // autoStart flag is for GUI environment only. 138 | bool autoStart=false; 139 | 140 | std::string errorMsg; 141 | 142 | FM77AVProfile(); 143 | void CleanUp(void); 144 | std::vector Serialize(void) const; 145 | bool Deserialize(const std::vector &text); 146 | }; 147 | 148 | 149 | 150 | /* } */ 151 | #endif 152 | -------------------------------------------------------------------------------- /src/fm77av/fm77avrender.h: -------------------------------------------------------------------------------- 1 | #ifndef FM77AVRENDER_IS_INCLUDED 2 | #define FM77AVRENDER_IS_INCLUDED 3 | /* { */ 4 | 5 | #include "fm77avdef.h" 6 | #include "fm77avcrtc.h" 7 | 8 | class FM77AVRender 9 | { 10 | private: 11 | unsigned int wid,hei; 12 | std::vector rgba; 13 | 14 | bool CRTEnabled; 15 | 16 | unsigned int scrnMode; 17 | unsigned int VRAMOffset[FM77AV40_NUM_VRAM_BANKS]; 18 | unsigned int VRAMAccessMask; 19 | 20 | unsigned char VRAM[FM77AV40_VRAM_SIZE]; 21 | 22 | public: 23 | class Image 24 | { 25 | public: 26 | unsigned int wid,hei; 27 | const unsigned char *rgba; 28 | }; 29 | class ImageCopy 30 | { 31 | public: 32 | unsigned int wid,hei; 33 | std::vector rgba; 34 | }; 35 | 36 | FM77AVRender(); 37 | 38 | /*! 39 | */ 40 | Image GetImage(void) const; 41 | 42 | /*! This function moves the image ownership to the caller. 43 | After this function, the internally-stored image of FM77AVRender is empty. 44 | */ 45 | ImageCopy GetImageCopy(void); 46 | 47 | /*! Create a bitmap image. 48 | */ 49 | void Create(int wid,int hei); 50 | 51 | /*! 52 | */ 53 | void Crop(unsigned int x0,unsigned int y0,unsigned int wid,unsigned int hei); 54 | 55 | /*! 56 | */ 57 | void Prepare(const class FM77AV &fm77av); 58 | 59 | /*! 60 | */ 61 | void BuildImage(const class FM77AVCRTC::Palette &palette); 62 | 63 | /*! 64 | */ 65 | void FlipUpsideDown(void); 66 | }; 67 | 68 | /* } */ 69 | #endif 70 | -------------------------------------------------------------------------------- /src/fm77av/fm77avthread.h: -------------------------------------------------------------------------------- 1 | #ifndef FM77AVTHREAD_IS_INCLUDED 2 | #define FM77AVTHREAD_IS_INCLUDED 3 | /* { */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include "fm77av.h" 9 | #include "fm77aveventlog.h" 10 | #include "outside_world.h" 11 | 12 | class FM77AVUIThread 13 | { 14 | public: 15 | std::mutex uiLock; 16 | bool vmTerminated=false; 17 | virtual void ExecCommandQueue(class FM77AVThread &fm77avThread,FM77AV &fm77avPtr,class Outside_World *outside_world){}; 18 | }; 19 | 20 | class FM77AVThread 21 | { 22 | private: 23 | FM77AV *fm77avPtr; 24 | int runMode=RUNMODE_RUN; 25 | bool returnOnPause=false; 26 | 27 | // This will be used for virtually slwoing down CPU when VM is lagging. 28 | int64_t timeDeficit=0; 29 | 30 | public: 31 | enum 32 | { 33 | NANOSECONDS_PER_TIME_SYNC= 1000000, // 1ms 34 | }; 35 | 36 | enum 37 | { 38 | RUNMODE_PAUSE, 39 | RUNMODE_RUN, 40 | RUNMODE_ONE_INSTRUCTION, 41 | RUNMODE_EXIT, 42 | }; 43 | 44 | class OutputControl 45 | { 46 | public: 47 | class CPUOutputControl 48 | { 49 | public: 50 | bool mute=false; 51 | mutable uint16_t lastPC=0; 52 | }; 53 | CPUOutputControl main,sub; 54 | }; 55 | 56 | OutputControl output; 57 | 58 | public: 59 | FM77AVThread(); 60 | ~FM77AVThread(); 61 | 62 | unsigned int GetRunMode(void) const; 63 | 64 | void SetRunMode(unsigned int runMode); 65 | 66 | void SetReturnOnPause(bool returnOnPause); 67 | 68 | /*! If one of main- or sub-CPUs is muted, returns the one NOT muted. 69 | */ 70 | unsigned int OnlyOneCPUIsUnmuted(void) const; 71 | 72 | void VMStart(FM77AV *fm77avPtr,class Outside_World *outside_world,Outside_World::WindowInterface *window,FM77AVUIThread *uiThread); 73 | void VMMainLoop(FM77AV *fm77avPtr,class Outside_World *outside_world,Outside_World::WindowInterface *window,Outside_World::Sound *soundPtr,FM77AVUIThread *uiThread); 74 | void VMEnd(FM77AV *fm77avPtr,class Outside_World *outside_world,Outside_World::WindowInterface *window,FM77AVUIThread *uiThread); 75 | private: 76 | void AdjustRealTime(FM77AV *fm77avPtr,long long int cpuTimePassed,std::chrono::time_point time0,class Outside_World::Sound *soundPtr); 77 | void CheckRenderingTimer(FM77AV &fm77av,Outside_World::WindowInterface &window); 78 | 79 | public: 80 | void PrintStatus(FM77AV &fm77av) const; 81 | void PrintStatus(FM77AV &fm77av,bool muteMain,bool muteSub) const; 82 | void PrintCPUState(FM77AV &fm77av,MC6809 &cpu,MemoryAccess &mem,unsigned int mainOrSub) const; 83 | }; 84 | 85 | /* } */ 86 | #endif 87 | -------------------------------------------------------------------------------- /src/fm77av/gameport/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(fm77avgameport fm77avgameport.h fm77avgameport.cpp) 2 | target_link_libraries(fm77avgameport device cpputil fm77av fm77avdef cheapmath) 3 | target_include_directories(fm77avgameport PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 4 | -------------------------------------------------------------------------------- /src/fm77av/gameport/fm77avgameport.h: -------------------------------------------------------------------------------- 1 | /* LICENSE>> 2 | Copyright 2020 Soji Yamakawa (CaptainYS, http://www.ysflight.com) 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. Redistributions in binary form 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. 9 | 10 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | 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 HOLDER 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. 13 | 14 | << LICENSE */ 15 | #ifndef GAMEPORT_IS_INCLUDED 16 | #define GAMEPORT_IS_INCLUDED 17 | /* { */ 18 | 19 | #include "cheapmath.h" 20 | #include "fm77avdef.h" 21 | 22 | class FM77AVGamePort : public Device 23 | { 24 | public: 25 | virtual const char *DeviceName(void) const{return "GAMEPORT";} 26 | 27 | enum 28 | { 29 | NONE, 30 | MOUSE, 31 | GAMEPAD, 32 | CYBERSTICK, 33 | CAPCOMCPSF, 34 | MOUSEREAD_RESET_TIMEOUT=1000000, // 1000000ns=1ms 35 | CYBERSTICK_TIMEOUT=2000000, // 2000000ns=2ms 36 | CYBERSTICK_READ_INTERVAL=3500, // 3500ns=3.5us 37 | CYBERSTICK_BOOT_IDLE_TIME=1000000000, // Don't activate for 1 second to prevent boot menu. 38 | }; 39 | 40 | enum 41 | { 42 | MAX_NUM_BUTTONS=32 43 | }; 44 | 45 | enum 46 | { 47 | MOUSESTATE_XHIGH, 48 | MOUSESTATE_XLOW, 49 | MOUSESTATE_YHIGH, 50 | MOUSESTATE_YLOW, 51 | 52 | CYBERSTICK_00A, 53 | CYBERSTICK_00B, // 54 | CYBERSTICK_01A, // I don't remember interval, but I guess 0.01ms separation is good. 55 | CYBERSTICK_01B, 56 | CYBERSTICK_02A, 57 | CYBERSTICK_02B, 58 | CYBERSTICK_03A, 59 | CYBERSTICK_03B, 60 | CYBERSTICK_04A, 61 | CYBERSTICK_04B, 62 | CYBERSTICK_05A, 63 | CYBERSTICK_05B, 64 | CYBERSTICK_06A, 65 | CYBERSTICK_06B, 66 | CYBERSTICK_07A, 67 | CYBERSTICK_07B, 68 | CYBERSTICK_08A, 69 | CYBERSTICK_08B, 70 | CYBERSTICK_09A, 71 | CYBERSTICK_09B, 72 | CYBERSTICK_10A, 73 | CYBERSTICK_10B, 74 | CYBERSTICK_11A, 75 | CYBERSTICK_11B, 76 | 77 | NUM_MOUSESTATE, 78 | }; 79 | 80 | class Port 81 | { 82 | public: 83 | int device; // MOUSE, GAMEPAD, or CYBERSTICK 84 | int state; 85 | bool COM=false; // COM from CPU. 86 | unsigned char TRIG=3; // TRIG from CPU. 87 | bool button[2],left,right,up,down,run,pause; 88 | int mouseHold=0; // PSY-O-BLADE expects zero mouse motion for the first reading. 89 | 90 | Vec2i mouseMotion; // For CyberStick, used as XY position. 91 | int zAxis=0; // For CyberStick 92 | int wAxis=0; // For CyberStick 93 | int trig=0; // For CyberStick and CAPCOM CPSF 94 | 95 | // Once CPU starts reading the mouse, mouseMotion should stay the same. 96 | // If the value changes after 4-bits of the motion x or y is read before 97 | // the rest 4-bits, it would mess up the pointer. 98 | // To prevent this situation, mouseMotion is copied to mouseMotionCopy 99 | // when the first 4-bit of DX is sent to the CPU. 100 | Vec2i mouseMotionCopy; 101 | int zAxisCopy; // For CyberStick 102 | int wAxisCopy; // For CyberStick 103 | 104 | long long int lastAccessTime; 105 | long long int lastStateChangeTime; 106 | 107 | 108 | // Used in Read() >> 109 | bool lastButtonRead[2]={false,false}; 110 | long long int lastButtonDownTime[2]={0,0}; 111 | long long int maxButtonHoldTime[2]={0,0}; 112 | // Used in Read() << 113 | 114 | 115 | void Write(long long int fm77avTime,bool COM,unsigned char TRIG); 116 | unsigned char Read(long long int fm77avTime); // Reading last coordinate should reset motion. Not a const. 117 | 118 | void SetGamePadState(bool Abutton,bool Bbutton,bool left,bool right,bool up,bool down,bool run,bool pause,long long int fm77avTime); 119 | void SetCyberStickState(int x,int y,int z,int w,unsigned int trig,long long int fm77avTime); 120 | void SetCAPCOMCPSFState(bool left,bool right,bool up,bool down,bool A,bool B,bool X,bool Y,bool L,bool R, bool start,bool select,long long int fm77avTime); 121 | 122 | void SetAutoShotTimer(unsigned int prevTrig,unsigned int trig,long long int fm77avTime); 123 | 124 | // Don't have to save state >> 125 | // BaseTime is set in Set***State when the button is pressed. 126 | long long int autoShotInterval[MAX_NUM_BUTTONS]; // 0->No auto shot 127 | long long int autoShotBaseTime[MAX_NUM_BUTTONS]; 128 | // Don't have to save state << 129 | }; 130 | 131 | class State 132 | { 133 | public: 134 | Port ports[2]; 135 | void PowerOn(void); 136 | void Reset(void); 137 | }; 138 | 139 | State state; 140 | 141 | static unsigned int EmulationTypeToDeviceType(unsigned int emulationType); 142 | 143 | FM77AVGamePort(class FM77AV *fm77avPtr); 144 | 145 | virtual void PowerOn(void); 146 | virtual void Reset(void); 147 | 148 | virtual uint32_t SerializeVersion(void) const; 149 | virtual void SpecificSerialize(std::vector &data,std::string stateFName) const; 150 | virtual bool SpecificDeserialize(const unsigned char *&data,std::string stateFName,uint32_t version); 151 | }; 152 | 153 | /* } */ 154 | #endif 155 | -------------------------------------------------------------------------------- /src/fm77av/keyboard/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(fm77avkeyboard fm77avkeyboard.h fm77avkeyboard.cpp fm77avrkana.h fm77avrkana.cpp) 2 | target_link_libraries(fm77avkeyboard fm77av fm77avkey memory cpputil fm77avdef) 3 | target_include_directories(fm77avkeyboard PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 4 | -------------------------------------------------------------------------------- /src/fm77av/keyboard/fm77avkeyboard.h: -------------------------------------------------------------------------------- 1 | #ifndef FM77AVKEYBOARD_IS_INCLUDED 2 | #define FM77AVKEYBOARD_IS_INCLUDED 3 | /* { */ 4 | 5 | #include "device.h" 6 | #include "fm77avkey.h" 7 | #include "fm77avrkana.h" 8 | #include 9 | #include 10 | 11 | class FM77AVKeyboard : public Device 12 | { 13 | public: 14 | virtual const char *DeviceName(void) const{return "KEYBOARD";} 15 | 16 | uint8_t AVKeyToScanCode[AVKEY_NUM_KEYCODE]; 17 | uint8_t AVKeyRemap[AVKEY_NUM_KEYCODE]; 18 | bool IsNumKey[AVKEY_NUM_KEYCODE]; 19 | bool IsArrowKey[AVKEY_NUM_KEYCODE]; 20 | bool heldDown[AVKEY_NUM_KEYCODE]; 21 | uint8_t AVKeyToRKanaKey[AVKEY_NUM_KEYCODE]; // Non-Zero only for relevant to r-kana. 22 | 23 | enum 24 | { 25 | KEYFLAG_SHIFT=1, 26 | KEYFLAG_CTRL=2, 27 | KEYFLAG_GRAPH=4, 28 | }; 29 | enum 30 | { 31 | ENCODING_JIS, 32 | ENCODING_FM16BETA, 33 | ENCODING_SCANCODE 34 | }; 35 | 36 | enum 37 | { 38 | AUTOTYPE_INTERVAL=50000000, // 20 chars per sec. 39 | AUTOTYPE_INTERVAL_RETURN=500000000, // Longer wait after RETURN key. 40 | }; 41 | 42 | enum // FM77AV40 Hardware Reference pp.230 43 | { 44 | CMD_SET_CODING=0x00, // 1-byte 00:FM-7 01:FM-16beta 02:Scan Code -> 0-byte 45 | CMD_GET_CODING=0x01, // 0-byte -> 1-byte 46 | CMD_SET_LED=0x02, // 1-byte 00:CAPS on 01:CAPS off 02:KANA on 03:KANA off 47 | CMD_GET_LED=0x03, // 0-byte -> 1-byte Bit0:CAPS Bit1:KANA 48 | CMD_SET_AUTO_REPEAT=0x04, // 1-byte 00:Repeat ON 01:Repeat OFF 49 | CMD_SET_AUTO_REPEAT_INTERVAL=0x05, // 2-bytes [0]Repeat Start Time [1]Repeat Interval in millisec 50 | CMD_REAL_TIME_CLOCK=0x80, // 1-byte 00:Read -> 7-bytes 01:Write+7 more parameters. 51 | CMD_DIGITIZE_MODE=0x81, // 1-byte parameter 0x00 52 | CMD_SET_SCREEN_MODE=0x82, // 1-byte 00:Computer Only 01:Superimpose 02:TV only 03:Digtize 53 | CMD_GET_SCREEN_MODE=0x83, // 0-byte -> 1-byte Screen Mode 54 | CMD_SET_TV_BRIGHTNESS=0x84, // 1-byte 00:Bright 01:Dark 55 | 56 | CMD_NULL=0xFF, 57 | }; 58 | // For command 00,02,04,05,80,81,82,84, undefined parameter will be ignored 59 | // and taken as a new command. pp.235 60 | 61 | 62 | class State 63 | { 64 | public: 65 | uint16_t encodingMode=ENCODING_JIS; 66 | // Death Force Expects non-zero read from $FD01 on reset. 67 | uint16_t lastKeyCode=0xFF; 68 | std::queue keyCodeQueue; 69 | 70 | uint64_t encoderAcknowledgeBy=0; 71 | uint64_t encoderDataReadyBy=0; 72 | uint16_t encoderCmd=0xFF; 73 | uint8_t nEncoderParam=0; 74 | uint8_t encoderParam[8]; // RTC-set (80 01) takes the longest 8-byte parameter. 75 | std::queue encoderQueue; 76 | 77 | bool CAPS=false,KANA=false; 78 | bool INSLED=false; 79 | uint8_t videoCaptureMode; // Should I implement video digitize/superimpose? I guess video capture card for Tsugaru before that. 80 | uint8_t videoCaptureBrightness; 81 | bool keyRepeat=true; 82 | uint64_t keyRepeatStartTime=700,keyRepeatInterval=70; 83 | }; 84 | State state; 85 | 86 | enum 87 | { 88 | AUTOSTOP_NONE, 89 | AUTOSTOP_AFTER_NUM_RELEASE, 90 | AUTOSTOP_AFTER_ARROW_RELEASE, 91 | AUTOSTOP_AFTER_NUM_RELEASE_AND_RETYPE, 92 | AUTOSTOP_AFTER_ARROW_RELEASE_AND_RETYPE, 93 | AUTOSTOP_AFTER_ANY_KEY_RELEASE, 94 | }; 95 | // What is this? 96 | // FM-7 series, until FM77AV could not sense key-release. It could sense key-press, 97 | // therefore the game program could know when to start moving a character, but never 98 | // knew when to stop by key-release. Therefore, we had to press a num-key to start 99 | // moving a character, and press num-5 to stop it. 100 | // That was a major complaints from the gamers who were used to other platforms. 101 | // But, I didn't have to keep the keys held down. I found it easier for my wrist though. 102 | // There were external joystick that plugged in to the keyboard connector and 103 | // automatically inserted num-5 after releasing the stick. Many games supported 104 | // gamepad after Fujitsu released YM2203C expansion card, in which case the game could 105 | // sense direction-button release. But, mainly the game program that also supported 106 | // FM-8 had no way of stopping a character on key-release. 107 | // Some games like Plazma Linesolved this problem by moving a character one step when 108 | // the key is pressed. Then, we had to pound on the key to move quickly. 109 | // The emulator can virtually solve the program by automatically inserting a key stroke 110 | // after releasing certain keys. 111 | // One of the most famous vertical-scrolling shooter among FM-7 users, Delphis, had a 112 | // even bigger problem. Your fighter jet stops when you drop a bomb by Z key, which made 113 | // the game extremely difficult to play. (I wrote a game-pad patch though). The emulator 114 | // can also solve this problem by re-typing the direction key after pressing other keys. 115 | static std::string AutoStopToStr(unsigned int autoStopType); 116 | static unsigned int StrToAutoStop(std::string str); 117 | 118 | class Variable 119 | { 120 | public: 121 | uint16_t autoStopKey=AVKEY_NUM_5; 122 | uint16_t autoStopRetypeKey=AVKEY_NULL; 123 | uint16_t autoStopAfterThis=AUTOSTOP_NONE; 124 | std::queue autoType; 125 | 126 | // If false, it ignores input from outside_world. 127 | // Used for preventing accidental key strokes while VM is paused. 128 | bool enableKeyStrokes=true; 129 | 130 | bool rKanaMode=false; 131 | std::string romaji; 132 | }; 133 | Variable var; 134 | std::unordered_map RomajiMap; 135 | 136 | FM77AVKeyboard(VMBase *vmBase); 137 | 138 | void WriteD431(uint8_t data); 139 | void WriteD432(uint8_t data); 140 | void AfterReadD431(void); 141 | uint8_t NonDestructiveReadD431(void) const; 142 | uint8_t NonDestructiveReadD432(void) const; 143 | 144 | void ClearEncoderQueue(void); 145 | void ProcessKeyCodeInQueue(void); 146 | 147 | virtual void RunScheduledTask(unsigned long long int fm77avTime); 148 | 149 | void Reset(void); 150 | 151 | void Type(unsigned int ASCIICode); // Virtually type a letter. 152 | 153 | void Press(unsigned int keyFlags,unsigned int keyCode); 154 | void Release(unsigned int keyFlags,unsigned int keyCode); 155 | protected: 156 | void PushKeyToQueueJISMode(unsigned int keyFlags,unsigned int keyCode); 157 | void PushASCIICodeToQueueJISMode(uint16_t ascii); 158 | bool NumKeyHeldDown(void) const; 159 | bool ArrowKeyHeldDown(void) const; 160 | 161 | public: 162 | uint64_t GetKeyRepeatStartTime(void) const; 163 | uint64_t GetKeyRepeatInterval(void) const; 164 | 165 | /* virtual */ uint32_t SerializeVersion(void) const; 166 | /* virtual */ void SpecificSerialize(std::vector &data,std::string stateFName) const; 167 | /* virtual */ bool SpecificDeserialize(const unsigned char *&data,std::string stateFName,uint32_t version); 168 | }; 169 | 170 | /* } */ 171 | #endif 172 | -------------------------------------------------------------------------------- /src/fm77av/keyboard/fm77avrkana.cpp: -------------------------------------------------------------------------------- 1 | #include "fm77avkey.h" 2 | #include "fm77avrkana.h" 3 | 4 | struct RKanaTable rKanaTable[]= 5 | { 6 | {"a", false, {0xB1,0,0,0}}, 7 | {"xa", false, {0xA7,0,0,0}}, 8 | {"la", false, {0xA7,0,0,0}}, 9 | 10 | {"i", false, {0xB2,0,0,0}}, 11 | {"yi", false, {0xB2,0,0,0}}, 12 | {"xi", false, {0xA8,0,0,0}}, 13 | {"li", false, {0xA8,0,0,0}}, 14 | 15 | {"u", false, {0xB3,0,0,0}}, 16 | {"wu", false, {0xB3,0,0,0}}, 17 | {"xu", false, {0xA9,0,0,0}}, 18 | {"lu", false, {0xA9,0,0,0}}, 19 | 20 | {"e", false, {0xB4,0,0,0}}, 21 | {"ye", false, {0xB4,0,0,0}}, 22 | {"xe", false, {0xAA,0,0,0}}, 23 | {"le", false, {0xAA,0,0,0}}, 24 | 25 | {"o", false, {0xB5,0,0,0}}, 26 | {"xo", false, {0xAB,0,0,0}}, 27 | {"lo", false, {0xAB,0,0,0}}, 28 | 29 | {"ka", false, {0xB6,0,0,0}}, 30 | {"ki", false, {0xB7,0,0,0}}, 31 | {"ku", false, {0xB8,0,0,0}}, 32 | {"ke", false, {0xB9,0,0,0}}, 33 | {"ko", false, {0xBA,0,0,0}}, 34 | 35 | {"kya", false, {0xB7,0xAC,0,0}}, 36 | {"kyi", false, {0xB7,0,0,0}}, 37 | {"kyu", false, {0xB7,0xAD,0,0}}, 38 | {"kye", false, {0xB7,0xAA,0,0}}, 39 | {"kyo", false, {0xB7,0xAE,0,0}}, 40 | 41 | {"ga", false, {0xB6,0xDE,0,0}}, 42 | {"gi", false, {0xB7,0xDE,0,0}}, 43 | {"gu", false, {0xB8,0xDE,0,0}}, 44 | {"ge", false, {0xB9,0xDE,0,0}}, 45 | {"go", false, {0xBA,0xDE,0,0}}, 46 | 47 | {"sa", false, {0xBB,0,0,0}}, 48 | {"si", false, {0xBC,0,0,0}}, 49 | {"shi", false, {0xBC,0,0,0}}, 50 | {"su", false, {0xBD,0,0,0}}, 51 | {"se", false, {0xBE,0,0,0}}, 52 | {"so", false, {0xBF,0,0,0}}, 53 | 54 | {"sha", false, {0xBC,0xAC,0,0}}, 55 | {"sya", false, {0xBC,0xAC,0,0}}, 56 | {"shu", false, {0xBC,0xAD,0,0}}, 57 | {"syu", false, {0xBC,0xAD,0,0}}, 58 | {"she", false, {0xBC,0xAA,0,0}}, 59 | {"sye", false, {0xBC,0xAA,0,0}}, 60 | {"sho", false, {0xBC,0xAE,0,0}}, 61 | {"syo", false, {0xBC,0xAE,0,0}}, 62 | 63 | {"ja", false, {0xBC,0xDE,0xA7,0}}, 64 | {"jya", false, {0xBC,0xDE,0xA7,0}}, 65 | {"ju", false, {0xBC,0xDE,0xAD,0}}, 66 | {"jyu", false, {0xBC,0xDE,0xAD,0}}, 67 | {"je", false, {0xBC,0xDE,0xAA,0}}, 68 | {"jye", false, {0xBC,0xDE,0xAA,0}}, 69 | {"jo", false, {0xBC,0xDE,0xAE,0}}, 70 | {"jyo", false, {0xBC,0xDE,0xAE,0}}, 71 | 72 | {"za", false, {0xBB,0xDE,0,0}}, 73 | {"zi", false, {0xBC,0xDE,0,0}}, 74 | {"ji", false, {0xBC,0xDE,0,0}}, 75 | {"zu", false, {0xBD,0xDE,0,0}}, 76 | {"ze", false, {0xBE,0xDE,0,0}}, 77 | {"zo", false, {0xBF,0xDE,0,0}}, 78 | 79 | {"ta", false, {0xC0,0,0,0}}, 80 | {"ti", false, {0xC1,0,0,0}}, 81 | {"chi", false, {0xC1,0,0,0}}, 82 | {"tu", false, {0xC2,0,0,0}}, 83 | {"tsu", false, {0xC2,0,0,0}}, 84 | {"te", false, {0xC3,0,0,0}}, 85 | {"to", false, {0xC4,0,0,0}}, 86 | 87 | {"tya", false, {0xC1,0xAC,0,0}}, 88 | {"tyi", false, {0xC3,0xA8,0,0}}, 89 | {"thi", false, {0xC3,0xA8,0,0}}, 90 | {"tyu", false, {0xC1,0xAD,0,0}}, 91 | {"tyo", false, {0xC1,0xAE,0,0}}, 92 | {"cha", false, {0xC1,0xAC,0,0}}, 93 | {"chu", false, {0xC1,0xAD,0,0}}, 94 | {"cho", false, {0xC1,0xAE,0,0}}, 95 | 96 | {"ltu", false, {0xAF,0,0,0}}, 97 | {"xtu", false, {0xAF,0,0,0}}, 98 | 99 | {"da", false, {0xC0,0xDE,0,0}}, 100 | {"di", false, {0xC1,0xDE,0,0}}, 101 | {"du", false, {0xC2,0xDE,0,0}}, 102 | {"de", false, {0xC3,0xDE,0,0}}, 103 | {"do", false, {0xC4,0xDE,0,0}}, 104 | 105 | {"dha", false, {0xC3,0xDE,0xAC,0}}, 106 | {"dhi", false, {0xC3,0xDE,0xA8,0}}, 107 | {"dhu", false, {0xC3,0xDE,0xAD,0}}, 108 | {"dhe", false, {0xC3,0xDE,0xAA,0}}, 109 | {"dho", false, {0xC3,0xDE,0xAE,0}}, 110 | 111 | {"dya", false, {0xC1,0xDE,0xAC,0}}, 112 | {"dyi", false, {0xC1,0xDE,0xA8,0}}, 113 | {"dyu", false, {0xC1,0xDE,0xAD,0}}, 114 | {"dye", false, {0xC1,0xDE,0xAA,0}}, 115 | {"dyo", false, {0xC1,0xDE,0xAE,0}}, 116 | 117 | {"na", false, {0xC5,0,0,0}}, 118 | {"ni", false, {0xC6,0,0,0}}, 119 | {"nu", false, {0xC7,0,0,0}}, 120 | {"ne", false, {0xC8,0,0,0}}, 121 | {"no", false, {0xC9,0,0,0}}, 122 | 123 | {"nya", false, {0xC6,0xAC,0,0}}, 124 | {"nyi", false, {0xC6,0xA8,0,0}}, 125 | {"nyu", false, {0xC6,0xAD,0,0}}, 126 | {"nye", false, {0xC6,0xAA,0,0}}, 127 | {"nyo", false, {0xC6,0xAE,0,0}}, 128 | 129 | {"ha", false, {0xCA,0,0,0}}, 130 | {"hi", false, {0xCB,0,0,0}}, 131 | {"hu", false, {0xCC,0,0,0}}, 132 | {"he", false, {0xCD,0,0,0}}, 133 | {"ho", false, {0xCE,0,0,0}}, 134 | 135 | {"pa", false, {0xCA,0xDF,0,0}}, 136 | {"pi", false, {0xCB,0xDF,0,0}}, 137 | {"pu", false, {0xCC,0xDF,0,0}}, 138 | {"pe", false, {0xCD,0xDF,0,0}}, 139 | {"po", false, {0xCE,0xDF,0,0}}, 140 | 141 | {"pya", false, {0xCB,0xDF,0xAC,0}}, 142 | {"pyi", false, {0xCB,0xDF,0xA8,0}}, 143 | {"pyu", false, {0xCB,0xDF,0xAD,0}}, 144 | {"pye", false, {0xCB,0xDF,0xAA,0}}, 145 | {"pyo", false, {0xCB,0xDF,0xAE,0}}, 146 | 147 | {"hya", false, {0xCB,0xAC,0,0}}, 148 | {"hyi", false, {0xCB,0xA8,0,0}}, 149 | {"hyu", false, {0xCB,0xAD,0,0}}, 150 | {"hye", false, {0xCB,0xAA,0,0}}, 151 | {"hyo", false, {0xCB,0xAE,0,0}}, 152 | 153 | {"ba", false, {0xCA,0xDE,0,0}}, 154 | {"bi", false, {0xCB,0xDE,0,0}}, 155 | {"bu", false, {0xCC,0xDE,0,0}}, 156 | {"be", false, {0xCD,0xDE,0,0}}, 157 | {"bo", false, {0xCE,0xDE,0,0}}, 158 | 159 | {"fa", false, {0xCC,0xA7,0,0}}, 160 | {"fi", false, {0xCC,0xA8,0,0}}, 161 | {"fu", false, {0xCC,0,0,0}}, 162 | {"fe", false, {0xCC,0xAA,0,0}}, 163 | {"fo", false, {0xCC,0xAB,0,0}}, 164 | 165 | {"va", false, {0xB3,0xDE,0xA7,0}}, 166 | {"vi", false, {0xB3,0xDE,0xA8,0}}, 167 | {"vu", false, {0xB3,0xDE,0xA9,0}}, 168 | {"ve", false, {0xB3,0xDE,0xAA,0}}, 169 | {"vo", false, {0xB3,0xDE,0xAB,0}}, 170 | 171 | {"ma", false, {0xCF,0,0,0}}, 172 | {"mi", false, {0xD0,0,0,0}}, 173 | {"mu", false, {0xD1,0,0,0}}, 174 | {"me", false, {0xD2,0,0,0}}, 175 | {"mo", false, {0xD3,0,0,0}}, 176 | 177 | {"mya", false, {0xD0,0xAC,0,0}}, 178 | {"myi", false, {0xD0,0xA8,0,0}}, 179 | {"myu", false, {0xD0,0xAD,0,0}}, 180 | {"mye", false, {0xD0,0xAA,0,0}}, 181 | {"myo", false, {0xD0,0xAE,0,0}}, 182 | 183 | {"ya", false, {0xD4,0,0,0}}, 184 | {"yu", false, {0xD5,0,0,0}}, 185 | {"yo", false, {0xD6,0,0,0}}, 186 | 187 | {"lya", false, {0xAC,0,0,0}}, 188 | {"lyu", false, {0xAD,0,0,0}}, 189 | {"lyo", false, {0xAE,0,0,0}}, 190 | 191 | {"xya", false, {0xAC,0,0,0}}, 192 | {"xyu", false, {0xAD,0,0,0}}, 193 | {"xyo", false, {0xAE,0,0,0}}, 194 | 195 | {"ra", false, {0xD7,0,0,0}}, 196 | {"ri", false, {0xD8,0,0,0}}, 197 | {"ru", false, {0xD9,0,0,0}}, 198 | {"re", false, {0xDA,0,0,0}}, 199 | {"ro", false, {0xDB,0,0,0}}, // This key doesn't exist in the US keyboard. Therefore it is impossible without rKana 200 | 201 | {"rya", false, {0xD8,0xAC,0,0}}, 202 | {"ryi", false, {0xD8,0xA8,0,0}}, 203 | {"ryu", false, {0xD8,0xAD,0,0}}, 204 | {"rye", false, {0xD8,0xAA,0,0}}, 205 | {"ryo", false, {0xD8,0xAE,0,0}}, 206 | 207 | {"wa", false, {0xDC,0,0,0}}, 208 | {"wi", false, {0xB3,0xA8,0,0}}, 209 | {"we", false, {0xB3,0xAA,0,0}}, 210 | {"wo", false, {0xA6,0,0,0}}, 211 | 212 | {"nn", false, {0xDD,0,0,0}}, 213 | 214 | {"-", false, {0xB0,0,0,0}}, 215 | 216 | 217 | // Small 218 | {"kk", true, {0xAF,0,0,0}}, 219 | {"gg", true, {0xAF,0,0,0}}, 220 | {"yy", true, {0xAF,0,0,0}}, 221 | {"ss", true, {0xAF,0,0,0}}, 222 | {"jj", true, {0xAF,0,0,0}}, 223 | {"zz", true, {0xAF,0,0,0}}, 224 | {"tt", true, {0xAF,0,0,0}}, 225 | {"dd", true, {0xAF,0,0,0}}, 226 | {"hh", true, {0xAF,0,0,0}}, 227 | {"pp", true, {0xAF,0,0,0}}, 228 | {"bb", true, {0xAF,0,0,0}}, 229 | {"ff", true, {0xAF,0,0,0}}, 230 | {"vv", true, {0xAF,0,0,0}}, 231 | {"mm", true, {0xAF,0,0,0}}, 232 | {"rr", true, {0xAF,0,0,0}}, 233 | {"ww", true, {0xAF,0,0,0}}, 234 | {"cc", true, {0xAF,0,0,0}}, 235 | 236 | {"nk", true, {0xDD,0,0,0}}, 237 | {"ng", true, {0xDD,0,0,0}}, 238 | {"ns", true, {0xDD,0,0,0}}, 239 | {"nj", true, {0xDD,0,0,0}}, 240 | {"nz", true, {0xDD,0,0,0}}, 241 | {"nt", true, {0xDD,0,0,0}}, 242 | {"nd", true, {0xDD,0,0,0}}, 243 | {"nh", true, {0xDD,0,0,0}}, 244 | {"np", true, {0xDD,0,0,0}}, 245 | {"nb", true, {0xDD,0,0,0}}, 246 | {"nf", true, {0xDD,0,0,0}}, 247 | {"nv", true, {0xDD,0,0,0}}, 248 | {"nm", true, {0xDD,0,0,0}}, 249 | {"nr", true, {0xDD,0,0,0}}, 250 | {"nw", true, {0xDD,0,0,0}}, 251 | 252 | {nullptr,false,{0,0,0,0}}, 253 | }; 254 | -------------------------------------------------------------------------------- /src/fm77av/keyboard/fm77avrkana.h: -------------------------------------------------------------------------------- 1 | #ifndef FM77AVRKANA_IS_INCLUDED 2 | #define FM77AVRKANA_IS_INCLUDED 3 | /* { */ 4 | 5 | struct RKanaTable 6 | { 7 | const char *keyComb; 8 | bool leaveFirstChar; 9 | unsigned char output[4]; 10 | }; 11 | extern struct RKanaTable rKanaTable[]; 12 | 13 | /* } */ 14 | #endif 15 | -------------------------------------------------------------------------------- /src/fm77av/serialport/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(fm77avserialport fm77avserialport.h fm77avserialport.cpp) 2 | target_link_libraries(fm77avserialport device cpputil fm77av fm77avdef i8251) 3 | target_include_directories(fm77avserialport PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 4 | -------------------------------------------------------------------------------- /src/fm77av/serialport/fm77avserialport.h: -------------------------------------------------------------------------------- 1 | /* LICENSE>> 2 | Copyright 2020 Soji Yamakawa (CaptainYS, http://www.ysflight.com) 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. Redistributions in binary form 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. 9 | 10 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | 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 HOLDER 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. 13 | 14 | << LICENSE */ 15 | #ifndef SERIALPORT_IS_INCLUDED 16 | #define SERIALPORT_IS_INCLUDED 17 | /* { */ 18 | 19 | #include 20 | #include 21 | #include "device.h" 22 | #include "fm77avdef.h" 23 | #include "i8251.h" 24 | 25 | class FM77AVSerialPort : public Device 26 | { 27 | public: 28 | virtual const char *DeviceName(void) const{return "SERIALPORT";} 29 | 30 | enum 31 | { 32 | CODE_SOH=0x01, 33 | CODE_STX=0x02, 34 | CODE_EOT=0x04, 35 | CODE_EOF=0x05, // Is it right? 36 | CODE_ACK=0x06, 37 | CODE_NAK=0x15, 38 | CODE_CAN=0x18, 39 | }; 40 | 41 | enum 42 | { 43 | INTENABLE_TXRDY=0x01, 44 | INTENABLE_RXRDY=0x02, 45 | INTENABLE_SYNDET=0x04, 46 | INTENABLE_CS=0x08, 47 | INTENABLE_CI=0x10, 48 | }; 49 | 50 | class DefaultClient : public i8251::Client 51 | { 52 | public: 53 | bool printRecvText=false; 54 | 55 | long long int toVMPtr=0; 56 | std::vector fromVM,toVM; 57 | 58 | enum 59 | { 60 | FILETFR_NONE, 61 | FILETFR_XMODEM_TO_VM, 62 | FILETFR_XMODEM1024_TO_VM, 63 | FILETFR_XMODEM_FROM_VM, 64 | }; 65 | unsigned int fileTfrMode=FILETFR_NONE; 66 | unsigned int fileTfrPtr=0; 67 | std::vector fileTfrData; 68 | std::string recvLine; 69 | bool XMODEM_EOT_SENT=false; 70 | bool XMODEM_USE_CRC=false; 71 | std::string hostRecvFName; 72 | 73 | void ClearXMODEM(void); 74 | void SetUpXMODEMtoVM(const std::vector &data,uint32_t packetLength); 75 | void SetUpXMODEMfromVM(std::string hostRecvFName); 76 | void SetUpXMODEMCRCfromVM(std::string hostRecvFName); 77 | 78 | void XMODEM_TO_VM_TransferNextBlock(uint32_t packetLength); 79 | unsigned int XMODEM_CRC(unsigned char ptr[],unsigned int len); 80 | 81 | virtual bool TxRDY(void); 82 | virtual void Tx(unsigned char data); 83 | virtual void SetStopBits(unsigned char stopBits); 84 | virtual void SetParity(bool enabled,bool evenParity); 85 | virtual void SetDataLength(unsigned char bitsPerData); 86 | virtual void SetBaudRate(unsigned int baudRate); 87 | virtual void Command(bool RTS,bool DTR,bool BREAK); 88 | virtual bool RxRDY(void); 89 | virtual unsigned char Rx(void); 90 | virtual unsigned char PeekRx(void) const; 91 | virtual bool DSR(void); 92 | }; 93 | 94 | 95 | class State 96 | { 97 | public: 98 | bool enabled[FM7_MAX_NUM_COMPORTS]; 99 | i8251 COM[FM7_MAX_NUM_COMPORTS]; 100 | }; 101 | State state; 102 | DefaultClient cli0; 103 | 104 | FM77AVSerialPort(class FM77AV *fm77avPtr); 105 | 106 | virtual void PowerOn(void); 107 | virtual void Reset(void); 108 | 109 | virtual uint32_t SerializeVersion(void) const; 110 | virtual void SpecificSerialize(std::vector &data,std::string stateFName) const; 111 | virtual bool SpecificDeserialize(const unsigned char *&data,std::string stateFName,uint32_t version); 112 | }; 113 | 114 | /* } */ 115 | #endif 116 | -------------------------------------------------------------------------------- /src/fm77av/sound/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TARGET_NAME fm77avsound) 2 | add_library(${TARGET_NAME} fm77avsound.h fm77avsound.cpp) 3 | target_link_libraries(${TARGET_NAME} cpputil device vgmrecorder ay38910 ym2203c fm77av fm77avdef yssimplesound) 4 | target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 5 | -------------------------------------------------------------------------------- /src/fm77av/sound/fm77avsound.h: -------------------------------------------------------------------------------- 1 | #ifndef FM77AVSOUND_IS_INCLUDED 2 | #define FM77AVSOUND_IS_INCLUDED 3 | /* { */ 4 | 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include "device.h" 11 | #include "ay38910.h" 12 | #include "ym2612.h" 13 | #include "fm77avdef.h" 14 | #include "vgmrecorder.h" 15 | #include "outside_world.h" 16 | 17 | class FM77AVSound : public Device 18 | { 19 | public: 20 | enum 21 | { 22 | #if !defined(__linux__) && !defined(__linux) 23 | MILLISEC_PER_WAVE=20, // Looks like time resolution of Wave Playback of Direct Sound is 10ms. 24 | // And it needs to be 10 times integer. 25 | #else 26 | MILLISEC_PER_WAVE=40, // Maybe because I am developing on VirtualBox, I am getting outrageously slow latency of 80ms (40ms*2). 27 | #endif 28 | // 2ms resolution is needed for "What?" sound of Xanadu. 29 | // Silpheed "Presented by Game Arts" requires higher time resolution. Will need to go down to 500us. 30 | // OK, now I introduced Register-Write Scheduling, which should solve the problem. 31 | MILLISEC_PER_WAVE_GENERATION=5, 32 | 33 | RINGBUFFER_CLEAR_TIME=1000000000, // Play this long after the last play-back to make sure ring buffer is clear. 34 | }; 35 | 36 | virtual const char *DeviceName(void) const{return "SOUND";} 37 | 38 | enum 39 | { 40 | BEEP_OFF, 41 | BEEP_ONE_SHOT, 42 | BEEP_CONTINUOUS, 43 | 44 | SINGLE_BEEP_DURATION=210000000, // 0.21 seconds from FM-7. 45 | BEEP_SOUND_AMPLITUDE=2048, 46 | }; 47 | enum 48 | { 49 | REG_GAMEPORTENABLE=7, 50 | REG_PORTA=14, 51 | REG_PORTB=15, 52 | }; 53 | 54 | class State 55 | { 56 | public: 57 | bool mute=false; 58 | 59 | YM2612 ym2203c; // Will use Tsugaru-Ben for emulate YM2203C. 60 | uint8_t ym2203cCommand=0; 61 | uint8_t ym2203cDataRead=0; 62 | uint8_t ym2203cDataWrite=0; 63 | unsigned int ym2203cAddrLatch=0; 64 | 65 | AY38910 ay38910; 66 | uint8_t ay38910regMode=0; // 0:High Impedance 1:Data Read 2:Data Write 3:AddrLatch 67 | uint8_t ay38910AddrLatch=0; 68 | uint8_t ay38910LastControl=0; 69 | uint8_t ay38910LastData=0; 70 | 71 | uint8_t beepState=BEEP_OFF; 72 | uint64_t beepStopTime=0; 73 | uint32_t beepTimeBalance=0; 74 | uint8_t beepWaveOut=0; 75 | 76 | void PowerOn(void); 77 | void Reset(void); 78 | void ResetVariables(void); 79 | }; 80 | State state; 81 | 82 | 83 | class Variable 84 | { 85 | public: 86 | bool vgmRecordingArmed=false; 87 | VGMRecorder vgmRecorder; 88 | }; 89 | Variable var; 90 | 91 | 92 | 93 | bool recordAudio=false; 94 | std::vector audioRecording; 95 | uint8_t ym2203cRegisterMonitor[256]; 96 | uint8_t ay38910RegisterMonitor[256]; 97 | 98 | int64_t ringBufferClearTimeLeft=0; 99 | uint64_t nextWaveFilledInMillisec=0; 100 | uint64_t nextWaveGenTime=0; 101 | std::vector nextWave; 102 | 103 | inline bool IsFMPlaying(void) const 104 | { 105 | return 0!=state.ym2203c.state.playingCh || 0 GetStatusText(void) const; 129 | 130 | /*! Call this function periodically to continue sound playback. 131 | */ 132 | void ProcessSound(Outside_World::Sound *soundPtr); 133 | 134 | /*! Call this function while VM is paused. 135 | */ 136 | void ProcessSilence(class Outside_World::Sound *outside_world); 137 | 138 | void StartRecording(void); 139 | void EndRecording(void); 140 | void SaveRecording(std::string fName) const; 141 | 142 | void ArmVGMRecording(void); 143 | void StartVGMRecording(void); 144 | void EndVGMRecording(void); 145 | void TrimVGMRecording(void); 146 | bool SaveVGMRecording(std::string fName) const; 147 | 148 | void SerializeYM2203CFMPart(std::vector &data) const; 149 | void DeserializeYM2203CFMPart(const unsigned char *&data,unsigned int version); 150 | void SerializeAY38910(std::vector &data) const; 151 | void DeserializeAY38910(const unsigned char *&data,unsigned int version); 152 | 153 | virtual uint32_t SerializeVersion(void) const; 154 | virtual void SpecificSerialize(std::vector &data,std::string stateFName) const; 155 | virtual bool SpecificDeserialize(const unsigned char *&data,std::string stateFName,uint32_t version); 156 | }; 157 | 158 | 159 | /* } */ 160 | #endif 161 | -------------------------------------------------------------------------------- /src/fm7lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TARGET_NAME fm7lib) 2 | add_library(${TARGET_NAME} fm7lib.cpp fm7lib.h cpplib.cpp cpplib.h) 3 | target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 4 | target_link_libraries(${TARGET_NAME} cpputil) 5 | -------------------------------------------------------------------------------- /src/fm7lib/cpplib.h: -------------------------------------------------------------------------------- 1 | #ifndef CPPLIB_IS_INCLUDED 2 | #define CPPLIB_IS_INCLUDED 3 | /* { */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace FM7Lib 10 | { 11 | 12 | /*! Convert a hexa-decimal number described in str to an integer. 13 | */ 14 | int Xtoi(const char str[]); 15 | 16 | /*! Convert a number described in str to an integer. 17 | If the number starts with "0x", "$", or "&H" it is taken as a hexa-decimal number. 18 | If the number ends with "H" it is taken as a hexa-decimal number. 19 | */ 20 | int Atoi(const char str[]); 21 | 22 | 23 | /*! Convert an unsigned integer to Intel-byteorder binary. 24 | I hope people didn't come up with a confusing name called Little Endian and Big Endian. 25 | Just say MSB last or MSB first!!!!! 26 | */ 27 | void UIntToIntelByteOrder(unsigned char bin[4],unsigned int i); 28 | void UShortToIntelByteOrder(unsigned char bin[2],unsigned short i); 29 | 30 | 31 | std::vector ReadBinaryFile(const char fn[]); 32 | std::vector ReadBinaryFile(FILE *fp); 33 | 34 | bool WriteBinaryFile(const char fn[],const std::vector &dat); 35 | bool WriteBinaryFile(FILE *fp,const std::vector &dat); 36 | 37 | std::vector ReadTextFile(const char fn[]); 38 | std::vector ReadTextFile(FILE *fp); 39 | 40 | bool WriteTextFile(const char fn[],const std::vector &text); 41 | bool WriteTextFile(FILE *fp,const std::vector &text); 42 | 43 | std::vector TextToByteArray(const std::vector &text,const char lineBreak[]); 44 | 45 | 46 | /*! Splits string with ' ' and '\t' and makes an array of arguments. 47 | */ 48 | std::vector QuickParser(const char str[]); 49 | 50 | 51 | /*! Turn small letters into capital letters. 52 | */ 53 | void Capitalize(std::string &s); 54 | 55 | 56 | /*! Convert '0' through '9' to 0 through 9 57 | 'A' through 'F' to 10 to 15 58 | 'a' through 'f' to 10 to 15 59 | */ 60 | int LetterToNum(char c); 61 | 62 | 63 | /*! Returns an extension of the file name. 64 | The returned string will include '.' if it has an extension. 65 | */ 66 | std::string GetExtension(const char fName[]); 67 | 68 | 69 | /*! Changes an extension of a file name. 70 | */ 71 | std::string ChangeExtension(const char orgFName[],const char newExt[]); 72 | 73 | 74 | 75 | /*! Removes an extension of a file name. 76 | */ 77 | std::string RemoveExtension(const char orgFName[]); 78 | 79 | 80 | 81 | /*! Returns a base name. 82 | If input is "c:\users\soji\nicefile.dat", "nicefile.dat" will be returned. 83 | */ 84 | std::string GetBaseName(const char path[]); 85 | 86 | 87 | 88 | /*! Check if the file exists. 89 | */ 90 | bool FileExist(const char fn[]); 91 | 92 | 93 | 94 | /*! Check if the string starts with the pattern. 95 | */ 96 | bool StrStartsWith(const std::string &str,const char ptn[]); 97 | 98 | 99 | 100 | /*! Skip the given pattern and return the pointer if there is a match. Or, it returns nullptr otherwise. 101 | */ 102 | const char *StrSkip(const char str[],const char ptn[]); 103 | 104 | 105 | 106 | /*! Skip space and tab and return the pointer. This function will not return nullptr. 107 | If it reaches the end of the string, it returns a pointer to an empty string. 108 | */ 109 | const char *StrSkipSpace(const char str[]); 110 | 111 | 112 | 113 | /*! Skip non-space (not space and not tab) and return the pointer. This function will not return nullptr. 114 | If it reaches the end of the string, it returns a pointer to an empty string. 115 | */ 116 | const char *StrSkipNonSpace(const char str[]); 117 | 118 | 119 | 120 | /*! Make a FM-FILE header. */ 121 | std::vector MakeFMFileHeader(const char filenameInD77[],unsigned char byte10,unsigned char byte11); 122 | 123 | 124 | 125 | /*! Create FM-FILE (0A0) format from a text. 126 | */ 127 | std::vector TextTo0A0(const std::vector &text,const char filenameInD77[]); 128 | 129 | 130 | 131 | /*! Create FM-FILE (0A0) format from a text. 132 | Text must be nullptr-terminated. 133 | */ 134 | std::vector TextTo0A0(const char * const text[],const char filenameInD77[]); 135 | 136 | 137 | 138 | /*! Create FM-FILE (2B0) format from a binary. 139 | */ 140 | std::vector BinaryTo2B0(const std::vector &dat,const char filenameInD77[],int storeAddr,int execAddr); 141 | 142 | 143 | 144 | /*! Create a image (raw data stored in the media) from a binary. 145 | */ 146 | std::vector BinaryToStoreImage(const std::vector &dat,int storeAddr,int execAddr); 147 | 148 | 149 | 150 | /*! Extract file-name part from a FM-FILE. 151 | */ 152 | std::string GetFileNameFromFMFile(const std::vector &dat); 153 | 154 | 155 | 156 | /*! Interpret raw text of hexadecimal numbers into array of unsigned chars. 157 | This function ignores spaces, tabs, and non-hexadecimal characters. 158 | */ 159 | std::vector RawHexToByteData(const std::vector &rawHexTxt); 160 | 161 | 162 | const char *BoolToStr(bool b); 163 | 164 | 165 | /*! Convert a string to a std::vector of unsigned chars. 166 | If the string starts with ' or ", it is taken as an ASCII string. 167 | Otherwise it is taken as a hexa-decimal numbers. 168 | 169 | 818A9B9C -> {0x81,0x8A,0x9B,0x9C} 170 | "ABCDEF" -> {'A','B','C','D','E','F'} 171 | */ 172 | std::vector StrToByteArray(const char str[]); 173 | 174 | 175 | } // namespace FM7Lib 176 | 177 | /* } */ 178 | #endif 179 | -------------------------------------------------------------------------------- /src/fm7lib/fm7lib.h: -------------------------------------------------------------------------------- 1 | #ifndef FM7LIB_IS_INCLUDED 2 | #define FM7LIB_IS_INCLUDED 3 | /* { */ 4 | 5 | #include 6 | #include 7 | 8 | class FM7File 9 | { 10 | public: 11 | enum 12 | { 13 | FTYPE_BASIC_BINARY, 14 | FTYPE_BASIC_ASCII, 15 | FTYPE_BINARY, 16 | FTYPE_DATA_BINARY, // I don't know if such a data type exists. This constant is for more like a reservation in the future. If the future exists!! 17 | FTYPE_DATA_ASCII, 18 | FTYPE_UNKNOWN 19 | }; 20 | 21 | std::string fName; 22 | 23 | void CleanUp(void); 24 | static int DecodeFMHeaderFileType(unsigned char byte10,unsigned char byte11); 25 | static const char *FileTypeToString(int fType); 26 | 27 | /*! Returns a default FM-File extension for file type. 28 | */ 29 | static const char *GetDefaultFMFileExtensionForType(int fType); 30 | }; 31 | 32 | class FM7BinaryFile : public FM7File 33 | { 34 | public: 35 | std::string fName; 36 | unsigned int storeAddr,execAddr; 37 | std::vector dat; 38 | 39 | FM7BinaryFile(); 40 | ~FM7BinaryFile(); 41 | void CleanUp(void); 42 | 43 | bool DecodeSREC(const std::vector &srec); 44 | bool DecodeSREC(const char *const srec[]); 45 | bool Decode2B0(const std::vector &dat,bool verbose=false); 46 | 47 | 48 | /*! Create a byte array for T77. 49 | The differencefrom a byte array for D77 is it doesn't have a 0x1A in the end. 50 | */ 51 | std::vector MakeByteArrayForT77(void) const; 52 | }; 53 | 54 | //////////////////////////////////////////////////////////// 55 | 56 | class SRECDecoder 57 | { 58 | private: 59 | unsigned char dat[65536],used[65536]; 60 | 61 | public: 62 | unsigned int storeAddr,length,execAddr; 63 | 64 | SRECDecoder(); 65 | bool Decode(const std::vector &fileDat); 66 | bool Decode(const char *const fileDat[]); 67 | std::vector data(void) const; 68 | 69 | private: 70 | bool DecodeOneLine(const char str[]); 71 | bool PostProc(void); 72 | std::vector GetByteData(const char str[]) const; 73 | }; 74 | 75 | /* } */ 76 | #endif 77 | -------------------------------------------------------------------------------- /src/main_cui/argv/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TARGET_NAME fm77avargv) 2 | add_library(${TARGET_NAME} fm77avargv.cpp fm77avargv.h) 3 | target_link_libraries(${TARGET_NAME} fm77avparam fm77avkey fm77avkeyboard d77 cpputil) 4 | target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 5 | -------------------------------------------------------------------------------- /src/main_cui/argv/fm77avargv.h: -------------------------------------------------------------------------------- 1 | #ifndef FM77AVARGV_IS_INCLUDED 2 | #define FM77AVARGV_IS_INCLUDED 3 | /* { */ 4 | 5 | #include "fm77avparam.h" 6 | 7 | class FM77AVArgv : public FM77AVParam 8 | { 9 | public: 10 | void Help(void); 11 | bool AnalyzeCommandParameter(int argc,char *argv[]); 12 | 13 | static bool DivideD77(std::string d77FName); 14 | }; 15 | 16 | /* } */ 17 | #endif 18 | -------------------------------------------------------------------------------- /src/main_cui/command/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TARGET_NAME fm77avcommand) 2 | add_library(${TARGET_NAME} fm77avcommand.cpp fm77avcommand.h fm77avlineparser.cpp fm77avlineparser.h) 3 | target_link_libraries(${TARGET_NAME} fm77av fm77avthread fm77avparam lineParser miscutil cpputil outside_world yspng) 4 | target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 5 | -------------------------------------------------------------------------------- /src/main_cui/command/fm77avlineparser.cpp: -------------------------------------------------------------------------------- 1 | #include "mc6809.h" 2 | #include "fm77avlineparser.h" 3 | #include "cpputil.h" 4 | 5 | FM77AVLineParserBase::FM77AVLineParserBase(const class MC6809 *main,const class MC6809 *sub,const class MC6809 *def) 6 | { 7 | this->mainCPU=main; 8 | this->subCPU=sub; 9 | this->defaultCPU=def; 10 | } 11 | /* virtual */ long long int FM77AVLineParserBase::EvaluateRawNumber(const std::string &str) const 12 | { 13 | auto cpu=defaultCPU; 14 | std::string cap=str; 15 | cpputil::Capitalize(cap); 16 | 17 | if("MAIN."==cap.substr(0,5)) 18 | { 19 | cpu=mainCPU; 20 | cap=cap.substr(5); 21 | } 22 | else if("M."==cap.substr(0,2)) 23 | { 24 | cpu=mainCPU; 25 | cap=cap.substr(2); 26 | } 27 | else if("SUB."==cap.substr(0,4)) 28 | { 29 | cpu=subCPU; 30 | cap=cap.substr(4); 31 | } 32 | else if("S."==cap.substr(0,2)) 33 | { 34 | cpu=subCPU; 35 | cap=cap.substr(2); 36 | } 37 | else if('\''==str[0] && 0!=str[1] && '\''==str[2]) 38 | { 39 | return int(str[1]); 40 | } 41 | 42 | auto reg=MC6809::StrToReg(cap); 43 | if(MC6809::REG_NULL!=reg) 44 | { 45 | if(nullptr!=cpu) 46 | { 47 | return cpu->GetRegisterValue(reg); 48 | } 49 | evaluationError=true; 50 | return 0; 51 | } 52 | else 53 | { 54 | return EvaluateNotARegister(str); 55 | } 56 | } 57 | long long int FM77AVLineParserBase::Evaluate(void) const 58 | { 59 | evaluationError=false; 60 | return LineParser::Evaluate(); 61 | } 62 | long long int FM77AVLineParser::EvaluateNotARegister(const std::string &str) const 63 | { 64 | return cpputil::Atoi(str.c_str()); 65 | } 66 | long long int FM77AVLineParserHexadecimal::EvaluateNotARegister(const std::string &str) const 67 | { 68 | return cpputil::Xtoi(str.c_str()); 69 | } 70 | -------------------------------------------------------------------------------- /src/main_cui/command/fm77avlineparser.h: -------------------------------------------------------------------------------- 1 | #ifndef FM77AVLINEPARSER_IS_INCLUDED 2 | #define FM77AVLINEPARSER_IS_INCLUDED 3 | /* { */ 4 | 5 | #include "lineparser.h" 6 | 7 | class FM77AVLineParserBase : public LineParser 8 | { 9 | public: 10 | mutable bool evaluationError=false; 11 | const class MC6809 *mainCPU=nullptr,*subCPU=nullptr,*defaultCPU=nullptr; 12 | 13 | FM77AVLineParserBase(const class MC6809 *main,const class MC6809 *sub,const class MC6809 *def); 14 | long long int Evaluate(void) const; 15 | virtual long long int EvaluateRawNumber(const std::string &str) const; 16 | 17 | virtual long long int EvaluateNotARegister(const std::string &str) const=0; 18 | }; 19 | 20 | class FM77AVLineParser : public FM77AVLineParserBase 21 | { 22 | public: 23 | FM77AVLineParser(const class MC6809 *main,const class MC6809 *sub,const class MC6809 *def) : FM77AVLineParserBase(main,sub,def){} 24 | long long int EvaluateNotARegister(const std::string &str) const; 25 | }; 26 | 27 | 28 | class FM77AVLineParserHexadecimal : public FM77AVLineParserBase 29 | { 30 | public: 31 | FM77AVLineParserHexadecimal(const class MC6809 *main,const class MC6809 *sub,const class MC6809 *def) : FM77AVLineParserBase(main,sub,def){} 32 | long long int EvaluateNotARegister(const std::string &str) const; 33 | }; 34 | 35 | /* } */ 36 | #endif 37 | -------------------------------------------------------------------------------- /src/main_cui/cuithread/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TARGET_NAME fm77avcuithread) 2 | add_library(${TARGET_NAME} fm77avcuithread.cpp fm77avcuithread.h) 3 | target_link_libraries(${TARGET_NAME} fm77av fm77avthread fm77avparam fm77avcommand) 4 | target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 5 | -------------------------------------------------------------------------------- /src/main_cui/cuithread/fm77avcuithread.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fm77avcuithread.h" 3 | 4 | 5 | 6 | void FM77AVCUIThread::Run(void) 7 | { 8 | std::cout << ">"; 9 | while(true!=vmTerminated && true!=cuiQuit) 10 | { 11 | std::string cmd; 12 | std::getline(std::cin,cmd); 13 | 14 | uiLock.lock(); 15 | cmdQueue.push(cmd); 16 | uiLock.unlock(); 17 | 18 | auto CMD=Interpret(cmd); 19 | if(CMD_QUIT==CMD.primaryCmd || CMD_FORCE_QUIT==CMD.primaryCmd) 20 | { 21 | break; 22 | } 23 | } 24 | } 25 | 26 | /* virtual */ void FM77AVCUIThread::ExecCommandQueue(class FM77AVThread &fm77avThread,FM77AV &fm77av,class Outside_World *outside_world) 27 | { 28 | if(true!=cmdQueue.empty()) 29 | { 30 | auto cmdStr=cmdQueue.front(); 31 | cmdQueue.pop(); 32 | auto cmd=FM77AVCommandInterpreter::Interpret(cmdStr); 33 | FM77AVCommandInterpreter::Execute(fm77avThread,fm77av,outside_world,cmd); 34 | std::cout << ">"; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main_cui/cuithread/fm77avcuithread.h: -------------------------------------------------------------------------------- 1 | #ifndef FM77AVCUITHREAD_IS_INCLUDED 2 | #define FM77AVCUITHREAD_IS_INCLUDED 3 | /* { */ 4 | 5 | #include 6 | #include "fm77avthread.h" 7 | #include "fm77avcommand.h" 8 | 9 | class FM77AVCUIThread : public FM77AVUIThread, public FM77AVCommandInterpreter 10 | { 11 | public: 12 | std::queue cmdQueue; 13 | void Run(void); 14 | virtual void ExecCommandQueue(class FM77AVThread &fm77avThread,FM77AV &fm77avPtr,class Outside_World *outside_world); 15 | }; 16 | 17 | /* } */ 18 | #endif 19 | -------------------------------------------------------------------------------- /src/main_cui/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "fm77avargv.h" 5 | #include "fm77av.h" 6 | #include "fm77avthread.h" 7 | #include "fm77avcuithread.h" 8 | #include "outside_world.h" 9 | 10 | #include "fssimplewindow_connection.h" 11 | 12 | 13 | 14 | #ifdef _WIN32 15 | #include 16 | #else 17 | static void timeBeginPeriod(int) 18 | { 19 | } 20 | static void timeEndPeriod(int) 21 | { 22 | } 23 | #endif 24 | 25 | 26 | void RunWindowThreadLoop(Outside_World::WindowInterface *window) 27 | { 28 | auto t0=std::chrono::high_resolution_clock::now(); 29 | while(true!=window->CheckVMClosed()) 30 | { 31 | window->Interval(); 32 | auto t=std::chrono::high_resolution_clock::now(); 33 | auto dt=t-t0; 34 | if(50<=std::chrono::duration_cast(dt).count() || true==window->winThr.newImageRendered) 35 | { 36 | window->Render(true); 37 | t0=t; 38 | window->winThr.newImageRendered=false; 39 | } 40 | else 41 | { 42 | timeBeginPeriod(1); 43 | std::this_thread::sleep_for(std::chrono::milliseconds(8)); 44 | timeEndPeriod(1); 45 | } 46 | } 47 | } 48 | 49 | int main(int argc,char *argv[]) 50 | { 51 | FM77AVArgv fm77avargv; 52 | if(true!=fm77avargv.AnalyzeCommandParameter(argc,argv)) 53 | { 54 | return 1; 55 | } 56 | 57 | std::cout << "FM7/77AV Emulator Mutsu" << std::endl; 58 | std::cout << "by CaptainYS" << std::endl; 59 | std::cout << "http://www.ysflight.com" << std::endl; 60 | 61 | std::unique_ptr fm77av(new FM77AV); 62 | std::unique_ptr outside_world(new FsSimpleWindowConnection); 63 | auto window=outside_world->CreateWindowInterface(); 64 | 65 | if(true!=fm77av->SetUp(fm77avargv,outside_world.get(),window)) 66 | { 67 | return 1; 68 | } 69 | 70 | static FM77AVThread vm; 71 | if(true==fm77avargv.pauseOnStart) 72 | { 73 | vm.SetRunMode(FM77AVThread::RUNMODE_PAUSE); 74 | } 75 | 76 | window->Start(); 77 | window->ClearVMClosedFlag(); 78 | 79 | if(true!=fm77avargv.unitTest) 80 | { 81 | FM77AVCUIThread cui; 82 | std::thread cuiThread(&FM77AVCUIThread::Run,&cui); 83 | auto sound=outside_world->CreateSound(); 84 | std::thread vmThread([&] 85 | { 86 | window->ClearVMClosedFlag(); 87 | vm.VMStart(fm77av.get(),outside_world.get(),window,&cui); 88 | vm.VMMainLoop(fm77av.get(),outside_world.get(),window,sound,&cui); 89 | vm.VMEnd(fm77av.get(),outside_world.get(),window,&cui); 90 | }); 91 | 92 | RunWindowThreadLoop(window); 93 | 94 | vmThread.join(); 95 | cuiThread.join(); 96 | 97 | window->Stop(); 98 | 99 | outside_world->DeleteSound(sound); 100 | outside_world->DeleteWindowInterface(window); 101 | } 102 | else 103 | { 104 | FM77AVUIThread noUI; 105 | auto sound=outside_world->CreateSound(); 106 | std::thread vmThread([&] 107 | { 108 | window->ClearVMClosedFlag(); 109 | vm.VMStart(fm77av.get(),outside_world.get(),window,&noUI); 110 | vm.VMMainLoop(fm77av.get(),outside_world.get(),window,sound,&noUI); 111 | vm.VMEnd(fm77av.get(),outside_world.get(),window,&noUI); 112 | }); 113 | 114 | RunWindowThreadLoop(window); 115 | 116 | vmThread.join(); 117 | 118 | window->Stop(); 119 | 120 | outside_world->DeleteSound(sound); 121 | outside_world->DeleteWindowInterface(window); 122 | 123 | return fm77av->TestSuccess(); 124 | } 125 | 126 | return 0; 127 | } 128 | -------------------------------------------------------------------------------- /src/mc6809/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TARGET_NAME mc6809) 2 | add_library(${TARGET_NAME} mc6809.h mc6809.cpp mc6809debugger.cpp mc6809symtable.h mc6809symtable.cpp) 3 | target_link_libraries(${TARGET_NAME} memory cpputil) 4 | target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 5 | -------------------------------------------------------------------------------- /src/mc6809/mc6809symtable.h: -------------------------------------------------------------------------------- 1 | #ifndef MC6809SYMTABLE_IS_INCLUDED 2 | #define MC6809SYMTABLE_IS_INCLUDED 3 | /* { */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class MC6809Symbol 11 | { 12 | public: 13 | enum 14 | { 15 | SYM_ANY, 16 | SYM_PROCEDURE, 17 | SYM_JUMP_DESTINATION, 18 | SYM_DATA_LABEL, 19 | SYM_RAW_DATA, // If disassembler hits this address, it just reads rawDataCount bytes and don't disassemble. 20 | SYM_TABLE_WORD, 21 | SYM_DP=255 22 | }; 23 | 24 | bool temporary=false; // If true, it will not be saved to file. 25 | bool immIsIOAddr=false; // If true, disassembler should take Imm operand as an IO-port address. 26 | bool immIsSymbol=false; // Take imm as a symbol. 27 | bool immIsASCII=false; // Take imm as ASCII code. 28 | bool offsetIsSymbol=false; // Take offset as a symbol. 29 | unsigned int symType; 30 | std::string return_type; 31 | std::string label; 32 | std::string inLineComment; 33 | std::string param; 34 | std::string imported; // Imported from .LST file. 35 | std::vector info; 36 | unsigned int rawDataBytes; 37 | 38 | MC6809Symbol(); 39 | void CleanUp(void); 40 | std::string Format(bool returnType=false,bool label=true,bool param=true) const; 41 | }; 42 | 43 | class MC6809SymbolTable 44 | { 45 | private: 46 | std::map symTable; 47 | std::map DPLabel; 48 | std::map IOLabel; 49 | public: 50 | std::map OS9Functions,OS9FunctionExplanation; 51 | 52 | MC6809SymbolTable(); 53 | void MakeOS9FunctionTable(void); 54 | 55 | bool Load(const std::vector &txt); 56 | std::vector Save(void) const; 57 | 58 | const MC6809Symbol *Find(unsigned int ptr) const; 59 | MC6809Symbol *Update(unsigned int ptr,const std::string &label); 60 | MC6809Symbol *SetComment(unsigned int ptr,const std::string &inLineComment); 61 | MC6809Symbol *SetImmIsIOPort(unsigned int ptr); 62 | MC6809Symbol *SetImportedLabel(unsigned int ptr,const std::string &label); 63 | MC6809Symbol *SetImmIsSymbol(unsigned int ptr); 64 | MC6809Symbol *SetImmIsASCII(unsigned int ptr); 65 | MC6809Symbol *SetOffsetIsSymbol(unsigned int ptr); 66 | 67 | void SetDPLabel(unsigned int DP,std::string label); 68 | std::string GetDPLabel(unsigned int DP) const; 69 | 70 | 71 | /*! Disassembler should take IMM operand at the given address as an IO-port address. 72 | */ 73 | MC6809Symbol *SetImmIsIO(unsigned int addr); 74 | 75 | bool Delete(unsigned int addr); 76 | bool DeleteComment(unsigned int addr); 77 | const std::map &GetTable(void) const; 78 | 79 | /*! Returns the number of bytes if the address is marked as byte data, otherwize returns zero. 80 | */ 81 | unsigned int GetRawDataBytes(unsigned int addr) const; 82 | 83 | /*! Print if a symbol is defined for the SEG:OFFSET 84 | */ 85 | void PrintIfAny(unsigned int addr,bool returnType=false,bool label=true,bool param=true) const; 86 | 87 | /*! This function does exhaustive search. 88 | */ 89 | std::pair FindSymbolFromLabel(const std::string &label) const; 90 | 91 | std::vector GetList(bool returnType=false,bool label=true,bool param=true) const; 92 | 93 | /*! 94 | */ 95 | std::string FormatImmLabel(unsigned int PC,unsigned int imm) const; 96 | 97 | /*! 98 | */ 99 | std::string FormatDataLabel(unsigned int PC,unsigned int imm) const; 100 | }; 101 | 102 | 103 | /* } */ 104 | #endif 105 | -------------------------------------------------------------------------------- /src/mc6809util/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TARGET_NAME mc6809util) 2 | add_library(${TARGET_NAME} mc6809util.h mc6809util.cpp) 3 | target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 4 | -------------------------------------------------------------------------------- /src/mc6809util/mc6809util.cpp: -------------------------------------------------------------------------------- 1 | #include "mc6809util.h" 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/mc6809util/mc6809util.h: -------------------------------------------------------------------------------- 1 | #ifndef MC6809UTIL_IS_INCLUDED 2 | #define MC6809UTIL_IS_INCLUDED 3 | /* { */ 4 | 5 | #include 6 | 7 | namespace mc6809util 8 | { 9 | inline uint16_t FetchWord(uint8_t *ptr) 10 | { 11 | return (ptr[0]<<8)|ptr[1]; 12 | } 13 | inline uint16_t FetchWord(uint8_t firstByte,uint8_t secondByte) 14 | { 15 | return (firstByte<<8)|secondByte; 16 | } 17 | inline void StoreWord(uint8_t *ptr,uint16_t data) 18 | { 19 | ptr[0]=(data>>8); 20 | ptr[1]=(data&0xFF); 21 | } 22 | inline void StoreWordSigned(uint8_t *ptr,int16_t data) 23 | { 24 | ptr[0]=(data>>8); 25 | ptr[1]=(data&0xFF); 26 | } 27 | inline void StoreWord(uint8_t &firstBytePtr,uint8_t &secondBytePtr,uint16_t data) 28 | { 29 | firstBytePtr=(data>>8); 30 | secondBytePtr=(data&0xFF); 31 | } 32 | 33 | }; 34 | 35 | /* } */ 36 | #endif 37 | -------------------------------------------------------------------------------- /src/memory/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(memory memory.h memory.cpp) 2 | target_link_libraries(memory fm77av device mc6809util) 3 | target_include_directories(memory PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 4 | 5 | 6 | 7 | add_library(fm77avmemory fm77avmemory.h fm77avmemory.cpp) 8 | target_link_libraries(fm77avmemory memory) 9 | target_include_directories(fm77avmemory PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 10 | 11 | 12 | 13 | add_library(plainmemory plainmemory.h plainmemory.cpp) 14 | target_link_libraries(plainmemory memory) 15 | target_include_directories(plainmemory PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 16 | -------------------------------------------------------------------------------- /src/memory/memory.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "memory.h" 5 | #include "mc6809util.h" 6 | #include "fm77av.h" 7 | #include "cpputil.h" 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/memory/memory.h: -------------------------------------------------------------------------------- 1 | #ifndef MEMORY_IS_INCLUDED 2 | #define MEMORY_IS_INCLUDED 3 | /* { */ 4 | 5 | #include 6 | #include "device.h" 7 | 8 | 9 | 10 | class CanAccessMemory 11 | { 12 | }; 13 | 14 | class MemoryAccess 15 | { 16 | public: 17 | // OK, OK. Now things got much more clear. Thank you, Mr. Apollo for the information. 18 | // MC6809 data sheet has a flow-chart for every instruction, and PSHS,PSHU,PULS, and PULU, 19 | // does dummy-read a byte. So, not just addressing. 20 | 21 | // Also, CLR instruction is in the same path as INC, NEG, COM, etc. So, even though 22 | // CLR always writes a value zero, it does dummy read, and it takes 2 clocks after dummy 23 | // read til zero is written. 24 | 25 | // A FM-7 masterpiece MAGUS was doing CLR $D40A to clear BUSY flag. It is a bug, 26 | // and it is most likely unintentional. It does not vindicate MAGUS. However, 27 | // now we know why the main-CPU thought the sub-CPU was ready. 28 | 29 | virtual void CLR(uint16_t addr){}; // Special treatment for CLR. 30 | 31 | virtual uint8_t FetchByte(const CanAccessMemory *accessFrom,uint16_t addr)=0; 32 | virtual uint16_t FetchWord(const CanAccessMemory *accessFrom,uint16_t addr)=0; 33 | virtual void StoreByte(const CanAccessMemory *accessFrom,uint16_t addr,uint8_t data)=0; 34 | virtual void StoreWord(const CanAccessMemory *accessFrom,uint16_t addr,uint16_t data)=0; 35 | 36 | // What are these? 37 | // 6809 uses memory-mapped I/O. Memory-Read may change the device status. 38 | // Fetching a byte for debugging purpose like memory dump or disassembly 39 | // shouldn't change the device status. For those purposes, non-destructive 40 | // fetch is necessary. 41 | virtual uint8_t NonDestructiveFetchByte(uint16_t addr) const=0; 42 | virtual uint16_t NonDestructiveFetchWord(uint16_t addr) const=0; 43 | }; 44 | 45 | /* } */ 46 | #endif 47 | -------------------------------------------------------------------------------- /src/memory/plainmemory.cpp: -------------------------------------------------------------------------------- 1 | #include "plainmemory.h" 2 | 3 | PlainMemoryAccess::PlainMemoryAccess() 4 | { 5 | for(auto &d : RAM) 6 | { 7 | d=0; 8 | } 9 | } 10 | /* virtual */ uint8_t PlainMemoryAccess::FetchByte(const CanAccessMemory *,uint16_t addr) 11 | { 12 | return RAM[addr]; 13 | } 14 | /* virtual */ uint16_t PlainMemoryAccess::FetchWord(const CanAccessMemory *,uint16_t addr) 15 | { 16 | return (RAM[addr]<<8)|RAM[addr+1]; 17 | } 18 | /* virtual */ void PlainMemoryAccess::StoreByte(const CanAccessMemory *,uint16_t addr,uint8_t data) 19 | { 20 | RAM[addr]=data; 21 | } 22 | /* virtual */ void PlainMemoryAccess::StoreWord(const CanAccessMemory *,uint16_t addr,uint16_t data) 23 | { 24 | RAM[addr]=(data>>8); 25 | RAM[addr+1]=(data&0xFF); 26 | } 27 | /* virtual */ uint8_t PlainMemoryAccess::NonDestructiveFetchByte(uint16_t addr) const 28 | { 29 | return RAM[addr]; 30 | } 31 | /* virtual */ uint16_t PlainMemoryAccess::NonDestructiveFetchWord(uint16_t addr) const 32 | { 33 | return (RAM[addr]<<8)|RAM[addr+1]; 34 | } 35 | -------------------------------------------------------------------------------- /src/memory/plainmemory.h: -------------------------------------------------------------------------------- 1 | #ifndef PLAINMEMORY_IS_INCLUDED 2 | #define PLAINMEMORY_IS_INCLUDED 3 | /* { */ 4 | 5 | #include 6 | #include "memory.h" 7 | 8 | class PlainMemoryAccess : public MemoryAccess 9 | { 10 | public: 11 | uint8_t RAM[64*1024]; 12 | 13 | PlainMemoryAccess(); 14 | virtual uint8_t FetchByte(const CanAccessMemory *accessFrom,uint16_t addr) override; 15 | virtual uint16_t FetchWord(const CanAccessMemory *accessFrom,uint16_t addr) override; 16 | virtual void StoreByte(const CanAccessMemory *accessFrom,uint16_t addr,uint8_t data) override; 17 | virtual void StoreWord(const CanAccessMemory *accessFrom,uint16_t addr,uint16_t data) override; 18 | virtual uint8_t NonDestructiveFetchByte(uint16_t addr) const override; 19 | virtual uint16_t NonDestructiveFetchWord(uint16_t addr) const override; 20 | }; 21 | 22 | /* } */ 23 | #endif 24 | -------------------------------------------------------------------------------- /src/miscutil/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(miscutil miscutil.cpp miscutil.h) 2 | target_link_libraries(miscutil mc6809 memory) 3 | target_include_directories(cpputil PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 4 | -------------------------------------------------------------------------------- /src/miscutil/miscutil.h: -------------------------------------------------------------------------------- 1 | /* LICENSE>> 2 | Copyright 2020 Soji Yamakawa (CaptainYS, http://www.ysflight.com) 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. Redistributions in binary form 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. 9 | 10 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | 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 HOLDER 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. 13 | 14 | << LICENSE */ 15 | #ifndef MISCUTIL_IS_INCLUDED 16 | #define MISCUTIL_IS_INCLUDED 17 | /* { */ 18 | 19 | #include 20 | #include 21 | 22 | #include "mc6809.h" 23 | #include "memory.h" 24 | 25 | namespace miscutil 26 | { 27 | /*! data must be at least wid*hei bytes long. */ 28 | std::vector MakeDump(const unsigned char data[],unsigned int STARTADDR,int wid,int hei,int skip,bool shiftJIS,bool includeASCII); 29 | std::vector MakeMemDump(const MC6809 &cpu,const MemoryAccess &mem,uint32_t addr,unsigned int length,bool shiftJIS); 30 | std::vector MakeMemDump2(const MC6809 &cpu,const MemoryAccess &mem,uint32_t addr,int wid,int hei,int skip,bool shiftJIS,bool includeASCII); 31 | 32 | unsigned char GetByte(const MC6809 &cpu,const MemoryAccess &mem,uint32_t addr); 33 | }; 34 | 35 | /* } */ 36 | #endif 37 | -------------------------------------------------------------------------------- /src/outside_world/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(outside_world outside_world.h outside_world.cpp icons.h icons.cpp) 2 | target_include_directories(outside_world PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 3 | target_link_libraries(outside_world fm77av fm77avdef fm77avparam fm77avrender) 4 | -------------------------------------------------------------------------------- /src/outside_world/icons.h: -------------------------------------------------------------------------------- 1 | extern const unsigned char FD_BUSY[]; 2 | extern const unsigned char FD_IDLE[]; 3 | extern const unsigned char TAPE_IDLE[]; 4 | extern const unsigned char TAPE_LOADING[]; 5 | extern const unsigned char TAPE_SAVING[]; 6 | extern const int MENU_wid; 7 | extern const int MENU_hei; 8 | extern const unsigned char MENU[]; 9 | extern const int PAUSE_wid; 10 | extern const int PAUSE_hei; 11 | extern const unsigned char PAUSE[]; 12 | extern const int CAPS_wid; 13 | extern const int CAPS_hei; 14 | extern const unsigned char CAPS[]; 15 | extern const int KANA_wid; 16 | extern const int KANA_hei; 17 | extern const unsigned char KANA[]; 18 | extern const int INS_wid; 19 | extern const int INS_hei; 20 | extern const unsigned char INS[]; 21 | -------------------------------------------------------------------------------- /src/resources/CAPS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainys/77AVEMU/b5e69050ba4e5fd5c98fe93820fc1588b5bd65b5/src/resources/CAPS.png -------------------------------------------------------------------------------- /src/resources/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TARGET_NAME png2cpp) 2 | add_executable(${TARGET_NAME} png2cpp.cpp) 3 | target_link_libraries(${TARGET_NAME} yspng cpputil) 4 | 5 | 6 | set(ICON_SOURCES 7 | ../outside_world/icons.h 8 | ../outside_world/icons.cpp 9 | ) 10 | 11 | set(PNGS 12 | FD_BUSY.png 13 | FD_IDLE.png 14 | INS.png 15 | KANA.png 16 | MENU.png 17 | PAUSE.png 18 | TAPE_IDLE.png 19 | TAPE_LOADING.png 20 | TAPE_SAVING.png 21 | ) 22 | 23 | add_custom_command( 24 | OUTPUT ${ICON_SOURCES} 25 | DEPENDS ${PNGS} 26 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 27 | COMMAND echo ${YS_COMMAND_BINARY_DIR}/png2cpp 28 | COMMAND ${TARGET_NAME} 29 | ) 30 | 31 | add_custom_target(ICONS DEPENDS ${ICON_SOURCES}) 32 | -------------------------------------------------------------------------------- /src/resources/FD_BUSY.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainys/77AVEMU/b5e69050ba4e5fd5c98fe93820fc1588b5bd65b5/src/resources/FD_BUSY.png -------------------------------------------------------------------------------- /src/resources/FD_IDLE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainys/77AVEMU/b5e69050ba4e5fd5c98fe93820fc1588b5bd65b5/src/resources/FD_IDLE.png -------------------------------------------------------------------------------- /src/resources/INS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainys/77AVEMU/b5e69050ba4e5fd5c98fe93820fc1588b5bd65b5/src/resources/INS.png -------------------------------------------------------------------------------- /src/resources/KANA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainys/77AVEMU/b5e69050ba4e5fd5c98fe93820fc1588b5bd65b5/src/resources/KANA.png -------------------------------------------------------------------------------- /src/resources/MENU.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainys/77AVEMU/b5e69050ba4e5fd5c98fe93820fc1588b5bd65b5/src/resources/MENU.png -------------------------------------------------------------------------------- /src/resources/PAUSE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainys/77AVEMU/b5e69050ba4e5fd5c98fe93820fc1588b5bd65b5/src/resources/PAUSE.png -------------------------------------------------------------------------------- /src/resources/TAPE_IDLE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainys/77AVEMU/b5e69050ba4e5fd5c98fe93820fc1588b5bd65b5/src/resources/TAPE_IDLE.png -------------------------------------------------------------------------------- /src/resources/TAPE_LOADING.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainys/77AVEMU/b5e69050ba4e5fd5c98fe93820fc1588b5bd65b5/src/resources/TAPE_LOADING.png -------------------------------------------------------------------------------- /src/resources/TAPE_SAVING.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captainys/77AVEMU/b5e69050ba4e5fd5c98fe93820fc1588b5bd65b5/src/resources/TAPE_SAVING.png -------------------------------------------------------------------------------- /src/resources/png2cpp.cpp: -------------------------------------------------------------------------------- 1 | #include "yspng.h" 2 | #include "cpputil.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // 16x16 icons to C++ source. 9 | 10 | std::string files[]= 11 | { 12 | "FD_BUSY", 13 | "FD_IDLE", 14 | "TAPE_IDLE", 15 | "TAPE_LOADING", 16 | "TAPE_SAVING", 17 | }; 18 | 19 | std::string nonSquareFiles[]= 20 | { 21 | "MENU", 22 | "PAUSE", 23 | "CAPS", 24 | "KANA", 25 | "INS", 26 | }; 27 | 28 | int main(void) 29 | { 30 | // Check all of them are 16x16 31 | for(auto fName : files) 32 | { 33 | fName+=".png"; 34 | std::cout << "Checking:"< 6 | #include 7 | #include 8 | 9 | #include "fm7lib.h" 10 | 11 | class T77File 12 | { 13 | public: 14 | std::vector t77; 15 | 16 | void CleanUp(void); 17 | 18 | /*! Read binary data of the existing .T77 file and give to this function. 19 | This function cleans the data, and then copies (or moves) dat to its own array. 20 | */ 21 | void DumpT77(const std::vector &dat); 22 | void DumpT77(std::vector &&dat); 23 | 24 | /*! Appends a T77 file. This function ignoures first 20 ($14) bytes of the 25 | incoming data and appends the rest to what's currently stored. 26 | */ 27 | void AppendT77(const std::vector &dat); 28 | 29 | class WAVOutOption 30 | { 31 | public: 32 | unsigned int Hz; 33 | unsigned int levelLow,levelHigh; 34 | unsigned int firstSilence; // In Milliseconds 35 | unsigned int silenceAfterFile; // In Milliseconds 36 | 37 | WAVOutOption(); 38 | }; 39 | protected: 40 | class WAVOutDataBuffer 41 | { 42 | public: 43 | FILE *fp; 44 | long long int totalLength; 45 | long long int bufUsed; 46 | std::vector buf; 47 | WAVOutDataBuffer(); 48 | void CleanUp(void); 49 | bool Pump(unsigned char dat); 50 | void Rewind(void); 51 | bool Flush(void); 52 | }; 53 | 54 | public: 55 | /*! This function writes .WAV file of this T77 format data. 56 | */ 57 | bool WriteWav(const char fName[],const WAVOutOption &opt) const; 58 | bool WriteWav(FILE *fp,const WAVOutOption &opt) const; 59 | protected: 60 | /*! Writes data to the file stream. If fp==nullptr, it just counts number of bytes. 61 | */ 62 | long long int WriteData(WAVOutDataBuffer &dataBuf,long long int &ptr,const WAVOutOption &opt) const; 63 | 64 | long long int CalculateNumSampleForMillisecond(long long int milliSec,const WAVOutOption &opt) const; 65 | }; 66 | 67 | class T77Encoder : public T77File 68 | { 69 | public: 70 | bool debug_makeIntentionalCheckSumError_headerBlock; 71 | bool debug_makeIntentionalCheckSumError_dataBlock; 72 | bool debug_mixNonFFinDataGap; 73 | 74 | T77Encoder(); 75 | ~T77Encoder(); 76 | void CleanUp(void); 77 | 78 | unsigned char CalculateCheckSum(const std::vector &blk); 79 | std::vector MakeHeaderBlock(const char t77fName[],int fType); 80 | std::vector MakeDataBlock(const std::vector &dat,long long int ptr,long long int nByte); 81 | std::vector MakeTerminalBlock(void); 82 | void StartT77Header(void); 83 | void AddBit(unsigned int bitData); 84 | void AddByte(unsigned char byteData); 85 | void AddGapBetweenFile(void); 86 | 87 | bool Encode(int fType,const char t77fName[],const std::vector &dat); 88 | bool Encode(int fType,const char t77fName[],const FM7BinaryFile &dat); 89 | bool EncodeFromFMFile(const char t77fName[],const std::vector &dat); 90 | }; 91 | 92 | class T77Decoder : public T77File 93 | { 94 | public: 95 | unsigned int OneZeroThr; 96 | // By default, 0x1A+0x1A=0x34 (Off bit), 0x30+0x30=0x60 (On bit). 97 | // To take in the middle, it should be somewhere like 0x48. 98 | std::vector filePtr; // Index to T77File::t77. 99 | std::vector > fileDump; 100 | 101 | public: 102 | T77Decoder(); 103 | 104 | long long int SkipLead(long long int ptr) const; 105 | int GetBit(long long int &ptr) const; 106 | bool FindFirstFFFFFF(long long int &ptr) const; 107 | bool Decode(void); 108 | 109 | 110 | 111 | class RawDecodingInfo 112 | { 113 | public: 114 | bool endOfFile; 115 | long long int ptr; 116 | long long int byteCtr; 117 | int byteData; 118 | }; 119 | RawDecodingInfo BeginRawDecoding(void) const; 120 | RawDecodingInfo RawReadByte(RawDecodingInfo info) const; 121 | 122 | 123 | static long long int GetHeaderBlockPointer(const std::vector &dump); 124 | static std::string GetDumpFileName(const std::vector &dump); 125 | static std::vector DumpToFMFormat(const std::vector &dump); 126 | }; 127 | 128 | /* } */ 129 | #endif 130 | -------------------------------------------------------------------------------- /src/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(test_disasm disasmtest.cpp) 2 | target_link_libraries(test_disasm mc6809 plainmemory cpputil) 3 | add_test(NAME 6809disasm COMMAND test_disasm) 4 | 5 | add_executable(test_division divisiontest.cpp) 6 | target_link_libraries(test_division mc6809 plainmemory cpputil) 7 | add_test(NAME 6809division COMMAND test_division) 8 | 9 | add_executable(test_adc_daa adc_daa.cpp) 10 | target_link_libraries(test_adc_daa mc6809 plainmemory cpputil) 11 | add_test(NAME 6809adc_daa COMMAND test_adc_daa) 12 | 13 | add_executable(test_memeval memeval.cpp) 14 | target_link_libraries(test_memeval fm77av cpputil) 15 | add_test(NAME test_memeval COMMAND test_memeval) 16 | 17 | if(APPLE) 18 | # Objective-C sucks. 19 | set_property(TARGET test_memeval APPEND_STRING PROPERTY COMPILE_FLAGS "-fobjc-arc") 20 | set_property(TARGET test_memeval APPEND_STRING PROPERTY LINK_FLAGS "-lobjc") 21 | endif() 22 | -------------------------------------------------------------------------------- /src/tests/adc_daa.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "mc6809.h" 4 | #include "mc6809util.h" 5 | #include "plainmemory.h" 6 | 7 | //0000 CC0766 LDD #$0766 8 | //0003 1E89 EXG A,B 9 | //0005 8B99 ADDA #$99 10 | //0007 19 DAA 11 | //0008 1E89 EXG A,B 12 | //000A 8999 ADCA #$99 13 | //000C 19 DAA 14 | //000D 39 RTS 15 | 16 | std::string code= 17 | "CC0766" 18 | "1E89" 19 | "8B99" 20 | "19" 21 | "1E89" 22 | "8999" 23 | "19" 24 | "39" 25 | ; 26 | 27 | 28 | 29 | class TestVM : public VMBase 30 | { 31 | public: 32 | virtual const char *DeviceName(void) const{return "TestVM";} 33 | }; 34 | 35 | // From Polar Star III. By adding $99999999 to BCD, it can essentially subtract 1. Same as adding $FFFF to subtract one. 36 | bool DAA(int bcd1,int bcd2,bool verbose) 37 | { 38 | TestVM vm; 39 | static MC6809 cpu(&vm); 40 | PlainMemoryAccess mem; 41 | 42 | cpu.Reset(); 43 | 44 | unsigned int addr=0x2000; 45 | for(int i=0; i>8); 58 | mem.RAM[0x2002]=(bcdToHex&0xFF); 59 | 60 | bcdToHex=((bcd2/1000)%10)*0x1000+ 61 | ((bcd2/100)%10) *0x100+ 62 | ((bcd2/10)%10) *0x10+ 63 | (bcd2%10); 64 | mem.RAM[0x2006]=(bcdToHex&0xFF); 65 | mem.RAM[0x200B]=(bcdToHex>>8); 66 | 67 | cpu.state.PC=0x2000; 68 | mem.RAM[0]=0; 69 | while(0==mem.RAM[0] && true!=vm.CheckAbort()) 70 | { 71 | auto inst=cpu.FetchInstruction(mem,cpu.state.PC); 72 | 73 | if(true==verbose) 74 | { 75 | for(auto str : cpu.GetStatusText()) 76 | { 77 | std::cout << str << std::endl; 78 | } 79 | 80 | auto byteCode=cpu.FormatByteCode(inst); 81 | while(byteCode.size()<11) 82 | { 83 | byteCode.push_back(' '); 84 | } 85 | 86 | auto disasm=cpu.Disassemble(inst,cpu.state.PC); 87 | std::cout << cpputil::Ustox(cpu.state.PC) << " " << byteCode << " " << disasm << std::endl; 88 | } 89 | 90 | if(cpu.state.PC==0x200D) 91 | { 92 | break; 93 | } 94 | 95 | cpu.RunOneInstruction(mem); 96 | } 97 | 98 | auto sum=(bcd1+bcd2)%10000; 99 | bcdToHex=((sum/1000)%10)*0x1000+ 100 | ((sum/100)%10) *0x100+ 101 | ((sum/10)%10) *0x10+ 102 | (sum%10); 103 | unsigned int D=cpu.state.A(); 104 | D<<=8; 105 | D|=cpu.state.B(); 106 | 107 | if(D!=bcdToHex) 108 | { 109 | return 1; 110 | } 111 | 112 | return 0; 113 | } 114 | 115 | int main(void) 116 | { 117 | for(int i=1; i<9999; ++i) 118 | { 119 | if(0!=DAA(i,9999,false)) 120 | { 121 | printf("Failed at %d\n",i); 122 | return 1; 123 | } 124 | } 125 | for(int i=0; i<=1000; ++i) 126 | { 127 | for(int j=0; j<=1000; ++j) 128 | { 129 | if(0!=DAA(i,j,false)) 130 | { 131 | printf("Failed at %d+%d\n",i,j); 132 | } 133 | } 134 | } 135 | std::cout << "All Passes." << std::endl; 136 | return 0; 137 | } 138 | -------------------------------------------------------------------------------- /src/tests/disasmtest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "mc6809.h" 4 | #include "plainmemory.h" 5 | 6 | // 2000 ORG $2000 7 | // 2000 8677 LDA #$77 8 | // 2002 C611 LDB #$11 9 | // 2004 CC1973 LDD #$1973 10 | // 2007 A58D0FF5 BITA $3000,PCR 11 | // 200B A886 EORA A,X 12 | // 200D A4A5 ANDA B,Y 13 | // 200F A7CB STA D,U 14 | // 2011 A680 LDA ,X+ 15 | // 2013 E6A1 LDB ,Y++ 16 | // 2015 A7C2 STA ,-U 17 | // 2017 AFC3 STX ,--U 18 | // 2019 AD9FFBFA JSR [$FBFA] 19 | // 201D 6E96 JMP [A,X] 20 | // 201F 3476 PSHS A,B,X,Y,U 21 | // 2021 3589 PULS CC,DP,PC 22 | // 2023 3652 PSHU A,X,S 23 | // 2025 35C8 PULS DP,U,PC 24 | // 2027 B7FD0F STA $FD0F 25 | // 202A 1E89 EXG A,B 26 | // 202C 1F01 TFR D,X 27 | // 202E 1E83 EXG A,U 28 | // 2030 1F40 TFR S,D 29 | // 2032 10AE9D1FC9 LDY [$4000,PCR] 30 | 31 | std::string code= 32 | "8677" 33 | "C611" 34 | "CC1973" 35 | "A58D0FF5" 36 | "A886" 37 | "A4A5" 38 | "A7CB" 39 | "A680" 40 | "E6A1" 41 | "A7C2" 42 | "AFC3" 43 | "AD9FFBFA" 44 | "6E96" 45 | "3476" 46 | "3589" 47 | "3652" 48 | "35C8" 49 | "B7FD0F" 50 | "1E89" 51 | "1F01" 52 | "1E83" 53 | "1F40" 54 | "10AE9D1FC9" 55 | ; 56 | 57 | std::string correctOutput[]= 58 | { 59 | "LDA #$77", 60 | "LDB #$11", 61 | "LDD #$1973", 62 | "BITA $3000,PCR", 63 | "EORA A,X", 64 | "ANDA B,Y", 65 | "STA D,U", 66 | "LDA ,X+", 67 | "LDB ,Y++", 68 | "STA ,-U", 69 | "STX ,--U", 70 | "JSR [$FBFA]", 71 | "JMP [A,X]", 72 | "PSHS A,B,X,Y,U", 73 | "PULS CC,DP,PC", 74 | "PSHU A,X,S", 75 | "PULS DP,U,PC", 76 | "STA $FD0F", 77 | "EXG A,B", 78 | "TFR D,X", 79 | "EXG A,U", 80 | "TFR S,D", 81 | "LDY [$4000,PCR]", 82 | "", 83 | "", 84 | "", 85 | "", 86 | "", 87 | "", 88 | "", 89 | "", 90 | "", 91 | "", 92 | "", 93 | }; 94 | 95 | 96 | 97 | class TestVM : public VMBase 98 | { 99 | public: 100 | virtual const char *DeviceName(void) const{return "TestVM";} 101 | }; 102 | 103 | int main(void) 104 | { 105 | static TestVM vm; 106 | static MC6809 cpu(&vm); // Debugger takes up stack. Make it static. 107 | static PlainMemoryAccess mem; 108 | 109 | unsigned int addr=0x2000; 110 | for(int i=0; i 2 | #include 3 | #include "mc6809.h" 4 | #include "mc6809util.h" 5 | #include "plainmemory.h" 6 | 7 | std::string code= 8 | "10CE6000" 9 | "CC1388" // 2004 CC1388 LDD #5000 10 | "ED8C16" 11 | "CC0032" // 200A CC0032 LDD #50 12 | "ED8C12" 13 | "8D12" 14 | "AE8C0D" 15 | "10AE8C07" 16 | 17 | "86FF" 18 | "B70000" 19 | 20 | "20FE" 21 | 22 | "0000" 23 | "0000" 24 | 25 | "3456" 26 | 27 | "EC8CF7" 28 | "A78C7E" 29 | "2A08" 30 | "43" 31 | "53" 32 | "C30001" 33 | "ED8CEA" 34 | 35 | "EC8CE9" 36 | "A78C6F" 37 | "2A08" 38 | "43" 39 | "53" 40 | "C30001" 41 | "ED8CDC" 42 | 43 | "8E0001" 44 | "AF8C26" 45 | "8E0000" 46 | 47 | "10A38CCD" 48 | "240F" 49 | "58" 50 | "49" 51 | "2B0B" 52 | 53 | "ED8CC6" 54 | "688C14" 55 | "698C10" 56 | "2AEB" 57 | 58 | "EC8CB9" 59 | "10A38CB7" 60 | "2507" 61 | 62 | "A38CB2" 63 | "30897FFF" 64 | 65 | "648CAB" 66 | "668CA9" 67 | 68 | "648CF5" 69 | "668CF3" 70 | "24E5" 71 | 72 | "AF8C9D" 73 | "ED8C98" 74 | "CC0000" 75 | 76 | "6D8C1C" 77 | "2A08" 78 | 79 | "A38C8D" 80 | "ED8C8A" 81 | 82 | "86FF" 83 | 84 | "A88C10" 85 | "2A0B" 86 | 87 | "CC0000" 88 | "A38DFF7E" 89 | "ED8DFF7A" 90 | 91 | "35D6" 92 | "0000" 93 | ; 94 | 95 | 96 | 97 | class TestVM : public VMBase 98 | { 99 | public: 100 | virtual const char *DeviceName(void) const{return "TestVM";} 101 | }; 102 | 103 | bool Divide(int numer,int denom,bool verbose) 104 | { 105 | TestVM vm; 106 | static MC6809 cpu(&vm); 107 | PlainMemoryAccess mem; 108 | 109 | cpu.Reset(); 110 | 111 | unsigned int addr=0x2000; 112 | for(int i=0; i 2 | #include "fm77av.h" 3 | #include "cpputil.h" 4 | 5 | bool Verify(FM77AV::MemoryEvaluation &eval,unsigned int shouldBe,std::string str) 6 | { 7 | eval.Decode(str); 8 | 9 | std::cout << "Testing " << str << std::endl; 10 | 11 | if(true==eval.error) 12 | { 13 | std::cout << "Error before evaluation." << std::endl; 14 | std::cout << eval.errorMessage << std::endl; 15 | return 1; 16 | } 17 | 18 | unsigned int value=eval.Evaluate(); 19 | if(true==eval.error) 20 | { 21 | std::cout << "Error after evaluation." << std::endl; 22 | std::cout << eval.errorMessage << std::endl; 23 | return 1; 24 | } 25 | 26 | std::cout << "Evaluated:" << cpputil::Itox(value) << std::endl; 27 | std::cout << "Should be:" << cpputil::Itox(shouldBe) << std::endl; 28 | if(shouldBe!=value) 29 | { 30 | std::cout << "Error!" << std::endl; 31 | eval.Print(); 32 | return false; 33 | } 34 | 35 | return true; 36 | } 37 | 38 | int main(void) 39 | { 40 | FM77AV *fm77av=new FM77AV; 41 | 42 | fm77av->physMem.state.data[0x31000]=0x4E; 43 | fm77av->physMem.state.data[0x31001]=0x5A; 44 | 45 | fm77av->physMem.state.data[0x3600A]=0x60; 46 | fm77av->physMem.state.data[0x3600B]=0x0A; 47 | 48 | for(int i=0x37000; i<0x37FFF; i+=2) 49 | { 50 | fm77av->physMem.state.data[i ]=(i>>8)&255; 51 | fm77av->physMem.state.data[i+1]=i&255; 52 | } 53 | 54 | fm77av->physMem.state.data[0x100]=0x75; 55 | fm77av->physMem.state.data[0x101]=0x00; 56 | 57 | FM77AV::MemoryEvaluation eval(fm77av); 58 | if(true!=Verify(eval,30,"(100+200)/10")) 59 | { 60 | return 1; 61 | } 62 | 63 | if(true!=Verify(eval,0x600A,"WORD_PHYS:0x3600A")) 64 | { 65 | return 1; 66 | } 67 | 68 | if(true!=Verify(eval,0x0A,"(WORD_M:0x1000-0x4E00)%0x50")) 69 | { 70 | return 1; 71 | } 72 | 73 | if(true!=Verify(eval,0x7700,"(WORD_M:($6700+$1000))")) 74 | { 75 | return 1; 76 | } 77 | 78 | if(true!=Verify(eval,0x7500,"WORD_M:(WORD_P:$100)")) 79 | { 80 | return 1; 81 | } 82 | 83 | std::cout << "Pass!" << std::endl; 84 | 85 | delete fm77av; 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /src/vgmrecorder/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Re-use code from Tsugaru 2 | set(TARGET_NAME vgmrecorder) 3 | set(VGMRECORDER_DIR "${TSUGARU_SOURCE_DIR}/vgmrecorder") 4 | add_compile_definitions(MUTSU_FM77AV) 5 | add_library(${TARGET_NAME} ${VGMRECORDER_DIR}/vgmrecorder.h ${VGMRECORDER_DIR}/vgmrecorder.cpp ${VGMRECORDER_DIR}/vgmrecorder_ym2203.cpp ${VGMRECORDER_DIR}/vgmrecorder_ay8910.cpp) 6 | target_include_directories(${TARGET_NAME} PUBLIC ${VGMRECORDER_DIR}) 7 | target_link_libraries(${TARGET_NAME} ym2203c) 8 | -------------------------------------------------------------------------------- /src/ym2203c/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Re-use code from Tsugaru 2 | set(TARGET_NAME ym2203c) 3 | set(YM2203C_DIR "${TSUGARU_SOURCE_DIR}/ym2612") 4 | add_compile_definitions(MUTSU_FM77AV) 5 | add_library(${TARGET_NAME} ${YM2203C_DIR}/ym2612.h ${YM2203C_DIR}/ym2612.cpp ${YM2203C_DIR}/ym2612wave.cpp) 6 | target_include_directories(${TARGET_NAME} PUBLIC ${YM2203C_DIR}) 7 | -------------------------------------------------------------------------------- /testasm/MAGUSBug.asm: -------------------------------------------------------------------------------- 1 | ; This program hsa been tested on real FM77AV 2 | ; This program is not supposed to return. 3 | ; Due to the undocumented behavior of Sub-CPU BUSY flag, EXEC &H2000 will return. 4 | ; See the bottom comment. 5 | 6 | ORG $2000 7 | PSHS A,B,X,Y 8 | 9 | WAIT_READY LDA $FD05 10 | BMI WAIT_READY 11 | LDA #$80 12 | STA $FD05 13 | WAIT_HALT LDA $FD05 14 | BPL WAIT_HALT 15 | 16 | LEAX SUBSYS_CMD,PCR 17 | LDY #$FC80 18 | LDB #$7F 19 | TRANSFER_LOOP LDA ,X+ 20 | STA ,Y+ 21 | DECB 22 | BNE TRANSFER_LOOP 23 | 24 | CLR $FD05 ; This is supposed to automatically raise BUSY flag. 25 | WAIT_UNHALT LDA $FD05 26 | BPL WAIT_UNHALT 27 | 28 | 29 | MAGUS_BUG_MAIN_WAIT 30 | CLR $FD05 31 | CLR $FD05 32 | LDA $FD05 33 | BMI MAGUS_BUG_MAIN_WAIT 34 | 35 | 36 | LDA #$80 37 | STA $FD05 38 | WAIT_HALT2 LDA $FD05 39 | BPL WAIT_HALT2 40 | 41 | STA $FC80 42 | CLR $FD05 43 | 44 | PULS A,B,X,Y,PC 45 | 46 | 47 | 48 | SUBSYS_CMD 49 | FCB 0,0 50 | FCB $3F 51 | FCB "YAMAUCHI" 52 | FCB $93 53 | FDB $D380+(TEST_ROUTINE-SUBSYS_CMD) 54 | FCB $90 55 | TEST_ROUTINE 56 | CLR $D380 57 | MAGUS_BUG_WAIT_SUB 58 | CLR $D40A 59 | CLR $D40A 60 | LDA $D380 ; Wait for main CPU write something to the first byte of the shared RAM. 61 | BEQ MAGUS_BUG_WAIT_SUB 62 | RTS 63 | 64 | 65 | ; The hypothesis: 66 | ; MAGUS was a masterpiece pinball game for FM-7 series. However, it had a bug in the program. 67 | ; 68 | ; In MAGUS, while the main CPU is waiting for the sub-CPU to become ready (clear of BUSY flag) in the following loop: 69 | ; 3082 7FFD05 CLR $FD05 (7 clocks) 70 | ; 3085 7FFD05 CLR $FD05 (7 clocks) 71 | ; 3088 F6FD05 LDB $FD05 (5 clocks) 72 | ; 308B 2BF5 BMI $3082 (3 clocks) 73 | ; 74 | ; the sub-CPU is waiting for the command from the main CPU in the following loop: 75 | ; C027 7FD40A CLR $D40A (7 clocks) 76 | ; C02A 7FD40A CLR $D40A (7 clocks) 77 | ; C02D B6D380 LDA $D380 (5 clocks) 78 | ; C030 27F5 BEQ $C027 (3 clocks) 79 | ; 80 | ; The problem is, CLR $D40A raises BUSY flag instead of clearing it. Therefore if the emulator emulates as is, 81 | ; the main CPU will never gets out of the wait loop. 82 | ; 83 | ; This code, however, works on actual FM-7. What's happening probably is CLR $FD05 from the main CPU continuously 84 | ; bombards CLR pin of a 74LS74, and CLR $D40A from the sub-CPU CLK pin. So, 74LS74 was receiving pulse of CLK and 85 | ; CLR simultaneously. It may put the state of 74LS74 unstable. BUSY flag is output ~Q pin from the particular 86 | ; 74LS74. The main CPU may be picking up when ~Q goes unstable, and took it as LOW. 87 | ; 88 | ; However, this chip is replaced with a custom chip MB113T614 in FM77AV. Nonetheless, the above bugged code works 89 | ; on FM77AV. How MB113T614 reacts to the bombardment to the $FD05 and $D40A is unknown. But, MAGUS was such a 90 | ; famous masterpiece for FM-7. Whoever was designing FM77AV might have tested it and recognized its bug, and 91 | ; maybe designed this custom chip so that MAGUS can run on FM77AV. 92 | ; 93 | ; FM-7 series emulator XM7 had a special option for running MAGUS. 94 | ; I haven't decided how to support MAGUS in Mutsu yet (when I am writing this line). 95 | 96 | -------------------------------------------------------------------------------- /testasm/cmp_inc.asm: -------------------------------------------------------------------------------- 1 | // The following program wrote FF to $1FFF on actual FM77AV. 2 | // It means BEQ EQ branched. 3 | // Therefore, CMPX compared the value of X after the pre-incrementation. 4 | 5 | ORG $2000 6 | FDB #$2000 7 | LDX #$2002 8 | CMPX ,--X 9 | BEQ EQ 10 | LDA #0 11 | STA $1FFF 12 | STX $1FFC 13 | RTS 14 | 15 | EQ LDA #$FF 16 | STA $1FFF 17 | STX $1FFC 18 | RTS 19 | -------------------------------------------------------------------------------- /testasm/cmpx_inc.asm: -------------------------------------------------------------------------------- 1 | ; 0 is written to $1FFF 2 | ORG $2000 3 | FDB $2000 4 | CLRA 5 | LDX #$2000 6 | CMPX ,X++ 7 | BEQ EQ 8 | STA $1FFF ; A=0 9 | RTS 10 | EQ COMA 11 | STA $1FFF ; A=FF 12 | RTS 13 | 14 | -------------------------------------------------------------------------------- /testasm/disasmtest.asm: -------------------------------------------------------------------------------- 1 | ORG $2000 2 | LDA #$77 3 | LDB #$11 4 | LDD #$1973 5 | BITA $3000,PCR 6 | EORA A,X 7 | ANDA B,Y 8 | STA D,U 9 | LDA ,X+ 10 | LDB ,Y++ 11 | STA ,-U 12 | STX ,--U 13 | JSR [$FBFA] 14 | JMP [A,X] 15 | PSHS A,B,X,Y,U 16 | PULS CC,DP,PC 17 | PSHU A,X,S 18 | PULS DP,U,PC 19 | STA $FD0F 20 | EXG A,B 21 | TFR D,X 22 | EXG A,U 23 | TFR S,D 24 | LDY [$4000,PCR] 25 | -------------------------------------------------------------------------------- /testasm/div16.asm: -------------------------------------------------------------------------------- 1 | ; by Soji Yamakawa 2017/10/24 2 | ; Division Signed 16bit/Signed 16bit integers 3 | 4 | EXPORT DIV16_NUMER 5 | EXPORT DIV16_DENOM 6 | EXPORT DIV16 7 | 8 | DIV16_NUMER RZB 2 ; Input Numerator, Output Remainder 9 | DIV16_DENOM RZB 2 ; Input Denominator, Output Quotient 10 | 11 | DIV16 PSHS A,B,X,U 12 | 13 | LDD DIV16_NUMER,PCR ; Updates NEGA flag 14 | STA DIV16_NUMERSGN,PCR 15 | BPL DIV16_NUMPOSI ; Jump NEGA==0 16 | COMA 17 | COMB 18 | ADDD #1 19 | STD DIV16_NUMER,PCR 20 | DIV16_NUMPOSI 21 | 22 | LDD DIV16_DENOM,PCR ; Updates NEGA flag 23 | STA DIV16_DENOMSGN,PCR 24 | BPL DIV16_DENPOSI ; Jump NEGA==0 25 | COMA 26 | COMB 27 | ADDD #1 28 | STD DIV16_DENOM,PCR 29 | DIV16_DENPOSI 30 | ; Come out with D=DENOM 31 | 32 | LDX #1 33 | STX DIV16_MULTI,PCR 34 | LDX #0 ; X will be the unsigned quotient 35 | 36 | ; Come in with D=DENOM 37 | DIV16_UPSHIFTLP CMPD DIV16_NUMER,PCR 38 | BCC DIV16_LOOP_IN 39 | LSLB 40 | ROLA 41 | BMI DIV16_LOOP_IN 42 | 43 | STD DIV16_DENOM,PCR 44 | LSL DIV16_MULTI+1,PCR 45 | ROL DIV16_MULTI,PCR 46 | BPL DIV16_UPSHIFTLP 47 | 48 | DIV16_LOOP_IN LDD DIV16_NUMER,PCR 49 | DIV16_LOOP CMPD DIV16_DENOM,PCR 50 | BLO DIV16_DONTADD 51 | 52 | SUBD DIV16_DENOM,PCR 53 | DIV16_MULTIM2 LEAX $7FFF,X ; $7FFF will be replaced with MULTI 54 | DIV16_MULTI EQU DIV16_MULTIM2+2 55 | 56 | DIV16_DONTADD LSR DIV16_DENOM,PCR ; Higher bits 57 | ROR DIV16_DENOM+1,PCR ; Lower bits 58 | 59 | LSR DIV16_MULTI,PCR 60 | ROR DIV16_MULTI+1,PCR 61 | BCC DIV16_LOOP 62 | 63 | DIV16_END STX DIV16_DENOM,PCR ; Quotient in DENOM 64 | STD DIV16_NUMER,PCR ; Remainder in NUMER 65 | LDD #0 66 | 67 | TST DIV16_NUMERSGN,PCR 68 | BPL DIV16_SETSIGN 69 | 70 | ; Remainder needs to be same sign as the numerator 71 | ; A and B are already zero. 72 | SUBD DIV16_NUMER,PCR 73 | STD DIV16_NUMER,PCR 74 | ; Remainder may be zero, in which case A register 75 | ; does not reflect the sign of the numerator. 76 | ; A must be reset to a negative number. 77 | LDA #-1 78 | 79 | DIV16_SETSIGN ; A is zero or positive if jumped from BPL, or if not -1. 80 | EORA DIV16_DENOMSGN,PCR 81 | BPL DIV16_RETURN 82 | 83 | LDD #0 84 | SUBD DIV16_DENOM,PCR 85 | STD DIV16_DENOM,PCR 86 | 87 | DIV16_RETURN PULS A,B,X,U,PC 88 | 89 | 90 | DIV16_SIGN RZB 2 91 | DIV16_NUMERSGN EQU DIV16_SIGN 92 | DIV16_DENOMSGN EQU DIV16_SIGN+1 93 | -------------------------------------------------------------------------------- /testasm/divtest.asm: -------------------------------------------------------------------------------- 1 | ; asm6809 divtest.asm div16.asm 2 | ORG $2000 3 | LDS #$6000 4 | LDD #5000 5 | STD DIV16_NUMER,PCR 6 | LDD #50 7 | STD DIV16_DENOM,PCR 8 | BSR DIV16 9 | LDX DIV16_DENOM,PCR 10 | LDY DIV16_NUMER,PCR 11 | 12 | LDA #$FF 13 | STA $0 14 | 15 | INF BRA INF 16 | 17 | -------------------------------------------------------------------------------- /testasm/encoder_get.asm: -------------------------------------------------------------------------------- 1 | ORG $4000 2 | 3 | BSR HALT 4 | 5 | LEAX SUBSYSCMD,PCR 6 | LDU #$FC80 7 | SENDLOOP LDA ,X+ 8 | STA ,U+ 9 | CMPU #$FCA0 10 | BNE SENDLOOP 11 | 12 | CLR $FD05 13 | BSR HALT 14 | 15 | LDX #$5000 16 | LDU #$FC80 17 | RECVLOOP LDA ,U+ 18 | STA ,X+ 19 | CMPU #$FCA0 20 | BNE RECVLOOP 21 | 22 | LDA #$80 23 | STA $FC80 24 | CLR $FD05 25 | RTS 26 | 27 | HALT LDA $FD05 28 | BMI HALT 29 | LDA #$80 30 | STA $FD05 31 | WAITHALT LDA $FD05 32 | BPL WAITHALT 33 | RTS 34 | 35 | 36 | SUBSYSCMD FCB 0,0 37 | FCB $45 38 | FCB 1 ; Get encoding 39 | FCB $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF 40 | -------------------------------------------------------------------------------- /testasm/encoder_get.lst: -------------------------------------------------------------------------------- 1 | MON 2 | M4000 3 | 8D 4 | 2E 5 | 30 6 | 8C 7 | 3B 8 | CE 9 | FC 10 | 80 11 | A6 12 | 80 13 | A7 14 | C0 15 | 11 16 | 83 17 | FC 18 | A0 19 | 26 20 | F6 21 | 7F 22 | FD 23 | 05 24 | 8D 25 | 19 26 | 8E 27 | 50 28 | 00 29 | CE 30 | FC 31 | 80 32 | A6 33 | C0 34 | A7 35 | 80 36 | 11 37 | 83 38 | FC 39 | A0 40 | 26 41 | F6 42 | 86 43 | 80 44 | B7 45 | FC 46 | 80 47 | 7F 48 | FD 49 | 05 50 | 39 51 | B6 52 | FD 53 | 05 54 | 2B 55 | FB 56 | 86 57 | 80 58 | B7 59 | FD 60 | 05 61 | B6 62 | FD 63 | 05 64 | 2A 65 | FB 66 | 39 67 | 00 68 | 00 69 | 45 70 | 01 71 | FF 72 | FF 73 | FF 74 | FF 75 | FF 76 | FF 77 | FF 78 | FF 79 | -------------------------------------------------------------------------------- /testasm/encoder_init.asm: -------------------------------------------------------------------------------- 1 | ORG $4000 2 | PSHS CC 3 | ORCC #$50 4 | 5 | BSR MMRINIT 6 | 7 | LDA #$80 8 | STA $FD05 9 | 10 | LDA #$1D ; Sub $D000 11 | STA $FD8D 12 | LDA #$80 13 | STA $FD93 14 | 15 | 16 | LDA #$80 17 | BSR ENCODER_WRITE 18 | CLRA 19 | BSR ENCODER_WRITE 20 | 21 | LDB #7 22 | LDU #$5000 23 | READ_LOOP 24 | BSR ENCODER_READ 25 | STA ,U+ 26 | DECB 27 | BNE READ_LOOP 28 | 29 | CLR $FD05 30 | 31 | BSR MMRINIT 32 | 33 | PULS CC,PC 34 | 35 | MMRINIT 36 | LDA #$30 37 | LDX #$FD80 38 | MMRINITLOOP 39 | STA ,X+ 40 | INCA 41 | CMPA #$40 42 | BNE MMRINITLOOP 43 | RTS 44 | 45 | ENCODER_WRITE 46 | STA $D381 47 | ENCODER_WRITE_WAIT 48 | LDA $D382 49 | ANDA #1 50 | BEQ ENCODER_WRITE_WAIT 51 | RTS 52 | 53 | ENCODER_READ 54 | LDA $D382 55 | BMI ENCODER_READ 56 | LDA $D381 57 | RTS 58 | -------------------------------------------------------------------------------- /testasm/fdc_headload.asm: -------------------------------------------------------------------------------- 1 | ; The purpose of this test program is to see change of STATUS on command $18 (Seek + Head Load) 2 | ; The result from actual FM7AV: 3 | ; Status byte changed $C4->$C5->$C1->$C0 4 | ; U register was at $30FF when seek command has completed. 5 | ; $C4->$C5 when FDC starts working (b0=BUSY flag) 6 | ; $C5->$C1 when track left track 0 (b2=TRACK00 flag) 7 | ; $C1->$C0 when FDC is done with seek (b0=BUSY flag) 8 | 9 | ; Conclusion: 10 | ; Even if h-flag (head-load) is specified in the FDC command, 11 | ; HEAD ENGAGED flag (b6) will not be set. 12 | 13 | ORG $1600 14 | 15 | PSHS A,B,X,Y,U,CC 16 | 17 | BSR WAIT_READY 18 | LDA #$00 ; Restore 19 | STA $FD18 20 | BSR WAIT_IRQ 21 | 22 | LEAU $1800,PCR 23 | 24 | BSR WAIT_READY 25 | LDA #10 26 | STA $FD1B 27 | LDA #$18 ; Seek 28 | STA $FD18 29 | 30 | WAIT_BUSY LDA $FD18 31 | STA ,U+ 32 | LSRA 33 | BCC WAIT_BUSY 34 | 35 | WAIT_SEEK LDA $FD18 36 | STA ,U+ 37 | LSRA 38 | BCS WAIT_SEEK 39 | 40 | STU $17FE,PCR 41 | 42 | FOLLOWUP LDA $FD18 43 | STA ,U+ 44 | CMPU #$5000 45 | BCS FOLLOWUP 46 | 47 | BSR WAIT_READY 48 | LDA #$00 ; Restore 49 | STA $FD18 50 | BSR WAIT_IRQ 51 | 52 | PULS A,B,X,Y,U,CC,PC 53 | 54 | WAIT_READY LDA $FD18 55 | ANDA #1 56 | BNE WAIT_READY 57 | RTS 58 | 59 | WAIT_IRQ LDA $FD1F 60 | LSLA 61 | BPL WAIT_IRQ 62 | RTS 63 | -------------------------------------------------------------------------------- /testasm/indexhole.asm: -------------------------------------------------------------------------------- 1 | ; OK. So, I thought that FM77AV FDD is running at 600rpm. Is it real? Or is it 300rpm? 2 | ; Just measure it to confirm. 3 | 4 | ; 60.95 seconds for 300 times index hole detection on actual FM77AV. 5 | 6 | ; So, 300 it is. 7 | 8 | LDX #300 9 | LOOP BSR WAITINDEX 10 | LEAX -1,X 11 | BNE LOOP 12 | RTS 13 | 14 | WAITINDEX 15 | LDA #2 16 | WAITINDEXIN BITA $FD18 17 | BEQ WAITINDEXIN 18 | 19 | WAITINDEXOUT BITA $FD18 20 | BNE WAITINDEXOUT 21 | 22 | RTS 23 | -------------------------------------------------------------------------------- /testasm/ldu_inc.asm: -------------------------------------------------------------------------------- 1 | ; The following code wrote 100 to $1ffC and $1FFE. 2 | ; Even with post-incrementation, the value is what read from the memory. 3 | ORG $2000 4 | FDB 100 5 | LDU #$2000 6 | LDU ,U++ 7 | STU $1FFC 8 | LDU #$2002 9 | LDU ,--U 10 | STU $1FFE 11 | RTS 12 | -------------------------------------------------------------------------------- /testasm/ldx_inc.asm: -------------------------------------------------------------------------------- 1 | ORG $2000 2 | FDB $FFFE 3 | LDX #$2000 4 | LDX ,X++ ; Value loaded is $FFFE, after incrementation it is 0 5 | BEQ EQ 6 | STX $1FFC 7 | LDA #$FF 8 | STA $1FFF 9 | RTS 10 | EQ 11 | STX $1FFC 12 | LDA #$00 13 | STA $1FFF 14 | RTS 15 | -------------------------------------------------------------------------------- /testasm/multiPage_hwDraw.asm: -------------------------------------------------------------------------------- 1 | ; F-BASIC V3.4 L20 draws a filled-box using sub-system command $15, which breaks the menu frame 2 | ; if drawn as is. 3 | ; Only explanation why it doesn't break is hardware-drawing and hardware line-drawing is affected 4 | ; by multi-page ($FD37). 5 | ; The explanation of the I/O tells low 3 bits controls CPU to VRAM access. But, does it also 6 | ; control hardware drawing? 7 | ; This program is to find answer to this question. 8 | 9 | ; This program writes #6 to $FD37 to mask CPU-to-VRAM access of Red and Green planes, and then 10 | ; fill the screen with hardware line drawing. 11 | ; If hardware line-drawing repects $FD37, the output should be blue. If it doesn't, the output 12 | ; should be white. 13 | 14 | ; The verdict from the real FM77AV was BLUE. In conclusion, FM77AV's hardware line drawing respects $FD37. 15 | 16 | ORG $2000 17 | 18 | PSHS A,B,X,Y,U 19 | 20 | SUB_HALT LDA $FD05 21 | BMI SUB_HALT 22 | LDA #$80 23 | STA $FD05 24 | STA $FC80 25 | CLR $FC82 26 | 27 | 28 | LDA #$30 29 | LDX #$FD80 30 | MMR_INIT_LOOP STA ,X+ 31 | INCA 32 | CMPA #$40 33 | BNE MMR_INIT_LOOP 34 | 35 | LDA #$1D 36 | STA $FD8D 37 | 38 | LDA #$80 39 | STA $FD93 40 | 41 | LDA #6 ; Mask Red and Green planes. If Hardware Drawing respects this register, I should see blue. 42 | STA $FD37 43 | 44 | LDX #$FFFF 45 | STX $D422 46 | 47 | LDY #0 48 | STY $D420 49 | LINE_LOOP 50 | LDB $D430 51 | ANDB #$10 52 | BEQ LINE_LOOP ; Wait ready 53 | 54 | LDX #$8007 55 | STX $D410 56 | 57 | LDB #8 58 | STB $D41B 59 | 60 | LDX #0 61 | STX $D424 62 | STY $D426 63 | LDX #639 64 | STX $D428 65 | STY $D42A 66 | 67 | LEAY 1,Y 68 | CMPY #200 69 | BNE LINE_LOOP 70 | 71 | 72 | WAIT_LINE_END LDB $D430 73 | ANDB #$10 74 | BEQ WAIT_LINE_END 75 | 76 | CLR $D410 77 | 78 | CLR $FD05 79 | CLR $FD37 80 | CLR $FD93 81 | PULS A,B,X,Y,U,PC 82 | 83 | -------------------------------------------------------------------------------- /testasm/puls.asm: -------------------------------------------------------------------------------- 1 | ; This program is to verify if 6809 was dummy-reading an extra byte PULS A,X,Y instruction. 2 | ; Dragon Buster FM77AV shows a vertical bar on the right of the screen. 3 | ; The bar was supposed to be cleared by hardware-drawing, which works by dummy-reading VRAM. 4 | ; Main-CPU uses this hardware-drawing when showing a field map, $26 bytes per line. 5 | ; When clearing the screen, it uses PULS instruction and appeared to dummy-read $25 bytes per line. 6 | ; Unless PULS is dummy-reading (or pre-reading) an additional byte from the RAM (sending a read 7 | ; signal to the hardware-draing chip), one byte per line is left uncleared. 8 | 9 | ; The test on actual FM77AV hardware confirmed that PULS A,X,Y indeed reads 6 bytes from the VRAM. 10 | ; Hardware-drawing chip sees the memory-read and fills 48 pixels in a row. 11 | 12 | ; PULS A,B,X,Y let the hardware-drawing fill 7 bytes, and PULS A,B,X,Y,U 9 bytes. 13 | 14 | ; PULS instruction reads one extra byte in conclusion. 15 | 16 | PSHS clsCC 17 | ORCC #$50 18 | STS SAVESTACK,PCR 19 | 20 | LDX #$FD80 21 | LDA #$30 22 | MMRLOOP STA ,X+ 23 | INCA 24 | CMPA #$40 25 | BNE MMRLOOP 26 | 27 | LDD #$101D 28 | STD $FD85 ; $5000 Mapped to VRAM First 4K, $6000 Mapped to SubCPU I/O 29 | 30 | LDA #$80 31 | STA $FD05 32 | 33 | LDA #$80 34 | STA $FD93 ; Enable MMR 35 | 36 | 37 | LDD #$8007 38 | STA $6430 ; Sub D430 mapped to 6430. Disable NMI, Active Page 0 39 | STD $6410 ; Enable Hardware Drawing, No compare, PSET, Color 7 40 | CLR $6412 ; No mask 41 | LDA #8 42 | STA $641B ; All banks enabled 43 | 44 | LDS #$5280 45 | PULS A,X,Y 46 | LDS #$52D0 47 | PULS A,B,X,Y 48 | LDS #$5320 49 | PULS A,B,X,Y,U 50 | 51 | CLR $FD05 52 | 53 | LDS SAVESTACK,PCR 54 | PULS CC,PC 55 | 56 | SAVESTACK FDB 0 57 | -------------------------------------------------------------------------------- /testasm/stx_inc.asm: -------------------------------------------------------------------------------- 1 | ; This code writes: 2 | ; $20 $20 to $1FFE 3 | ; $1F $FC to $1FFC 4 | ; Regardless of pre-decrementation or post-incrementation, 5 | ; the value stored is after the pre-dec or post-inc. 6 | 7 | ORG $2000 8 | LDX #$1FFE 9 | STX ,X++ 10 | LDX #$1FFE 11 | STX ,--X 12 | RTS 13 | -------------------------------------------------------------------------------- /testasm/subhalt.asm: -------------------------------------------------------------------------------- 1 | ; This program is for testing if Sub-CPU halts a few clocks after #$80 is written to $FD05. 2 | ; Conclusion: There was no such delay observed in real FM77AV. 3 | 4 | ORG $3FFE 5 | 6 | RESULT FDB 0 7 | 8 | PSHS A,B,X,Y,U,DP 9 | 10 | LDA #$FD 11 | TFR A,DP 12 | 13 | WAIT_READY LDA <$05 14 | BMI WAIT_READY 15 | 16 | LDX #0 17 | LDA #$80 18 | STA <$05 19 | LDA <$05 20 | BMI SUB_HALTED 21 | 22 | WAIT_BUSY LEAX 1,X 23 | LDA <$05 24 | BPL WAIT_BUSY 25 | 26 | SUB_HALTED 27 | CLR $FC82 28 | LDA #$80 29 | STA $FC80 30 | CLR <$05 31 | 32 | STX RESULT,PCR 33 | 34 | PULS A,B,X,Y,U,DP,PC 35 | 36 | -------------------------------------------------------------------------------- /testasm/tfr_u_a.asm: -------------------------------------------------------------------------------- 1 | ; Confirmed on real FM77AV. 2 | ; TFR U,A transfers low 8-bits to A. 3 | PSHS A,U 4 | LDU #$7711 5 | TFR U,A 6 | STA DST,PCR 7 | PULS A,U,PC 8 | DST FCB 0 9 | --------------------------------------------------------------------------------