├── .appveyor.yml ├── .github └── workflows │ └── pvs-studio.yml ├── .gitignore ├── LICENSE ├── README.md ├── astyle-cpp-options ├── emulator ├── !astyle.bat ├── !version.bat ├── BKBTL-VS2015.sln ├── BKBTL-VS2015.vcxproj ├── BKBTL-VS2015.vcxproj.filters ├── Common.cpp ├── Common.h ├── ConsoleView.cpp ├── DebugView.cpp ├── Dialogs.cpp ├── Dialogs.h ├── DisasmView.cpp ├── Emulator.cpp ├── Emulator.h ├── Joystick.cpp ├── Joystick.h ├── KeyboardView.cpp ├── Main.cpp ├── Main.h ├── MainWindow.cpp ├── MemoryMapView.cpp ├── MemoryView.cpp ├── ScreenView.cpp ├── Settings.cpp ├── SoundGen.cpp ├── SoundGen.h ├── SpriteView.cpp ├── TapeView.cpp ├── TeletypeView.cpp ├── ToolWindow.cpp ├── ToolWindow.h ├── Views.h ├── emubase │ ├── Board.cpp │ ├── Board.h │ ├── Defines.h │ ├── Disasm.cpp │ ├── Emubase.h │ ├── Floppy.cpp │ ├── Processor.cpp │ ├── Processor.h │ └── SoundAY.cpp ├── manifest.xml ├── res │ ├── BKBTL.ico │ ├── BKBTL.rc │ ├── Keyboard.png │ ├── Keyboard11m.png │ ├── Toolbar.bmp │ ├── resource.h │ └── small.ico ├── stdafx.cpp ├── stdafx.h └── util │ ├── BitmapFile.cpp │ ├── BitmapFile.h │ ├── WavPcmFile.cpp │ └── WavPcmFile.h └── roms ├── b11m_bos.rom ├── b11m_ext.rom ├── b11m_mstd.rom ├── basic10_1.rom ├── basic10_2.rom ├── basic10_3.rom ├── basic11m_0.rom ├── basic11m_1.rom ├── disk_253.rom ├── disk_326.rom ├── disk_327.rom ├── focal.rom ├── monit10.rom └── tests.rom /.appveyor.yml: -------------------------------------------------------------------------------- 1 | 2 | init: 3 | - git config --global core.autocrlf input 4 | 5 | clone_folder: C:\projects\bkbtl 6 | shallow_clone: true 7 | 8 | matrix: 9 | fast_finish: false 10 | 11 | configuration: 12 | - Debug 13 | - Release 14 | - Product 15 | 16 | environment: 17 | matrix: 18 | - toolchain: msvc15 19 | project_name: emulator\BKBTL-VS2015.sln 20 | platform: x86 21 | APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 22 | # - toolchain: msvc17 23 | # project_name: emulator\BKBTL-VS2015.sln 24 | # platform: x86 25 | # APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 26 | # - toolchain: msvc19 27 | # project_name: emulator\BKBTL-VS2015.sln 28 | # platform: x86 29 | # APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 30 | 31 | build: 32 | project: $(project_name) 33 | -------------------------------------------------------------------------------- /.github/workflows/pvs-studio.yml: -------------------------------------------------------------------------------- 1 | name: PVS-Studio analysis 2 | 3 | on: workflow_dispatch 4 | 5 | defaults: 6 | run: 7 | shell: cmd 8 | 9 | jobs: 10 | build-analyze: 11 | runs-on: windows-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v3 15 | - name: Download PVS Studio 16 | uses: suisei-cn/actions-download-file@v1.3.0 17 | with: 18 | url: https://files.pvs-studio.com/PVS-Studio_setup.exe 19 | target: .\Distrib 20 | - name: Install PVS Studio 21 | run: | 22 | .\Distrib\PVS-Studio_setup.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /COMPONENTS=Core 23 | - name: Configure PVS Studio 24 | run: | 25 | "C:\Program Files (x86)\PVS-Studio\PVS-Studio_Cmd.exe" credentials -u ${{ secrets.PVS_STUDIO_USERNAME }} -n ${{ secrets.PVS_STUDIO_KEY }} 26 | - name: Run PVS Studio 27 | run: | 28 | mkdir Results 29 | "C:\Program Files (x86)\PVS-Studio\PVS-Studio_Cmd.exe" -t .\emulator\BKBTL-VS2015.sln -e %GITHUB_WORKSPACE% -o .\Results\BKBTL.plog 30 | continue-on-error: true 31 | - name: Convert the report 32 | run: | 33 | "C:\Program Files (x86)\PVS-Studio\PlogConverter.exe" -t Html,Totals -o .\Results\ -r D:\Work\MyProjects\bkbtl -d V536,V1042 .\Results\BKBTL.plog 34 | - name: Upload the report 35 | uses: actions/upload-artifact@v3 36 | with: 37 | name: BKBTL-PVS 38 | path: .\Results\ 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Debug 2 | Product 3 | Release 4 | *.ncb 5 | *.suo 6 | *.user 7 | *.suppress 8 | *.sdf 9 | *.opensdf 10 | *.VC.db 11 | *.VC.opendb 12 | .vs 13 | ipch 14 | *.rom 15 | trace.log 16 | /emulator/Version.h 17 | BKBTL.APS 18 | trace.log 19 | *.dsk 20 | *.img 21 | *.bkd 22 | *.lst 23 | *.txt 24 | *.bkst 25 | /x-* 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bkbtl - BKBTL emulator, Win32 version 2 | 3 | [![License: LGPL v3](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0) 4 | [![Build status](https://ci.appveyor.com/api/projects/status/a1p2sovj2ew7iime?svg=true)](https://ci.appveyor.com/project/nzeemin/bkbtl) 5 | [![CodeFactor](https://www.codefactor.io/repository/github/nzeemin/bkbtl/badge)](https://www.codefactor.io/repository/github/nzeemin/bkbtl) 6 | 7 | ![GitHub all releases](https://img.shields.io/github/downloads/nzeemin/bkbtl/total) 8 | 9 | 10 | ## На русском / In Russian 11 | 12 | **BKBTL** — **BK Back to Life!** — это проект эмуляции советского бытового компьютера [БК-0010/БК-0011](http://ru.wikipedia.org/wiki/БК), построенного на 16-разрядном процессоре К1801ВМ1, совместимом по системе команд с семейством PDP-11. Проект начат 14 ноября 2009 года. Основан на коде проекта [UKNCBTL](https://github.com/nzeemin/ukncbtl). 13 | 14 | В проект BKBTL входят репозитории: 15 | * **bkbtl** — Windows-версия. Написана под Win32 и требует поддержки Юникода, поэтому набор версий Windows — 2000/2003/2008/XP/Vista/7. 16 | * [**bkbtl-qt**](https://github.com/nzeemin/bkbtl-qt) — Qt-версия. Работает под Windows, Linux и Mac OS X. В Qt-версии нет поддержки звука, нет окна карты памяти, нет поддержки внешнего джойстика; в остальном возможности те же. 17 | * [**bkbtl-testbench**](https://github.com/nzeemin/bkbtl-testbench) — тестовый стенд для регрессионного тестирования. 18 | * [**bkbtl-doc**](https://github.com/nzeemin/bkbtl-doc) — документация и скриншоты. 19 | 20 | ### Состояние эмулятора 21 | 22 | Бета-версия. Многие игры пока не работают. Дисковод более-менее работает в конфигурации БК-0011М. 23 | 24 | Поддерживаются конфигурации: 25 | БК-0010.01+Бейсик, БК-0010.01+Фокал+тесты, БК-0010.01+дисковод, БК-0011М+тесты, БК-0011М+дисковод. 26 | 27 | Эмулируется: 28 | * БК-0010.01 и БК-0011М 29 | * процессор (тест 791401 проходит, тест 791404 НЕ проходит) 30 | * материнская плата (частично, тест памяти 791323 НЕ проходит) 31 | * экран — черно-белый, цветной, усеченный режим, палитры цветного режима БК-0011 32 | * клавиатура — маппинг PC-клавиатуры на БК-клавиатуру зависит от переключателя РУС/ЛАТ в БК (но размаплены не все клавиши) 33 | * чтение с магнитофона (из файла формата WAV), запись на магнитофон (в WAV-файл) 34 | * звук пьезодинамика БК 35 | * Covox 36 | * джойстик (клавиши NumPad, внешний джойстик) 37 | * ИРПС на регистрах 177560..0177566 (пока только передача данных в отладочное окно) — используется для прогона тестов 38 | * дисковод (более-менее в конфигурации БК-0011М) 39 | * AY-3-8910 40 | 41 | Планируется сделать: 42 | 43 | * сделать правильную систему прерываний процессора (пока сделано ближе к ВМ2) 44 | * прогон тестов 791404 и 791323, отладка работы машины на них 45 | * доделать маппинг клавиатуры 46 | * программируемый таймер (нужно доделать) 47 | * мышь 48 | 49 | 50 | ## In English 51 | 52 | **BKBTL** — **BK Back to Life!** — is [BK0010/BK0011](http://en.wikipedia.org/wiki/Elektronika_BK) emulator. 53 | The emulation project started on Nov. 14, 2009 and based on [UKNCBTL](https://github.com/nzeemin/ukncbtl) code. 54 | BK is soviet home computer based on 16-bit PDP-11 compatible processor K1801VM1. 55 | 56 | The BKBTL project consists of: 57 | * [**bkbtl**](https://github.com/nzeemin/bkbtl) — Win32 version, for Windows. 58 | * [**bkbtl-qt**](https://github.com/nzeemin/bkbtl-qt) is Qt based BKBTL branch, works under Windows, Linux and Mac OS X. 59 | * [**bkbtl-testbench**](https://github.com/nzeemin/bkbtl-testbench) — test bench for regression testing. 60 | * [**bkbtl-doc**](https://github.com/nzeemin/bkbtl-doc) — documentation and screenshots. 61 | * Project wiki: https://github.com/nzeemin/bkbtl-doc/wiki 62 | 63 | Current status: Beta, under development. 64 | 65 | Emulated: 66 | * BK-0010.01 and BK-0011M 67 | * CPU 68 | * Motherboard 69 | * Screen — black and white mode, color mode, short mode, BK0011 color mode palettes 70 | * Keyboard (but mapped not all BK keys) 71 | * Reading from tape (WAV file), writing to tape (WAV file) 72 | * Sound 73 | * Joystick (numpad keys, external joystick) 74 | * Covox 75 | * Floppy drive (at least in BK11M configuration) 76 | * Programmable timer (partially) 77 | 78 | -------------------------------------------------------------------------------- /astyle-cpp-options: -------------------------------------------------------------------------------- 1 | ## Formatting options for 2 | ## Astyle - Source code indenter, formatter, and beautifier for C, C++, and Java Source Code 3 | ## http://astyle.sourceforge.net/ 4 | 5 | # Indent as C/C++ 6 | --mode=c 7 | # Use CRLF line end style 8 | --lineend=windows 9 | 10 | # Allman style formatting/indenting uses broken brackets 11 | --style=break 12 | 13 | # Indent using 4 spaces per indent 14 | --indent=spaces=4 15 | --indent-namespaces 16 | # Indent 'case X:' blocks from the 'case X:' headers. Case statements not enclosed in blocks are NOT indented. 17 | --indent-cases 18 | 19 | --min-conditional-indent=0 20 | --max-instatement-indent=8 21 | 22 | # Insert space padding around operators 23 | --pad-oper 24 | # Insert space padding after paren headers only (e.g. 'if', 'for', 'while'...) 25 | --pad-header 26 | 27 | --break-closing-brackets 28 | 29 | # Don't break one-line blocks 30 | --keep-one-line-blocks 31 | # Don't break complex statements and multiple statements residing on a single line 32 | --keep-one-line-statements 33 | -------------------------------------------------------------------------------- /emulator/!astyle.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set ASTYLEEXE=c:\bin\astyle.exe 3 | set ASTYLEOPT=-n -Q --options=..\astyle-cpp-options 4 | %ASTYLEEXE% %ASTYLEOPT% emubase\*.h emubase\*.cpp Util\*.h Util\*.cpp 5 | %ASTYLEEXE% %ASTYLEOPT% *.h *.cpp --exclude=Version.h --exclude=stdafx.h --exclude=stdafx.cpp 6 | -------------------------------------------------------------------------------- /emulator/!version.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | for /f "tokens=2 delims==" %%a in ('wmic OS Get localdatetime /value') do set "dt=%%a" 4 | set "YY=%dt:~2,2%" & set "YYYY=%dt:~0,4%" & set "MM=%dt:~4,2%" & set "DD=%dt:~6,2%" 5 | REM echo Year: %YYYY% 6 | 7 | REM set YYYY=2020 8 | REM git log --tags --simplify-by-decoration --pretty="format:%%cI %%d" | find /c "%YYYY%" 9 | 10 | set VERMINOR= 11 | for /f "tokens=* USEBACKQ" %%a in ( 12 | `git log --tags --simplify-by-decoration --pretty^=^"format^:%%cI^" ^| find ^/c ^"%YYYY%^"` 13 | ) do set VERMINOR=%%a 14 | REM echo Version minor: %VERMINOR% 15 | set /A VERMINOR=%VERMINOR%+1 16 | REM echo %VERMINOR% 17 | 18 | echo Version: %YYYY%.%VERMINOR% 19 | 20 | for /f %%i in ('git rev-list HEAD --count') do set REVISION=%%i 21 | set /A REVISION=%REVISION%+0 22 | echo Revision: %REVISION% 23 | 24 | echo. > Version.h 25 | echo #define APP_VERSION_STRING "%YYYY%.%VERMINOR%" >> Version.h 26 | echo. >> Version.h 27 | echo #define APP_REVISION %REVISION% >> Version.h 28 | -------------------------------------------------------------------------------- /emulator/BKBTL-VS2015.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BKBTL", "BKBTL-VS2015.vcxproj", "{50C37290-5770-42A8-B0A1-88571C4214FD}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x86 = Debug|x86 11 | Product|x86 = Product|x86 12 | Release|x86 = Release|x86 13 | EndGlobalSection 14 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 15 | {50C37290-5770-42A8-B0A1-88571C4214FD}.Debug|x86.ActiveCfg = Debug|Win32 16 | {50C37290-5770-42A8-B0A1-88571C4214FD}.Debug|x86.Build.0 = Debug|Win32 17 | {50C37290-5770-42A8-B0A1-88571C4214FD}.Product|x86.ActiveCfg = Product|Win32 18 | {50C37290-5770-42A8-B0A1-88571C4214FD}.Product|x86.Build.0 = Product|Win32 19 | {50C37290-5770-42A8-B0A1-88571C4214FD}.Release|x86.ActiveCfg = Release|Win32 20 | {50C37290-5770-42A8-B0A1-88571C4214FD}.Release|x86.Build.0 = Release|Win32 21 | EndGlobalSection 22 | GlobalSection(SolutionProperties) = preSolution 23 | HideSolutionNode = FALSE 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /emulator/BKBTL-VS2015.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Product 10 | Win32 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | 18 | BKBTL 19 | {50C37290-5770-42A8-B0A1-88571C4214FD} 20 | BKBTL 21 | Win32Proj 22 | 23 | 24 | 25 | Application 26 | v120_xp 27 | Unicode 28 | true 29 | 30 | 31 | Application 32 | v120_xp 33 | Unicode 34 | true 35 | 36 | 37 | Application 38 | v120_xp 39 | Unicode 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | $(SolutionDir)$(Configuration)\ 56 | $(Configuration)\ 57 | false 58 | true 59 | $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir) 60 | 61 | 62 | $(SolutionDir)$(Configuration)\ 63 | $(Configuration)\ 64 | false 65 | true 66 | $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir) 67 | 68 | 69 | $(SolutionDir)$(Configuration)\ 70 | $(Configuration)\ 71 | false 72 | true 73 | $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir) 74 | 75 | 76 | 77 | Disabled 78 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 79 | true 80 | EnableFastChecks 81 | MultiThreadedDebug 82 | Use 83 | Level4 84 | ProgramDatabase 85 | stdafx.h 86 | 87 | 88 | Vfw32.lib;comctl32.lib;winmm.lib;advapi32.lib;Windowscodecs.lib;%(AdditionalDependencies) 89 | true 90 | Windows 91 | false 92 | 93 | MachineX86 94 | true 95 | 96 | 97 | manifest.xml;%(AdditionalManifestFiles) 98 | 99 | 100 | 101 | 102 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 103 | MultiThreaded 104 | Use 105 | Level4 106 | ProgramDatabase 107 | 108 | 109 | Vfw32.lib;comctl32.lib;winmm.lib;Windowscodecs.lib;%(AdditionalDependencies) 110 | true 111 | Windows 112 | true 113 | true 114 | false 115 | 116 | MachineX86 117 | 118 | 119 | manifest.xml;%(AdditionalManifestFiles) 120 | 121 | 122 | 123 | 124 | Updating Version.h file... 125 | "!version.bat" 126 | 127 | 128 | WIN32;NDEBUG;_WINDOWS;PRODUCT;%(PreprocessorDefinitions) 129 | MultiThreaded 130 | Use 131 | Level3 132 | ProgramDatabase 133 | 134 | 135 | Vfw32.lib;comctl32.lib;winmm.lib;Windowscodecs.lib;%(AdditionalDependencies) 136 | true 137 | Windows 138 | true 139 | true 140 | false 141 | 142 | MachineX86 143 | true 144 | 145 | 146 | manifest.xml;%(AdditionalManifestFiles) 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | Create 173 | Create 174 | Create 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /emulator/BKBTL-VS2015.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {7d452430-e1ea-4900-a898-bba738f6c517} 6 | 7 | 8 | {500e3849-29dd-4d33-a2d2-cc45c9d34dac} 9 | 10 | 11 | {10e7b8b1-4f0b-4b55-a01a-11cbd357109a} 12 | 13 | 14 | 15 | 16 | emubase 17 | 18 | 19 | emubase 20 | 21 | 22 | emubase 23 | 24 | 25 | emubase 26 | 27 | 28 | util 29 | 30 | 31 | util 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | emubase 58 | 59 | 60 | emubase 61 | 62 | 63 | emubase 64 | 65 | 66 | emubase 67 | 68 | 69 | util 70 | 71 | 72 | util 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | res 98 | 99 | 100 | -------------------------------------------------------------------------------- /emulator/Common.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // Common.cpp 12 | 13 | #include "stdafx.h" 14 | #include "Main.h" 15 | #include "Views.h" 16 | 17 | ////////////////////////////////////////////////////////////////////// 18 | 19 | 20 | BOOL AssertFailedLine(LPCSTR lpszFileName, int nLine) 21 | { 22 | TCHAR buffer[360]; 23 | _sntprintf(buffer, sizeof(buffer) / sizeof(TCHAR) - 1, 24 | _T("ASSERTION FAILED\n\nFile: %S\nLine: %d\n\n") 25 | _T("Press Abort to stop the program, Retry to break to the debugger, or Ignore to continue execution."), 26 | lpszFileName, nLine); 27 | int result = MessageBox(NULL, buffer, _T("ASSERT"), MB_ICONSTOP | MB_ABORTRETRYIGNORE); 28 | 29 | switch (result) 30 | { 31 | case IDRETRY: 32 | return TRUE; 33 | case IDIGNORE: 34 | return FALSE; 35 | case IDABORT: 36 | PostQuitMessage(255); 37 | } 38 | return FALSE; 39 | } 40 | 41 | void AlertInfo(LPCTSTR sMessage) 42 | { 43 | ::MessageBox(NULL, sMessage, g_szTitle, MB_OK | MB_ICONINFORMATION | MB_TOPMOST); 44 | } 45 | void AlertWarning(LPCTSTR sMessage) 46 | { 47 | ::MessageBox(NULL, sMessage, g_szTitle, MB_OK | MB_ICONEXCLAMATION | MB_TOPMOST); 48 | } 49 | void AlertWarningFormat(LPCTSTR sFormat, ...) 50 | { 51 | const size_t buffersize = 512; 52 | TCHAR buffer[buffersize]; 53 | 54 | va_list ptr; 55 | va_start(ptr, sFormat); 56 | _vsntprintf_s(buffer, buffersize, buffersize - 1, sFormat, ptr); 57 | va_end(ptr); 58 | 59 | ::MessageBox(NULL, buffer, g_szTitle, MB_OK | MB_ICONEXCLAMATION | MB_TOPMOST); 60 | } 61 | BOOL AlertOkCancel(LPCTSTR sMessage) 62 | { 63 | int result = ::MessageBox(NULL, sMessage, g_szTitle, MB_OKCANCEL | MB_ICONQUESTION | MB_TOPMOST); 64 | return (result == IDOK); 65 | } 66 | 67 | 68 | ////////////////////////////////////////////////////////////////////// 69 | // DebugPrint and DebugLog 70 | 71 | #if defined(PRODUCT) 72 | 73 | void DebugPrint(LPCTSTR) {} 74 | void DebugPrintFormat(LPCTSTR, ...) {} 75 | void DebugLogClear() {} 76 | void DebugLogCloseFile() {} 77 | void DebugLog(LPCTSTR) {} 78 | void DebugLogFormat(LPCTSTR, ...) {} 79 | 80 | #else 81 | 82 | void DebugPrint(LPCTSTR message) 83 | { 84 | if (g_hwndConsole == NULL) 85 | return; 86 | 87 | ConsoleView_Print(message); 88 | } 89 | 90 | void DebugPrintFormat(LPCTSTR pszFormat, ...) 91 | { 92 | const size_t buffersize = 512; 93 | TCHAR buffer[buffersize]; 94 | 95 | va_list ptr; 96 | va_start(ptr, pszFormat); 97 | _vsntprintf_s(buffer, buffersize, buffersize - 1, pszFormat, ptr); 98 | va_end(ptr); 99 | 100 | DebugPrint(buffer); 101 | } 102 | 103 | const LPCTSTR TRACELOG_FILE_NAME = _T("trace.log"); 104 | const LPCTSTR TRACELOG_NEWLINE = _T("\r\n"); 105 | 106 | HANDLE Common_LogFile = NULL; 107 | 108 | void DebugLogCreateFile() 109 | { 110 | if (Common_LogFile == NULL) 111 | { 112 | Common_LogFile = ::CreateFile(TRACELOG_FILE_NAME, 113 | GENERIC_WRITE, FILE_SHARE_READ, NULL, 114 | CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 115 | } 116 | } 117 | 118 | void DebugLogCloseFile() 119 | { 120 | if (Common_LogFile == NULL) 121 | return; 122 | 123 | ::CloseHandle(Common_LogFile); 124 | Common_LogFile = NULL; 125 | } 126 | 127 | void DebugLogClear() 128 | { 129 | DebugLogCreateFile(); 130 | 131 | if (Common_LogFile != NULL) 132 | { 133 | // Trunkate to zero length 134 | ::SetFilePointer(Common_LogFile, 0, 0, 0); 135 | ::SetEndOfFile(Common_LogFile); 136 | } 137 | } 138 | 139 | void DebugLog(LPCTSTR message) 140 | { 141 | DebugLogCreateFile(); 142 | 143 | SetFilePointer(Common_LogFile, 0, NULL, FILE_END); 144 | 145 | int nLength = lstrlen(message) * sizeof(TCHAR); 146 | 147 | char ascii[256]; *ascii = 0; 148 | WideCharToMultiByte(CP_ACP, 0, message, nLength, ascii, 256, NULL, NULL); 149 | 150 | DWORD dwBytesWritten = 0; 151 | //WriteFile(Common_LogFile, message, dwLength, &dwBytesWritten, NULL); 152 | WriteFile(Common_LogFile, ascii, strlen(ascii), &dwBytesWritten, NULL); 153 | 154 | //dwLength = lstrlen(TRACELOG_NEWLINE) * sizeof(TCHAR); 155 | //WriteFile(Common_LogFile, TRACELOG_NEWLINE, dwLength, &dwBytesWritten, NULL); 156 | } 157 | 158 | void DebugLogFormat(LPCTSTR pszFormat, ...) 159 | { 160 | const size_t buffersize = 512; 161 | TCHAR buffer[buffersize]; 162 | 163 | va_list ptr; 164 | va_start(ptr, pszFormat); 165 | _vsntprintf_s(buffer, buffersize, buffersize - 1, pszFormat, ptr); 166 | va_end(ptr); 167 | 168 | DebugLog(buffer); 169 | } 170 | 171 | #endif // !defined(PRODUCT) 172 | 173 | 174 | ////////////////////////////////////////////////////////////////////// 175 | 176 | 177 | // Названия регистров процессора 178 | const TCHAR* REGISTER_NAME[] = { _T("R0"), _T("R1"), _T("R2"), _T("R3"), _T("R4"), _T("R5"), _T("SP"), _T("PC") }; 179 | 180 | 181 | HFONT CreateMonospacedFont() 182 | { 183 | HFONT font; 184 | LOGFONT logfont; memset(&logfont, 0, sizeof(logfont)); 185 | logfont.lfHeight = 12; 186 | logfont.lfWeight = FW_NORMAL; 187 | logfont.lfCharSet = DEFAULT_CHARSET; 188 | logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; 189 | logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; 190 | logfont.lfQuality = DEFAULT_QUALITY; 191 | logfont.lfPitchAndFamily = FIXED_PITCH; 192 | 193 | Settings_GetDebugFontName(logfont.lfFaceName); 194 | font = CreateFontIndirect(&logfont); 195 | if (font != NULL) 196 | return font; 197 | 198 | _tcscpy_s(logfont.lfFaceName, 32, _T("Lucida Console")); 199 | font = CreateFontIndirect(&logfont); 200 | if (font != NULL) 201 | return font; 202 | 203 | _tcscpy_s(logfont.lfFaceName, 32, _T("Courier")); 204 | font = CreateFontIndirect(&logfont); 205 | if (font != NULL) 206 | return font; 207 | 208 | return NULL; 209 | } 210 | 211 | HFONT CreateDialogFont() 212 | { 213 | HFONT font = CreateFont( 214 | 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, 215 | DEFAULT_CHARSET, 216 | OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, 217 | VARIABLE_PITCH, 218 | _T("MS Shell Dlg 2")); 219 | 220 | return font; 221 | } 222 | 223 | void GetFontWidthAndHeight(HDC hdc, int* pWidth, int* pHeight) 224 | { 225 | TEXTMETRIC tm; 226 | GetTextMetrics(hdc, &tm); 227 | if (pWidth != NULL) 228 | *pWidth = tm.tmAveCharWidth; 229 | if (pHeight != NULL) 230 | *pHeight = tm.tmHeight; 231 | } 232 | 233 | // Print octal 16-bit value to buffer 234 | // buffer size at least 7 characters 235 | void PrintOctalValue(TCHAR* buffer, WORD value) 236 | { 237 | for (int p = 0; p < 6; p++) 238 | { 239 | int digit = value & 7; 240 | buffer[5 - p] = _T('0') + (TCHAR)digit; 241 | value = (value >> 3); 242 | } 243 | buffer[6] = 0; 244 | } 245 | // Print hex 16-bit value to buffer 246 | // buffer size at least 5 characters 247 | void PrintHexValue(TCHAR* buffer, WORD value) 248 | { 249 | for (int p = 0; p < 4; p++) 250 | { 251 | int digit = value & 15; 252 | buffer[3 - p] = (digit < 10) ? _T('0') + (TCHAR)digit : _T('a') + (TCHAR)(digit - 10); 253 | value = (value >> 4); 254 | } 255 | buffer[4] = 0; 256 | } 257 | // Print binary 16-bit value to buffer 258 | // buffer size at least 17 characters 259 | void PrintBinaryValue(TCHAR* buffer, WORD value) 260 | { 261 | for (int b = 0; b < 16; b++) 262 | { 263 | int bit = (value >> b) & 1; 264 | buffer[15 - b] = bit ? _T('1') : _T('0'); 265 | } 266 | buffer[16] = 0; 267 | } 268 | 269 | // Parse octal value from text 270 | BOOL ParseOctalValue(LPCTSTR text, WORD* pValue) 271 | { 272 | WORD value = 0; 273 | TCHAR* pChar = (TCHAR*) text; 274 | for (int p = 0; ; p++) 275 | { 276 | if (p > 6) return FALSE; 277 | TCHAR ch = *pChar; pChar++; 278 | if (ch == 0) break; 279 | if (ch < _T('0') || ch > _T('7')) return FALSE; 280 | value = (value << 3); 281 | TCHAR digit = ch - _T('0'); 282 | value += digit; 283 | } 284 | *pValue = value; 285 | return TRUE; 286 | } 287 | 288 | void DrawOctalValue(HDC hdc, int x, int y, WORD value) 289 | { 290 | TCHAR buffer[7]; 291 | PrintOctalValue(buffer, value); 292 | TextOut(hdc, x, y, buffer, (int) _tcslen(buffer)); 293 | } 294 | void DrawHexValue(HDC hdc, int x, int y, WORD value) 295 | { 296 | TCHAR buffer[7]; 297 | PrintHexValue(buffer, value); 298 | TextOut(hdc, x, y, buffer, (int) _tcslen(buffer)); 299 | } 300 | void DrawBinaryValue(HDC hdc, int x, int y, WORD value) 301 | { 302 | TCHAR buffer[17]; 303 | PrintBinaryValue(buffer, value); 304 | TextOut(hdc, x, y, buffer, 16); 305 | } 306 | 307 | void CopyTextToClipboard(LPCTSTR text) 308 | { 309 | ASSERT(text != nullptr); 310 | size_t bufferLength = (_tcslen(text) + 1) * sizeof(TCHAR); 311 | 312 | // Prepare global memory object for the text 313 | HGLOBAL hglbCopy = ::GlobalAlloc(GMEM_MOVEABLE, bufferLength); 314 | LPTSTR lptstrCopy = (LPTSTR)::GlobalLock(hglbCopy); 315 | memcpy(lptstrCopy, text, bufferLength); 316 | ::GlobalUnlock(hglbCopy); 317 | 318 | // Send the text to the Clipboard 319 | ::OpenClipboard(g_hwnd); 320 | ::EmptyClipboard(); 321 | ::SetClipboardData(CF_UNICODETEXT, hglbCopy); 322 | ::CloseClipboard(); 323 | } 324 | 325 | // BK to Unicode conversion table 326 | const TCHAR BK_CHAR_CODES[] = 327 | { 328 | 0x3C0, 0x2534, 0x2665, 0x2510, 0x2561, 0x251C, 0x2514, 0x2550, 0x2564, 0x2660, 0x250C, 0x252C, 0x2568, 0x2193, 0x253C, 0x2551, 329 | 0x2524, 0x2190, 0x256C, 0x2191, 0x2663, 0x2500, 0x256B, 0x2502, 0x2666, 0x2518, 0x256A, 0x2565, 0x2567, 0x255E, 0x2192, 0x2593, 330 | 0x44E, 0x430, 0x431, 0x446, 0x434, 0x435, 0x444, 0x433, 0x445, 0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D, 0x43E, 331 | 0x43F, 0x44F, 0x440, 0x441, 0x442, 0x443, 0x436, 0x432, 0x44C, 0x44B, 0x437, 0x448, 0x44D, 0x449, 0x447, 0x44A, 332 | 0x42E, 0x410, 0x411, 0x426, 0x414, 0x415, 0x424, 0x413, 0x425, 0x418, 0x419, 0x41A, 0x41B, 0x41C, 0x41D, 0x41E, 333 | 0x41F, 0x42F, 0x420, 0x421, 0x422, 0x423, 0x416, 0x412, 0x42C, 0x42B, 0x417, 0x428, 0x42D, 0x429, 0x427, 0x42A, 334 | }; 335 | // Translate one KOI8-R character to Unicode character 336 | TCHAR Translate_BK_Unicode(BYTE ch) 337 | { 338 | if (ch < 32) return _T('·'); 339 | if (ch < 127) return (TCHAR) ch; 340 | if (ch == 127) return (TCHAR) 0x25A0; 341 | if (/*ch >= 128 &&*/ ch < 160) return _T('·'); 342 | return BK_CHAR_CODES[ch - 160]; 343 | } 344 | 345 | // KOI7-R (Russian) to Unicode conversion table 346 | const TCHAR KOI7R_CODES[] = 347 | { 348 | 0x44E, 0x430, 0x431, 0x446, 0x434, 0x435, 0x444, 0x433, 0x445, 0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D, 0x43E, 349 | 0x43F, 0x44F, 0x440, 0x441, 0x442, 0x443, 0x436, 0x432, 0x44C, 0x44B, 0x437, 0x448, 0x44D, 0x449, 0x447, 0x44A, 350 | 0x42E, 0x410, 0x411, 0x426, 0x414, 0x415, 0x424, 0x413, 0x425, 0x418, 0x419, 0x41A, 0x41B, 0x41C, 0x41D, 0x41E, 351 | 0x41F, 0x42F, 0x420, 0x421, 0x422, 0x423, 0x416, 0x412, 0x42C, 0x42B, 0x417, 0x428, 0x42D, 0x429, 0x427, 0x42A, 352 | }; 353 | // Translate one KOI7 character to Cyrillic Unicode character 354 | TCHAR Translate_KOI7R_Unicode(BYTE ch) 355 | { 356 | if (ch < 64 || ch >= 128) return (TCHAR) ch; 357 | return KOI7R_CODES[ch - 64]; 358 | } 359 | 360 | 361 | ////////////////////////////////////////////////////////////////////// 362 | // Path funcations 363 | 364 | LPCTSTR GetFileNameFromFilePath(LPCTSTR lpfilepath) 365 | { 366 | LPCTSTR lpfilename = _tcsrchr(lpfilepath, _T('\\')); 367 | if (lpfilename == NULL) 368 | return lpfilepath; 369 | else 370 | return lpfilename + 1; 371 | } 372 | 373 | 374 | ////////////////////////////////////////////////////////////////////// 375 | -------------------------------------------------------------------------------- /emulator/Common.h: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // Common.h 12 | 13 | #pragma once 14 | 15 | ////////////////////////////////////////////////////////////////////// 16 | 17 | #ifdef _DEBUG 18 | #define APP_VERSION_STRING "DEBUG" 19 | #define APP_REVISION 0 20 | #elif !defined(PRODUCT) 21 | #define APP_VERSION_STRING "RELEASE" 22 | #define APP_REVISION 0 23 | #else 24 | #include "Version.h" 25 | #endif 26 | 27 | ////////////////////////////////////////////////////////////////////// 28 | // Assertions checking - MFC-like ASSERT macro 29 | 30 | #ifdef _DEBUG 31 | 32 | BOOL AssertFailedLine(LPCSTR lpszFileName, int nLine); 33 | #define ASSERT(f) (void) ((f) || !AssertFailedLine(__FILE__, __LINE__) || (DebugBreak(), 0)) 34 | #define VERIFY(f) ASSERT(f) 35 | 36 | #else // _DEBUG 37 | 38 | #define ASSERT(f) ((void)0) 39 | #define VERIFY(f) ((void)f) 40 | 41 | #endif // !_DEBUG 42 | 43 | 44 | ////////////////////////////////////////////////////////////////////// 45 | // Alerts 46 | 47 | void AlertInfo(LPCTSTR sMessage); 48 | void AlertWarning(LPCTSTR sMessage); 49 | void AlertWarningFormat(LPCTSTR sFormat, ...); 50 | BOOL AlertOkCancel(LPCTSTR sMessage); 51 | 52 | 53 | ////////////////////////////////////////////////////////////////////// 54 | // DebugPrint 55 | 56 | void DebugPrint(LPCTSTR message); 57 | void DebugPrintFormat(LPCTSTR pszFormat, ...); 58 | void DebugLogClear(); 59 | void DebugLogCloseFile(); 60 | void DebugLog(LPCTSTR message); 61 | void DebugLogFormat(LPCTSTR pszFormat, ...); 62 | 63 | 64 | ////////////////////////////////////////////////////////////////////// 65 | 66 | 67 | // Processor register names 68 | const TCHAR* REGISTER_NAME[]; 69 | 70 | const int BK_SCREEN_WIDTH = 512; 71 | const int BK_SCREEN_HEIGHT = 256; 72 | 73 | 74 | HFONT CreateMonospacedFont(); 75 | HFONT CreateDialogFont(); 76 | 77 | void GetFontWidthAndHeight(HDC hdc, int* pWidth, int* pHeight); 78 | 79 | void PrintOctalValue(TCHAR* buffer, WORD value); 80 | void PrintHexValue(TCHAR* buffer, WORD value); 81 | void PrintBinaryValue(TCHAR* buffer, WORD value); 82 | 83 | BOOL ParseOctalValue(LPCTSTR text, WORD* pValue); 84 | 85 | void DrawOctalValue(HDC hdc, int x, int y, WORD value); 86 | void DrawHexValue(HDC hdc, int x, int y, WORD value); 87 | void DrawBinaryValue(HDC hdc, int x, int y, WORD value); 88 | 89 | TCHAR Translate_BK_Unicode(BYTE ch); 90 | TCHAR Translate_KOI7R_Unicode(BYTE ch); 91 | 92 | void CopyTextToClipboard(LPCTSTR text); 93 | 94 | LPCTSTR GetFileNameFromFilePath(LPCTSTR lpfilepath); 95 | 96 | 97 | ////////////////////////////////////////////////////////////////////// 98 | -------------------------------------------------------------------------------- /emulator/Dialogs.h: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // Dialogs.h 12 | 13 | #pragma once 14 | 15 | ////////////////////////////////////////////////////////////////////// 16 | 17 | 18 | void ShowAboutBox(); 19 | void ShowCommandLineHelpBox(); 20 | 21 | // Input octal value 22 | // strTitle - dialog caption 23 | // strPrompt - label text 24 | BOOL InputBoxOctal(HWND hwndOwner, LPCTSTR strTitle, WORD* pValue); 25 | 26 | BOOL ShowSaveDialog(HWND hwndOwner, LPCTSTR strTitle, LPCTSTR strFilter, LPCTSTR strDefExt, TCHAR* bufFileName); 27 | BOOL ShowOpenDialog(HWND hwndOwner, LPCTSTR strTitle, LPCTSTR strFilter, TCHAR* bufFileName); 28 | 29 | void ShowLoadBinDialog(); 30 | 31 | void ShowSettingsDialog(); 32 | BOOL ShowSettingsColorsDialog(); 33 | 34 | 35 | ////////////////////////////////////////////////////////////////////// 36 | -------------------------------------------------------------------------------- /emulator/Emulator.h: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // Emulator.h 12 | 13 | #pragma once 14 | 15 | #include "emubase/Board.h" 16 | 17 | ////////////////////////////////////////////////////////////////////// 18 | 19 | 20 | const int MAX_BREAKPOINTCOUNT = 16; 21 | const int MAX_WATCHESCOUNT = 16; 22 | 23 | extern CMotherboard* g_pBoard; 24 | extern BKConfiguration g_nEmulatorConfiguration; // Current configuration 25 | extern bool g_okEmulatorRunning; 26 | 27 | extern uint8_t* g_pEmulatorRam; // RAM values - for change tracking 28 | extern uint8_t* g_pEmulatorChangedRam; // RAM change flags 29 | extern uint16_t g_wEmulatorCpuPC; // Current PC value 30 | extern uint16_t g_wEmulatorPrevCpuPC; // Previous PC value 31 | 32 | 33 | ////////////////////////////////////////////////////////////////////// 34 | 35 | 36 | bool Emulator_Init(); 37 | bool Emulator_InitConfiguration(BKConfiguration configuration); 38 | BKConfiguration Emulator_GetConfiguration(); 39 | LPCTSTR Emulator_GetConfigurationName(); 40 | void Emulator_Done(); 41 | 42 | bool Emulator_AddCPUBreakpoint(uint16_t address); 43 | bool Emulator_RemoveCPUBreakpoint(uint16_t address); 44 | void Emulator_SetTempCPUBreakpoint(uint16_t address); 45 | const uint16_t* Emulator_GetCPUBreakpointList(); 46 | bool Emulator_IsBreakpoint(); 47 | bool Emulator_IsBreakpoint(uint16_t address); 48 | void Emulator_RemoveAllBreakpoints(); 49 | 50 | bool Emulator_AddWatch(uint16_t address); 51 | const uint16_t* Emulator_GetWatchList(); 52 | bool Emulator_RemoveWatch(uint16_t address); 53 | void Emulator_RemoveAllWatches(); 54 | 55 | void Emulator_SetSound(bool soundOnOff); 56 | void Emulator_SetCovox(bool covoxOnOff); 57 | void Emulator_SetSoundAY(bool onoff); 58 | void Emulator_Start(); 59 | void Emulator_Stop(); 60 | void Emulator_Reset(); 61 | bool Emulator_SystemFrame(); 62 | void Emulator_ProcessJoystick(); 63 | uint32_t Emulator_GetUptime(); // BK uptime, in seconds 64 | void Emulator_SetSpeed(uint16_t realspeed); 65 | 66 | void Emulator_GetScreenSize(int scrmode, int* pwid, int* phei); 67 | const uint32_t * Emulator_GetPalette(int screenMode); 68 | void Emulator_PrepareScreenRGB32(void* pBits, int screenMode); 69 | 70 | // Update cached values after Run or Step 71 | void Emulator_OnUpdate(); 72 | uint16_t Emulator_GetChangeRamStatus(uint16_t address); 73 | 74 | bool Emulator_SaveImage(LPCTSTR sFilePath); 75 | bool Emulator_LoadImage(LPCTSTR sFilePath); 76 | 77 | 78 | ////////////////////////////////////////////////////////////////////// 79 | -------------------------------------------------------------------------------- /emulator/Joystick.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // Joystick.cpp 12 | 13 | #include "stdafx.h" 14 | #include 15 | #include "Joystick.h" 16 | 17 | ////////////////////////////////////////////////////////////////////// 18 | 19 | 20 | int g_nJoystickCurrent = 0; // Number of current joystick: 1 or 2; 0 = none 21 | JOYCAPS g_JoystickCaps; // Capabilities of the current joystick 22 | 23 | 24 | ////////////////////////////////////////////////////////////////////// 25 | 26 | 27 | void Joystick_Init() 28 | { 29 | } 30 | void Joystick_Done() 31 | { 32 | } 33 | 34 | BOOL Joystick_SelectJoystick(int joystickNum) 35 | { 36 | if (joystickNum == 0) 37 | { 38 | g_nJoystickCurrent = 0; 39 | return TRUE; 40 | } 41 | 42 | UINT numDevs = joyGetNumDevs(); 43 | if (numDevs == 0) 44 | return FALSE; 45 | 46 | UINT joystick; 47 | if (joystickNum == 1) 48 | joystick = JOYSTICKID1; 49 | else if (joystickNum == 2) 50 | joystick = JOYSTICKID2; 51 | else 52 | return FALSE; 53 | 54 | MMRESULT result; 55 | JOYINFO joyinfo; 56 | result = joyGetPos(joystick, &joyinfo); 57 | if (result != JOYERR_NOERROR) 58 | return FALSE; 59 | result = joyGetDevCaps(joystick, &g_JoystickCaps, sizeof(g_JoystickCaps)); 60 | if (result != JOYERR_NOERROR) 61 | return FALSE; 62 | 63 | g_nJoystickCurrent = joystickNum; 64 | return TRUE; 65 | } 66 | 67 | UINT Joystick_GetJoystickState() 68 | { 69 | UINT joystick; 70 | if (g_nJoystickCurrent == 1) 71 | joystick = JOYSTICKID1; 72 | else if (g_nJoystickCurrent == 2) 73 | joystick = JOYSTICKID2; 74 | else 75 | return 0; 76 | 77 | JOYINFO joyinfo; 78 | MMRESULT result = joyGetPos(joystick, &joyinfo); 79 | if (result != JOYERR_NOERROR) 80 | return 0; 81 | 82 | UINT state = 0; 83 | // Buttons 84 | if (joyinfo.wButtons & JOY_BUTTON1) state |= JOYSTICK_BUTTON1; 85 | if (joyinfo.wButtons & JOY_BUTTON2) state |= JOYSTICK_BUTTON2; 86 | if (joyinfo.wButtons & JOY_BUTTON3) state |= JOYSTICK_BUTTON3; 87 | if (joyinfo.wButtons & JOY_BUTTON4) state |= JOYSTICK_BUTTON4; 88 | 89 | // Position 90 | UINT xCenter = (g_JoystickCaps.wXmax - g_JoystickCaps.wXmin) / 2 + g_JoystickCaps.wXmin; 91 | UINT xLeft = (g_JoystickCaps.wXmin + xCenter) / 2; 92 | UINT xRight = (g_JoystickCaps.wXmax + xCenter) / 2; 93 | if (joyinfo.wXpos < xLeft) state |= JOYSTICK_LEFT; 94 | if (joyinfo.wXpos > xRight) state |= JOYSTICK_RIGHT; 95 | 96 | UINT yCenter = (g_JoystickCaps.wYmax - g_JoystickCaps.wYmin) / 2 + g_JoystickCaps.wYmin; 97 | UINT yTop = (g_JoystickCaps.wYmin + yCenter) / 2; 98 | UINT yBottom = (g_JoystickCaps.wYmax + yCenter) / 2; 99 | if (joyinfo.wYpos < yTop) state |= JOYSTICK_UP; 100 | if (joyinfo.wYpos > yBottom) state |= JOYSTICK_DOWN; 101 | 102 | return state; 103 | } 104 | 105 | 106 | ////////////////////////////////////////////////////////////////////// 107 | -------------------------------------------------------------------------------- /emulator/Joystick.h: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // Joystick.h 12 | // 13 | 14 | #pragma once 15 | 16 | ////////////////////////////////////////////////////////////////////// 17 | 18 | 19 | // "Standard" SWCorp. joystick 20 | //#define JOYSTICK_BUTTON1 00001 21 | //#define JOYSTICK_BUTTON2 00002 22 | //#define JOYSTICK_BUTTON3 00004 23 | //#define JOYSTICK_BUTTON4 00010 24 | //#define JOYSTICK_RIGHT 00020 25 | //#define JOYSTICK_DOWN 00040 26 | //#define JOYSTICK_LEFT 01000 27 | //#define JOYSTICK_UP 02000 28 | 29 | // "Break House" joystick 30 | #define JOYSTICK_BUTTON1 0x01 31 | #define JOYSTICK_BUTTON2 0x02 32 | #define JOYSTICK_BUTTON3 0x04 33 | #define JOYSTICK_BUTTON4 0x08 34 | #define JOYSTICK_LEFT 0x10 35 | #define JOYSTICK_DOWN 0x20 36 | #define JOYSTICK_RIGHT 0x40 37 | #define JOYSTICK_UP 0x80 38 | 39 | void Joystick_Init(); 40 | void Joystick_Done(); 41 | 42 | BOOL Joystick_SelectJoystick(int joystickNum); 43 | UINT Joystick_GetJoystickState(); 44 | 45 | 46 | ////////////////////////////////////////////////////////////////////// 47 | -------------------------------------------------------------------------------- /emulator/Main.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // BKBTL.cpp : Defines the entry point for the application. 12 | 13 | #include "stdafx.h" 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "Main.h" 23 | #include "Emulator.h" 24 | #include "Views.h" 25 | #include "Joystick.h" 26 | #include "util/BitmapFile.h" 27 | 28 | 29 | ////////////////////////////////////////////////////////////////////// 30 | // Global Variables 31 | 32 | HINSTANCE g_hInst = NULL; // current instance 33 | HWND g_hwnd = NULL; 34 | long m_nMainLastFrameTicks = 0; 35 | 36 | 37 | ////////////////////////////////////////////////////////////////////// 38 | // Forward declarations 39 | 40 | BOOL InitInstance(HINSTANCE, int); 41 | void DoneInstance(); 42 | void ParseCommandLine(); 43 | 44 | LPCTSTR g_CommandLineHelp = 45 | _T("Usage: BKBTL [options]\r\n\r\n") 46 | _T("Command line options:\r\n\r\n") 47 | _T("/h /help\r\n\tShow command line options (this box)\r\n") 48 | _T("/autostart /autostarton\r\n\tStart emulation on window open\r\n") 49 | _T("/noautostart /autostartoff\r\n\tDo not start emulation on window open\r\n") 50 | _T("/debug /debugon /debugger\r\n\tSwitch to debug mode\r\n") 51 | _T("/nodebug /debugoff\r\n\tSwitch off the debug mode\r\n") 52 | _T("/sound /soundon\r\n\tTurn sound on\r\n") 53 | _T("/nosound /soundoff\r\n\tTurn sound off\r\n") 54 | _T("/diskN:filePath\r\n\tAttach disk image, N=0..3\r\n"); 55 | 56 | 57 | ////////////////////////////////////////////////////////////////////// 58 | 59 | 60 | int APIENTRY _tWinMain( 61 | HINSTANCE hInstance, 62 | HINSTANCE hPrevInstance, 63 | LPTSTR lpCmdLine, 64 | int nCmdShow) 65 | { 66 | UNREFERENCED_PARAMETER(hPrevInstance); 67 | UNREFERENCED_PARAMETER(lpCmdLine); 68 | 69 | #ifdef _DEBUG 70 | _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF); 71 | int n = 0; 72 | _CrtSetBreakAlloc(n); 73 | #endif 74 | 75 | g_hInst = hInstance; // Store instance handle in our global variable 76 | 77 | LARGE_INTEGER nFrameStartTime; 78 | nFrameStartTime.QuadPart = 0; 79 | 80 | // Initialize global strings 81 | LoadString(g_hInst, IDS_APP_TITLE, g_szTitle, MAX_LOADSTRING); 82 | LoadString(g_hInst, IDC_APPLICATION, g_szWindowClass, MAX_LOADSTRING); 83 | MainWindow_RegisterClass(); 84 | 85 | // Perform application initialization 86 | if (! InitInstance(hInstance, nCmdShow)) 87 | return FALSE; 88 | 89 | HACCEL hAccelTable = ::LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_APPLICATION)); 90 | 91 | if (Option_ShowHelp) 92 | ::PostMessage(g_hwnd, WM_COMMAND, ID_HELP_COMMAND_LINE_HELP, NULL); 93 | 94 | LARGE_INTEGER nPerformanceFrequency; 95 | ::QueryPerformanceFrequency(&nPerformanceFrequency); 96 | 97 | TIMECAPS caps; 98 | VERIFY(!::timeGetDevCaps(&caps, sizeof(caps))); 99 | VERIFY(!::timeBeginPeriod(caps.wPeriodMin)); 100 | 101 | // Main message loop 102 | MSG msg; 103 | for (;;) 104 | { 105 | ::QueryPerformanceCounter(&nFrameStartTime); 106 | 107 | if (!g_okEmulatorRunning) 108 | ::Sleep(1); 109 | else 110 | { 111 | if (!Emulator_SystemFrame()) // Breakpoint hit 112 | { 113 | Emulator_Stop(); 114 | // Turn on degugger if not yet 115 | if (!Settings_GetDebug()) 116 | ::PostMessage(g_hwnd, WM_COMMAND, ID_VIEW_DEBUG, 0); 117 | else 118 | ::FlashWindow(g_hwnd, TRUE); 119 | } 120 | 121 | ScreenView_RedrawScreen(); 122 | } 123 | 124 | // Process all queue 125 | while (::PeekMessage( &msg, NULL, 0, 0, PM_REMOVE )) 126 | { 127 | if (msg.message == WM_QUIT) 128 | goto endprog; 129 | 130 | if (::TranslateAccelerator(g_hwnd, hAccelTable, &msg)) 131 | continue; 132 | 133 | ::TranslateMessage(&msg); 134 | ::DispatchMessage(&msg); 135 | } 136 | 137 | if (g_okEmulatorRunning && !Settings_GetSound()) 138 | { 139 | WORD speed = Settings_GetRealSpeed(); 140 | if (speed == 0) 141 | ::Sleep(0); // Speed MAX, consume 100% of one CPU core 142 | else 143 | { 144 | LONGLONG nFrameDelay; 145 | switch (speed) 146 | { 147 | case 0x7ffd: nFrameDelay = 1000ll / FRAMERATE * 10; break; // Speed 10% 148 | case 0x7ffe: nFrameDelay = 1000ll / FRAMERATE * 4; break; // Speed 25% 149 | case 0x7fff: nFrameDelay = 1000ll / FRAMERATE * 2; break; // Speed 50% 150 | case 2: nFrameDelay = 1000ll / FRAMERATE / 2; break; // Speed 200% 151 | case 3: nFrameDelay = 1000ll / FRAMERATE / 4; break; // Speed 400% 152 | default: // Speed 100% 153 | nFrameDelay = 1000ll / FRAMERATE; // 1000 millisec / 50 = 20 millisec 154 | break; 155 | } 156 | 157 | for (;;) 158 | { 159 | LARGE_INTEGER nFrameFinishTime; // Frame start time 160 | ::QueryPerformanceCounter(&nFrameFinishTime); 161 | LONGLONG nTimeElapsed = (nFrameFinishTime.QuadPart - nFrameStartTime.QuadPart) 162 | * 1000ll / nPerformanceFrequency.QuadPart; 163 | if (nTimeElapsed <= 0 || nTimeElapsed >= nFrameDelay) 164 | break; 165 | LONGLONG nDelayRemaining = nFrameDelay - nTimeElapsed; 166 | ::Sleep((DWORD)(nDelayRemaining / 2)); 167 | } 168 | } 169 | } 170 | 171 | //// Time bomb for perfomance analysis 172 | //if (Emulator_GetUptime() >= 300) // 5 minutes 173 | // ::PostQuitMessage(0); 174 | } 175 | endprog: 176 | 177 | ::timeEndPeriod(caps.wPeriodMin); 178 | DoneInstance(); 179 | 180 | #ifdef _DEBUG 181 | if (_CrtDumpMemoryLeaks()) 182 | ::MessageBeep(MB_ICONEXCLAMATION); 183 | #endif 184 | 185 | return (int) msg.wParam; 186 | } 187 | 188 | 189 | // 190 | // FUNCTION: InitInstance(HINSTANCE, int) 191 | // 192 | // PURPOSE: Saves instance handle and creates main window 193 | // 194 | // COMMENTS: 195 | // 196 | // In this function, we save the instance handle in a global variable and 197 | // create and display the main program window. 198 | // 199 | BOOL InitInstance(HINSTANCE /*hInstance*/, int /*nCmdShow*/) 200 | { 201 | INITCOMMONCONTROLSEX ics; ics.dwSize = sizeof(ics); 202 | ics.dwICC = ICC_WIN95_CLASSES; 203 | InitCommonControlsEx(&ics); 204 | 205 | BitmapFile_Init(); 206 | 207 | #if !defined(PRODUCT) 208 | DebugLogClear(); 209 | #endif 210 | Settings_Init(); 211 | Joystick_Init(); 212 | Joystick_SelectJoystick(Settings_GetJoystick()); 213 | 214 | ParseCommandLine(); // Override settings by command-line option if needed 215 | 216 | if (!Emulator_Init()) 217 | return FALSE; 218 | 219 | int conf = Settings_GetConfiguration(); 220 | if (conf == 0) conf = BK_CONF_BK0010_BASIC; 221 | if (!Emulator_InitConfiguration((BKConfiguration)conf)) 222 | return FALSE; 223 | 224 | Emulator_SetSound(Settings_GetSound() != 0); 225 | Emulator_SetSpeed(Settings_GetRealSpeed()); 226 | Emulator_SetCovox(Settings_GetSoundCovox() != 0); 227 | Emulator_SetSoundAY(Settings_GetSoundAY() != 0); 228 | 229 | if (!CreateMainWindow()) 230 | return FALSE; 231 | 232 | return TRUE; 233 | } 234 | 235 | // Instance finalization 236 | void DoneInstance() 237 | { 238 | ScreenView_Done(); 239 | DisasmView_Done(); 240 | 241 | Emulator_Done(); 242 | 243 | Joystick_Done(); 244 | 245 | BitmapFile_Done(); 246 | 247 | Settings_Done(); 248 | } 249 | 250 | void ParseCommandLine() 251 | { 252 | LPTSTR commandline = ::GetCommandLine(); 253 | 254 | int argnum = 0; 255 | LPTSTR* args = CommandLineToArgvW(commandline, &argnum); 256 | 257 | for (int curargn = 1; curargn < argnum; curargn++) 258 | { 259 | LPTSTR arg = args[curargn]; 260 | 261 | if (_tcscmp(arg, _T("/help")) == 0 || _tcscmp(arg, _T("/h")) == 0) 262 | { 263 | Option_ShowHelp = true; 264 | } 265 | else if (_tcscmp(arg, _T("/autostart")) == 0 || _tcscmp(arg, _T("/autostarton")) == 0) 266 | { 267 | Settings_SetAutostart(TRUE); 268 | } 269 | else if (_tcscmp(arg, _T("/autostartoff")) == 0 || _tcscmp(arg, _T("/noautostart")) == 0) 270 | { 271 | Settings_SetAutostart(FALSE); 272 | } 273 | else if (_tcscmp(arg, _T("/debug")) == 0 || _tcscmp(arg, _T("/debugon")) == 0 || _tcscmp(arg, _T("/debugger")) == 0) 274 | { 275 | Settings_SetDebug(TRUE); 276 | } 277 | else if (_tcscmp(arg, _T("/debugoff")) == 0 || _tcscmp(arg, _T("/nodebug")) == 0) 278 | { 279 | Settings_SetDebug(FALSE); 280 | } 281 | else if (_tcscmp(arg, _T("/sound")) == 0 || _tcscmp(arg, _T("/soundon")) == 0) 282 | { 283 | Settings_SetSound(TRUE); 284 | } 285 | else if (_tcscmp(arg, _T("/soundoff")) == 0 || _tcscmp(arg, _T("/nosound")) == 0) 286 | { 287 | Settings_SetSound(FALSE); 288 | } 289 | else if (_tcslen(arg) > 7 && _tcsncmp(arg, _T("/disk"), 5) == 0) // "/diskN:filePath", N=A..D 290 | { 291 | if (arg[5] >= _T('A') && arg[5] <= _T('D') && arg[6] == ':') 292 | { 293 | int slot = arg[5] - _T('A'); 294 | LPCTSTR filePath = arg + 7; 295 | Settings_SetFloppyFilePath(slot, filePath); 296 | } 297 | } 298 | //TODO: "/state:filepath" 299 | } 300 | 301 | ::LocalFree(args); 302 | } 303 | 304 | 305 | ////////////////////////////////////////////////////////////////////// 306 | -------------------------------------------------------------------------------- /emulator/Main.h: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | #pragma once 12 | 13 | #include "res/resource.h" 14 | 15 | ////////////////////////////////////////////////////////////////////// 16 | 17 | 18 | #define FRAMERATE 25 // Количество фремов в секунду 19 | 20 | #define MAX_LOADSTRING 100 21 | 22 | extern TCHAR g_szTitle[MAX_LOADSTRING]; // The title bar text 23 | extern TCHAR g_szWindowClass[MAX_LOADSTRING]; // Main window class name 24 | 25 | extern HINSTANCE g_hInst; // current instance 26 | 27 | 28 | ////////////////////////////////////////////////////////////////////// 29 | // Main Window 30 | 31 | extern HWND g_hwnd; // Main window handle 32 | 33 | extern LPCTSTR g_CommandLineHelp; 34 | 35 | void MainWindow_RegisterClass(); 36 | BOOL CreateMainWindow(); 37 | void MainWindow_RestoreSettings(); 38 | void MainWindow_UpdateMenu(); 39 | void MainWindow_UpdateWindowTitle(); 40 | void MainWindow_UpdateAllViews(); 41 | BOOL MainWindow_InitToolbar(); 42 | BOOL MainWindow_InitStatusbar(); 43 | void MainWindow_ShowHideDebug(); 44 | void MainWindow_ShowHideToolbar(); 45 | void MainWindow_ShowHideKeyboard(); 46 | void MainWindow_ShowHideTape(); 47 | void MainWindow_ShowHideMemoryMap(); 48 | void MainWindow_ShowHideSpriteViewer(); 49 | void MainWindow_AdjustWindowSize(); 50 | 51 | void MainWindow_SetToolbarImage(int commandId, int imageIndex); 52 | void MainWindow_SetStatusbarText(int part, LPCTSTR message); 53 | void MainWindow_SetStatusbarBitmap(int part, UINT resourceId); 54 | void MainWindow_SetStatusbarIcon(int part, HICON hIcon); 55 | 56 | enum ToolbarButtons 57 | { 58 | ToolbarButtonRun = 0, 59 | ToolbarButtonReset = 1, 60 | // Separator 61 | ToolbarButtonDiskA = 3, 62 | ToolbarButtonDiskB = 4, 63 | ToolbarButtonDiskC = 5, 64 | ToolbarButtonDiskD = 6, 65 | // Separator 66 | ToolbarButtonColor = 8, 67 | ToolbarButtonSound = 9, 68 | ToolbarButtonScreenshot = 10, 69 | }; 70 | 71 | enum ToolbarButtonImages 72 | { 73 | ToolbarImageRun = 0, 74 | ToolbarImagePause = 1, 75 | ToolbarImageReset = 2, 76 | ToolbarImageFloppyDisk = 3, 77 | ToolbarImageFloppySlot = 4, 78 | ToolbarImageCartridge = 5, 79 | ToolbarImageCartSlot = 6, 80 | ToolbarImageSoundOn = 7, 81 | ToolbarImageSoundOff = 8, 82 | ToolbarImageFloppyDiskWP = 9, 83 | ToolbarImageColorScreen = 10, 84 | ToolbarImageBWScreen = 11, 85 | ToolbarImageScreenshot = 12, 86 | ToolbarImageDebugger = 14, 87 | ToolbarImageStepInto = 15, 88 | ToolbarImageStepOver = 16, 89 | ToolbarImageWordByte = 18, 90 | ToolbarImageGotoAddress = 19, 91 | ToolbarImageSpriteViewer = 20, 92 | ToolbarImageHexMode = 21, 93 | }; 94 | 95 | enum StatusbarParts 96 | { 97 | StatusbarPartMessage = 0, 98 | StatusbarPartSound = 1, 99 | StatusbarPartFloppyEngine = 2, 100 | StatusbarPartFPS = 3, 101 | StatusbarPartUptime = 4, 102 | }; 103 | 104 | 105 | enum ColorIndices 106 | { 107 | ColorDebugText = 0, 108 | ColorDebugBackCurrent = 1, 109 | ColorDebugValueChanged = 2, 110 | ColorDebugPrevious = 3, 111 | ColorDebugMemoryRom = 4, 112 | ColorDebugMemoryIO = 5, 113 | ColorDebugMemoryNA = 6, 114 | ColorDebugValue = 7, 115 | ColorDebugValueRom = 8, 116 | ColorDebugSubtitles = 9, 117 | ColorDebugJump = 10, 118 | ColorDebugJumpYes = 11, 119 | ColorDebugJumpNo = 12, 120 | ColorDebugJumpHint = 13, 121 | ColorDebugHint = 14, 122 | ColorDebugBreakpoint = 15, 123 | ColorDebugHighlight = 16, 124 | ColorDebugBreakptZone = 17, 125 | 126 | ColorIndicesCount = 18, 127 | }; 128 | 129 | 130 | ////////////////////////////////////////////////////////////////////// 131 | // Settings 132 | 133 | void Settings_Init(); 134 | void Settings_Done(); 135 | BOOL Settings_GetWindowRect(RECT * pRect); 136 | void Settings_SetWindowRect(const RECT * pRect); 137 | void Settings_SetWindowMaximized(BOOL flag); 138 | BOOL Settings_GetWindowMaximized(); 139 | void Settings_SetConfiguration(int configuration); 140 | int Settings_GetConfiguration(); 141 | void Settings_SetFloppyFilePath(int slot, LPCTSTR sFilePath); 142 | void Settings_GetFloppyFilePath(int slot, LPTSTR buffer); 143 | void Settings_SetScreenViewMode(int mode); 144 | int Settings_GetScreenViewMode(); 145 | void Settings_SetScreenHeightMode(int mode); 146 | int Settings_GetScreenHeightMode(); 147 | void Settings_SetDebug(BOOL flag); 148 | BOOL Settings_GetDebug(); 149 | void Settings_GetDebugFontName(LPTSTR buffer); 150 | void Settings_SetDebugFontName(LPCTSTR sFontName); 151 | WORD Settings_GetDebugBreakpoint(int bpno); 152 | void Settings_SetDebugBreakpoint(int bpno, WORD address); 153 | void Settings_SetDebugMemoryAddress(WORD address); 154 | WORD Settings_GetDebugMemoryAddress(); 155 | void Settings_SetDebugMemoryBase(WORD address); 156 | WORD Settings_GetDebugMemoryBase(); 157 | BOOL Settings_GetDebugMemoryByte(); 158 | void Settings_SetDebugMemoryByte(BOOL flag); 159 | void Settings_SetDebugMemoryNumeral(WORD mode); 160 | WORD Settings_GetDebugMemoryNumeral(); 161 | void Settings_SetAutostart(BOOL flag); 162 | BOOL Settings_GetAutostart(); 163 | void Settings_SetRealSpeed(WORD speed); 164 | WORD Settings_GetRealSpeed(); 165 | void Settings_SetSound(BOOL flag); 166 | BOOL Settings_GetSound(); 167 | void Settings_SetSoundVolume(WORD value); 168 | WORD Settings_GetSoundVolume(); 169 | void Settings_SetSoundCovox(BOOL flag); 170 | BOOL Settings_GetSoundCovox(); 171 | void Settings_SetSoundAY(BOOL flag); 172 | BOOL Settings_GetSoundAY(); 173 | void Settings_SetJoystick(int joystick); 174 | int Settings_GetJoystick(); 175 | void Settings_SetToolbar(BOOL flag); 176 | BOOL Settings_GetToolbar(); 177 | void Settings_SetKeyboard(BOOL flag); 178 | BOOL Settings_GetKeyboard(); 179 | void Settings_SetTape(BOOL flag); 180 | BOOL Settings_GetTape(); 181 | void Settings_SetMemoryMap(BOOL flag); 182 | BOOL Settings_GetMemoryMap(); 183 | WORD Settings_GetSpriteAddress(); 184 | void Settings_SetSpriteAddress(WORD value); 185 | WORD Settings_GetSpriteWidth(); 186 | void Settings_SetSpriteWidth(WORD value); 187 | 188 | LPCTSTR Settings_GetColorFriendlyName(ColorIndices colorIndex); 189 | COLORREF Settings_GetColor(ColorIndices colorIndex); 190 | COLORREF Settings_GetDefaultColor(ColorIndices colorIndex); 191 | void Settings_SetColor(ColorIndices colorIndex, COLORREF color); 192 | 193 | 194 | ////////////////////////////////////////////////////////////////////// 195 | // Options 196 | 197 | extern bool Option_ShowHelp; 198 | 199 | 200 | ////////////////////////////////////////////////////////////////////// 201 | -------------------------------------------------------------------------------- /emulator/MemoryMapView.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // MemoryMapView.cpp 12 | 13 | #include "stdafx.h" 14 | #include 15 | #include "Main.h" 16 | #include "Views.h" 17 | #include "ToolWindow.h" 18 | #include "Emulator.h" 19 | 20 | ////////////////////////////////////////////////////////////////////// 21 | 22 | 23 | HWND g_hwndMemoryMap = (HWND)INVALID_HANDLE_VALUE; // MemoryMap view window handler 24 | WNDPROC m_wndprocMemoryMapToolWindow = NULL; // Old window proc address of the ToolWindow 25 | 26 | HWND m_hwndMemoryMapViewer = (HWND)INVALID_HANDLE_VALUE; 27 | HDRAWDIB m_hMemoryMapDrawDib = NULL; 28 | BITMAPINFO m_bmpinfoMemoryMap; 29 | HBITMAP m_hMemoryMapBitmap = NULL; 30 | DWORD * m_pMemoryMap_bits = NULL; 31 | 32 | const int m_nMemoryMap_ViewCX = 256; 33 | const int m_nMemoryMap_ViewCY = 256; 34 | 35 | int m_nMemoryMap_xpos = 0; 36 | int m_nMemoryMap_ypos = 0; 37 | int m_nMemoryMap_scale = 1; 38 | 39 | void MemoryMapView_OnDraw(HDC hdc); 40 | BOOL MemoryMapView_OnKeyDown(WPARAM vkey, LPARAM lParam); 41 | BOOL MemoryMapView_OnVScroll(WPARAM wParam, LPARAM lParam); 42 | BOOL MemoryMapView_OnHScroll(WPARAM wParam, LPARAM lParam); 43 | BOOL MemoryMapView_OnMouseWheel(WPARAM wParam, LPARAM lParam); 44 | void MemoryMapView_InitBitmap(); 45 | void MemoryMapView_DoneBitmap(); 46 | void MemoryMapView_PrepareBitmap(); 47 | void MemoryMapView_Zoom(BOOL inout); 48 | void MemoryMapView_Scroll(int dx, int dy); 49 | void MemoryMapView_UpdateScrollPos(); 50 | 51 | 52 | ////////////////////////////////////////////////////////////////////// 53 | 54 | 55 | void MemoryMapView_RegisterClass() 56 | { 57 | WNDCLASSEX wcex; 58 | wcex.cbSize = sizeof(WNDCLASSEX); 59 | 60 | wcex.style = CS_HREDRAW | CS_VREDRAW; 61 | wcex.lpfnWndProc = MemoryMapViewViewerWndProc; 62 | wcex.cbClsExtra = 0; 63 | wcex.cbWndExtra = 0; 64 | wcex.hInstance = g_hInst; 65 | wcex.hIcon = NULL; 66 | wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 67 | wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 68 | wcex.lpszMenuName = NULL; 69 | wcex.lpszClassName = CLASSNAME_MEMORYMAPVIEW; 70 | wcex.hIconSm = NULL; 71 | 72 | RegisterClassEx(&wcex); 73 | } 74 | 75 | void MemoryMapView_Create(HWND hwndParent, int x, int y) 76 | { 77 | int cxScroll = ::GetSystemMetrics(SM_CXVSCROLL); 78 | int cyScroll = ::GetSystemMetrics(SM_CYHSCROLL); 79 | int cyCaption = TOOLWINDOW_CAPTION_HEIGHT; 80 | 81 | int width = m_nMemoryMap_ViewCX + cxScroll; 82 | int height = m_nMemoryMap_ViewCY + cyScroll + cyCaption; 83 | g_hwndMemoryMap = CreateWindow( 84 | CLASSNAME_TOOLWINDOW, _T("Memory Map"), 85 | WS_CHILD | WS_VISIBLE, 86 | x, y, width, height, 87 | hwndParent, NULL, g_hInst, NULL); 88 | 89 | // ToolWindow subclassing 90 | m_wndprocMemoryMapToolWindow = (WNDPROC)LongToPtr( SetWindowLongPtr( 91 | g_hwndMemoryMap, GWLP_WNDPROC, PtrToLong(MemoryMapViewWndProc)) ); 92 | 93 | RECT rcClient; GetClientRect(g_hwndMemoryMap, &rcClient); 94 | 95 | m_hwndMemoryMapViewer = CreateWindow( 96 | CLASSNAME_MEMORYMAPVIEW, NULL, 97 | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | WS_TABSTOP, 98 | 0, 0, rcClient.right, rcClient.bottom, 99 | g_hwndMemoryMap, NULL, g_hInst, NULL); 100 | 101 | MemoryMapView_InitBitmap(); 102 | MemoryMapView_UpdateScrollPos(); 103 | } 104 | 105 | void MemoryMapView_InitBitmap() 106 | { 107 | m_hMemoryMapDrawDib = DrawDibOpen(); 108 | HDC hdc = ::GetDC(g_hwnd); 109 | 110 | m_bmpinfoMemoryMap.bmiHeader.biSize = sizeof( BITMAPINFOHEADER ); 111 | m_bmpinfoMemoryMap.bmiHeader.biWidth = 256; 112 | m_bmpinfoMemoryMap.bmiHeader.biHeight = 256; 113 | m_bmpinfoMemoryMap.bmiHeader.biPlanes = 1; 114 | m_bmpinfoMemoryMap.bmiHeader.biBitCount = 32; 115 | m_bmpinfoMemoryMap.bmiHeader.biCompression = BI_RGB; 116 | m_bmpinfoMemoryMap.bmiHeader.biSizeImage = 0; 117 | m_bmpinfoMemoryMap.bmiHeader.biXPelsPerMeter = 0; 118 | m_bmpinfoMemoryMap.bmiHeader.biYPelsPerMeter = 0; 119 | m_bmpinfoMemoryMap.bmiHeader.biClrUsed = 0; 120 | m_bmpinfoMemoryMap.bmiHeader.biClrImportant = 0; 121 | 122 | m_hMemoryMapBitmap = CreateDIBSection( hdc, &m_bmpinfoMemoryMap, DIB_RGB_COLORS, (void **)&m_pMemoryMap_bits, NULL, 0 ); 123 | 124 | VERIFY(::ReleaseDC(g_hwnd, hdc)); 125 | } 126 | 127 | void MemoryMapView_DoneBitmap() 128 | { 129 | if (m_hMemoryMapBitmap != NULL) 130 | { 131 | VERIFY(::DeleteObject(m_hMemoryMapBitmap)); m_hMemoryMapBitmap = NULL; 132 | } 133 | 134 | DrawDibClose( m_hMemoryMapDrawDib ); 135 | } 136 | 137 | LRESULT CALLBACK MemoryMapViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 138 | { 139 | UNREFERENCED_PARAMETER(lParam); 140 | switch (message) 141 | { 142 | case WM_SETFOCUS: 143 | ::SetFocus(m_hwndMemoryMapViewer); 144 | break; 145 | case WM_DESTROY: 146 | g_hwndMemoryMap = (HWND) INVALID_HANDLE_VALUE; // We are closed! Bye-bye!.. 147 | return CallWindowProc(m_wndprocMemoryMapToolWindow, hWnd, message, wParam, lParam); 148 | default: 149 | return CallWindowProc(m_wndprocMemoryMapToolWindow, hWnd, message, wParam, lParam); 150 | } 151 | return (LRESULT)FALSE; 152 | } 153 | 154 | LRESULT CALLBACK MemoryMapViewViewerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 155 | { 156 | UNREFERENCED_PARAMETER(lParam); 157 | switch (message) 158 | { 159 | case WM_PAINT: 160 | { 161 | PAINTSTRUCT ps; 162 | HDC hdc = BeginPaint(hWnd, &ps); 163 | 164 | MemoryMapView_OnDraw(hdc); // Draw memory dump 165 | 166 | EndPaint(hWnd, &ps); 167 | } 168 | break; 169 | case WM_DESTROY: 170 | // Free resources 171 | MemoryMapView_DoneBitmap(); 172 | return DefWindowProc(hWnd, message, wParam, lParam); 173 | case WM_LBUTTONDOWN: 174 | SetFocus(hWnd); 175 | break; 176 | case WM_KEYDOWN: 177 | return (LRESULT) MemoryMapView_OnKeyDown(wParam, lParam); 178 | case WM_HSCROLL: 179 | return (LRESULT) MemoryMapView_OnHScroll(wParam, lParam); 180 | case WM_VSCROLL: 181 | return (LRESULT) MemoryMapView_OnVScroll(wParam, lParam); 182 | case WM_MOUSEWHEEL: 183 | return (LRESULT) MemoryMapView_OnMouseWheel(wParam, lParam); 184 | default: 185 | return DefWindowProc(hWnd, message, wParam, lParam); 186 | } 187 | return (LRESULT)FALSE; 188 | } 189 | 190 | void MemoryMapView_Zoom(BOOL inout) 191 | { 192 | if (inout) 193 | { 194 | if (m_nMemoryMap_scale >= 40) 195 | return; 196 | m_nMemoryMap_scale += 1; 197 | } 198 | else 199 | { 200 | if (m_nMemoryMap_scale <= 2) 201 | return; 202 | m_nMemoryMap_scale -= 1; 203 | } 204 | 205 | InvalidateRect(m_hwndMemoryMapViewer, NULL, FALSE); 206 | MemoryMapView_UpdateScrollPos(); 207 | } 208 | void MemoryMapView_ScrollTo(int newxpos, int newypos) 209 | { 210 | int maxxpos = 256 - m_nMemoryMap_ViewCX / m_nMemoryMap_scale; 211 | int maxypos = 256 - m_nMemoryMap_ViewCY / m_nMemoryMap_scale; 212 | if (newxpos < 0) newxpos = 0; 213 | if (newxpos > maxxpos) newxpos = maxxpos; 214 | if (newypos < 0) newypos = 0; 215 | if (newypos > maxypos) newypos = maxypos; 216 | 217 | m_nMemoryMap_xpos = newxpos; 218 | m_nMemoryMap_ypos = newypos; 219 | 220 | InvalidateRect(m_hwndMemoryMapViewer, NULL, TRUE); 221 | 222 | MemoryMapView_UpdateScrollPos(); 223 | } 224 | void MemoryMapView_Scroll(int dx, int dy) 225 | { 226 | int newxpos = m_nMemoryMap_xpos + dx; 227 | int newypos = m_nMemoryMap_ypos + dy; 228 | MemoryMapView_ScrollTo(newxpos, newypos); 229 | } 230 | 231 | BOOL MemoryMapView_OnMouseWheel(WPARAM wParam, LPARAM /*lParam*/) 232 | { 233 | short zDelta = GET_WHEEL_DELTA_WPARAM(wParam); 234 | 235 | MemoryMapView_Scroll(0, (zDelta > 0) ? -24 : 24); 236 | 237 | return FALSE; 238 | } 239 | 240 | BOOL MemoryMapView_OnKeyDown(WPARAM vkey, LPARAM /*lParam*/) 241 | { 242 | switch (vkey) 243 | { 244 | case VK_OEM_MINUS: 245 | MemoryMapView_Zoom(FALSE); 246 | break; 247 | case VK_OEM_PLUS: 248 | MemoryMapView_Zoom(TRUE); 249 | break; 250 | case VK_LEFT: 251 | MemoryMapView_Scroll(-2, 0); 252 | break; 253 | case VK_RIGHT: 254 | MemoryMapView_Scroll(2, 0); 255 | break; 256 | case VK_UP: 257 | MemoryMapView_Scroll(0, -2); 258 | break; 259 | case VK_DOWN: 260 | MemoryMapView_Scroll(0, 2); 261 | break; 262 | default: 263 | return TRUE; 264 | } 265 | return FALSE; 266 | } 267 | 268 | BOOL MemoryMapView_OnHScroll(WPARAM wParam, LPARAM /*lParam*/) 269 | { 270 | WORD scrollpos = HIWORD(wParam); 271 | WORD scrollcmd = LOWORD(wParam); 272 | switch (scrollcmd) 273 | { 274 | case SB_LINEDOWN: 275 | MemoryMapView_Scroll(8, 0); 276 | break; 277 | case SB_LINEUP: 278 | MemoryMapView_Scroll(-8, 0); 279 | break; 280 | case SB_PAGEDOWN: 281 | MemoryMapView_Scroll(m_nMemoryMap_ViewCX / m_nMemoryMap_scale, 0); 282 | break; 283 | case SB_PAGEUP: 284 | MemoryMapView_Scroll(-m_nMemoryMap_ViewCX / m_nMemoryMap_scale, 0); 285 | break; 286 | case SB_THUMBPOSITION: 287 | MemoryMapView_ScrollTo(scrollpos, m_nMemoryMap_ypos); 288 | break; 289 | } 290 | 291 | return FALSE; 292 | } 293 | 294 | BOOL MemoryMapView_OnVScroll(WPARAM wParam, LPARAM /*lParam*/) 295 | { 296 | WORD scrollpos = HIWORD(wParam); 297 | WORD scrollcmd = LOWORD(wParam); 298 | switch (scrollcmd) 299 | { 300 | case SB_LINEDOWN: 301 | MemoryMapView_Scroll(0, 8); 302 | break; 303 | case SB_LINEUP: 304 | MemoryMapView_Scroll(0, -8); 305 | break; 306 | case SB_PAGEDOWN: 307 | MemoryMapView_Scroll(0, m_nMemoryMap_ViewCY / m_nMemoryMap_scale); 308 | break; 309 | case SB_PAGEUP: 310 | MemoryMapView_Scroll(0, -m_nMemoryMap_ViewCY / m_nMemoryMap_scale); 311 | break; 312 | case SB_THUMBPOSITION: 313 | MemoryMapView_ScrollTo(m_nMemoryMap_xpos, scrollpos); 314 | break; 315 | } 316 | 317 | return FALSE; 318 | } 319 | 320 | void MemoryMapView_OnDraw(HDC hdc) 321 | { 322 | ASSERT(g_pBoard != NULL); 323 | 324 | MemoryMapView_PrepareBitmap(); 325 | 326 | DrawDibDraw(m_hMemoryMapDrawDib, hdc, 327 | -m_nMemoryMap_xpos * m_nMemoryMap_scale, -m_nMemoryMap_ypos * m_nMemoryMap_scale, 328 | 256 * m_nMemoryMap_scale, 256 * m_nMemoryMap_scale, 329 | &m_bmpinfoMemoryMap.bmiHeader, m_pMemoryMap_bits, 0, 0, 330 | 256, 256, 331 | 0); 332 | } 333 | 334 | void MemoryMapView_RedrawMap() 335 | { 336 | if (g_hwndMemoryMap == (HWND)INVALID_HANDLE_VALUE) return; 337 | 338 | MemoryMapView_PrepareBitmap(); 339 | 340 | HDC hdc = GetDC(g_hwndMemoryMap); 341 | MemoryMapView_OnDraw(hdc); 342 | VERIFY(::ReleaseDC(g_hwndMemoryMap, hdc)); 343 | } 344 | 345 | void MemoryMapView_UpdateScrollPos() 346 | { 347 | SCROLLINFO siH; 348 | ZeroMemory(&siH, sizeof(siH)); 349 | siH.cbSize = sizeof(siH); 350 | siH.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL; 351 | siH.nPage = m_nMemoryMap_ViewCX / m_nMemoryMap_scale; 352 | siH.nPos = m_nMemoryMap_xpos; 353 | siH.nMin = 0; 354 | siH.nMax = 256 - 1; 355 | SetScrollInfo(m_hwndMemoryMapViewer, SB_HORZ, &siH, TRUE); 356 | 357 | SCROLLINFO siV; 358 | ZeroMemory(&siV, sizeof(siV)); 359 | siV.cbSize = sizeof(siV); 360 | siV.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL; 361 | siV.nPage = m_nMemoryMap_ViewCY / m_nMemoryMap_scale; 362 | siV.nPos = m_nMemoryMap_ypos; 363 | siV.nMin = 0; 364 | siV.nMax = 256 - 1; 365 | SetScrollInfo(m_hwndMemoryMapViewer, SB_VERT, &siV, TRUE); 366 | } 367 | 368 | void MemoryMapView_PrepareBitmap() 369 | { 370 | for (int y = 0; y < 256; y += 1) 371 | { 372 | DWORD* pBits = m_pMemoryMap_bits + (256 - 1 - y) * 256; 373 | for (int x = 0; x < 256; x += 2) 374 | { 375 | WORD address = (WORD)(x + y * 256); 376 | int addrtype; 377 | WORD value = g_pBoard->GetWordView(address, FALSE, FALSE, &addrtype); 378 | COLORREF color1, color2; 379 | BYTE val; 380 | switch (addrtype & ADDRTYPE_MASK) 381 | { 382 | case ADDRTYPE_IO: 383 | color1 = color2 = RGB(128, 0, 128); 384 | break; 385 | case ADDRTYPE_DENY: 386 | color1 = color2 = RGB(0, 0, 128); 387 | break; 388 | case ADDRTYPE_ROM: 389 | val = (value & 0xff00) >> 8; 390 | color1 = RGB(192, val, val); 391 | val = value & 0x00ff; 392 | color2 = RGB(192, val, val); 393 | break; 394 | case ADDRTYPE_RAM: 395 | val = (value & 0xff00) >> 8; 396 | color1 = RGB(val, val, val); 397 | val = value & 0x00ff; 398 | color2 = RGB(val, val, val); 399 | break; 400 | default: 401 | color1 = color2 = RGB(0, 0, 0); 402 | break; 403 | } 404 | 405 | *pBits = color1; 406 | pBits++; 407 | *pBits = color2; 408 | pBits++; 409 | } 410 | } 411 | } 412 | 413 | 414 | ////////////////////////////////////////////////////////////////////// 415 | 416 | -------------------------------------------------------------------------------- /emulator/Settings.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // Settings.cpp 12 | 13 | #include "stdafx.h" 14 | #include "Main.h" 15 | 16 | ////////////////////////////////////////////////////////////////////// 17 | 18 | 19 | const TCHAR m_Settings_IniAppName[] = _T("BKBTL"); 20 | TCHAR m_Settings_IniPath[MAX_PATH]; 21 | 22 | 23 | ////////////////////////////////////////////////////////////////////// 24 | // Options 25 | 26 | bool Option_ShowHelp = false; 27 | 28 | 29 | ////////////////////////////////////////////////////////////////////// 30 | 31 | 32 | void Settings_Init() 33 | { 34 | // Prepare m_Settings_IniPath: get .exe file path and change extension to .ini 35 | ::GetModuleFileName(GetModuleHandle(NULL), m_Settings_IniPath, MAX_PATH); 36 | TCHAR* pExt = m_Settings_IniPath + _tcslen(m_Settings_IniPath) - 3; 37 | *pExt++ = _T('i'); 38 | *pExt++ = _T('n'); 39 | *pExt = _T('i'); 40 | } 41 | void Settings_Done() 42 | { 43 | } 44 | 45 | BOOL Settings_SaveStringValue(LPCTSTR sName, LPCTSTR sValue) 46 | { 47 | BOOL result = WritePrivateProfileString( 48 | m_Settings_IniAppName, sName, sValue, m_Settings_IniPath); 49 | return result; 50 | } 51 | BOOL Settings_LoadStringValue(LPCTSTR sName, LPTSTR sBuffer, int nBufferLengthChars) 52 | { 53 | DWORD result = GetPrivateProfileString( 54 | m_Settings_IniAppName, sName, NULL, sBuffer, nBufferLengthChars, m_Settings_IniPath); 55 | if (result > 0) 56 | return TRUE; 57 | 58 | sBuffer[0] = _T('\0'); 59 | return FALSE; 60 | } 61 | 62 | BOOL Settings_SaveDwordValue(LPCTSTR sName, DWORD dwValue) 63 | { 64 | TCHAR buffer[12]; 65 | _sntprintf(buffer, sizeof(buffer) / sizeof(TCHAR) - 1, _T("%lu"), dwValue); 66 | 67 | return Settings_SaveStringValue(sName, buffer); 68 | } 69 | BOOL Settings_LoadDwordValue(LPCTSTR sName, DWORD* dwValue) 70 | { 71 | TCHAR buffer[12]; 72 | if (!Settings_LoadStringValue(sName, buffer, 12)) 73 | return FALSE; 74 | 75 | int result = _stscanf(buffer, _T("%lu"), dwValue); 76 | if (result == 0) 77 | return FALSE; 78 | 79 | return TRUE; 80 | } 81 | 82 | BOOL Settings_SaveColorValue(LPCTSTR sName, COLORREF color) 83 | { 84 | // 00BBGGRR -> 00RRGGBB conversion 85 | DWORD dwValue = ((color & 0x0000ff) << 16) | (color & 0x00ff00) | ((color & 0xff0000) >> 16); 86 | 87 | TCHAR buffer[12]; 88 | _sntprintf(buffer, sizeof(buffer) / sizeof(TCHAR) - 1, _T("%06lX"), dwValue); 89 | 90 | return Settings_SaveStringValue(sName, buffer); 91 | } 92 | BOOL Settings_LoadColorValue(LPCTSTR sName, COLORREF* pColor) 93 | { 94 | TCHAR buffer[12]; 95 | if (!Settings_LoadStringValue(sName, buffer, 12)) 96 | return FALSE; 97 | 98 | DWORD dwValue; 99 | int result = _stscanf(buffer, _T("%lX"), &dwValue); 100 | if (result == 0) 101 | return FALSE; 102 | 103 | // 00RRGGBB -> 00BBGGRR conversion 104 | *pColor = ((dwValue & 0x0000ff) << 16) | (dwValue & 0x00ff00) | ((dwValue & 0xff0000) >> 16); 105 | 106 | return TRUE; 107 | } 108 | 109 | 110 | BOOL Settings_SaveBinaryValue(LPCTSTR sName, const void * pData, int size) 111 | { 112 | TCHAR* buffer = static_cast(::calloc(size * 2 + 1, sizeof(TCHAR))); 113 | if (buffer == NULL) 114 | return FALSE; 115 | const BYTE* p = static_cast(pData); 116 | TCHAR* buf = buffer; 117 | for (int i = 0; i < size; i++) 118 | { 119 | int a = *p; 120 | _sntprintf(buf, 3, _T("%02X"), a); 121 | p++; 122 | buf += 2; 123 | } 124 | 125 | BOOL result = Settings_SaveStringValue(sName, buffer); 126 | 127 | free(buffer); 128 | 129 | return result; 130 | } 131 | 132 | BOOL Settings_LoadBinaryValue(LPCTSTR sName, void * pData, int size) 133 | { 134 | size_t buffersize = size * 2 + 1; 135 | TCHAR* buffer = static_cast(::calloc(buffersize, sizeof(TCHAR))); 136 | if (buffer == NULL) 137 | return FALSE; 138 | if (!Settings_LoadStringValue(sName, buffer, buffersize)) 139 | { 140 | free(buffer); 141 | return FALSE; 142 | } 143 | 144 | BYTE* p = static_cast(pData); 145 | TCHAR* buf = buffer; 146 | for (int i = 0; i < size; i++) 147 | { 148 | BYTE v = 0; 149 | 150 | TCHAR ch = *buf; 151 | if (ch >= _T('0') && ch <= _T('9')) 152 | v = (BYTE)(ch - _T('0')); 153 | else if (ch >= _T('A') && ch <= _T('F')) 154 | v = (BYTE)(ch - _T('A') + 10); 155 | else // Not hex 156 | { 157 | free(buffer); 158 | return FALSE; 159 | } 160 | buf++; 161 | 162 | v = v << 4; 163 | 164 | ch = *buf; 165 | if (ch >= _T('0') && ch <= _T('9')) 166 | v |= (BYTE)(ch - _T('0')); 167 | else if (ch >= _T('A') && ch <= _T('F')) 168 | v |= (BYTE)(ch - _T('A') + 10); 169 | else // Not hex 170 | { 171 | free(buffer); 172 | return FALSE; 173 | } 174 | buf++; 175 | 176 | *p = v; 177 | p++; 178 | } 179 | 180 | free(buffer); 181 | 182 | return TRUE; 183 | } 184 | 185 | 186 | ////////////////////////////////////////////////////////////////////// 187 | 188 | 189 | #define SETTINGS_GETSET_DWORD(PARAMNAME, PARAMNAMESTR, OUTTYPE, DEFVALUE) \ 190 | OUTTYPE m_Settings_##PARAMNAME = DEFVALUE; \ 191 | BOOL m_Settings_##PARAMNAME##_Valid = FALSE; \ 192 | void Settings_Set##PARAMNAME(OUTTYPE newvalue) { \ 193 | m_Settings_##PARAMNAME = newvalue; \ 194 | m_Settings_##PARAMNAME##_Valid = TRUE; \ 195 | Settings_SaveDwordValue(PARAMNAMESTR, (DWORD) newvalue); \ 196 | } \ 197 | OUTTYPE Settings_Get##PARAMNAME() { \ 198 | if (!m_Settings_##PARAMNAME##_Valid) { \ 199 | DWORD dwValue = (DWORD)(DEFVALUE); \ 200 | Settings_LoadDwordValue(PARAMNAMESTR, &dwValue); \ 201 | m_Settings_##PARAMNAME = (OUTTYPE) dwValue; \ 202 | m_Settings_##PARAMNAME##_Valid = TRUE; \ 203 | } \ 204 | return m_Settings_##PARAMNAME; \ 205 | } 206 | 207 | 208 | BOOL Settings_GetWindowRect(RECT * pRect) 209 | { 210 | RECT rc; 211 | if (Settings_LoadBinaryValue(_T("WindowRect"), &rc, sizeof(RECT))) 212 | { 213 | ::memcpy(pRect, &rc, sizeof(RECT)); 214 | return TRUE; 215 | } 216 | 217 | return FALSE; 218 | } 219 | void Settings_SetWindowRect(const RECT * pRect) 220 | { 221 | Settings_SaveBinaryValue(_T("WindowRect"), pRect, sizeof(RECT)); 222 | } 223 | 224 | SETTINGS_GETSET_DWORD(WindowMaximized, _T("WindowMaximized"), BOOL, FALSE); 225 | 226 | SETTINGS_GETSET_DWORD(Configuration, _T("Configuration"), int, 0); 227 | 228 | void Settings_GetFloppyFilePath(int slot, LPTSTR buffer) 229 | { 230 | TCHAR bufValueName[8]; 231 | lstrcpy(bufValueName, _T("Floppy0")); 232 | bufValueName[6] = _T('0') + (TCHAR)slot; 233 | Settings_LoadStringValue(bufValueName, buffer, MAX_PATH); 234 | } 235 | void Settings_SetFloppyFilePath(int slot, LPCTSTR sFilePath) 236 | { 237 | TCHAR bufValueName[8]; 238 | lstrcpy(bufValueName, _T("Floppy0")); 239 | bufValueName[6] = _T('0') + (TCHAR)slot; 240 | Settings_SaveStringValue(bufValueName, sFilePath); 241 | } 242 | 243 | SETTINGS_GETSET_DWORD(ScreenViewMode, _T("ScreenViewMode"), int, 0); 244 | 245 | SETTINGS_GETSET_DWORD(ScreenHeightMode, _T("ScreenHeightMode"), int, 0); 246 | 247 | SETTINGS_GETSET_DWORD(Toolbar, _T("Toolbar"), BOOL, TRUE); 248 | 249 | SETTINGS_GETSET_DWORD(Debug, _T("Debug"), BOOL, FALSE); 250 | 251 | void Settings_GetDebugFontName(LPTSTR buffer) 252 | { 253 | if (!Settings_LoadStringValue(_T("DebugFontName"), buffer, 32)) 254 | { 255 | _tcscpy(buffer, _T("Lucida Console")); 256 | } 257 | } 258 | void Settings_SetDebugFontName(LPCTSTR sFontName) 259 | { 260 | Settings_SaveStringValue(_T("DebugFontName"), sFontName); 261 | } 262 | 263 | void Settings_SetDebugBreakpoint(int bpno, WORD address) 264 | { 265 | TCHAR bufValueName[14]; 266 | lstrcpy(bufValueName, _T("DebugBreakpt0")); 267 | bufValueName[12] = bpno < 10 ? _T('0') + (TCHAR)bpno : _T('A') + (TCHAR)(bpno - 10); 268 | if (address == 0177777) 269 | Settings_SaveStringValue(bufValueName, NULL); // delete value 270 | else 271 | Settings_SaveDwordValue(bufValueName, address); 272 | } 273 | WORD Settings_GetDebugBreakpoint(int bpno) 274 | { 275 | TCHAR bufValueName[14]; 276 | lstrcpy(bufValueName, _T("DebugBreakpt0")); 277 | bufValueName[12] = bpno < 10 ? _T('0') + (TCHAR)bpno : _T('A') + (TCHAR)(bpno - 10); 278 | DWORD dwValue = 0xFFFFFFFF; 279 | Settings_LoadDwordValue(bufValueName, &dwValue); 280 | return (WORD)dwValue; 281 | } 282 | 283 | SETTINGS_GETSET_DWORD(DebugMemoryAddress, _T("DebugMemoryAddress"), WORD, 0); 284 | SETTINGS_GETSET_DWORD(DebugMemoryBase, _T("DebugMemoryBase"), WORD, 0); 285 | SETTINGS_GETSET_DWORD(DebugMemoryByte, _T("DebugMemoryByte"), BOOL, FALSE); 286 | SETTINGS_GETSET_DWORD(DebugMemoryNumeral, _T("DebugMemoryNumeral"), WORD, 0); 287 | 288 | SETTINGS_GETSET_DWORD(Autostart, _T("Autostart"), BOOL, FALSE); 289 | 290 | SETTINGS_GETSET_DWORD(RealSpeed, _T("RealSpeed"), WORD, 1); 291 | 292 | SETTINGS_GETSET_DWORD(Sound, _T("Sound"), BOOL, FALSE); 293 | SETTINGS_GETSET_DWORD(SoundVolume, _T("SoundVolume"), WORD, 0x3fff); 294 | SETTINGS_GETSET_DWORD(SoundCovox, _T("SoundCovox"), BOOL, FALSE); 295 | SETTINGS_GETSET_DWORD(SoundAY, _T("SoundAY"), BOOL, FALSE); 296 | 297 | SETTINGS_GETSET_DWORD(Joystick, _T("Joystick"), int, 0); 298 | 299 | SETTINGS_GETSET_DWORD(Keyboard, _T("Keyboard"), BOOL, TRUE); 300 | 301 | SETTINGS_GETSET_DWORD(Tape, _T("Tape"), BOOL, FALSE); 302 | 303 | SETTINGS_GETSET_DWORD(MemoryMap, _T("MemoryMap"), BOOL, FALSE); 304 | 305 | SETTINGS_GETSET_DWORD(SpriteAddress, _T("SpriteAddress"), WORD, 0); 306 | 307 | SETTINGS_GETSET_DWORD(SpriteWidth, _T("SpriteWidth"), WORD, 2); 308 | 309 | 310 | ////////////////////////////////////////////////////////////////////// 311 | // Colors 312 | 313 | struct ColorDescriptorStruct 314 | { 315 | LPCTSTR settingname; 316 | COLORREF defaultcolor; 317 | BOOL valid; 318 | LPCTSTR friendlyname; 319 | COLORREF currentcolor; 320 | } 321 | static ColorDescriptors[ColorIndicesCount] = 322 | { 323 | { _T("ColorDebugText"), RGB(0, 0, 0), FALSE, _T("Debug Text") }, 324 | { _T("ColorDebugBackCurrent"), RGB(255, 255, 224), FALSE, _T("Debug Current Line Background") }, 325 | { _T("ColorDebugValueChanged"), RGB(255, 0, 0), FALSE, _T("Debug Value Changed") }, 326 | { _T("ColorDebugPrevious"), RGB(0, 0, 255), FALSE, _T("Debug Previous Address Marker") }, 327 | { _T("ColorDebugMemoryROM"), RGB(0, 0, 255), FALSE, _T("Debug Memory ROM") }, 328 | { _T("ColorDebugMemoryIO"), RGB(0, 128, 0), FALSE, _T("Debug Memory IO") }, 329 | { _T("ColorDebugMemoryNA"), RGB(128, 128, 128), FALSE, _T("Debug Memory NA") }, 330 | { _T("ColorDebugValue"), RGB(128, 128, 128), FALSE, _T("Debug Value") }, 331 | { _T("ColorDebugValueRom"), RGB(128, 128, 192), FALSE, _T("Debug Value ROM") }, 332 | { _T("ColorDebugSubtitles"), RGB(0, 128, 0), FALSE, _T("Debug Subtitles") }, 333 | { _T("ColorDebugJump"), RGB(80, 192, 224), FALSE, _T("Debug Jump") }, 334 | { _T("ColorDebugJumpYes"), RGB(80, 240, 80), FALSE, _T("Debug Jump Yes") }, 335 | { _T("ColorDebugJumpNo"), RGB(180, 180, 180), FALSE, _T("Debug Jump No") }, 336 | { _T("ColorDebugJumpHint"), RGB(40, 128, 160), FALSE, _T("Debug Jump Hint") }, 337 | { _T("ColorDebugHint"), RGB(40, 40, 160), FALSE, _T("Debug Hint") }, 338 | { _T("ColorDebugBreakpoint"), RGB(255, 128, 128), FALSE, _T("Debug Breakpoint") }, 339 | { _T("ColorDebugHighlight"), RGB(200, 230, 255), FALSE, _T("Debug Highlight") }, 340 | { _T("ColorDebugBreakptZone"), RGB(242, 242, 242), FALSE, _T("Debug Breakpoint Zone") }, 341 | }; 342 | 343 | LPCTSTR Settings_GetColorFriendlyName(ColorIndices colorIndex) 344 | { 345 | ColorDescriptorStruct* desc = ColorDescriptors + colorIndex; 346 | 347 | return desc->friendlyname; 348 | } 349 | 350 | COLORREF Settings_GetColor(ColorIndices colorIndex) 351 | { 352 | if (colorIndex < 0 || colorIndex >= ColorIndicesCount) 353 | return 0; 354 | 355 | ColorDescriptorStruct* desc = ColorDescriptors + colorIndex; 356 | 357 | if (desc->valid) 358 | return desc->currentcolor; 359 | 360 | COLORREF color; 361 | if (Settings_LoadColorValue(desc->settingname, &color)) 362 | desc->currentcolor = color; 363 | else 364 | desc->currentcolor = desc->defaultcolor; 365 | 366 | desc->valid = TRUE; 367 | return desc->currentcolor; 368 | } 369 | 370 | void Settings_SetColor(ColorIndices colorIndex, COLORREF color) 371 | { 372 | if (colorIndex < 0 || colorIndex >= ColorIndicesCount) 373 | return; 374 | 375 | ColorDescriptorStruct* desc = ColorDescriptors + colorIndex; 376 | 377 | desc->currentcolor = color; 378 | desc->valid = TRUE; 379 | 380 | Settings_SaveColorValue(desc->settingname, color); 381 | } 382 | 383 | COLORREF Settings_GetDefaultColor(ColorIndices colorIndex) 384 | { 385 | if (colorIndex < 0 || colorIndex >= ColorIndicesCount) 386 | return 0; 387 | 388 | ColorDescriptorStruct* desc = ColorDescriptors + colorIndex; 389 | 390 | return desc->defaultcolor; 391 | } 392 | 393 | 394 | ////////////////////////////////////////////////////////////////////// 395 | -------------------------------------------------------------------------------- /emulator/SoundGen.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // SoundGen.cpp 12 | 13 | #include "stdafx.h" 14 | #include "emubase/Emubase.h" 15 | #include "SoundGen.h" 16 | #include "mmsystem.h" 17 | 18 | ////////////////////////////////////////////////////////////////////// 19 | 20 | 21 | static void CALLBACK waveOutProc(HWAVEOUT, UINT, DWORD, DWORD, DWORD); 22 | 23 | static CRITICAL_SECTION waveCriticalSection; 24 | static WAVEHDR* waveBlocks; 25 | static volatile int waveFreeBlockCount; 26 | static int waveCurrentBlock; 27 | 28 | static bool m_SoundGenInitialized = false; 29 | 30 | HWAVEOUT hWaveOut; 31 | 32 | WAVEFORMATEX wfx; 33 | char buffer[BUFSIZE]; 34 | 35 | int bufcurpos; 36 | 37 | 38 | ////////////////////////////////////////////////////////////////////// 39 | 40 | 41 | static void CALLBACK WaveCallback(HWAVEOUT /*hwo*/, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR /*dwParam1*/, DWORD_PTR /*dwParam2*/) 42 | { 43 | int* freeBlockCounter = reinterpret_cast(dwInstance); 44 | if (uMsg != WOM_DONE) 45 | return; 46 | 47 | EnterCriticalSection(&waveCriticalSection); 48 | (*freeBlockCounter)++; 49 | 50 | LeaveCriticalSection(&waveCriticalSection); 51 | } 52 | 53 | void SoundGen_Initialize(WORD volume) 54 | { 55 | if (m_SoundGenInitialized) 56 | return; 57 | 58 | size_t totalBufferSize = (BLOCK_SIZE + sizeof(WAVEHDR)) * BLOCK_COUNT; 59 | 60 | unsigned char* mbuffer = static_cast(HeapAlloc( 61 | GetProcessHeap(), 62 | HEAP_ZERO_MEMORY, 63 | totalBufferSize)); 64 | if (mbuffer == nullptr) 65 | { 66 | return; 67 | } 68 | 69 | waveBlocks = reinterpret_cast(mbuffer); 70 | mbuffer += sizeof(WAVEHDR) * BLOCK_COUNT; 71 | for (int i = 0; i < BLOCK_COUNT; i++) 72 | { 73 | waveBlocks[i].dwBufferLength = BLOCK_SIZE; 74 | waveBlocks[i].lpData = reinterpret_cast(mbuffer); 75 | mbuffer += BLOCK_SIZE; 76 | } 77 | 78 | waveFreeBlockCount = BLOCK_COUNT; 79 | waveCurrentBlock = 0; 80 | 81 | wfx.nSamplesPerSec = SOUNDSAMPLERATE; 82 | wfx.wBitsPerSample = 16; 83 | wfx.nChannels = 2; 84 | wfx.cbSize = 0; 85 | wfx.wFormatTag = WAVE_FORMAT_PCM; 86 | wfx.nBlockAlign = (wfx.wBitsPerSample * wfx.nChannels) >> 3; 87 | wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec; 88 | 89 | MMRESULT result = waveOutOpen( 90 | &hWaveOut, WAVE_MAPPER, &wfx, (DWORD_PTR)WaveCallback, (DWORD_PTR)&waveFreeBlockCount, CALLBACK_FUNCTION); 91 | if (result != MMSYSERR_NOERROR) 92 | { 93 | return; 94 | } 95 | 96 | waveOutSetVolume(hWaveOut, ((DWORD)volume << 16) | ((DWORD)volume)); 97 | 98 | InitializeCriticalSection(&waveCriticalSection); 99 | bufcurpos = 0; 100 | 101 | m_SoundGenInitialized = true; 102 | } 103 | 104 | void SoundGen_Finalize() 105 | { 106 | if (!m_SoundGenInitialized) 107 | return; 108 | 109 | while (waveFreeBlockCount < BLOCK_COUNT) 110 | Sleep(1); 111 | 112 | for (int i = 0; i < waveFreeBlockCount; i++) 113 | { 114 | if (waveBlocks[i].dwFlags & WHDR_PREPARED) 115 | waveOutUnprepareHeader(hWaveOut, &waveBlocks[i], sizeof(WAVEHDR)); 116 | } 117 | 118 | DeleteCriticalSection(&waveCriticalSection); 119 | waveOutClose(hWaveOut); 120 | 121 | HeapFree(GetProcessHeap(), 0, waveBlocks); 122 | waveBlocks = nullptr; 123 | 124 | m_SoundGenInitialized = false; 125 | } 126 | 127 | void SoundGen_SetVolume(WORD volume) 128 | { 129 | if (!m_SoundGenInitialized) 130 | return; 131 | 132 | waveOutSetVolume(hWaveOut, ((DWORD)volume << 16) | ((DWORD)volume)); 133 | } 134 | 135 | void SoundGen_SetSpeed(WORD speedpercent) 136 | { 137 | DWORD dwRate = 0x00010000; 138 | if (speedpercent > 0 && speedpercent < 1000) 139 | dwRate = (((DWORD)speedpercent / 100) << 16) | ((speedpercent % 100) * 0x00010000 / 100); 140 | 141 | waveOutSetPlaybackRate(hWaveOut, dwRate); 142 | } 143 | 144 | void CALLBACK SoundGen_FeedDAC(unsigned short L, unsigned short R) 145 | { 146 | if (!m_SoundGenInitialized) 147 | return; 148 | 149 | unsigned int word = ((unsigned int)R << 16) + L; 150 | memcpy(&buffer[bufcurpos], &word, 4); 151 | bufcurpos += 4; 152 | 153 | if (bufcurpos >= BUFSIZE) 154 | { 155 | WAVEHDR* current = &waveBlocks[waveCurrentBlock]; 156 | 157 | if (current->dwFlags & WHDR_PREPARED) 158 | waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR)); 159 | 160 | memcpy(current->lpData, buffer, BUFSIZE); 161 | current->dwBufferLength = BLOCK_SIZE; 162 | 163 | waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR)); 164 | waveOutWrite(hWaveOut, current, sizeof(WAVEHDR)); 165 | 166 | EnterCriticalSection(&waveCriticalSection); 167 | waveFreeBlockCount--; 168 | LeaveCriticalSection(&waveCriticalSection); 169 | 170 | while (!waveFreeBlockCount) 171 | Sleep(1); 172 | 173 | waveCurrentBlock++; 174 | if (waveCurrentBlock >= BLOCK_COUNT) 175 | waveCurrentBlock = 0; 176 | 177 | bufcurpos = 0; 178 | } 179 | } 180 | 181 | 182 | ////////////////////////////////////////////////////////////////////// 183 | -------------------------------------------------------------------------------- /emulator/SoundGen.h: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // SoundGen.h 12 | 13 | #pragma once 14 | 15 | ////////////////////////////////////////////////////////////////////// 16 | 17 | 18 | #define BUFSIZE ((SOUNDSAMPLERATE / 25) * 4) 19 | #define BLOCK_COUNT 8 20 | #define BLOCK_SIZE BUFSIZE 21 | 22 | void SoundGen_Initialize(WORD volume); 23 | void SoundGen_Finalize(); 24 | void SoundGen_SetVolume(WORD volume); 25 | void SoundGen_SetSpeed(WORD speedpercent); 26 | void CALLBACK SoundGen_FeedDAC(unsigned short L, unsigned short R); 27 | 28 | 29 | ////////////////////////////////////////////////////////////////////// 30 | -------------------------------------------------------------------------------- /emulator/SpriteView.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // SpriteView.cpp 12 | 13 | #include "stdafx.h" 14 | #include 15 | #include "Main.h" 16 | #include "Views.h" 17 | #include "ToolWindow.h" 18 | #include "Dialogs.h" 19 | #include "Emulator.h" 20 | #include "emubase/Emubase.h" 21 | 22 | ////////////////////////////////////////////////////////////////////// 23 | 24 | 25 | HWND g_hwndSprite = (HWND)INVALID_HANDLE_VALUE; // Sprite view window handler 26 | WNDPROC m_wndprocSpriteToolWindow = NULL; // Old window proc address of the ToolWindow 27 | 28 | HWND m_hwndSpriteViewer = (HWND)INVALID_HANDLE_VALUE; 29 | HDRAWDIB m_hSpriteDrawDib = NULL; 30 | BITMAPINFO m_bmpinfoSprite; 31 | HBITMAP m_hSpriteBitmap = NULL; 32 | DWORD * m_pSprite_bits = NULL; 33 | 34 | const int m_nSprite_scale = 2; 35 | const int m_nSprite_ImageCX = 262; 36 | const int m_nSprite_ImageCY = 256; 37 | const int m_nSprite_ViewCX = m_nSprite_ImageCX * m_nSprite_scale; 38 | const int m_nSprite_ViewCY = m_nSprite_ImageCY * m_nSprite_scale; 39 | 40 | WORD m_wSprite_BaseAddress = 0; 41 | int m_nSprite_width = 2; 42 | int m_nSprite_PageSizeBytes = m_nSprite_ImageCY * (m_nSprite_ImageCX / (8 + 2)); 43 | 44 | void SpriteView_OnDraw(HDC hdc); 45 | BOOL SpriteView_OnKeyDown(WPARAM vkey, LPARAM lParam); 46 | BOOL SpriteView_OnVScroll(WPARAM wParam, LPARAM lParam); 47 | BOOL SpriteView_OnMouseWheel(WPARAM wParam, LPARAM lParam); 48 | void SpriteView_InitBitmap(); 49 | void SpriteView_DoneBitmap(); 50 | void SpriteView_UpdateWindowText(); 51 | void SpriteView_PrepareBitmap(); 52 | void SpriteView_UpdateScrollPos(); 53 | 54 | 55 | ////////////////////////////////////////////////////////////////////// 56 | 57 | void SpriteView_RegisterClass() 58 | { 59 | WNDCLASSEX wcex; 60 | wcex.cbSize = sizeof(WNDCLASSEX); 61 | 62 | wcex.style = CS_HREDRAW | CS_VREDRAW; 63 | wcex.lpfnWndProc = SpriteViewViewerWndProc; 64 | wcex.cbClsExtra = 0; 65 | wcex.cbWndExtra = 0; 66 | wcex.hInstance = g_hInst; 67 | wcex.hIcon = NULL; 68 | wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 69 | wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 70 | wcex.lpszMenuName = NULL; 71 | wcex.lpszClassName = CLASSNAME_SPRITEVIEW; 72 | wcex.hIconSm = NULL; 73 | 74 | RegisterClassEx(&wcex); 75 | } 76 | 77 | void SpriteView_Create(int x, int y) 78 | { 79 | int cxBorder = ::GetSystemMetrics(SM_CXDLGFRAME); 80 | int cyBorder = ::GetSystemMetrics(SM_CYDLGFRAME); 81 | int cxScroll = ::GetSystemMetrics(SM_CXVSCROLL); 82 | int cyCaption = ::GetSystemMetrics(SM_CYSMCAPTION); 83 | 84 | int width = m_nSprite_ViewCX + cxScroll + cxBorder * 2; 85 | int height = m_nSprite_ViewCY + cyBorder * 2 + cyCaption; 86 | g_hwndSprite = CreateWindowEx( 87 | WS_EX_TOOLWINDOW | WS_EX_TOPMOST, 88 | CLASSNAME_OVERLAPPEDWINDOW, _T("Sprite Viewer"), 89 | WS_POPUPWINDOW | WS_CAPTION | WS_VISIBLE, 90 | x, y, width, height, 91 | NULL, NULL, g_hInst, NULL); 92 | 93 | // ToolWindow subclassing 94 | m_wndprocSpriteToolWindow = (WNDPROC)LongToPtr(SetWindowLongPtr( 95 | g_hwndSprite, GWLP_WNDPROC, PtrToLong(SpriteViewWndProc))); 96 | 97 | RECT rcClient; GetClientRect(g_hwndSprite, &rcClient); 98 | 99 | m_hwndSpriteViewer = CreateWindow( 100 | CLASSNAME_SPRITEVIEW, NULL, 101 | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 102 | 0, 0, rcClient.right, rcClient.bottom, 103 | g_hwndSprite, NULL, g_hInst, NULL); 104 | 105 | m_wSprite_BaseAddress = Settings_GetSpriteAddress(); 106 | m_nSprite_width = (int)Settings_GetSpriteWidth(); 107 | if (m_nSprite_width <= 0) m_nSprite_width = 1; 108 | if (m_nSprite_width > 32) m_nSprite_width = 32; 109 | 110 | SpriteView_InitBitmap(); 111 | SpriteView_UpdateWindowText(); 112 | SpriteView_UpdateScrollPos(); 113 | ::SetFocus(m_hwndSpriteViewer); 114 | } 115 | 116 | void SpriteView_InitBitmap() 117 | { 118 | m_hSpriteDrawDib = DrawDibOpen(); 119 | HDC hdc = GetDC(g_hwnd); 120 | 121 | m_bmpinfoSprite.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 122 | m_bmpinfoSprite.bmiHeader.biWidth = m_nSprite_ImageCX; 123 | m_bmpinfoSprite.bmiHeader.biHeight = m_nSprite_ImageCY; 124 | m_bmpinfoSprite.bmiHeader.biPlanes = 1; 125 | m_bmpinfoSprite.bmiHeader.biBitCount = 32; 126 | m_bmpinfoSprite.bmiHeader.biCompression = BI_RGB; 127 | m_bmpinfoSprite.bmiHeader.biSizeImage = 0; 128 | m_bmpinfoSprite.bmiHeader.biXPelsPerMeter = 0; 129 | m_bmpinfoSprite.bmiHeader.biYPelsPerMeter = 0; 130 | m_bmpinfoSprite.bmiHeader.biClrUsed = 0; 131 | m_bmpinfoSprite.bmiHeader.biClrImportant = 0; 132 | 133 | m_hSpriteBitmap = CreateDIBSection(hdc, &m_bmpinfoSprite, DIB_RGB_COLORS, (void **)&m_pSprite_bits, NULL, 0); 134 | 135 | VERIFY(::ReleaseDC(g_hwnd, hdc)); 136 | } 137 | 138 | void SpriteView_DoneBitmap() 139 | { 140 | if (m_hSpriteBitmap != NULL) 141 | { 142 | VERIFY(::DeleteObject(m_hSpriteBitmap)); m_hSpriteBitmap = NULL; 143 | } 144 | 145 | DrawDibClose(m_hSpriteDrawDib); 146 | } 147 | 148 | LRESULT CALLBACK SpriteViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 149 | { 150 | UNREFERENCED_PARAMETER(lParam); 151 | switch (message) 152 | { 153 | case WM_SETFOCUS: 154 | ::SetFocus(m_hwndSpriteViewer); 155 | break; 156 | case WM_DESTROY: 157 | g_hwndSprite = (HWND)INVALID_HANDLE_VALUE; // We are closed! Bye-bye!.. 158 | return CallWindowProc(m_wndprocSpriteToolWindow, hWnd, message, wParam, lParam); 159 | default: 160 | return CallWindowProc(m_wndprocSpriteToolWindow, hWnd, message, wParam, lParam); 161 | } 162 | return (LRESULT)FALSE; 163 | } 164 | 165 | LRESULT CALLBACK SpriteViewViewerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 166 | { 167 | UNREFERENCED_PARAMETER(lParam); 168 | switch (message) 169 | { 170 | case WM_PAINT: 171 | { 172 | PAINTSTRUCT ps; 173 | HDC hdc = BeginPaint(hWnd, &ps); 174 | 175 | SpriteView_OnDraw(hdc); // Draw memory dump 176 | 177 | EndPaint(hWnd, &ps); 178 | } 179 | break; 180 | case WM_DESTROY: 181 | // Free resources 182 | SpriteView_DoneBitmap(); 183 | return DefWindowProc(hWnd, message, wParam, lParam); 184 | case WM_LBUTTONDOWN: 185 | SetFocus(hWnd); 186 | break; 187 | case WM_KEYDOWN: 188 | return (LRESULT)SpriteView_OnKeyDown(wParam, lParam); 189 | case WM_VSCROLL: 190 | return (LRESULT)SpriteView_OnVScroll(wParam, lParam); 191 | case WM_MOUSEWHEEL: 192 | return (LRESULT)SpriteView_OnMouseWheel(wParam, lParam); 193 | default: 194 | return DefWindowProc(hWnd, message, wParam, lParam); 195 | } 196 | return (LRESULT)FALSE; 197 | } 198 | 199 | void SpriteView_OnDraw(HDC hdc) 200 | { 201 | ASSERT(g_pBoard != NULL); 202 | 203 | SpriteView_PrepareBitmap(); 204 | 205 | DrawDibDraw(m_hSpriteDrawDib, hdc, 206 | 0, 0, 207 | m_nSprite_ImageCX * m_nSprite_scale, m_nSprite_ImageCY * m_nSprite_scale, 208 | &m_bmpinfoSprite.bmiHeader, m_pSprite_bits, 0, 0, 209 | m_nSprite_ImageCX, m_nSprite_ImageCY, 210 | 0); 211 | } 212 | 213 | void SpriteView_GoToAddress(WORD address) 214 | { 215 | if (address == m_wSprite_BaseAddress) 216 | return; 217 | 218 | m_wSprite_BaseAddress = address; 219 | Settings_SetSpriteAddress(m_wSprite_BaseAddress); 220 | 221 | SpriteView_UpdateWindowText(); 222 | SpriteView_PrepareBitmap(); 223 | InvalidateRect(m_hwndSpriteViewer, NULL, TRUE); 224 | SpriteView_UpdateScrollPos(); 225 | } 226 | void SpriteView_SetSpriteWidth(int width) 227 | { 228 | if (width < 1) width = 1; 229 | if (width > m_nSprite_ImageCX / 8) width = m_nSprite_ImageCX / 8; 230 | if (width == m_nSprite_width) 231 | return; 232 | 233 | m_nSprite_width = width; 234 | Settings_SetSpriteWidth((WORD)width); 235 | 236 | SpriteView_UpdateWindowText(); 237 | SpriteView_PrepareBitmap(); 238 | InvalidateRect(m_hwndSpriteViewer, NULL, TRUE); 239 | SpriteView_UpdateScrollPos(); 240 | } 241 | 242 | void SpriteView_UpdateWindowText() 243 | { 244 | TCHAR buffer[48]; 245 | _sntprintf(buffer, sizeof(buffer) / sizeof(TCHAR) - 1, 246 | _T("Sprite Viewer - address %06o, width %d"), m_wSprite_BaseAddress, m_nSprite_width); 247 | ::SetWindowText(g_hwndSprite, buffer); 248 | } 249 | 250 | BOOL SpriteView_OnKeyDown(WPARAM vkey, LPARAM /*lParam*/) 251 | { 252 | switch (vkey) 253 | { 254 | case VK_LEFT: 255 | SpriteView_GoToAddress(m_wSprite_BaseAddress - (WORD)(m_nSprite_ImageCY * m_nSprite_width)); 256 | break; 257 | case VK_RIGHT: 258 | SpriteView_GoToAddress(m_wSprite_BaseAddress + (WORD)(m_nSprite_ImageCY * m_nSprite_width)); 259 | break; 260 | case VK_UP: 261 | if (GetKeyState(VK_CONTROL) & 0x8000) 262 | SpriteView_GoToAddress(m_wSprite_BaseAddress - (WORD)m_nSprite_width); 263 | else 264 | SpriteView_GoToAddress(m_wSprite_BaseAddress - 1); 265 | break; 266 | case VK_DOWN: 267 | if (GetKeyState(VK_CONTROL) & 0x8000) 268 | SpriteView_GoToAddress(m_wSprite_BaseAddress + (WORD)m_nSprite_width); 269 | else 270 | SpriteView_GoToAddress(m_wSprite_BaseAddress + 1); 271 | break; 272 | case VK_OEM_4: // '[' -- Decrement Sprite Width 273 | SpriteView_SetSpriteWidth(m_nSprite_width - 1); 274 | break; 275 | case VK_OEM_6: // ']' -- Increment Sprite Width 276 | SpriteView_SetSpriteWidth(m_nSprite_width + 1); 277 | break; 278 | case 0x47: // 'G' - Go To Address 279 | { 280 | WORD value = m_wSprite_BaseAddress; 281 | if (InputBoxOctal(m_hwndSpriteViewer, _T("Go To Address"), &value)) 282 | SpriteView_GoToAddress(value); 283 | break; 284 | } 285 | case VK_HOME: 286 | SpriteView_GoToAddress(0); 287 | break; 288 | case VK_END: 289 | SpriteView_GoToAddress((WORD)(0x10000 - 1)); 290 | break; 291 | case VK_PRIOR: 292 | SpriteView_GoToAddress(m_wSprite_BaseAddress - (WORD)m_nSprite_PageSizeBytes); 293 | break; 294 | case VK_NEXT: 295 | SpriteView_GoToAddress(m_wSprite_BaseAddress + (WORD)m_nSprite_PageSizeBytes); 296 | break; 297 | default: 298 | return TRUE; 299 | } 300 | return FALSE; 301 | } 302 | 303 | BOOL SpriteView_OnMouseWheel(WPARAM wParam, LPARAM /*lParam*/) 304 | { 305 | short zDelta = GET_WHEEL_DELTA_WPARAM(wParam); 306 | 307 | int nDelta = zDelta / 120; 308 | if (nDelta > 4) nDelta = 4; 309 | if (nDelta < -4) nDelta = -4; 310 | 311 | SpriteView_GoToAddress(m_wSprite_BaseAddress - (WORD)(nDelta * 3 * m_nSprite_width)); 312 | 313 | return FALSE; 314 | } 315 | 316 | BOOL SpriteView_OnVScroll(WPARAM wParam, LPARAM /*lParam*/) 317 | { 318 | //WORD scrollpos = HIWORD(wParam); 319 | WORD scrollcmd = LOWORD(wParam); 320 | switch (scrollcmd) 321 | { 322 | case SB_LINEDOWN: 323 | SpriteView_GoToAddress(m_wSprite_BaseAddress + (WORD)m_nSprite_width); 324 | break; 325 | case SB_LINEUP: 326 | SpriteView_GoToAddress(m_wSprite_BaseAddress - (WORD)m_nSprite_width); 327 | break; 328 | case SB_PAGEDOWN: 329 | SpriteView_GoToAddress(m_wSprite_BaseAddress + (WORD)m_nSprite_PageSizeBytes); 330 | break; 331 | case SB_PAGEUP: 332 | SpriteView_GoToAddress(m_wSprite_BaseAddress - (WORD)m_nSprite_PageSizeBytes); 333 | break; 334 | case SB_THUMBPOSITION: 335 | { 336 | WORD scrollpos = HIWORD(wParam); 337 | SpriteView_GoToAddress(scrollpos); 338 | } 339 | break; 340 | } 341 | 342 | return FALSE; 343 | } 344 | 345 | void SpriteView_UpdateScrollPos() 346 | { 347 | int columns = 0; 348 | int cx = m_nSprite_ImageCX; 349 | while (cx > m_nSprite_width * 8) 350 | { 351 | columns++; 352 | cx -= m_nSprite_width * 8; 353 | if (cx <= 2) 354 | break; 355 | cx -= 2; 356 | } 357 | m_nSprite_PageSizeBytes = m_nSprite_ImageCY * columns * m_nSprite_width; 358 | 359 | SCROLLINFO si; 360 | ZeroMemory(&si, sizeof(si)); 361 | si.cbSize = sizeof(si); 362 | si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE; 363 | si.nPage = m_nSprite_PageSizeBytes; 364 | si.nPos = m_wSprite_BaseAddress; 365 | si.nMin = 0; 366 | si.nMax = 0x10000 - 1 + m_nSprite_PageSizeBytes; 367 | SetScrollInfo(m_hwndSpriteViewer, SB_VERT, &si, TRUE); 368 | } 369 | 370 | void SpriteView_PrepareBitmap() 371 | { 372 | // Clear bitmap 373 | memset(m_pSprite_bits, 0x7f, m_nSprite_ImageCX * m_nSprite_ImageCY * 4); 374 | 375 | WORD address = m_wSprite_BaseAddress; 376 | 377 | for (int x = 0; x + m_nSprite_width * 8 <= m_nSprite_ImageCX; x += m_nSprite_width * 8 + 2) 378 | { 379 | for (int y = 0; y < m_nSprite_ImageCY; y++) 380 | { 381 | DWORD* pBits = m_pSprite_bits + (m_nSprite_ImageCY - 1 - y) * m_nSprite_ImageCX + x; 382 | 383 | for (int w = 0; w < m_nSprite_width; w++) 384 | { 385 | // Get byte from memory 386 | int addrtype = 0; 387 | bool okHalt = g_pBoard->GetCPU()->IsHaltMode(); 388 | WORD value = g_pBoard->GetWordView(address & ~1, okHalt, FALSE, &addrtype); 389 | if (address & 1) 390 | value = value >> 8; 391 | 392 | for (int i = 0; i < 8; i++) 393 | { 394 | COLORREF color = (value & 1) ? 0xffffff : 0; 395 | *pBits = color; 396 | pBits++; 397 | 398 | value = value >> 1; 399 | } 400 | 401 | address++; 402 | } 403 | } 404 | } 405 | } 406 | 407 | 408 | ////////////////////////////////////////////////////////////////////// 409 | -------------------------------------------------------------------------------- /emulator/TeletypeView.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // TeletypeView.cpp 12 | 13 | #include "stdafx.h" 14 | #include "Main.h" 15 | #include "Views.h" 16 | #include "ToolWindow.h" 17 | 18 | ////////////////////////////////////////////////////////////////////// 19 | 20 | 21 | HWND g_hwndTeletype = (HWND)INVALID_HANDLE_VALUE; // Teletype view window handler 22 | WNDPROC m_wndprocTeletypeToolWindow = NULL; // Old window proc address of the ToolWindow 23 | 24 | HWND m_hwndTeletypeLog = (HWND)INVALID_HANDLE_VALUE; // Teletype log window - read-only edit control 25 | HFONT m_hfontTeletype = NULL; 26 | 27 | 28 | ////////////////////////////////////////////////////////////////////// 29 | 30 | 31 | void TeletypeView_Create(int x, int y, int width, int height) 32 | { 33 | //int cxBorder = ::GetSystemMetrics(SM_CXDLGFRAME); 34 | //int cyBorder = ::GetSystemMetrics(SM_CYDLGFRAME); 35 | //int cxScroll = ::GetSystemMetrics(SM_CXVSCROLL); 36 | //int cyScroll = ::GetSystemMetrics(SM_CYHSCROLL); 37 | //int cyCaption = ::GetSystemMetrics(SM_CYSMCAPTION); 38 | 39 | g_hwndTeletype = CreateWindowEx( 40 | WS_EX_TOOLWINDOW | WS_EX_TOPMOST, 41 | CLASSNAME_OVERLAPPEDWINDOW, _T("BK Teletype"), 42 | WS_POPUPWINDOW | WS_CAPTION | WS_VISIBLE, 43 | x, y, width, height, 44 | NULL, NULL, g_hInst, NULL); 45 | 46 | // ToolWindow subclassing 47 | m_wndprocTeletypeToolWindow = (WNDPROC)LongToPtr( SetWindowLongPtr( 48 | g_hwndTeletype, GWLP_WNDPROC, PtrToLong(TeletypeViewWndProc)) ); 49 | 50 | RECT rcClient; ::GetClientRect(g_hwndTeletype, &rcClient); 51 | 52 | m_hwndTeletypeLog = CreateWindowEx( 53 | WS_EX_CLIENTEDGE, 54 | _T("EDIT"), NULL, 55 | WS_CHILD | WS_VSCROLL | WS_VISIBLE | ES_READONLY | ES_MULTILINE, 56 | 0, 0, 57 | rcClient.right, rcClient.bottom, 58 | g_hwndTeletype, NULL, g_hInst, NULL); 59 | 60 | m_hfontTeletype = CreateMonospacedFont(); 61 | ::SendMessage(m_hwndTeletypeLog, WM_SETFONT, (WPARAM)m_hfontTeletype, 0); 62 | 63 | ::ShowWindow(g_hwndTeletype, SW_SHOW); 64 | } 65 | 66 | // Adjust position of client windows 67 | void TeletypeView_AdjustWindowLayout() 68 | { 69 | RECT rc; GetClientRect(g_hwndTeletype, &rc); 70 | 71 | if (m_hwndTeletypeLog != (HWND)INVALID_HANDLE_VALUE) 72 | SetWindowPos(m_hwndTeletypeLog, NULL, 0, 0, rc.right, rc.bottom, SWP_NOZORDER); 73 | } 74 | 75 | LRESULT CALLBACK TeletypeViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 76 | { 77 | UNREFERENCED_PARAMETER(lParam); 78 | LRESULT lResult; 79 | switch (message) 80 | { 81 | case WM_DESTROY: 82 | g_hwndTeletype = (HWND)INVALID_HANDLE_VALUE; // We are closed! Bye-bye!.. 83 | return CallWindowProc(m_wndprocTeletypeToolWindow, hWnd, message, wParam, lParam); 84 | case WM_SIZE: 85 | lResult = CallWindowProc(m_wndprocTeletypeToolWindow, hWnd, message, wParam, lParam); 86 | TeletypeView_AdjustWindowLayout(); 87 | return lResult; 88 | default: 89 | return CallWindowProc(m_wndprocTeletypeToolWindow, hWnd, message, wParam, lParam); 90 | } 91 | } 92 | 93 | void TeletypeView_Output(LPCTSTR message) 94 | { 95 | // Put selection to the end of text 96 | SendMessage(m_hwndTeletypeLog, EM_SETSEL, 0x100000, 0x100000); 97 | // Insert the message 98 | SendMessage(m_hwndTeletypeLog, EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)message); 99 | // Scroll to caret 100 | SendMessage(m_hwndTeletypeLog, EM_SCROLLCARET, 0, 0); 101 | } 102 | 103 | void TeletypeView_OutputSymbol(TCHAR symbol) 104 | { 105 | if (m_hwndTeletypeLog == NULL) return; 106 | 107 | TCHAR message[2]; 108 | message[0] = symbol; 109 | message[1] = 0; 110 | 111 | TeletypeView_Output(message); 112 | } 113 | 114 | 115 | ////////////////////////////////////////////////////////////////////// 116 | -------------------------------------------------------------------------------- /emulator/ToolWindow.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // ToolWindow.cpp 12 | 13 | #include "stdafx.h" 14 | #include "Main.h" 15 | #include "ToolWindow.h" 16 | #include 17 | 18 | ////////////////////////////////////////////////////////////////////// 19 | 20 | 21 | void ToolWindow_RegisterClass() 22 | { 23 | WNDCLASSEX wcex; 24 | wcex.cbSize = sizeof(WNDCLASSEX); 25 | 26 | wcex.style = CS_HREDRAW | CS_VREDRAW; 27 | wcex.lpfnWndProc = ToolWindow_WndProc; 28 | wcex.cbClsExtra = 0; 29 | wcex.cbWndExtra = 0; 30 | wcex.hInstance = g_hInst; 31 | wcex.hIcon = NULL; 32 | wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 33 | wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); 34 | wcex.lpszMenuName = NULL; 35 | wcex.lpszClassName = CLASSNAME_TOOLWINDOW; 36 | wcex.hIconSm = NULL; 37 | 38 | RegisterClassEx(&wcex); 39 | } 40 | 41 | LRESULT CALLBACK ToolWindow_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 42 | { 43 | UNREFERENCED_PARAMETER(lParam); 44 | switch (message) 45 | { 46 | case WM_NCCALCSIZE: 47 | { 48 | LPRECT pRect = (LPRECT) lParam; 49 | pRect->top += TOOLWINDOW_CAPTION_HEIGHT; 50 | } 51 | break; 52 | case WM_NCPAINT: 53 | { 54 | RECT rcClient; ::GetClientRect(hWnd, &rcClient); 55 | RECT rcWindow; ::GetWindowRect(hWnd, &rcWindow); 56 | MapWindowPoints(NULL, hWnd, (LPPOINT)&rcWindow, 2); 57 | 58 | rcClient.left -= rcWindow.left; rcClient.top -= rcWindow.top; 59 | rcClient.right -= rcWindow.left; rcClient.bottom -= rcWindow.top; 60 | rcWindow.left -= rcWindow.left; rcWindow.top -= rcWindow.top; 61 | rcWindow.right -= rcWindow.left; rcWindow.bottom -= rcWindow.top; 62 | 63 | HDC hdc = ::GetWindowDC(hWnd); 64 | ::ExcludeClipRect(hdc, rcClient.left, rcClient.top, rcClient.right, rcClient.bottom); 65 | 66 | // Draw caption background 67 | BOOL okActive = (::GetActiveWindow() == hWnd); 68 | HBRUSH brushCaption = ::GetSysColorBrush(okActive ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION); 69 | RECT rc; 70 | rc.left = rc.top = 0; 71 | rc.right = rcWindow.right; rc.bottom = TOOLWINDOW_CAPTION_HEIGHT; 72 | ::FillRect(hdc, &rc, brushCaption); 73 | 74 | // Draw caption text 75 | TCHAR buffer[64]; 76 | ::GetWindowText(hWnd, buffer, 64); 77 | rc.left += 8; rc.right -= 8; 78 | HFONT hfont = CreateDialogFont(); 79 | HGDIOBJ hOldFont = ::SelectObject(hdc, hfont); 80 | ::SetTextColor(hdc, ::GetSysColor(COLOR_CAPTIONTEXT)); 81 | ::SetBkMode(hdc, TRANSPARENT); 82 | ::DrawText(hdc, buffer, (int)wcslen(buffer), &rc, DT_LEFT | DT_VCENTER | DT_SINGLELINE); 83 | ::SelectObject(hdc, hOldFont); 84 | VERIFY(::DeleteObject(hfont)); 85 | 86 | VERIFY(::ReleaseDC(hWnd, hdc)); 87 | } 88 | break; 89 | case WM_SETTEXT: 90 | { 91 | LRESULT lResult = DefWindowProc(hWnd, message, wParam, lParam); 92 | 93 | // Invalidate non-client area 94 | RECT rcWindow; ::GetWindowRect(hWnd, &rcWindow); 95 | MapWindowPoints(NULL, hWnd, (LPPOINT)&rcWindow, 2); 96 | ::RedrawWindow(hWnd, &rcWindow, NULL, RDW_FRAME | RDW_INVALIDATE); 97 | 98 | return lResult; 99 | } 100 | default: 101 | return DefWindowProc(hWnd, message, wParam, lParam); 102 | } 103 | return (LRESULT)FALSE; 104 | } 105 | 106 | 107 | ////////////////////////////////////////////////////////////////////// 108 | 109 | 110 | void OverlappedWindow_RegisterClass() 111 | { 112 | WNDCLASSEX wcex; 113 | wcex.cbSize = sizeof(WNDCLASSEX); 114 | 115 | wcex.style = CS_HREDRAW | CS_VREDRAW; 116 | wcex.lpfnWndProc = DefWindowProc; 117 | wcex.cbClsExtra = 0; 118 | wcex.cbWndExtra = 0; 119 | wcex.hInstance = g_hInst; 120 | wcex.hIcon = NULL; 121 | wcex.hCursor = LoadCursor(NULL, IDC_ARROW); 122 | wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); 123 | wcex.lpszMenuName = NULL; 124 | wcex.lpszClassName = CLASSNAME_OVERLAPPEDWINDOW; 125 | wcex.hIconSm = NULL; 126 | 127 | RegisterClassEx(&wcex); 128 | } 129 | 130 | 131 | ////////////////////////////////////////////////////////////////////// 132 | 133 | bool m_SplitterWindow_IsMoving = false; 134 | int m_SplitterWindow_MovingStartY = 0; 135 | 136 | const int SPLITTERWINDOW_MINWINDOWHEIGHT = 64; 137 | 138 | void SplitterWindow_RegisterClass() 139 | { 140 | WNDCLASSEX wcex; 141 | wcex.cbSize = sizeof(WNDCLASSEX); 142 | 143 | wcex.style = CS_HREDRAW | CS_VREDRAW; 144 | wcex.lpfnWndProc = SplitterWindow_WndProc; 145 | wcex.cbClsExtra = 0; 146 | wcex.cbWndExtra = 8 * 2; 147 | wcex.hInstance = g_hInst; 148 | wcex.hIcon = NULL; 149 | wcex.hCursor = LoadCursor(NULL, IDC_SIZENS); 150 | wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); 151 | wcex.lpszMenuName = NULL; 152 | wcex.lpszClassName = CLASSNAME_SPLITTERWINDOW; 153 | wcex.hIconSm = NULL; 154 | 155 | RegisterClassEx(&wcex); 156 | } 157 | 158 | HWND SplitterWindow_Create(HWND hwndParent, HWND hwndTop, HWND hwndBottom) 159 | { 160 | ASSERT(hwndParent != NULL); 161 | ASSERT(hwndTop != NULL); 162 | ASSERT(hwndBottom != NULL); 163 | 164 | HWND hwnd = CreateWindow( 165 | CLASSNAME_SPLITTERWINDOW, NULL, 166 | WS_CHILD | WS_VISIBLE, 167 | 0, 0, 100, 4, 168 | hwndParent, NULL, g_hInst, NULL); 169 | 170 | SetWindowLongPtr(hwnd, 0, (LONG_PTR)hwndTop); 171 | SetWindowLongPtr(hwnd, 8, (LONG_PTR)hwndBottom); 172 | 173 | m_SplitterWindow_IsMoving = false; 174 | 175 | return hwnd; 176 | } 177 | 178 | void SplitterWindow_MoveWindows(HWND hwndSplitter, int deltaY) 179 | { 180 | if (deltaY == 0) 181 | return; 182 | 183 | HWND hwndTop = (HWND)GetWindowLongPtr(hwndSplitter, 0); 184 | HWND hwndBottom = (HWND)GetWindowLongPtr(hwndSplitter, 8); 185 | 186 | RECT rcTop; ::GetWindowRect(hwndTop, &rcTop); 187 | ::ScreenToClient(g_hwnd, (POINT*)&rcTop); 188 | ::ScreenToClient(g_hwnd, ((POINT*)&rcTop) + 1); 189 | RECT rcBottom; ::GetWindowRect(hwndBottom, &rcBottom); 190 | ::ScreenToClient(g_hwnd, (POINT*)&rcBottom); 191 | ::ScreenToClient(g_hwnd, ((POINT*)&rcBottom) + 1); 192 | 193 | if (deltaY < 0 && rcTop.bottom - rcTop.top + deltaY < SPLITTERWINDOW_MINWINDOWHEIGHT) 194 | deltaY = SPLITTERWINDOW_MINWINDOWHEIGHT - (rcTop.bottom - rcTop.top); 195 | if (deltaY > 0 && rcBottom.bottom - rcBottom.top - deltaY < SPLITTERWINDOW_MINWINDOWHEIGHT) 196 | deltaY = (rcBottom.bottom - rcBottom.top) - SPLITTERWINDOW_MINWINDOWHEIGHT; 197 | 198 | SetWindowPos(hwndTop, NULL, rcTop.left, rcTop.top, rcTop.right - rcTop.left, rcTop.bottom - rcTop.top + deltaY, SWP_NOZORDER); 199 | SetWindowPos(hwndBottom, NULL, rcBottom.left, rcBottom.top + deltaY, rcBottom.right - rcBottom.left, rcBottom.bottom - rcBottom.top - deltaY, SWP_NOZORDER); 200 | SetWindowPos(hwndSplitter, NULL, rcBottom.left, rcBottom.top + deltaY - 4, rcBottom.right - rcBottom.left, 4, SWP_NOZORDER); 201 | } 202 | 203 | LRESULT CALLBACK SplitterWindow_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 204 | { 205 | UNREFERENCED_PARAMETER(lParam); 206 | switch (message) 207 | { 208 | case WM_LBUTTONDOWN: 209 | m_SplitterWindow_IsMoving = true; 210 | m_SplitterWindow_MovingStartY = GET_Y_LPARAM(lParam); 211 | ::SetCapture(hWnd); 212 | //TODO: Draw frame 213 | return 0; 214 | case WM_LBUTTONUP: 215 | if (m_SplitterWindow_IsMoving) 216 | { 217 | m_SplitterWindow_IsMoving = false; 218 | ::ReleaseCapture(); 219 | 220 | int deltaY = GET_Y_LPARAM(lParam) - m_SplitterWindow_MovingStartY; 221 | SplitterWindow_MoveWindows(hWnd, deltaY); 222 | } 223 | return 0; 224 | case WM_MOUSEMOVE: 225 | if ((wParam == MK_LBUTTON) && m_SplitterWindow_IsMoving) 226 | { 227 | //TODO: Redraw frame 228 | } 229 | return 0; 230 | default: 231 | return DefWindowProc(hWnd, message, wParam, lParam); 232 | } 233 | //return (LRESULT)FALSE; 234 | } 235 | 236 | 237 | ////////////////////////////////////////////////////////////////////// 238 | -------------------------------------------------------------------------------- /emulator/ToolWindow.h: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // ToolWindow.h 12 | 13 | #pragma once 14 | 15 | ////////////////////////////////////////////////////////////////////// 16 | 17 | 18 | #define CLASSNAMEPREFIX _T("BKBTL") 19 | 20 | const LPCTSTR CLASSNAME_TOOLWINDOW = CLASSNAMEPREFIX _T("TOOLWINDOW"); 21 | const LPCTSTR CLASSNAME_OVERLAPPEDWINDOW = CLASSNAMEPREFIX _T("OVERLAPPEDWINDOW"); 22 | const LPCTSTR CLASSNAME_SPLITTERWINDOW = CLASSNAMEPREFIX _T("SPLITTERWINDOW"); 23 | 24 | const int TOOLWINDOW_CAPTION_HEIGHT = 16; 25 | 26 | void ToolWindow_RegisterClass(); 27 | LRESULT CALLBACK ToolWindow_WndProc(HWND, UINT, WPARAM, LPARAM); 28 | 29 | void OverlappedWindow_RegisterClass(); 30 | 31 | void SplitterWindow_RegisterClass(); 32 | LRESULT CALLBACK SplitterWindow_WndProc(HWND, UINT, WPARAM, LPARAM); 33 | HWND SplitterWindow_Create(HWND hwndParent, HWND hwndTop, HWND hwndBottom); 34 | 35 | 36 | ////////////////////////////////////////////////////////////////////// 37 | 38 | -------------------------------------------------------------------------------- /emulator/Views.h: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // Views.h 12 | // Defines for all views of the application 13 | 14 | #pragma once 15 | 16 | ////////////////////////////////////////////////////////////////////// 17 | // Window class names 18 | 19 | #define CLASSNAMEPREFIX _T("BKBTL") 20 | 21 | const LPCTSTR CLASSNAME_SCREENVIEW = CLASSNAMEPREFIX _T("SCREEN"); 22 | const LPCTSTR CLASSNAME_KEYBOARDVIEW = CLASSNAMEPREFIX _T("KEYBOARD"); 23 | const LPCTSTR CLASSNAME_DEBUGVIEW = CLASSNAMEPREFIX _T("DEBUG"); 24 | const LPCTSTR CLASSNAME_DISASMVIEW = CLASSNAMEPREFIX _T("DISASM"); 25 | const LPCTSTR CLASSNAME_MEMORYVIEW = CLASSNAMEPREFIX _T("MEMORY"); 26 | const LPCTSTR CLASSNAME_MEMORYMAPVIEW = CLASSNAMEPREFIX _T("MEMORYMAP"); 27 | const LPCTSTR CLASSNAME_SPRITEVIEW = CLASSNAMEPREFIX _T("SPRITE"); 28 | const LPCTSTR CLASSNAME_TELETYPEVIEW = CLASSNAMEPREFIX _T("TELETYPE"); 29 | const LPCTSTR CLASSNAME_CONSOLEVIEW = CLASSNAMEPREFIX _T("CONSOLE"); 30 | const LPCTSTR CLASSNAME_TAPEVIEW = CLASSNAMEPREFIX _T("TAPE"); 31 | 32 | 33 | ////////////////////////////////////////////////////////////////////// 34 | // ScreenView 35 | 36 | extern HWND g_hwndScreen; // Screen View window handle 37 | 38 | void ScreenView_RegisterClass(); 39 | void ScreenView_Init(); 40 | void ScreenView_Done(); 41 | int ScreenView_GetScreenMode(); 42 | void ScreenView_SetScreenMode(int); 43 | void ScreenView_PrepareScreen(); 44 | void ScreenView_ScanKeyboard(); 45 | void ScreenView_ProcessKeyboard(); 46 | void ScreenView_RedrawScreen(); // Force to call PrepareScreen and to draw the image 47 | void ScreenView_Create(HWND hwndParent, int x, int y); 48 | LRESULT CALLBACK ScreenViewWndProc(HWND, UINT, WPARAM, LPARAM); 49 | BOOL ScreenView_SaveScreenshot(LPCTSTR sFileName); 50 | HGLOBAL ScreenView_GetScreenshotAsDIB(); 51 | void ScreenView_KeyEvent(BYTE keyscan, BOOL pressed); 52 | 53 | 54 | ////////////////////////////////////////////////////////////////////// 55 | // KeyboardView 56 | 57 | extern HWND g_hwndKeyboard; // Keyboard View window handle 58 | 59 | void KeyboardView_RegisterClass(); 60 | void KeyboardView_Init(); 61 | void KeyboardView_Done(); 62 | void KeyboardView_Create(HWND hwndParent, int x, int y, int width, int height); 63 | LRESULT CALLBACK KeyboardViewWndProc(HWND, UINT, WPARAM, LPARAM); 64 | void KeyboardView_Update(); 65 | void KeyboardView_KeyEvent(BYTE keyscan, BOOL pressed); 66 | 67 | 68 | ////////////////////////////////////////////////////////////////////// 69 | // DebugView 70 | 71 | extern HWND g_hwndDebug; // Debug View window handle 72 | 73 | void DebugView_RegisterClass(); 74 | void DebugView_Init(); 75 | void DebugView_Create(HWND hwndParent, int x, int y, int width, int height); 76 | void DebugView_Redraw(); 77 | LRESULT CALLBACK DebugViewWndProc(HWND, UINT, WPARAM, LPARAM); 78 | LRESULT CALLBACK DebugViewViewerWndProc(HWND, UINT, WPARAM, LPARAM); 79 | void DebugView_OnUpdate(); 80 | BOOL DebugView_IsRegisterChanged(int regno); 81 | 82 | 83 | ////////////////////////////////////////////////////////////////////// 84 | // DisasmView 85 | 86 | extern HWND g_hwndDisasm; // Disasm View window handle 87 | 88 | void DisasmView_RegisterClass(); 89 | void DisasmView_Init(); 90 | void DisasmView_Done(); 91 | void DisasmView_Create(HWND hwndParent, int x, int y, int width, int height); 92 | void DisasmView_Redraw(); 93 | LRESULT CALLBACK DisasmViewWndProc(HWND, UINT, WPARAM, LPARAM); 94 | LRESULT CALLBACK DisasmViewViewerWndProc(HWND, UINT, WPARAM, LPARAM); 95 | void DisasmView_OnUpdate(); 96 | void DisasmView_LoadUnloadSubtitles(); 97 | 98 | 99 | ////////////////////////////////////////////////////////////////////// 100 | // MemoryView 101 | 102 | extern HWND g_hwndMemory; // Memory view window handler 103 | 104 | enum MemoryViewNumeralMode 105 | { 106 | MEMMODENUM_OCT = 0, 107 | MEMMODENUM_HEX = 1, 108 | }; 109 | 110 | void MemoryView_RegisterClass(); 111 | void MemoryView_Create(HWND hwndParent, int x, int y, int width, int height); 112 | LRESULT CALLBACK MemoryViewWndProc(HWND, UINT, WPARAM, LPARAM); 113 | LRESULT CALLBACK MemoryViewViewerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); 114 | void MemoryView_SwitchWordByte(); 115 | void MemoryView_SwitchNumeralMode(); 116 | void MemoryView_SelectAddress(); 117 | 118 | 119 | ////////////////////////////////////////////////////////////////////// 120 | // MemoryMapView 121 | 122 | extern HWND g_hwndMemoryMap; // MemoryMap view window handler 123 | 124 | void MemoryMapView_RegisterClass(); 125 | void MemoryMapView_Create(HWND hwndParent, int x, int y); 126 | LRESULT CALLBACK MemoryMapViewWndProc(HWND, UINT, WPARAM, LPARAM); 127 | LRESULT CALLBACK MemoryMapViewViewerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); 128 | void MemoryMapView_RedrawMap(); 129 | 130 | 131 | ////////////////////////////////////////////////////////////////////// 132 | // SpriteView 133 | 134 | extern HWND g_hwndSprite; // Sprite view window handler 135 | 136 | void SpriteView_RegisterClass(); 137 | void SpriteView_Create(int x, int y); 138 | LRESULT CALLBACK SpriteViewWndProc(HWND, UINT, WPARAM, LPARAM); 139 | LRESULT CALLBACK SpriteViewViewerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); 140 | 141 | 142 | ////////////////////////////////////////////////////////////////////// 143 | // TeletypeView 144 | 145 | extern HWND g_hwndTeletype; // Teletype View window handle 146 | void TeletypeView_RegisterClass(); 147 | void TeletypeView_Create(int x, int y, int width, int height); 148 | LRESULT CALLBACK TeletypeViewWndProc(HWND, UINT, WPARAM, LPARAM); 149 | LRESULT CALLBACK TeletypeViewViewerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); 150 | void TeletypeView_OutputSymbol(TCHAR symbol); 151 | void TeletypeView_Output(LPCTSTR message); 152 | 153 | 154 | ////////////////////////////////////////////////////////////////////// 155 | // ConsoleView 156 | 157 | extern HWND g_hwndConsole; // Console View window handle 158 | 159 | void ConsoleView_RegisterClass(); 160 | void ConsoleView_Create(HWND hwndParent, int x, int y, int width, int height); 161 | LRESULT CALLBACK ConsoleViewWndProc(HWND, UINT, WPARAM, LPARAM); 162 | void ConsoleView_PrintFormat(LPCTSTR pszFormat, ...); 163 | void ConsoleView_Print(LPCTSTR message); 164 | void ConsoleView_Activate(); 165 | void ConsoleView_StepInto(); 166 | void ConsoleView_StepOver(); 167 | void ConsoleView_ClearConsole(); 168 | void ConsoleView_DeleteAllBreakpoints(); 169 | 170 | 171 | ////////////////////////////////////////////////////////////////////// 172 | // TapeView 173 | 174 | extern HWND g_hwndTape; // Tape View window handle 175 | 176 | void TapeView_RegisterClass(); 177 | void TapeView_Create(HWND hwndParent, int x, int y, int width, int height); 178 | LRESULT CALLBACK TapeViewWndProc(HWND, UINT, WPARAM, LPARAM); 179 | 180 | 181 | ////////////////////////////////////////////////////////////////////// 182 | -------------------------------------------------------------------------------- /emulator/emubase/Board.h: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // Board.h 12 | // 13 | 14 | #pragma once 15 | 16 | class CProcessor; 17 | 18 | 19 | ////////////////////////////////////////////////////////////////////// 20 | 21 | // Machine configurations 22 | enum BKConfiguration 23 | { 24 | // Configuration options 25 | BK_COPT_BK0010 = 0, 26 | BK_COPT_BK0011 = 1, 27 | BK_COPT_ROM_BASIC = 2, 28 | BK_COPT_ROM_FOCAL = 4, 29 | BK_COPT_FDD = 16, 30 | 31 | // Configurations BK-0010(01) 32 | BK_CONF_BK0010_BASIC = // БК-0010(01) и BASIC-86 33 | BK_COPT_BK0010 | BK_COPT_ROM_BASIC, 34 | BK_CONF_BK0010_FOCAL = // БК-0010(01) и Фокал + тесты 35 | BK_COPT_BK0010 | BK_COPT_ROM_FOCAL, 36 | BK_CONF_BK0010_FDD = // БК-0010(01) и блок КНГМД с 16 КБ ОЗУ 37 | BK_COPT_BK0010 | BK_COPT_FDD, 38 | // Configurations BK-0011M 39 | BK_CONF_BK0011 = // БК-0011М без блока КНГМД 40 | BK_COPT_BK0011, 41 | BK_CONF_BK0011_FDD = // БК-0011М и блок КНГМД 42 | BK_COPT_BK0011 | BK_COPT_FDD, 43 | }; 44 | 45 | 46 | ////////////////////////////////////////////////////////////////////// 47 | 48 | 49 | // TranslateAddress result code 50 | #define ADDRTYPE_RAM 0 // RAM 51 | #define ADDRTYPE_ROM 32 // ROM 52 | #define ADDRTYPE_IO 64 // I/O port 53 | #define ADDRTYPE_DENY 128 // Access denied 54 | #define ADDRTYPE_MASK 224 // RAM type mask 55 | #define ADDRTYPE_RAMMASK 7 // RAM chunk number mask 56 | 57 | // Trace flags 58 | #define TRACE_NONE 0 // Turn off all tracing 59 | #define TRACE_CPUROM 1 // Trace CPU instructions from ROM 60 | #define TRACE_CPURAM 2 // Trace CPU instructions from RAM 61 | #define TRACE_CPU 3 // Trace CPU instructions (mask) 62 | #define TRACE_FLOPPY 0100 // Trace floppies 63 | #define TRACE_ALL 0177777 // Trace all 64 | 65 | //floppy debug 66 | #define FLOPPY_FSM_WAITFORLSB 0 67 | #define FLOPPY_FSM_WAITFORMSB 1 68 | #define FLOPPY_FSM_WAITFORTERM1 2 69 | #define FLOPPY_FSM_WAITFORTERM2 3 70 | 71 | // Emulator image constants 72 | #define BKIMAGE_HEADER_SIZE 32 73 | #define BKIMAGE_SIZE 200704 74 | #define BKIMAGE_HEADER1 0x30304B41 // "BK00" 75 | #define BKIMAGE_HEADER2 0x214C5442 // "BTL!" 76 | #define BKIMAGE_VERSION 0x00010000 // 1.0 77 | 78 | 79 | ////////////////////////////////////////////////////////////////////// 80 | // BK special key codes 81 | 82 | #define BK_KEY_REPEAT 0201 83 | #define BK_KEY_LOWER 0273 84 | #define BK_KEY_UPPER 0274 85 | #define BK_KEY_BACKSHIFT 0275 86 | #define BK_KEY_AR2 0276 87 | #define BK_KEY_STOP 0277 88 | 89 | // События от джойстика - передавать в метод KeyboardEvent 90 | #define BK_KEY_JOYSTICK_BUTTON1 0260 91 | #define BK_KEY_JOYSTICK_BUTTON2 0261 92 | #define BK_KEY_JOYSTICK_BUTTON3 0262 93 | #define BK_KEY_JOYSTICK_BUTTON4 0263 94 | #define BK_KEY_JOYSTICK_RIGHT 0264 95 | #define BK_KEY_JOYSTICK_DOWN 0265 96 | #define BK_KEY_JOYSTICK_LEFT 0266 97 | #define BK_KEY_JOYSTICK_UP 0267 98 | 99 | // Состояния клавиатуры БК - возвращаются из метода GetKeyboardRegister 100 | #define KEYB_RUS 0x01 101 | #define KEYB_LAT 0x02 102 | #define KEYB_LOWERREG 0x10 103 | 104 | 105 | // Tape emulator callback used to read a tape recorded data. 106 | // Input: 107 | // samples Number of samples to play. 108 | // Output: 109 | // result Bit to put in tape input port. 110 | typedef bool (CALLBACK* TAPEREADCALLBACK)(unsigned int samples); 111 | 112 | // Tape emulator callback used to write a data to tape. 113 | // Input: 114 | // value Sample value to write. 115 | typedef void (CALLBACK* TAPEWRITECALLBACK)(int value, unsigned int samples); 116 | 117 | // Sound generator callback function type 118 | typedef void (CALLBACK* SOUNDGENCALLBACK)(unsigned short L, unsigned short R); 119 | 120 | // Teletype callback function type - board calls it if symbol ready to transmit 121 | typedef void (CALLBACK* TELETYPECALLBACK)(unsigned char value); 122 | 123 | class CFloppyController; 124 | class CSoundAY; 125 | 126 | ////////////////////////////////////////////////////////////////////// 127 | 128 | class CMotherboard // BK computer 129 | { 130 | private: // Devices 131 | CProcessor* m_pCPU; // CPU device 132 | CFloppyController* m_pFloppyCtl; // FDD control 133 | CSoundAY* m_pSoundAY; 134 | private: // Memory 135 | uint16_t m_Configuration; // See BK_COPT_Xxx flag constants 136 | uint8_t m_MemoryMap; // Memory map, every bit defines how 8KB mapped: 0 - RAM, 1 - ROM 137 | uint8_t m_MemoryMapOnOff; // Memory map, every bit defines how 8KB: 0 - deny, 1 - OK 138 | uint8_t* m_pRAM; // RAM, 8 * 16 = 128 KB 139 | uint8_t* m_pROM; // ROM, 4 * 16 = 64 KB 140 | public: // Construct / destruct 141 | CMotherboard(); 142 | ~CMotherboard(); 143 | public: // Getting devices 144 | CProcessor* GetCPU() { return m_pCPU; } 145 | public: // Memory access //TODO: Make it private 146 | uint16_t GetRAMWord(uint16_t offset) const; 147 | uint16_t GetRAMWord(uint8_t chunk, uint16_t offset) const; 148 | uint8_t GetRAMByte(uint16_t offset) const; 149 | uint8_t GetRAMByte(uint8_t chunk, uint16_t offset) const; 150 | void SetRAMWord(uint16_t offset, uint16_t word); 151 | void SetRAMWord(uint8_t chunk, uint16_t offset, uint16_t word); 152 | void SetRAMByte(uint16_t offset, uint8_t byte); 153 | void SetRAMByte(uint8_t chunk, uint16_t offset, uint8_t byte); 154 | uint16_t GetROMWord(uint16_t offset) const; 155 | uint8_t GetROMByte(uint16_t offset) const; 156 | public: // Debug 157 | void DebugTicks(); // One Debug CPU tick -- use for debug step or debug breakpoint 158 | void SetCPUBreakpoints(const uint16_t* bps) { m_CPUbps = bps; } // Set CPU breakpoint list 159 | uint32_t GetTrace() const { return m_dwTrace; } 160 | void SetTrace(uint32_t dwTrace); 161 | public: // System control 162 | void SetConfiguration(uint16_t conf); 163 | uint16_t GetConfiguration() const { return m_Configuration; } 164 | void Reset(); // Reset computer 165 | void LoadROM(int bank, const uint8_t* pBuffer); // Load 8 KB ROM image from the biffer 166 | void LoadRAM(int startbank, const uint8_t* pBuffer, int length); // Load data into the RAM 167 | void Tick50(); // Tick 50 Hz - goes to CPU EVNT line 168 | void TimerTick(); // Timer Tick, 31250 Hz, 32uS -- dividers are within timer routine 169 | void ResetDevices(); // INIT signal 170 | void SetSoundAY(bool onoff); 171 | public: 172 | void ExecuteCPU(); // Execute one CPU instruction 173 | bool SystemFrame(); // Do one frame -- use for normal run 174 | void KeyboardEvent(uint8_t scancode, bool okPressed, bool okAr2); // Key pressed or released 175 | uint16_t GetKeyboardRegister() const; 176 | uint16_t GetPrinterOutPort() const { return m_Port177714out; } 177 | void SetPrinterInPort(uint8_t data); 178 | bool IsTapeMotorOn() const { return (m_Port177716tap & 0200) == 0; } 179 | int GetSoundChanges() const { return m_SoundChanges; } ///< Sound signal 0 to 1 changes since the beginning of the frame 180 | public: // Floppy 181 | bool AttachFloppyImage(int slot, LPCTSTR sFileName); 182 | void DetachFloppyImage(int slot); 183 | bool IsFloppyImageAttached(int slot) const; 184 | bool IsFloppyReadOnly(int slot) const; 185 | bool IsFloppyEngineOn() const; // Check if the floppy drive engine rotates the disks 186 | public: // Callbacks 187 | void SetTapeReadCallback(TAPEREADCALLBACK callback, int sampleRate); 188 | void SetTapeWriteCallback(TAPEWRITECALLBACK callback, int sampleRate); 189 | void SetSoundGenCallback(SOUNDGENCALLBACK callback); 190 | void SetTeletypeCallback(TELETYPECALLBACK callback); 191 | public: // Memory 192 | // Read command for execution 193 | uint16_t GetWordExec(uint16_t address, bool okHaltMode) { return GetWord(address, okHaltMode, true); } 194 | // Read word from memory 195 | uint16_t GetWord(uint16_t address, bool okHaltMode) { return GetWord(address, okHaltMode, false); } 196 | // Read word 197 | uint16_t GetWord(uint16_t address, bool okHaltMode, bool okExec); 198 | // Write word 199 | void SetWord(uint16_t address, bool okHaltMode, uint16_t word); 200 | // Read byte 201 | uint8_t GetByte(uint16_t address, bool okHaltMode); 202 | // Write byte 203 | void SetByte(uint16_t address, bool okHaltMode, uint8_t byte); 204 | // Read word from memory for debugger 205 | uint16_t GetWordView(uint16_t address, bool okHaltMode, bool okExec, int* pAddrType) const; 206 | // Read word from port for debugger 207 | uint16_t GetPortView(uint16_t address) const; 208 | // Read SEL register 209 | uint16_t GetSelRegister() const { return m_Port177716; } 210 | // Get palette number 0..15 (BK0011 only) 211 | uint8_t GetPalette() const { return (m_Port177662wr >> 8) & 0x0f; } 212 | // Get video buffer address 213 | const uint8_t* GetVideoBuffer() const; 214 | private: 215 | void TapeInput(bool inputBit); // Tape input bit received 216 | private: 217 | // Determine memory type for given address - see ADDRTYPE_Xxx constants 218 | // okHaltMode - processor mode (USER/HALT) 219 | // okExec - true: read instruction for execution; false: read memory 220 | // pOffset - result - offset in memory plane 221 | int TranslateAddress(uint16_t address, bool okHaltMode, bool okExec, uint16_t* pOffset) const; 222 | private: // Access to I/O ports 223 | uint16_t GetPortWord(uint16_t address); 224 | void SetPortWord(uint16_t address, uint16_t word); 225 | uint8_t GetPortByte(uint16_t address); 226 | void SetPortByte(uint16_t address, uint8_t byte); 227 | public: // Saving/loading emulator status 228 | void SaveToImage(uint8_t* pImage); 229 | void LoadFromImage(const uint8_t* pImage); 230 | private: // Ports: implementation 231 | uint16_t m_Port177560; // Serial port input state register 232 | uint16_t m_Port177562; // Serial port input data register 233 | uint16_t m_Port177564; // Serial port output state register 234 | uint16_t m_Port177566; // Serial port output data register 235 | uint16_t m_Port177660; // Keyboard status register 236 | uint16_t m_Port177662rd; // Keyboard register 237 | uint16_t m_Port177662wr; // Palette register 238 | uint16_t m_Port177664; // Scroll register 239 | uint16_t m_Port177714in; // Parallel port, input register 240 | uint16_t m_Port177714out; // Parallel port, output register 241 | uint16_t m_Port177716; // System register (read only) 242 | uint16_t m_Port177716mem; // System register (memory) 243 | uint16_t m_Port177716tap; // System register (tape) 244 | bool m_okSoundAY; 245 | uint8_t m_nSoundAYReg; // AY current register 246 | private: // Timer implementation 247 | uint16_t m_timer; 248 | uint16_t m_timerreload; 249 | uint16_t m_timerflags; 250 | uint16_t m_timerdivider; 251 | void SetTimerReload(uint16_t val); //sets timer reload value 252 | void SetTimerState(uint16_t val); //sets timer state 253 | private: 254 | const uint16_t* m_CPUbps; // CPU breakpoint list, ends with 177777 value 255 | uint32_t m_dwTrace; // Trace flags 256 | int m_SoundPrevValue; // Previous value of the sound signal 257 | int m_SoundChanges; // Sound signal 0 to 1 changes since the beginning of the frame 258 | private: 259 | TAPEREADCALLBACK m_TapeReadCallback; 260 | TAPEWRITECALLBACK m_TapeWriteCallback; 261 | int m_nTapeSampleRate; 262 | SOUNDGENCALLBACK m_SoundGenCallback; 263 | TELETYPECALLBACK m_TeletypeCallback; 264 | private: 265 | void DoSound(); 266 | }; 267 | 268 | 269 | ////////////////////////////////////////////////////////////////////// 270 | -------------------------------------------------------------------------------- /emulator/emubase/Defines.h: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // Defines.h 12 | // PDP11-like processor defines 13 | 14 | #pragma once 15 | 16 | 17 | ////////////////////////////////////////////////////////////////////// 18 | 19 | inline uint8_t GetDigit(uint16_t word, int pos) 20 | { 21 | //return (word >>= pos * 3) % 8; 22 | return static_cast((word >>= ((pos << 1) + pos)) & 7); 23 | } 24 | 25 | // Constants for "pos" argument 26 | #define SRC 2 27 | #define DST 0 28 | 29 | 30 | ////////////////////////////////////////////////////////////////////// 31 | 32 | // Process Status Word (PSW) bits 33 | #define PSW_C 1 // Carry 34 | #define PSW_V 2 // Arithmetic overflow 35 | #define PSW_Z 4 // Zero result 36 | #define PSW_N 8 // Negative result 37 | #define PSW_T 16 // Trap/Debug 38 | #define PSW_P 0200 // Priority 39 | #define PSW_HALT 0400 // Halt 40 | 41 | // Commands -- no operands 42 | #define PI_HALT 0000000 43 | #define PI_WAIT 0000001 44 | #define PI_RTI 0000002 45 | #define PI_BPT 0000003 46 | #define PI_IOT 0000004 47 | #define PI_RESET 0000005 48 | #define PI_RTT 0000006 49 | #define PI_MFPT 0000007 50 | #define PI_HALT10 0000010 51 | #define PI_HALT11 0000011 52 | #define PI_HALT12 0000012 53 | #define PI_HALT13 0000013 54 | #define PI_HALT14 0000014 55 | #define PI_HALT15 0000015 56 | #define PI_HALT16 0000016 57 | #define PI_HALT17 0000017 58 | #define PI_NOP 0000240 59 | #define PI_CLC 0000241 60 | #define PI_CLV 0000242 61 | #define PI_CLVC 0000243 62 | #define PI_CLZ 0000244 63 | #define PI_CLZC 0000245 64 | #define PI_CLZV 0000246 65 | #define PI_CLZVC 0000247 66 | #define PI_CLN 0000250 67 | #define PI_CLNC 0000251 68 | #define PI_CLNV 0000252 69 | #define PI_CLNVC 0000253 70 | #define PI_CLNZ 0000254 71 | #define PI_CLNZC 0000255 72 | #define PI_CLNZV 0000256 73 | #define PI_CCC 0000257 74 | #define PI_NOP260 0000260 75 | #define PI_SEC 0000261 76 | #define PI_SEV 0000262 77 | #define PI_SEVC 0000263 78 | #define PI_SEZ 0000264 79 | #define PI_SEZC 0000265 80 | #define PI_SEZV 0000266 81 | #define PI_SEZVC 0000267 82 | #define PI_SEN 0000270 83 | #define PI_SENC 0000271 84 | #define PI_SENV 0000272 85 | #define PI_SENVC 0000273 86 | #define PI_SENZ 0000274 87 | #define PI_SENZC 0000275 88 | #define PI_SENZV 0000276 89 | #define PI_SCC 0000277 90 | #define PI_MED 0076600 91 | 92 | // Commands -- single operand 93 | #define PI_RTS 0000200 94 | 95 | // Commands -- two operands 96 | #define PI_JMP 0000100 97 | #define PI_SWAB 0000300 98 | #define PI_CLR 0005000 99 | #define PI_COM 0005100 100 | #define PI_INC 0005200 101 | #define PI_DEC 0005300 102 | #define PI_NEG 0005400 103 | #define PI_ADC 0005500 104 | #define PI_SBC 0005600 105 | #define PI_TST 0005700 106 | #define PI_ROR 0006000 107 | #define PI_ROL 0006100 108 | #define PI_ASR 0006200 109 | #define PI_ASL 0006300 110 | #define PI_MARK 0006400 111 | #define PI_SXT 0006700 112 | #define PI_MTPS 0106400 113 | #define PI_MFPS 0106700 114 | 115 | // Commands -- branchs 116 | #define PI_BR 0000400 117 | #define PI_BNE 0001000 118 | #define PI_BEQ 0001400 119 | #define PI_BGE 0002000 120 | #define PI_BLT 0002400 121 | #define PI_BGT 0003000 122 | #define PI_BLE 0003400 123 | #define PI_BPL 0100000 124 | #define PI_BMI 0100400 125 | #define PI_BHI 0101000 126 | #define PI_BLOS 0101400 127 | #define PI_BVC 0102000 128 | #define PI_BVS 0102400 129 | #define PI_BHIS 0103000 130 | #define PI_BLO 0103400 131 | 132 | #define PI_EMT 0104000 133 | #define PI_TRAP 0104400 134 | 135 | // Commands -- three operands 136 | #define PI_JSR 0004000 137 | #define PI_MUL 0070000 138 | #define PI_DIV 0071000 139 | #define PI_ASH 0072000 140 | #define PI_ASHC 0073000 141 | #define PI_XOR 0074000 142 | #define PI_SOB 0077000 143 | 144 | // Commands -- four operands 145 | #define PI_MOV 0010000 146 | #define PI_CMP 0020000 147 | #define PI_BIT 0030000 148 | #define PI_BIC 0040000 149 | #define PI_BIS 0050000 150 | 151 | #define PI_ADD 0060000 152 | #define PI_SUB 0160000 153 | 154 | // Commands -- VM2 specifics 155 | #define PI_MUL 0070000 156 | #define PI_DIV 0071000 157 | #define PI_ASH 0072000 158 | #define PI_ASHC 0073000 159 | #define PI_FADD 0075000 160 | #define PI_FSUB 0075010 161 | #define PI_FMUL 0075020 162 | #define PI_FDIV 0075030 163 | 164 | -------------------------------------------------------------------------------- /emulator/emubase/Emubase.h: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // Emubase.h Header for use of all emubase classes 12 | // 13 | 14 | #pragma once 15 | 16 | #include "Board.h" 17 | #include "Processor.h" 18 | 19 | 20 | ////////////////////////////////////////////////////////////////////// 21 | 22 | 23 | #define SOUNDSAMPLERATE 22050 24 | 25 | 26 | ////////////////////////////////////////////////////////////////////// 27 | // Disassembler 28 | 29 | // Disassemble one instruction of KM1801VM2 processor 30 | // pMemory - memory image (we read only words of the instruction) 31 | // sInstr - instruction mnemonics buffer - at least 8 characters 32 | // sArg - instruction arguments buffer - at least 32 characters 33 | // Return value: number of words in the instruction 34 | uint16_t DisassembleInstruction(const uint16_t* pMemory, uint16_t addr, TCHAR* sInstr, TCHAR* sArg); 35 | 36 | bool Disasm_CheckForJump(const uint16_t* memory, int* pDelta); 37 | 38 | // Prepare "Jump Hint" string, and also calculate condition for conditional jump 39 | // Returns: jump prediction flag: true = will jump, false = will not jump 40 | bool Disasm_GetJumpConditionHint( 41 | const uint16_t* memory, const CProcessor * pProc, const CMotherboard * pBoard, LPTSTR buffer); 42 | 43 | // Prepare "Instruction Hint" for a regular instruction (not a branch/jump one) 44 | // buffer, buffer2 - buffers for 1st and 2nd lines of the instruction hint, min size 42 45 | // Returns: number of hint lines; 0 = no hints 46 | int Disasm_GetInstructionHint( 47 | const uint16_t* memory, const CProcessor * pProc, const CMotherboard * pBoard, 48 | LPTSTR buffer, LPTSTR buffer2); 49 | 50 | 51 | ////////////////////////////////////////////////////////////////////// 52 | // CFloppy 53 | 54 | #define FLOPPY_FSM_IDLE 0 55 | 56 | #define FLOPPY_CMD_ENGINESTART 020 57 | #define FLOPPY_CMD_SIDEUP 040 58 | #define FLOPPY_CMD_DIR 0100 59 | #define FLOPPY_CMD_STEP 0200 60 | #define FLOPPY_CMD_READDATA 0400 61 | #define FLOPPY_CMD_WRITEMARKER 01000 62 | #define FLOPPY_CMD_PRECORRECTION 02000 63 | 64 | //dir == 0 to center (towards trk0) 65 | //dir == 1 from center (towards trk80) 66 | 67 | #define FLOPPY_STATUS_TRACK0 01 68 | #define FLOPPY_STATUS_RDY 02 69 | #define FLOPPY_STATUS_WRITEPROTECT 04 70 | #define FLOPPY_STATUS_MOREDATA 0200 71 | #define FLOPPY_STATUS_CHECKSUMOK 040000 72 | #define FLOPPY_STATUS_INDEXMARK 0100000 73 | 74 | #define FLOPPY_RAWTRACKSIZE 6250 // Raw track size, bytes 75 | #define FLOPPY_RAWMARKERSIZE (FLOPPY_RAWTRACKSIZE / 2) 76 | #define FLOPPY_INDEXLENGTH 30 // Length of index hole, in bytes of raw track image 77 | 78 | struct CFloppyDrive 79 | { 80 | FILE* fpFile; 81 | bool okReadOnly; // Write protection flag 82 | uint16_t dataptr; // Data offset within m_data - "head" position 83 | uint8_t data[FLOPPY_RAWTRACKSIZE]; // Raw track image for the current track 84 | uint8_t marker[FLOPPY_RAWMARKERSIZE]; // Marker positions 85 | uint16_t datatrack; // Track number of data in m_data array 86 | uint16_t dataside; // Disk side of data in m_data array 87 | 88 | public: 89 | CFloppyDrive(); 90 | void Reset(); 91 | }; 92 | 93 | class CFloppyController 94 | { 95 | protected: 96 | CFloppyDrive m_drivedata[4]; 97 | int m_drive; // Drive number: from 0 to 3; -1 if not selected 98 | CFloppyDrive* m_pDrive; // Current drive; nullptr if not selected 99 | uint16_t m_track; // Track number: from 0 to 79 100 | uint16_t m_side; // Disk side: 0 or 1 101 | uint16_t m_status; // See FLOPPY_STATUS_XXX defines 102 | uint16_t m_flags; // See FLOPPY_CMD_XXX defines 103 | uint16_t m_datareg; // Read mode data register 104 | uint16_t m_writereg; // Write mode data register 105 | bool m_writeflag; // Write mode data register has data 106 | bool m_writemarker; // Write marker in m_marker 107 | uint16_t m_shiftreg; // Write mode shift register 108 | bool m_shiftflag; // Write mode shift register has data 109 | bool m_shiftmarker; // Write marker in m_marker 110 | bool m_writing; // TRUE = write mode, false = read mode 111 | bool m_searchsynctrig; // Search for sync trigger 112 | bool m_searchsync; // Read sub-mode: TRUE = search for sync, false = just read 113 | bool m_crccalculus; // TRUE = CRC is calculated now 114 | bool m_trackchanged; // TRUE = m_data was changed - need to save it into the file 115 | bool m_okTrace; // Trace mode on/off 116 | 117 | public: 118 | CFloppyController(); 119 | ~CFloppyController(); 120 | void Reset(); 121 | 122 | public: 123 | bool AttachImage(int drive, LPCTSTR sFileName); 124 | void DetachImage(int drive); 125 | bool IsAttached(int drive) const { return (m_drivedata[drive].fpFile != nullptr); } 126 | bool IsReadOnly(int drive) const { return m_drivedata[drive].okReadOnly; } // return (m_status & FLOPPY_STATUS_WRITEPROTECT) != 0; } 127 | bool IsEngineOn() { return (m_flags & FLOPPY_CMD_ENGINESTART) != 0; } 128 | uint16_t GetData(); // Reading port 177132 - data 129 | uint16_t GetState(); // Reading port 177130 - device status 130 | uint16_t GetDataView() const { return m_datareg; } // Get port 177132 value for debugger 131 | uint16_t GetStateView() const { return m_status; } // Get port 177130 value for debugger 132 | void SetCommand(uint16_t cmd); // Writing to port 177130 - commands 133 | void WriteData(uint16_t Data); // Writing to port 177132 - data 134 | void Periodic(); // Rotate disk; call it each 64 us - 15625 times per second 135 | void SetTrace(bool okTrace) { m_okTrace = okTrace; } // Set trace mode on/off 136 | 137 | private: 138 | void PrepareTrack(); 139 | void FlushChanges(); // If current track was changed - save it 140 | }; 141 | 142 | 143 | ////////////////////////////////////////////////////////////////////// 144 | 145 | class CSoundAY 146 | { 147 | protected: 148 | int index; 149 | int ready; 150 | unsigned Regs[16]; 151 | int32_t lastEnable; 152 | int32_t PeriodA, PeriodB, PeriodC, PeriodN, PeriodE; 153 | int32_t CountA, CountB, CountC, CountN, CountE; 154 | uint32_t VolA, VolB, VolC, VolE; 155 | uint8_t EnvelopeA, EnvelopeB, EnvelopeC; 156 | uint8_t OutputA, OutputB, OutputC, OutputN; 157 | int8_t CountEnv; 158 | uint8_t Hold, Alternate, Attack, Holding; 159 | int32_t RNG; 160 | protected: 161 | static unsigned int VolTable[32]; 162 | 163 | public: 164 | CSoundAY(); 165 | void Reset(); 166 | 167 | public: 168 | void SetReg(int r, int v); 169 | void Callback(uint8_t* stream, int length); 170 | 171 | protected: 172 | static void BuildMixerTable(); 173 | }; 174 | 175 | 176 | ////////////////////////////////////////////////////////////////////// 177 | -------------------------------------------------------------------------------- /emulator/manifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /emulator/res/BKBTL.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nzeemin/bkbtl/01c755430088bca9c57310c26cb6470acbe32d2a/emulator/res/BKBTL.ico -------------------------------------------------------------------------------- /emulator/res/BKBTL.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nzeemin/bkbtl/01c755430088bca9c57310c26cb6470acbe32d2a/emulator/res/BKBTL.rc -------------------------------------------------------------------------------- /emulator/res/Keyboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nzeemin/bkbtl/01c755430088bca9c57310c26cb6470acbe32d2a/emulator/res/Keyboard.png -------------------------------------------------------------------------------- /emulator/res/Keyboard11m.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nzeemin/bkbtl/01c755430088bca9c57310c26cb6470acbe32d2a/emulator/res/Keyboard11m.png -------------------------------------------------------------------------------- /emulator/res/Toolbar.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nzeemin/bkbtl/01c755430088bca9c57310c26cb6470acbe32d2a/emulator/res/Toolbar.bmp -------------------------------------------------------------------------------- /emulator/res/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by BKBTL.rc 4 | // 5 | #define IDC_MYICON 2 6 | #define IDD_BKBTL_DIALOG 102 7 | #define IDS_APP_TITLE 103 8 | #define IDD_ABOUTBOX 103 9 | #define IDM_ABOUT 104 10 | #define IDM_EXIT 105 11 | #define IDI_APPICON 107 12 | #define IDI_SMALL 108 13 | #define IDC_APPLICATION 109 14 | #define IDR_MAINFRAME 128 15 | #define IDD_INPUTBOX 129 16 | #define IDI_DISKETTE 138 17 | #define IDI_DISKETTEWP 139 18 | #define IDB_KEYBOARD 140 19 | #define IDB_KEYBOARD11M 141 20 | #define IDB_TOOLBAR 142 21 | #define IDD_CREATEDISK 143 22 | #define IDD_LOADBIN 144 23 | #define IDD_SETTINGS 145 24 | #define IDD_SETTINGS_COLORS 146 25 | #define IDD_COMMANDLINEHELP 152 26 | #define IDC_EDIT1 1000 27 | #define IDC_BUILDDATE 1001 28 | #define IDC_EDITADDR 1001 29 | #define IDC_TRACKS40 1002 30 | #define IDC_EDIT2 1002 31 | #define IDC_EDITSIZE 1002 32 | #define IDC_RADIO2 1003 33 | #define IDC_TRACKS80 1003 34 | #define IDC_EDITNAME 1003 35 | #define IDC_BUTTONBROWSE 1004 36 | #define IDC_EDITFILE 1005 37 | #define IDC_VOLUME 1006 38 | #define IDC_BUTTON1 1025 39 | #define IDC_BUTTON2 1026 40 | #define IDC_TREE1 1028 41 | #define IDC_LIST1 1029 42 | #define IDC_DEBUGFONT 1030 43 | #define IDC_SYSLINK1 1032 44 | #define IDC_VERSION 1033 45 | #define IDC_COMBO1 1034 46 | #define ID_FILE 32771 47 | #define ID_FILE_SAVESTATE 32772 48 | #define ID_FILE_LOADSTATE 32773 49 | #define ID_FILE_SCREENSHOT 32774 50 | #define ID_FILE_SAVESCREENSHOTAS 32775 51 | #define ID_FILE_SCREENSHOTTOCLIPBOARD 32776 52 | #define ID_FILE_LOADBIN 32777 53 | #define ID_FILE_CREATEDISK 32778 54 | #define ID_FILE_SETTINGS 32779 55 | #define ID_FILE_SETTINGS_COLORS 32780 56 | #define ID_VIEW 32784 57 | #define ID_VIEW_MEMORY 32785 58 | #define ID_VIEW_KEYBOARD 32786 59 | #define ID_VIEW_TAPE 32787 60 | #define ID_VIEW_TOOLBAR 32788 61 | #define ID_VIEW_RGBSCREEN 32789 62 | #define ID_EMULATOR 32793 63 | #define ID_EMULATOR_RUN 32794 64 | #define ID_EMULATOR_RESET 32795 65 | #define ID_EMULATOR_AUTOSTART 32796 66 | #define ID_EMULATOR_SPEED10 32797 67 | #define ID_EMULATOR_SPEED25 32798 68 | #define ID_EMULATOR_SPEED50 32799 69 | #define ID_EMULATOR_SPEEDMAX 32800 70 | #define ID_EMULATOR_REALSPEED 32801 71 | #define ID_EMULATOR_SPEED200 32802 72 | #define ID_EMULATOR_SPEED400 32803 73 | #define ID_EMULATOR_CONF 32804 74 | #define ID_EMULATOR_FLOPPY0 32805 75 | #define ID_EMULATOR_FLOPPY1 32806 76 | #define ID_EMULATOR_FLOPPY2 32807 77 | #define ID_EMULATOR_FLOPPY3 32808 78 | #define ID_CONF_BK0010MONIT 32812 79 | #define ID_CONF_BK0010BASIC 32813 80 | #define ID_CONF_BK0010FOCAL 32814 81 | #define ID_CONF_BK0010FDD 32815 82 | #define ID_CONF_BK0011 32816 83 | #define ID_CONF_BK0011FDD 32817 84 | #define ID_EMULATOR_JOYSTICKNUMPAD 32820 85 | #define ID_EMULATOR_JOYSTICK1 32821 86 | #define ID_EMULATOR_JOYSTICK2 32822 87 | #define ID_EMULATOR_SOUND 32831 88 | #define ID_EMULATOR_COVOX 32832 89 | #define ID_EMULATOR_SOUNDAY 32833 90 | #define ID_SCREEN 32846 91 | #define ID_VIEW_SCREENMODE0 32847 92 | #define ID_VIEW_SCREENMODE1 32848 93 | #define ID_VIEW_SCREENMODE2 32849 94 | #define ID_VIEW_SCREENMODE3 32850 95 | #define ID_VIEW_SCREENMODE4 32851 96 | #define ID_VIEW_SCREENMODE5 32852 97 | #define ID_VIEW_SCREENMODE6 32853 98 | #define ID_VIEW_SCREENMODE7 32854 99 | #define ID_VIEW_SCREENMODE8 32855 100 | #define ID_VIEW_SCREENMODE9 32856 101 | #define ID_VIEW_SCREENMODE10 32857 102 | #define ID_VIEW_SCREENMODE11 32858 103 | #define ID_VIEW_SCREENMODE12 32859 104 | #define ID_VIEW_SCREENMODE13 32860 105 | #define ID_VIEW_SCREENMODE14 32861 106 | #define ID_VIEW_SCREENMODE15 32862 107 | #define ID_DEBUG 32881 108 | #define ID_VIEW_DEBUG 32882 109 | #define ID_DEBUG_STEPINTO 32883 110 | #define ID_DEBUG_STEPOVER 32884 111 | #define ID_DEBUG_TELETYPE 32885 112 | #define ID_DEBUG_SPRITES 32886 113 | #define ID_VIEW_MEMORYMAP 32887 114 | #define ID_DEBUG_MEMORY_WORDBYTE 32894 115 | #define ID_DEBUG_MEMORY_HEXMODE 32895 116 | #define ID_DEBUG_MEMORY_GOTO 32896 117 | #define ID_DEBUG_CLEARCONSOLE 32897 118 | #define ID_DEBUG_DELETEALLBREAKPTS 32898 119 | #define ID_DEBUG_SUBTITLES 32899 120 | #define ID_DEBUG_COPY_ADDRESS 32900 121 | #define ID_DEBUG_COPY_VALUE 32901 122 | #define ID_DEBUG_GOTO_ADDRESS 32902 123 | #define ID_HELP_COMMAND_LINE_HELP 32921 124 | #define IDC_STATIC -1 125 | 126 | // Next default values for new objects 127 | // 128 | #ifdef APSTUDIO_INVOKED 129 | #ifndef APSTUDIO_READONLY_SYMBOLS 130 | #define _APS_NO_MFC 1 131 | #define _APS_NEXT_RESOURCE_VALUE 153 132 | #define _APS_NEXT_COMMAND_VALUE 32999 133 | #define _APS_NEXT_CONTROL_VALUE 1035 134 | #define _APS_NEXT_SYMED_VALUE 110 135 | #endif 136 | #endif 137 | -------------------------------------------------------------------------------- /emulator/res/small.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nzeemin/bkbtl/01c755430088bca9c57310c26cb6470acbe32d2a/emulator/res/small.ico -------------------------------------------------------------------------------- /emulator/stdafx.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // stdafx.cpp : source file that includes just the standard includes 12 | // BKBTL.pch will be the pre-compiled header 13 | // stdafx.obj will contain the pre-compiled type information 14 | 15 | #include "stdafx.h" 16 | 17 | // TODO: reference any additional headers you need in STDAFX.H 18 | // and not in this file 19 | -------------------------------------------------------------------------------- /emulator/stdafx.h: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // stdafx.h : include file for standard system include files, 12 | // or project specific include files that are used frequently, but 13 | // are changed infrequently 14 | // 15 | 16 | #pragma once 17 | 18 | //NOTE: I know, we use unsafe string copy functions 19 | #define _CRT_SECURE_NO_WARNINGS 20 | 21 | // NOTE: This trick is needed to bind assembly manifest to the current version of the VC CRT 22 | // See also: http://msdn.microsoft.com/ru-ru/library/cc664727.aspx 23 | #define _BIND_TO_CURRENT_CRT_VERSION 1 24 | 25 | // Modify the following defines if you have to target a platform prior to the ones specified below. 26 | // Refer to MSDN for the latest info on corresponding values for different platforms. 27 | #ifndef WINVER // Allow use of features specific to Windows XP or later. 28 | #define WINVER 0x0501 // Change this to the appropriate value to target other versions of Windows. 29 | #endif 30 | 31 | #ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. 32 | #define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. 33 | #endif 34 | 35 | #ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later. 36 | #define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. 37 | #endif 38 | 39 | #ifndef _WIN32_IE // Allow use of features specific to IE 6.0 or later. 40 | #define _WIN32_IE 0x0600 // Change this to the appropriate value to target other versions of IE. 41 | #endif 42 | 43 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 44 | // Windows Header Files: 45 | #include 46 | 47 | // C RunTime Header Files 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | 54 | // Define C99 stdint.h types for VS2008 55 | #ifdef _MSC_VER 56 | typedef signed __int8 int8_t; 57 | typedef unsigned __int8 uint8_t; 58 | typedef unsigned __int16 uint16_t; 59 | typedef signed __int32 int32_t; 60 | typedef unsigned __int32 uint32_t; 61 | typedef unsigned __int64 uint64_t; 62 | #else 63 | #include 64 | #include 65 | #endif 66 | 67 | // TODO: reference additional headers your program requires here 68 | 69 | #include "Common.h" 70 | -------------------------------------------------------------------------------- /emulator/util/BitmapFile.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // BitmapFile.cpp 12 | 13 | #include "stdafx.h" 14 | #include "BitmapFile.h" 15 | 16 | #include 17 | #include 18 | #pragma comment(lib, "WindowsCodecs.lib") 19 | 20 | 21 | ////////////////////////////////////////////////////////////////////// 22 | // Globals 23 | 24 | IWICImagingFactory * BitmapFile_pIWICFactory = NULL; 25 | 26 | 27 | void BitmapFile_Init() 28 | { 29 | // Initialize COM 30 | CoInitialize(NULL); 31 | 32 | CoCreateInstance( 33 | CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, 34 | IID_PPV_ARGS(&BitmapFile_pIWICFactory)); 35 | } 36 | 37 | void BitmapFile_Done() 38 | { 39 | BitmapFile_pIWICFactory->Release(); 40 | BitmapFile_pIWICFactory = NULL; 41 | } 42 | 43 | 44 | ////////////////////////////////////////////////////////////////////// 45 | 46 | 47 | HBITMAP CreateHBITMAP(IWICBitmapSource * ipBitmap) 48 | { 49 | // get image attributes and check for valid image 50 | UINT width = 0; 51 | UINT height = 0; 52 | if (FAILED(ipBitmap->GetSize(&width, &height)) || width == 0 || height == 0) 53 | return NULL; 54 | 55 | // prepare structure giving bitmap information (negative height indicates a top-down DIB) 56 | BITMAPINFO bminfo; 57 | ZeroMemory(&bminfo, sizeof(bminfo)); 58 | bminfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 59 | bminfo.bmiHeader.biWidth = width; 60 | bminfo.bmiHeader.biHeight = -((LONG)height); 61 | bminfo.bmiHeader.biPlanes = 1; 62 | bminfo.bmiHeader.biBitCount = 32; 63 | bminfo.bmiHeader.biCompression = BI_RGB; 64 | 65 | // create a DIB section that can hold the image 66 | void * pvImageBits = NULL; 67 | HDC hdcScreen = ::GetDC(NULL); 68 | HBITMAP hbmp = ::CreateDIBSection(hdcScreen, &bminfo, DIB_RGB_COLORS, &pvImageBits, NULL, 0); 69 | ReleaseDC(NULL, hdcScreen); 70 | if (hbmp == NULL) 71 | return NULL; 72 | 73 | // extract the image into the HBITMAP 74 | 75 | const UINT cbStride = width * 4; 76 | const UINT cbImage = cbStride * height; 77 | if (FAILED(ipBitmap->CopyPixels(NULL, cbStride, cbImage, static_cast(pvImageBits)))) 78 | { 79 | // couldn't extract image; delete HBITMAP 80 | ::DeleteObject(hbmp); 81 | return NULL; 82 | } 83 | 84 | return hbmp; 85 | } 86 | 87 | HBITMAP BitmapFile_LoadPngFromResource(LPCTSTR lpName) 88 | { 89 | IWICImagingFactory * piFactory = BitmapFile_pIWICFactory; 90 | ASSERT(piFactory != NULL); 91 | 92 | HRESULT hr = NULL; 93 | 94 | // find the resource 95 | HRSRC hrsrc = FindResource(NULL, lpName, _T("IMAGE")); 96 | if (hrsrc == NULL) 97 | return NULL; 98 | 99 | // load the resource 100 | DWORD dwResourceSize = ::SizeofResource(NULL, hrsrc); 101 | HGLOBAL hglbImage = ::LoadResource(NULL, hrsrc); 102 | if (hglbImage == NULL) 103 | return NULL; 104 | 105 | // lock the resource, getting a pointer to its data 106 | LPVOID pvSourceResourceData = ::LockResource(hglbImage); 107 | if (pvSourceResourceData == NULL) 108 | return NULL; 109 | 110 | IWICStream *pIWICStream = NULL; 111 | hr = piFactory->CreateStream(&pIWICStream); 112 | if (hr != S_OK) 113 | return NULL; 114 | 115 | hr = pIWICStream->InitializeFromMemory(reinterpret_cast(pvSourceResourceData), dwResourceSize); 116 | if (hr != S_OK) 117 | return NULL; 118 | 119 | IWICBitmapDecoder *pIDecoder = NULL; 120 | hr = piFactory->CreateDecoderFromStream(pIWICStream, NULL, WICDecodeMetadataCacheOnLoad, &pIDecoder); 121 | if (hr != S_OK) 122 | return NULL; 123 | 124 | IWICBitmapFrameDecode *pIDecoderFrame = NULL; 125 | hr = pIDecoder->GetFrame(0, &pIDecoderFrame); 126 | ::FreeResource(hglbImage); 127 | if (hr != S_OK) 128 | return NULL; 129 | 130 | // convert the image to 32bpp BGRA format with pre-multiplied alpha 131 | // (it may not be stored in that format natively in the PNG resource, 132 | // but we need this format to create the DIB to use on-screen) 133 | IWICBitmapSource * ipBitmap = NULL; 134 | hr = WICConvertBitmapSource(GUID_WICPixelFormat32bppPBGRA, pIDecoderFrame, &ipBitmap); 135 | pIDecoderFrame->Release(); 136 | if (hr != S_OK) 137 | return NULL; 138 | 139 | // create a HBITMAP containing the image 140 | HBITMAP hbmp = CreateHBITMAP(ipBitmap); 141 | ipBitmap->Release(); 142 | if (hbmp == NULL) 143 | return NULL; 144 | 145 | pIWICStream->Release(); 146 | return hbmp; 147 | } 148 | 149 | 150 | ////////////////////////////////////////////////////////////////////// 151 | 152 | 153 | bool BitmapFile_SaveImageFile( 154 | const uint32_t* pBits, 155 | LPCTSTR sFileName, BitmapFileFormat format, 156 | int width, int height) 157 | { 158 | ASSERT(pBits != NULL); 159 | ASSERT(sFileName != NULL); 160 | 161 | IWICImagingFactory * piFactory = BitmapFile_pIWICFactory; 162 | ASSERT(piFactory != NULL); 163 | 164 | GUID containerFormatGuid = GUID_ContainerFormatPng; 165 | switch (format) 166 | { 167 | case BitmapFileFormatBmp: 168 | containerFormatGuid = GUID_ContainerFormatBmp; break; 169 | case BitmapFileFormatTiff: 170 | containerFormatGuid = GUID_ContainerFormatTiff; break; 171 | default: 172 | containerFormatGuid = GUID_ContainerFormatPng; 173 | } 174 | 175 | bool result = false; 176 | HRESULT hr = NULL; 177 | IWICStream *piStream = NULL; 178 | IWICBitmapFrameEncode *piBitmapFrame = NULL; 179 | IPropertyBag2 *pPropertyBag = NULL; 180 | WICPixelFormatGUID formatGUID = GUID_WICPixelFormat24bppBGR; 181 | 182 | IWICBitmapEncoder *piEncoder = NULL; 183 | hr = piFactory->CreateEncoder(containerFormatGuid, NULL, &piEncoder); 184 | if (hr != S_OK) goto Cleanup; 185 | 186 | hr = piFactory->CreateStream(&piStream); 187 | if (hr != S_OK) goto Cleanup; 188 | 189 | hr = piStream->InitializeFromFilename(sFileName, GENERIC_WRITE); 190 | if (hr != S_OK) goto Cleanup; 191 | 192 | hr = piEncoder->Initialize(piStream, WICBitmapEncoderNoCache); 193 | if (hr != S_OK) goto Cleanup; 194 | 195 | hr = piEncoder->CreateNewFrame(&piBitmapFrame, &pPropertyBag); 196 | if (hr != S_OK) goto Cleanup; 197 | 198 | hr = piBitmapFrame->Initialize(pPropertyBag); 199 | if (hr != S_OK) goto Cleanup; 200 | 201 | hr = piBitmapFrame->SetSize(width, height); 202 | if (hr != S_OK) goto Cleanup; 203 | 204 | hr = piBitmapFrame->SetPixelFormat(&formatGUID); 205 | if (hr != S_OK) goto Cleanup; 206 | 207 | hr = IsEqualGUID(formatGUID, GUID_WICPixelFormat24bppBGR) ? S_OK : E_FAIL; 208 | if (hr != S_OK) goto Cleanup; 209 | 210 | // Convert upside-down 32bpp bitmap to normal 24bpp bitmap 211 | UINT cbStride = (width * 24 + 7) / 8; 212 | UINT cbBufferSize = height * cbStride; 213 | BYTE *pbBuffer = new BYTE[cbBufferSize]; 214 | for (int line = 0; line < height; line++) 215 | { 216 | const BYTE* pSrc = reinterpret_cast(pBits) + (height - line - 1) * width * 4; 217 | BYTE* pDst = pbBuffer + line * width * 3; 218 | for (int x = 0; x < width; x++) 219 | { 220 | *pDst++ = *pSrc++; 221 | *pDst++ = *pSrc++; 222 | *pDst++ = *pSrc++; 223 | pSrc++; 224 | } 225 | } 226 | 227 | hr = piBitmapFrame->WritePixels(height, cbStride, cbBufferSize, pbBuffer); 228 | delete[] pbBuffer; 229 | if (hr != S_OK) goto Cleanup; 230 | 231 | hr = piBitmapFrame->Commit(); 232 | if (hr != S_OK) goto Cleanup; 233 | 234 | hr = piEncoder->Commit(); 235 | if (hr != S_OK) goto Cleanup; 236 | 237 | result = true; 238 | 239 | Cleanup: 240 | if (piEncoder != NULL) 241 | piEncoder->Release(); 242 | if (piBitmapFrame != NULL) 243 | piBitmapFrame->Release(); 244 | if (pPropertyBag != NULL) 245 | pPropertyBag->Release(); 246 | if (piStream != NULL) 247 | piStream->Release(); 248 | 249 | return result; 250 | } 251 | 252 | 253 | ////////////////////////////////////////////////////////////////////// 254 | -------------------------------------------------------------------------------- /emulator/util/BitmapFile.h: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // BitmapFile.h 12 | 13 | #pragma once 14 | 15 | ////////////////////////////////////////////////////////////////////// 16 | 17 | 18 | void BitmapFile_Init(); 19 | void BitmapFile_Done(); 20 | 21 | enum BitmapFileFormat 22 | { 23 | BitmapFileFormatBmp = 1, 24 | BitmapFileFormatPng = 2, 25 | BitmapFileFormatTiff = 3, 26 | }; 27 | 28 | HBITMAP BitmapFile_LoadPngFromResource(LPCTSTR lpName); 29 | 30 | // Save the image as .PNG file 31 | bool BitmapFile_SaveImageFile( 32 | const uint32_t* pBits, 33 | LPCTSTR sFileName, BitmapFileFormat format, 34 | int screenWidth, int screenHeight); 35 | 36 | 37 | ////////////////////////////////////////////////////////////////////// 38 | -------------------------------------------------------------------------------- /emulator/util/WavPcmFile.cpp: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // WavPcmFile.cpp 12 | 13 | #include "stdafx.h" 14 | #include "WavPcmFile.h" 15 | #include 16 | #include 17 | 18 | 19 | ////////////////////////////////////////////////////////////////////// 20 | 21 | // WAV PCM format description: https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ 22 | 23 | static const char magic1[4] = { 'R', 'I', 'F', 'F' }; 24 | static const char magic2[4] = { 'W', 'A', 'V', 'E' }; 25 | static const char format_tag_id[4] = { 'f', 'm', 't', ' ' }; 26 | static const char data_tag_id[4] = { 'd', 'a', 't', 'a' }; 27 | 28 | const int WAV_FORMAT_PCM = 1; 29 | 30 | struct WAVPCMFILE 31 | { 32 | FILE* fpFile; 33 | int nChannels; 34 | int nBitsPerSample; 35 | int nSampleFrequency; 36 | int nBlockAlign; 37 | uint32_t dwDataOffset; 38 | uint32_t dwDataSize; 39 | uint32_t dwCurrentPosition; 40 | bool okWriting; 41 | }; 42 | 43 | int WavPcmFile_GetFrequency(HWAVPCMFILE wavpcmfile) 44 | { 45 | if (wavpcmfile == INVALID_HANDLE_VALUE) 46 | return 0; 47 | 48 | WAVPCMFILE* pWavPcm = reinterpret_cast(wavpcmfile); 49 | 50 | return pWavPcm->nSampleFrequency; 51 | } 52 | 53 | uint32_t WavPcmFile_GetLength(HWAVPCMFILE wavpcmfile) 54 | { 55 | if (wavpcmfile == INVALID_HANDLE_VALUE) 56 | return 0; 57 | 58 | WAVPCMFILE* pWavPcm = reinterpret_cast(wavpcmfile); 59 | 60 | return pWavPcm->dwDataSize / pWavPcm->nBlockAlign; 61 | } 62 | 63 | uint32_t WavPcmFile_GetPosition(HWAVPCMFILE wavpcmfile) 64 | { 65 | if (wavpcmfile == INVALID_HANDLE_VALUE) 66 | return 0; 67 | 68 | WAVPCMFILE* pWavPcm = reinterpret_cast(wavpcmfile); 69 | 70 | return pWavPcm->dwCurrentPosition; 71 | } 72 | 73 | void WavPcmFile_SetPosition(HWAVPCMFILE wavpcmfile, uint32_t position) 74 | { 75 | if (wavpcmfile == INVALID_HANDLE_VALUE) 76 | return; 77 | 78 | WAVPCMFILE* pWavPcm = reinterpret_cast(wavpcmfile); 79 | 80 | uint32_t offsetInData = position * pWavPcm->nBlockAlign; 81 | ::fseek(pWavPcm->fpFile, pWavPcm->dwDataOffset + offsetInData, SEEK_SET); 82 | 83 | pWavPcm->dwCurrentPosition = position; 84 | } 85 | 86 | HWAVPCMFILE WavPcmFile_Create(LPCTSTR filename, int sampleRate) 87 | { 88 | const int bitsPerSample = 8; 89 | const int channels = 1; 90 | const int blockAlign = channels * bitsPerSample / 8; 91 | 92 | FILE* fpFileNew = ::_tfsopen(filename, _T("w+b"), _SH_DENYWR); 93 | if (fpFileNew == nullptr) 94 | return static_cast(INVALID_HANDLE_VALUE); // Failed to create file 95 | 96 | // Prepare and write file header 97 | uint8_t consolidated_header[12 + 8 + 16 + 8]; 98 | ::memset(consolidated_header, 0, sizeof(consolidated_header)); 99 | 100 | memcpy(&consolidated_header[0], magic1, 4); // RIFF 101 | memcpy(&consolidated_header[8], magic2, 4); // WAVE 102 | 103 | memcpy(&consolidated_header[12], format_tag_id, 4); // fmt 104 | *reinterpret_cast(consolidated_header + 16) = 16; // Size of "fmt" chunk 105 | *reinterpret_cast(consolidated_header + 20) = WAV_FORMAT_PCM; // AudioFormat = PCM 106 | *reinterpret_cast(consolidated_header + 22) = channels; // NumChannels = mono 107 | *reinterpret_cast(consolidated_header + 24) = sampleRate; // SampleRate 108 | *reinterpret_cast(consolidated_header + 28) = sampleRate * channels * bitsPerSample / 8; // ByteRate 109 | *reinterpret_cast(consolidated_header + 32) = blockAlign; 110 | *reinterpret_cast(consolidated_header + 34) = bitsPerSample; 111 | 112 | memcpy(&consolidated_header[36], data_tag_id, 4); // data 113 | 114 | // Write consolidated header 115 | uint32_t bytesWritten = ::fwrite(consolidated_header, 1, sizeof(consolidated_header), fpFileNew); 116 | if (bytesWritten != sizeof(consolidated_header)) 117 | { 118 | ::fclose(fpFileNew); 119 | return static_cast(INVALID_HANDLE_VALUE); // Failed to write consolidated header 120 | } 121 | 122 | WAVPCMFILE* pWavPcm = static_cast(::calloc(1, sizeof(WAVPCMFILE))); 123 | if (pWavPcm == nullptr) 124 | { 125 | ::fclose(fpFileNew); 126 | return static_cast(INVALID_HANDLE_VALUE); // Failed to allocate memory 127 | } 128 | pWavPcm->fpFile = fpFileNew; 129 | pWavPcm->nChannels = channels; 130 | pWavPcm->nSampleFrequency = sampleRate; 131 | pWavPcm->nBitsPerSample = bitsPerSample; 132 | pWavPcm->nBlockAlign = blockAlign; 133 | pWavPcm->dwDataOffset = sizeof(consolidated_header); 134 | pWavPcm->dwDataSize = 0; 135 | pWavPcm->okWriting = true; 136 | 137 | WavPcmFile_SetPosition(reinterpret_cast(pWavPcm), 0); 138 | 139 | return reinterpret_cast(pWavPcm); 140 | } 141 | 142 | HWAVPCMFILE WavPcmFile_Open(LPCTSTR filename) 143 | { 144 | FILE* fpFileOpen = ::_tfsopen(filename, _T("rb"), _SH_DENYWR); 145 | if (fpFileOpen == nullptr) 146 | return static_cast(INVALID_HANDLE_VALUE); // Failed to open file 147 | 148 | uint32_t offset = 0; 149 | ::fseek(fpFileOpen, 0, SEEK_END); 150 | uint32_t fileSize = ::ftell(fpFileOpen); 151 | ::fseek(fpFileOpen, 0, SEEK_SET); 152 | 153 | uint8_t fileHeader[12]; 154 | size_t bytesRead = ::fread(fileHeader, 1, sizeof(fileHeader), fpFileOpen); 155 | if (bytesRead != sizeof(fileHeader) || 156 | memcmp(&fileHeader[0], magic1, 4) != 0 || 157 | memcmp(&fileHeader[8], magic2, 4) != 0) 158 | { 159 | ::fclose(fpFileOpen); 160 | return static_cast(INVALID_HANDLE_VALUE); // Failed to read file header OR invalid 'RIFF' tag OR invalid 'WAVE' tag 161 | } 162 | offset += bytesRead; 163 | 164 | uint32_t statedSize = *reinterpret_cast(fileHeader + 4) + 8; 165 | if (statedSize > fileSize) 166 | statedSize = fileSize; 167 | 168 | uint8_t tagHeader[8]; 169 | uint16_t formatTag[8]; 170 | bool formatSpecified = false; 171 | uint16_t formatType = 1, channels = 1, bitsPerSample = 1, blockAlign = 0; 172 | uint32_t sampleFrequency = 22050, bytesPerSecond, dataOffset = 0, dataSize = 0; 173 | while (offset < statedSize) 174 | { 175 | bytesRead = ::fread(tagHeader, 1, sizeof(tagHeader), fpFileOpen); 176 | if (bytesRead != sizeof(tagHeader)) 177 | { 178 | ::fclose(fpFileOpen); 179 | return static_cast(INVALID_HANDLE_VALUE); // Failed to read tag header 180 | } 181 | offset += bytesRead; 182 | 183 | uint32_t tagSize = *reinterpret_cast(tagHeader + 4); 184 | if (!memcmp(tagHeader, format_tag_id, 4)) 185 | { 186 | if (formatSpecified || tagSize < sizeof(formatTag)) 187 | { 188 | ::fclose(fpFileOpen); 189 | return static_cast(INVALID_HANDLE_VALUE); // Wrong tag header 190 | } 191 | formatSpecified = true; 192 | 193 | bytesRead = ::fread(formatTag, 1, sizeof(formatTag), fpFileOpen); 194 | if (bytesRead != sizeof(formatTag)) 195 | { 196 | ::fclose(fpFileOpen); 197 | return static_cast(INVALID_HANDLE_VALUE); // Failed to read format tag 198 | } 199 | 200 | formatType = formatTag[0]; 201 | channels = formatTag[1]; 202 | sampleFrequency = formatTag[2]; 203 | bytesPerSecond = formatTag[4]; 204 | blockAlign = formatTag[6]; 205 | bitsPerSample = formatTag[7]; 206 | 207 | if (formatType != WAV_FORMAT_PCM) 208 | { 209 | ::fclose(fpFileOpen); 210 | return static_cast(INVALID_HANDLE_VALUE); // Unsupported format 211 | } 212 | if (sampleFrequency * bitsPerSample * channels / 8 != bytesPerSecond || 213 | (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 32)) 214 | { 215 | ::fclose(fpFileOpen); 216 | return static_cast(INVALID_HANDLE_VALUE); // Wrong format tag 217 | } 218 | } 219 | else if (!memcmp(tagHeader, data_tag_id, 4)) 220 | { 221 | if (!formatSpecified) 222 | { 223 | ::fclose(fpFileOpen); 224 | return static_cast(INVALID_HANDLE_VALUE); // Wrong tag 225 | } 226 | 227 | dataOffset = offset; 228 | dataSize = tagSize; 229 | } 230 | else // Ignore all other tags 231 | { 232 | } 233 | 234 | offset += tagSize; 235 | ::fseek(fpFileOpen, offset, SEEK_SET); 236 | } 237 | 238 | WAVPCMFILE* pWavPcm = static_cast(::calloc(1, sizeof(WAVPCMFILE))); 239 | if (pWavPcm == nullptr) 240 | { 241 | ::fclose(fpFileOpen); 242 | return static_cast(INVALID_HANDLE_VALUE); // Failed to allocate memory 243 | } 244 | pWavPcm->fpFile = fpFileOpen; 245 | pWavPcm->nChannels = channels; 246 | pWavPcm->nSampleFrequency = sampleFrequency; 247 | pWavPcm->nBitsPerSample = bitsPerSample; 248 | pWavPcm->nBlockAlign = blockAlign; 249 | pWavPcm->dwDataOffset = dataOffset; 250 | pWavPcm->dwDataSize = dataSize; 251 | pWavPcm->okWriting = false; 252 | 253 | WavPcmFile_SetPosition(reinterpret_cast(pWavPcm), 0); 254 | 255 | return reinterpret_cast(pWavPcm); 256 | } 257 | 258 | void WavPcmFile_Close(HWAVPCMFILE wavpcmfile) 259 | { 260 | if (wavpcmfile == INVALID_HANDLE_VALUE) 261 | return; 262 | 263 | WAVPCMFILE* pWavPcm = reinterpret_cast(wavpcmfile); 264 | 265 | if (pWavPcm->okWriting) 266 | { 267 | // Write data chunk size 268 | ::fseek(pWavPcm->fpFile, 4, SEEK_SET); 269 | uint32_t chunkSize = 36 + pWavPcm->dwDataSize; 270 | uint32_t bytesWritten = ::fwrite(&chunkSize, 1, 4, pWavPcm->fpFile); 271 | // Write data subchunk size 272 | ::fseek(pWavPcm->fpFile, 40, SEEK_SET); 273 | bytesWritten = ::fwrite(&(pWavPcm->dwDataSize), 1, 4, pWavPcm->fpFile); 274 | } 275 | 276 | ::fclose(pWavPcm->fpFile); 277 | pWavPcm->fpFile = nullptr; 278 | ::free(pWavPcm); 279 | } 280 | 281 | bool WavPcmFile_WriteOne(HWAVPCMFILE wavpcmfile, unsigned int value) 282 | { 283 | if (wavpcmfile == INVALID_HANDLE_VALUE) 284 | return false; 285 | 286 | WAVPCMFILE* pWavPcm = reinterpret_cast(wavpcmfile); 287 | if (!pWavPcm->okWriting) 288 | return false; 289 | ASSERT(pWavPcm->nBitsPerSample == 8); 290 | ASSERT(pWavPcm->nChannels == 1); 291 | 292 | uint8_t data = (uint8_t)((value >> 24) & 0xff); 293 | 294 | size_t bytesWritten = ::fwrite(&data, 1, 1, pWavPcm->fpFile); 295 | if (bytesWritten != 1) 296 | return false; 297 | 298 | pWavPcm->dwCurrentPosition++; 299 | pWavPcm->dwDataSize += pWavPcm->nBlockAlign; 300 | 301 | return true; 302 | } 303 | 304 | unsigned int WavPcmFile_ReadOne(HWAVPCMFILE wavpcmfile) 305 | { 306 | if (wavpcmfile == INVALID_HANDLE_VALUE) 307 | return 0; 308 | 309 | WAVPCMFILE* pWavPcm = reinterpret_cast(wavpcmfile); 310 | if (pWavPcm->okWriting) 311 | return 0; 312 | 313 | // Read one sample 314 | uint32_t bytesToRead = pWavPcm->nBlockAlign; 315 | uint8_t data[16]; 316 | size_t bytesRead = ::fread(data, 1, bytesToRead, pWavPcm->fpFile); 317 | if (bytesRead != bytesToRead) 318 | return 0; 319 | 320 | pWavPcm->dwCurrentPosition++; 321 | 322 | // Decode first channel 323 | unsigned int value = 0; 324 | switch (pWavPcm->nBitsPerSample) 325 | { 326 | case 8: 327 | value = *data; 328 | value = value << 24; 329 | break; 330 | case 16: 331 | value = *reinterpret_cast(data); 332 | value = value << 16; 333 | break; 334 | case 32: 335 | value = *reinterpret_cast(data); 336 | break; 337 | } 338 | 339 | return value; 340 | } 341 | 342 | 343 | ////////////////////////////////////////////////////////////////////// 344 | -------------------------------------------------------------------------------- /emulator/util/WavPcmFile.h: -------------------------------------------------------------------------------- 1 | /* This file is part of BKBTL. 2 | BKBTL is free software: you can redistribute it and/or modify it under the terms 3 | of the GNU Lesser General Public License as published by the Free Software Foundation, 4 | either version 3 of the License, or (at your option) any later version. 5 | BKBTL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 6 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 7 | See the GNU Lesser General Public License for more details. 8 | You should have received a copy of the GNU Lesser General Public License along with 9 | BKBTL. If not, see . */ 10 | 11 | // WavPcmFile.h 12 | 13 | #pragma once 14 | 15 | ////////////////////////////////////////////////////////////////////// 16 | 17 | DECLARE_HANDLE(HWAVPCMFILE); 18 | 19 | // Creates WAV file, one-channel, 8 bits per sample 20 | HWAVPCMFILE WavPcmFile_Create(LPCTSTR filename, int sampleRate); 21 | // Prepare WAV file of PCM format for reading 22 | HWAVPCMFILE WavPcmFile_Open(LPCTSTR filename); 23 | // Close WAV file 24 | void WavPcmFile_Close(HWAVPCMFILE wavpcmfile); 25 | 26 | // Samples per second, Hz 27 | int WavPcmFile_GetFrequency(HWAVPCMFILE wavpcmfile); 28 | // Length of the stream, in samples 29 | uint32_t WavPcmFile_GetLength(HWAVPCMFILE wavpcmfile); 30 | 31 | // Current position in the stream, in samples, zero-based 32 | uint32_t WavPcmFile_GetPosition(HWAVPCMFILE wavpcmfile); 33 | // Set current position in the stream, in samples, zero-based 34 | void WavPcmFile_SetPosition(HWAVPCMFILE wavpcmfile, uint32_t position); 35 | 36 | // Read one sample scaled to int type range 37 | unsigned int WavPcmFile_ReadOne(HWAVPCMFILE wavpcmfile); 38 | // Write one sample scaled to int type range 39 | bool WavPcmFile_WriteOne(HWAVPCMFILE wavpcmfile, unsigned int value); 40 | 41 | 42 | ////////////////////////////////////////////////////////////////////// 43 | -------------------------------------------------------------------------------- /roms/b11m_bos.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nzeemin/bkbtl/01c755430088bca9c57310c26cb6470acbe32d2a/roms/b11m_bos.rom -------------------------------------------------------------------------------- /roms/b11m_ext.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nzeemin/bkbtl/01c755430088bca9c57310c26cb6470acbe32d2a/roms/b11m_ext.rom -------------------------------------------------------------------------------- /roms/b11m_mstd.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nzeemin/bkbtl/01c755430088bca9c57310c26cb6470acbe32d2a/roms/b11m_mstd.rom -------------------------------------------------------------------------------- /roms/basic10_1.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nzeemin/bkbtl/01c755430088bca9c57310c26cb6470acbe32d2a/roms/basic10_1.rom -------------------------------------------------------------------------------- /roms/basic10_2.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nzeemin/bkbtl/01c755430088bca9c57310c26cb6470acbe32d2a/roms/basic10_2.rom -------------------------------------------------------------------------------- /roms/basic10_3.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nzeemin/bkbtl/01c755430088bca9c57310c26cb6470acbe32d2a/roms/basic10_3.rom -------------------------------------------------------------------------------- /roms/basic11m_0.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nzeemin/bkbtl/01c755430088bca9c57310c26cb6470acbe32d2a/roms/basic11m_0.rom -------------------------------------------------------------------------------- /roms/basic11m_1.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nzeemin/bkbtl/01c755430088bca9c57310c26cb6470acbe32d2a/roms/basic11m_1.rom -------------------------------------------------------------------------------- /roms/disk_253.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nzeemin/bkbtl/01c755430088bca9c57310c26cb6470acbe32d2a/roms/disk_253.rom -------------------------------------------------------------------------------- /roms/disk_326.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nzeemin/bkbtl/01c755430088bca9c57310c26cb6470acbe32d2a/roms/disk_326.rom -------------------------------------------------------------------------------- /roms/disk_327.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nzeemin/bkbtl/01c755430088bca9c57310c26cb6470acbe32d2a/roms/disk_327.rom -------------------------------------------------------------------------------- /roms/focal.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nzeemin/bkbtl/01c755430088bca9c57310c26cb6470acbe32d2a/roms/focal.rom -------------------------------------------------------------------------------- /roms/monit10.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nzeemin/bkbtl/01c755430088bca9c57310c26cb6470acbe32d2a/roms/monit10.rom -------------------------------------------------------------------------------- /roms/tests.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nzeemin/bkbtl/01c755430088bca9c57310c26cb6470acbe32d2a/roms/tests.rom --------------------------------------------------------------------------------