├── .gitattributes ├── .gitignore ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── CMakeLists.txt ├── DevectorWPF.sln ├── LICENSE.txt ├── README.md ├── resources ├── boot │ ├── boot.bin │ ├── boot.txt │ ├── boots.bin │ └── boots.txt ├── fonts │ ├── medium.ttf │ └── medium_italic.ttf ├── images │ └── vector_keyboard.jpg ├── imgui.ini ├── ramDisks.bin └── settings.json ├── rom ├── .saved.fdd ├── beeper │ ├── gtoc64.rom │ ├── hvphas.rom │ ├── music.txt │ ├── phphunk.rom │ ├── pirat.rom │ ├── readme.txt │ ├── rock.rom │ └── rublov.rom ├── fdd │ ├── Robotz65a.fdd │ ├── Robotz66a - Copy.fdd │ ├── Robotz66a.fdd │ ├── badaps.fdd │ ├── galery.fdd │ ├── galery.txt │ ├── out1.fdd │ └── rds308.fdd ├── file_name.rec ├── file_name2.rec ├── games │ ├── ADSKOK.ROM │ ├── DFIGHT.ROM │ ├── FATAXCOL.ROM │ ├── GameNoname_eng.json │ ├── GameNoname_eng.rom │ ├── GameNoname_eng_labels.txt │ ├── GameNoname_labels.txt │ ├── GameNoname_rus.rom │ ├── GameNoname_rus_labels.txt │ ├── cronex.rom │ ├── exolon.json │ ├── exolon.rom │ ├── maric.json │ ├── maric.rom │ ├── ot.rom │ ├── putup.rom │ ├── river_raid.rom │ ├── vetka - Copy.fdd │ └── vetka.fdd ├── not_working │ ├── .saved.fdd │ ├── 8080EX1.COM │ ├── b-ice.fdd │ ├── card.fdd │ ├── cdpacman.fdd │ ├── pillars.rom │ └── t-rex-05.fdd ├── ramdisk_test.ROM ├── scrltst2 │ ├── 00.jpg │ ├── 14.jpg │ ├── 18.jpg │ ├── README.txt │ └── scrltst2.rom ├── timing_tests │ ├── b-ice.com │ ├── b-ice.xor │ ├── b-ice.zip │ ├── hwdit512.rom │ ├── kittham1.rom │ ├── mineswep.rom │ ├── sunsetb.rom │ └── tiedye2.rom └── v_tests │ ├── bord2.rom │ ├── clrspace.rom │ ├── test512.rom │ ├── vst.rom │ ├── vst_realV06C.jpg │ ├── vstvi53.jpg │ ├── vstvi53.rom │ └── vstvi53_real6128.jpg └── src ├── core ├── audio.cpp ├── audio.h ├── breakpoint.cpp ├── breakpoint.h ├── breakpoints.cpp ├── breakpoints.h ├── code_perf.h ├── cpu_i8080.cpp ├── cpu_i8080.h ├── debug_data.cpp ├── debug_data.h ├── debugger.cpp ├── debugger.h ├── disasm.cpp ├── disasm.h ├── display.cpp ├── display.h ├── fdc_wd1793.cpp ├── fdc_wd1793.h ├── fdd_consts.h ├── hardware.cpp ├── hardware.h ├── hardware_consts.h ├── io.cpp ├── io.h ├── keyboard.cpp ├── keyboard.h ├── memory.cpp ├── memory.h ├── memory_consts.h ├── memory_edit.h ├── recorder.cpp ├── recorder.h ├── script.cpp ├── script.h ├── scripts.cpp ├── scripts.h ├── sound_ay8910.cpp ├── sound_ay8910.h ├── timer_i8253.cpp ├── timer_i8253.h ├── trace_log.cpp ├── trace_log.h ├── watchpoint.cpp ├── watchpoint.h ├── watchpoints.cpp └── watchpoints.h ├── glad ├── include │ ├── KHR │ │ └── khrplatform.h │ └── glad │ │ └── glad.h └── src │ └── glad.c ├── main_imgui ├── main │ ├── devector_app.cpp │ ├── devector_app.h │ ├── imgui_app.cpp │ ├── imgui_app.h │ ├── main.cpp │ └── ui │ │ ├── about_window.cpp │ │ ├── about_window.h │ │ ├── base_window.cpp │ │ ├── base_window.h │ │ ├── breakpoints_window.cpp │ │ ├── breakpoints_window.h │ │ ├── debugdata_window.cpp │ │ ├── debugdata_window.h │ │ ├── disasm_window.cpp │ │ ├── disasm_window.h │ │ ├── display_window.cpp │ │ ├── display_window.h │ │ ├── feedback_window.cpp │ │ ├── feedback_window.h │ │ ├── hardware_stats_window.cpp │ │ ├── hardware_stats_window.h │ │ ├── hex_viewer_window.cpp │ │ ├── hex_viewer_window.h │ │ ├── keyboard_window.cpp │ │ ├── keyboard_window.h │ │ ├── mem_display_window.cpp │ │ ├── mem_display_window.h │ │ ├── recorder_window.cpp │ │ ├── recorder_window.h │ │ ├── search_window.cpp │ │ ├── search_window.h │ │ ├── trace_log_window.cpp │ │ ├── trace_log_window.h │ │ ├── watchpoints_window.cpp │ │ └── watchpoints_window.h └── utils │ ├── imgui_utils.cpp │ └── imgui_utils.h ├── main_wpf ├── Devector │ ├── About.xaml │ ├── About.xaml.cs │ ├── App.xaml │ ├── App.xaml.cs │ ├── ArgsParser.cs │ ├── AssemblyInfo.cs │ ├── Breakpoints.xaml │ ├── Breakpoints.xaml.cs │ ├── Consts.cs │ ├── DarkTheme.xaml │ ├── Devector.csproj │ ├── DevectorWindow.cs │ ├── Disasm.xaml │ ├── Disasm.xaml.cs │ ├── HardwareStats.xaml │ ├── HardwareStats.xaml.cs │ ├── HardwareStatsViewModel.cs │ ├── HexViewer.xaml │ ├── HexViewer.xaml.cs │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ ├── MemoryDisplay.xaml │ ├── MemoryDisplay.xaml.cs │ ├── Properties │ │ ├── Resources.Designer.cs │ │ ├── Resources.resx │ │ ├── Settings.Designer.cs │ │ ├── Settings.settings │ │ └── launchSettings.json │ ├── RamMappingViewModel.cs │ ├── Recorder.xaml │ ├── Recorder.xaml.cs │ ├── RelayCommand.cs │ ├── SDLScancodes.cs │ ├── ScreenKeyboard.xaml │ ├── ScreenKeyboard.xaml.cs │ ├── Shaders.cs │ ├── TraceLog.xaml │ ├── TraceLog.xaml.cs │ ├── Types.cs │ ├── Viewport.cs │ ├── Watchpoints.xaml │ └── Watchpoints.xaml.cs ├── GLAD │ ├── GLAD.vcxproj │ └── GLAD.vcxproj.filters ├── HAL │ ├── HAL.vcxproj │ ├── HAL.vcxproj.filters │ ├── halwrapper.cpp │ ├── halwrapper.h │ ├── win_gl_utils.cpp │ └── win_gl_utils.h └── SDL │ ├── dll │ └── x64 │ │ └── SDL3.dll │ └── lib │ └── x64 │ └── SDL3.lib ├── njson └── json.hpp ├── stb_image └── stb_image.h └── utils ├── args_parser.cpp ├── args_parser.h ├── consts.h ├── gl_utils.cpp ├── gl_utils.h ├── json_utils.cpp ├── json_utils.h ├── result.h ├── str_utils.cpp ├── str_utils.h ├── tqueue.h ├── types.h ├── utils.cpp └── utils.h /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Debug from bin folder", 6 | "type": "cppdbg", 7 | "request": "launch", 8 | "program": "${workspaceFolder}/../devector/bin/devector.exe", 9 | "args": [ 10 | "-path", "C:/Work/Programming/guimos_jdundel/build/debug/bin/GJ.fdd" 11 | ], 12 | "stopAtEntry": false, 13 | "cwd": "${workspaceFolder}/../guimos_jdundel/", 14 | "environment": [], 15 | "externalConsole": false, 16 | "MIMode": "gdb", 17 | "miDebuggerPath": "gdb.exe", 18 | "setupCommands": [ 19 | { 20 | "description": "Enable pretty-printing for gdb", 21 | "text": "-enable-pretty-printing", 22 | "ignoreFailures": true 23 | } 24 | ], 25 | } 26 | ] 27 | } 28 | 29 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.asm": "retroasm_8080", 4 | "*.dasm": "retroasm_8080", 5 | "algorithm": "cpp", 6 | "any": "cpp", 7 | "array": "cpp", 8 | "atomic": "cpp", 9 | "bit": "cpp", 10 | "cctype": "cpp", 11 | "charconv": "cpp", 12 | "chrono": "cpp", 13 | "clocale": "cpp", 14 | "cmath": "cpp", 15 | "codecvt": "cpp", 16 | "compare": "cpp", 17 | "concepts": "cpp", 18 | "condition_variable": "cpp", 19 | "cstdarg": "cpp", 20 | "cstddef": "cpp", 21 | "cstdint": "cpp", 22 | "cstdio": "cpp", 23 | "cstdlib": "cpp", 24 | "cstring": "cpp", 25 | "ctime": "cpp", 26 | "cwchar": "cpp", 27 | "deque": "cpp", 28 | "exception": "cpp", 29 | "filesystem": "cpp", 30 | "format": "cpp", 31 | "forward_list": "cpp", 32 | "fstream": "cpp", 33 | "functional": "cpp", 34 | "future": "cpp", 35 | "initializer_list": "cpp", 36 | "iomanip": "cpp", 37 | "ios": "cpp", 38 | "iosfwd": "cpp", 39 | "iostream": "cpp", 40 | "istream": "cpp", 41 | "iterator": "cpp", 42 | "limits": "cpp", 43 | "list": "cpp", 44 | "locale": "cpp", 45 | "map": "cpp", 46 | "memory": "cpp", 47 | "mutex": "cpp", 48 | "new": "cpp", 49 | "numeric": "cpp", 50 | "optional": "cpp", 51 | "ostream": "cpp", 52 | "queue": "cpp", 53 | "ranges": "cpp", 54 | "ratio": "cpp", 55 | "span": "cpp", 56 | "sstream": "cpp", 57 | "stdexcept": "cpp", 58 | "stop_token": "cpp", 59 | "streambuf": "cpp", 60 | "string": "cpp", 61 | "system_error": "cpp", 62 | "thread": "cpp", 63 | "tuple": "cpp", 64 | "type_traits": "cpp", 65 | "typeinfo": "cpp", 66 | "unordered_map": "cpp", 67 | "utility": "cpp", 68 | "valarray": "cpp", 69 | "vector": "cpp", 70 | "xfacet": "cpp", 71 | "xhash": "cpp", 72 | "xiosbase": "cpp", 73 | "xlocale": "cpp", 74 | "xlocbuf": "cpp", 75 | "xlocinfo": "cpp", 76 | "xlocmes": "cpp", 77 | "xlocmon": "cpp", 78 | "xlocnum": "cpp", 79 | "xloctime": "cpp", 80 | "xmemory": "cpp", 81 | "xstring": "cpp", 82 | "xtr1common": "cpp", 83 | "xtree": "cpp", 84 | "xutility": "cpp", 85 | "*.rh": "cpp", 86 | "sdl_keyboard.h": "c", 87 | "sdl_scancode.h": "c", 88 | "coroutine": "cpp", 89 | "variant": "cpp", 90 | "*.tcc": "cpp", 91 | "cwctype": "cpp", 92 | "memory_resource": "cpp", 93 | "random": "cpp", 94 | "string_view": "cpp", 95 | "numbers": "cpp", 96 | "semaphore": "cpp", 97 | "cinttypes": "cpp", 98 | "bitset": "cpp", 99 | "complex": "cpp", 100 | "regex": "cpp", 101 | "set": "cpp", 102 | "source_location": "cpp", 103 | "stack": "cpp", 104 | "stdfloat": "cpp", 105 | "typeindex": "cpp", 106 | "unordered_set": "cpp" 107 | } 108 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "type": "cppbuild", 5 | "label": "C/C++: g++.exe build active file", 6 | "command": "C:\\msys64\\ucrt64\\bin\\g++.exe", 7 | "args": [ 8 | "-fdiagnostics-color=always", 9 | "-g", 10 | "${file}", 11 | "-o", 12 | "${fileDirname}\\${fileBasenameNoExtension}.exe" 13 | ], 14 | "options": { 15 | "cwd": "${fileDirname}" 16 | }, 17 | "problemMatcher": [ 18 | "$gcc" 19 | ], 20 | "group": "build", 21 | "detail": "Task generated by Debugger." 22 | }, 23 | { 24 | "type": "cppbuild", 25 | "label": "C/C++: cl.exe build active file", 26 | "command": "cl.exe", 27 | "args": [ 28 | "/Zi", 29 | "/EHsc", 30 | "/nologo", 31 | "/Fe${fileDirname}\\${fileBasenameNoExtension}.exe", 32 | "${file}" 33 | ], 34 | "options": { 35 | "cwd": "${fileDirname}" 36 | }, 37 | "problemMatcher": [ 38 | "$msCompile" 39 | ], 40 | "group": { 41 | "kind": "build", 42 | "isDefault": true 43 | }, 44 | "detail": "Task generated by Debugger." 45 | } 46 | ], 47 | "version": "2.0.0" 48 | } -------------------------------------------------------------------------------- /DevectorWPF.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.11.35327.3 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Devector", "src\main_wpf\Devector\Devector.csproj", "{C2736150-2854-4D69-BC87-32FBDE70995A}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HAL", "src\main_wpf\HAL\HAL.vcxproj", "{0DA7FBD6-4EF0-4FF2-9C6A-9F9FF740A3F7}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GLAD", "src\main_wpf\GLAD\GLAD.vcxproj", "{8CE8592A-8617-41B1-8E7A-96BFC2DA040E}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|x64 = Debug|x64 16 | Debug|x86 = Debug|x86 17 | Release|Any CPU = Release|Any CPU 18 | Release|x64 = Release|x64 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {C2736150-2854-4D69-BC87-32FBDE70995A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {C2736150-2854-4D69-BC87-32FBDE70995A}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {C2736150-2854-4D69-BC87-32FBDE70995A}.Debug|x64.ActiveCfg = Debug|Any CPU 25 | {C2736150-2854-4D69-BC87-32FBDE70995A}.Debug|x64.Build.0 = Debug|Any CPU 26 | {C2736150-2854-4D69-BC87-32FBDE70995A}.Debug|x86.ActiveCfg = Debug|Any CPU 27 | {C2736150-2854-4D69-BC87-32FBDE70995A}.Debug|x86.Build.0 = Debug|Any CPU 28 | {C2736150-2854-4D69-BC87-32FBDE70995A}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {C2736150-2854-4D69-BC87-32FBDE70995A}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {C2736150-2854-4D69-BC87-32FBDE70995A}.Release|x64.ActiveCfg = Release|Any CPU 31 | {C2736150-2854-4D69-BC87-32FBDE70995A}.Release|x64.Build.0 = Release|Any CPU 32 | {C2736150-2854-4D69-BC87-32FBDE70995A}.Release|x86.ActiveCfg = Release|Any CPU 33 | {C2736150-2854-4D69-BC87-32FBDE70995A}.Release|x86.Build.0 = Release|Any CPU 34 | {0DA7FBD6-4EF0-4FF2-9C6A-9F9FF740A3F7}.Debug|Any CPU.ActiveCfg = Debug|x64 35 | {0DA7FBD6-4EF0-4FF2-9C6A-9F9FF740A3F7}.Debug|Any CPU.Build.0 = Debug|x64 36 | {0DA7FBD6-4EF0-4FF2-9C6A-9F9FF740A3F7}.Debug|x64.ActiveCfg = Debug|x64 37 | {0DA7FBD6-4EF0-4FF2-9C6A-9F9FF740A3F7}.Debug|x64.Build.0 = Debug|x64 38 | {0DA7FBD6-4EF0-4FF2-9C6A-9F9FF740A3F7}.Debug|x86.ActiveCfg = Debug|Win32 39 | {0DA7FBD6-4EF0-4FF2-9C6A-9F9FF740A3F7}.Debug|x86.Build.0 = Debug|Win32 40 | {0DA7FBD6-4EF0-4FF2-9C6A-9F9FF740A3F7}.Release|Any CPU.ActiveCfg = Release|x64 41 | {0DA7FBD6-4EF0-4FF2-9C6A-9F9FF740A3F7}.Release|Any CPU.Build.0 = Release|x64 42 | {0DA7FBD6-4EF0-4FF2-9C6A-9F9FF740A3F7}.Release|x64.ActiveCfg = Release|x64 43 | {0DA7FBD6-4EF0-4FF2-9C6A-9F9FF740A3F7}.Release|x64.Build.0 = Release|x64 44 | {0DA7FBD6-4EF0-4FF2-9C6A-9F9FF740A3F7}.Release|x86.ActiveCfg = Release|Win32 45 | {0DA7FBD6-4EF0-4FF2-9C6A-9F9FF740A3F7}.Release|x86.Build.0 = Release|Win32 46 | {8CE8592A-8617-41B1-8E7A-96BFC2DA040E}.Debug|Any CPU.ActiveCfg = Debug|x64 47 | {8CE8592A-8617-41B1-8E7A-96BFC2DA040E}.Debug|Any CPU.Build.0 = Debug|x64 48 | {8CE8592A-8617-41B1-8E7A-96BFC2DA040E}.Debug|x64.ActiveCfg = Debug|x64 49 | {8CE8592A-8617-41B1-8E7A-96BFC2DA040E}.Debug|x64.Build.0 = Debug|x64 50 | {8CE8592A-8617-41B1-8E7A-96BFC2DA040E}.Debug|x86.ActiveCfg = Debug|Win32 51 | {8CE8592A-8617-41B1-8E7A-96BFC2DA040E}.Debug|x86.Build.0 = Debug|Win32 52 | {8CE8592A-8617-41B1-8E7A-96BFC2DA040E}.Release|Any CPU.ActiveCfg = Release|x64 53 | {8CE8592A-8617-41B1-8E7A-96BFC2DA040E}.Release|Any CPU.Build.0 = Release|x64 54 | {8CE8592A-8617-41B1-8E7A-96BFC2DA040E}.Release|x64.ActiveCfg = Release|x64 55 | {8CE8592A-8617-41B1-8E7A-96BFC2DA040E}.Release|x64.Build.0 = Release|x64 56 | {8CE8592A-8617-41B1-8E7A-96BFC2DA040E}.Release|x86.ActiveCfg = Release|Win32 57 | {8CE8592A-8617-41B1-8E7A-96BFC2DA040E}.Release|x86.Build.0 = Release|Win32 58 | EndGlobalSection 59 | GlobalSection(SolutionProperties) = preSolution 60 | HideSolutionNode = FALSE 61 | EndGlobalSection 62 | GlobalSection(ExtensibilityGlobals) = postSolution 63 | SolutionGuid = {FE458A55-05EA-44EB-AFC6-21B0571FFC5B} 64 | EndGlobalSection 65 | EndGlobal 66 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [year] [fullname] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Devector 2 | 3 | ## Overview 4 | 5 | Devector is a multi-platform emulator of a Soviet personal computer Vector06c. It is designed to simplify the development process and speed up the work. Currently, it is in the early stages of development, so please use it on your own risk. 6 | 7 | ## Features 8 | 9 | - A multi-platform precise emulator of a Soviet personal computer Vector06c 10 | - Debugging functionality 11 | - FDD support 12 | - Up to 8 Ram-Disk support 13 | - AY & bipper & 3-channel timer support 14 | - Recording a playback with options to store, load, and play it 15 | 16 | ## Usage 17 | 18 | To run the emulator: 19 | `./Devector.exe` <-settingsPath settings.json> <-path rom_fdd_rec_file> 20 | 21 | ## Build 22 | 23 | ImGui frontend: 24 | 25 | On Windows 26 | 27 | It requires VS 2019+ c++ development environment installed 28 | 1. Install MSYS2. https://www.msys2.org/ 29 | 2. Run MSYS2 terminal 30 | 3. In this terminal, install the MinGW-w64 toolchain: 31 | 32 | pacman -S --needed base-devel mingw-w64-ucrt-x86_64-toolchain. 33 | Enter Y when prompted 34 | 35 | 4. Update Path environment variable adding following paths: 36 | 37 | C:\msys64\ucrt64\bin 38 | 39 | 5. mkdir build 40 | 6. cd build 41 | 7. cmake --build build --target all 42 | 43 | 44 | On Linux 45 | 1. sudo apt update 46 | 2. sudo apt-get install build-essential git gcc-13 g++-13 make cmake libgl1-mesa-dev xorg-dev ninja-build libgtk-3-dev libx11-dev 47 | 3. mkdir build 48 | 3. cd build 49 | 4. cmake -G Ninja .. 50 | 5. ninja 51 | or 52 | 4. cmake .. 53 | 5. cmake --build . 54 | 55 | WPF frontend: 56 | It requires VS 2019+ c++ development environment installed 57 | 1. open DevectorWPF.sln VS Studio solution 58 | 2. install NuGet package: 59 | 1. Tools -> NuGet Package Manager -> Package Manager Console 60 | 2. Install-Package ModernWpfUI 61 | 3. build 62 | 63 | ## Contributing 64 | 65 | Contributions are welcome! If you find a bug or have an idea for a feature, please create an issue or submit a pull request. 66 | 67 | ## License 68 | 69 | Devector is licensed under the MIT License. See the LICENSE file for more information. 70 | 71 | ## Acknowledgements 72 | 73 | Special thanks to the following people for their contributions: 74 | 75 | - [Svofski](https://github.com/svofski) 76 | - [Viktor Pykhonin](https://github.com/vpyk/) 77 | - [Yuri Larin](https://github.com/ImproverX) 78 | - [zx-pk.ru comunity](https://zx-pk.ru/) 79 | -------------------------------------------------------------------------------- /resources/boot/boot.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/resources/boot/boot.bin -------------------------------------------------------------------------------- /resources/boot/boots.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/resources/boot/boots.bin -------------------------------------------------------------------------------- /resources/boot/boots.txt: -------------------------------------------------------------------------------- 1 | (с) Тимошенко Александр (aka TIMSoft) URL: http://vector06c.narod.ru 2 | 3 | "boots" v3.0 4 | САМЫЙ универсальный загрузчик на 2кБ для ПК "Вектор-06Ц" 5 | 6 | В разработке использован код 7 | "Кишиневского" и "Кировского" загрузчиков, 8 | а также код загрузчиков неизвестного 9 | авторства и происхождения 10 | 11 | 12 | 1. ЛИЦЕНЗИОННОЕ СОГЛАШЕНИЕ 13 | 14 | Программа является freeware и может распространяться свободно при 15 | условии отсутствия прямой коммерческой выгоды. Автор не несет никакой 16 | ответственности за последствия использования данной программы. 17 | 18 | 19 | 2. КОМПЛЕКТ ПОСТАВКИ 20 | 21 | boots.bin - файл загрузчика 22 | boots.txt - данное описание 23 | 24 | 25 | 3. ОПИСАНИЕ ПРОГРАММЫ И ПРИНЦИП РАБОТЫ 26 | 27 | 3.1. Программа "boots.bin" предназначена для начальной загрузки 28 | ПК"Вектор-06Ц" и прошивается в ПЗУ объемом 2 кБайт типа К573РФ5 29 | 30 | 3.2. Поддерживаемые устройства (перечислены в зависимости от приоритета при 31 | загрузке): 32 | 33 | - электронный квазидиск 34 | - дисковод 35 | - жесткий диск 36 | - сетевой адаптер (документально не описан, но в загрузчике предусмотрен) 37 | - модуль внешнего ППЗУ 38 | - магнитофон 39 | - 0-модемное соединение с IBM PC (далее РС) через порты ПУ-LPT 40 | 41 | Для поддержки 0-модемного соединения необходимо использовать программу 42 | "0modem", последнюю версию которой можно получить по адресу: 43 | http://vector06c.narod.ru 44 | 45 | 3.3. Режимы работы (задаются при перезагрузке путем удержания клавиш): 46 | 47 | КЛАВИША РЕЖИМ 48 | нет - квазидиск 49 | F1 - магнитофон 50 | F2 - МППЗУ 51 | F1+F2 - дисковод 52 | F2+F3 - жесткий диск 53 | F1+F3 - сетевой адаптер 54 | AP2 - загрузка из РС через порты ПУ-LPT 55 | 56 | Если для загрузки выбрано неподключенное устройство, загрузка будет 57 | производиться со следующего подключенного устройства согласно приоритету. 58 | 59 | Удерживание клавиши УС при перезагрузке отменяет очистку ОЗУ (кроме 60 | экранной области c адресами 0C000H-0DFFFH). 61 | 62 | 3.4. Некоторые примеры использования: 63 | 64 | а) Необходимо загрузить данные из РС 65 | - АР2+ВВОД+БЛК - ввод данных из РС 66 | - СБР+БЛК - запуск 67 | 68 | б) Необходимо загрузить данные из РС для обработки: 69 | - загрузить монитор-отладчик 70 | - СБР+БЛК - запуск, выбор режима 71 | - УС+АР2+ВВОД+БЛК - ввод данных из РС 72 | - СБР+БЛК - возврат в монитор 73 | 74 | в) Необходимо загрузить данные с магнитофона для обработки: 75 | - загрузить монитор-отладчик 76 | - СБР+БЛК - запуск, выбор режима 77 | - УС+ВВОД+БЛК - ввод данных с магнитофона 78 | - СБР+БЛК - возврат в монитор 79 | 80 | 81 | 4. ИСТОРИЯ РАЗРАБОТКИ 82 | 83 | v3.0 84 | [+] добавлена поддержка загрузки с жесткого диска 85 | [+] оптимизирован код 86 | 87 | v2.0 88 | [+] подпрограммы работы с дисководом взяты из Кировского загрузчика, 89 | теперь загрузка ведется значительно быстрее. В отличие от Кишиневского 90 | загрузчика, Кировский предполагает, что все программы, загружаемые с 91 | диска, размещаются с адреса 0100Н. Если это в корне неверно - сообщите 92 | по адресу, указанному в п.6 и пришлите образ диска 93 | 94 | 95 | 5. БЛАГОДАРНОСТИ 96 | 97 | - TMKSoft в лице Михаила Таланова за помощь с программным обеспечением 98 | для Вектора и информационную поддержку. 99 | 100 | - Пантелееву Роману Евгеньевичу и Hавалону Аpтему Виктоpовичу за их 101 | замечательный эмулятор ПК "Вектор-06Ц", который во многом облегчил 102 | работу, а также дал понять, что Вектор еще не забыт :-) 103 | 104 | 105 | 6. КООРДИНАТЫ АВТОРА 106 | 107 | Тимошенко Александр Валерьевич (aka TIMSoft) 108 | URL: http://vector06c.narod.ru 109 | E-mail: timsoft@mail.ru 110 | ICQ UIN: #22350135 (Sherhan) 111 | 112 | Ваши отзывы, замечания и пожелания будут с интересом рассмотрены. 113 | 114 | г.Чернигов (Украина) 28.04.99 -------------------------------------------------------------------------------- /resources/fonts/medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/resources/fonts/medium.ttf -------------------------------------------------------------------------------- /resources/fonts/medium_italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/resources/fonts/medium_italic.ttf -------------------------------------------------------------------------------- /resources/images/vector_keyboard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/resources/images/vector_keyboard.jpg -------------------------------------------------------------------------------- /resources/ramDisks.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/resources/ramDisks.bin -------------------------------------------------------------------------------- /resources/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "bootPath": "boot/boot.bin", 3 | "breakpointsWindowVisisble": true, 4 | "debugdataWindowVisible": true, 5 | "disasmWindowVisible": true, 6 | "displayWindowVisible": true, 7 | "fontItalicPath": "fonts/medium_italic.ttf", 8 | "fontItalicSize": 18.0, 9 | "fontPath": "fonts/medium.ttf", 10 | "fontSize": 18.0, 11 | "hardwareStatsWindowVisible": true, 12 | "hexViewerWindowVisible": true, 13 | "keyboardWindowVisible": false, 14 | "m_mountRecentFddImg": true, 15 | "mainWindowHeight": 1369, 16 | "mainWindowWidth": 3440, 17 | "mainWindowX": 0, 18 | "mainWindowY": 23, 19 | "memDisplayWindowVisible": true, 20 | "pathImgKeyboard": "images/vector_keyboard.jpg", 21 | "ramDiskClearAfterRestart": false, 22 | "ramDiskDataPath": "ramDisks.bin", 23 | "recentFiles": [ 24 | ], 25 | "recorderWindowVisible": true, 26 | "restartOnLoadFdd": true, 27 | "searchWindowVisible": false, 28 | "showSaveDiscardFddDialog": true, 29 | "traceLogWindowVisible": true, 30 | "watchpointsWindowVisible": true 31 | } 32 | -------------------------------------------------------------------------------- /rom/.saved.fdd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/.saved.fdd -------------------------------------------------------------------------------- /rom/beeper/gtoc64.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/beeper/gtoc64.rom -------------------------------------------------------------------------------- /rom/beeper/hvphas.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/beeper/hvphas.rom -------------------------------------------------------------------------------- /rom/beeper/music.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/beeper/music.txt -------------------------------------------------------------------------------- /rom/beeper/phphunk.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/beeper/phphunk.rom -------------------------------------------------------------------------------- /rom/beeper/pirat.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/beeper/pirat.rom -------------------------------------------------------------------------------- /rom/beeper/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/beeper/readme.txt -------------------------------------------------------------------------------- /rom/beeper/rock.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/beeper/rock.rom -------------------------------------------------------------------------------- /rom/beeper/rublov.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/beeper/rublov.rom -------------------------------------------------------------------------------- /rom/fdd/Robotz65a.fdd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/fdd/Robotz65a.fdd -------------------------------------------------------------------------------- /rom/fdd/Robotz66a - Copy.fdd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/fdd/Robotz66a - Copy.fdd -------------------------------------------------------------------------------- /rom/fdd/Robotz66a.fdd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/fdd/Robotz66a.fdd -------------------------------------------------------------------------------- /rom/fdd/badaps.fdd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/fdd/badaps.fdd -------------------------------------------------------------------------------- /rom/fdd/galery.fdd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/fdd/galery.fdd -------------------------------------------------------------------------------- /rom/fdd/galery.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/fdd/galery.txt -------------------------------------------------------------------------------- /rom/fdd/out1.fdd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/fdd/out1.fdd -------------------------------------------------------------------------------- /rom/fdd/rds308.fdd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/fdd/rds308.fdd -------------------------------------------------------------------------------- /rom/file_name.rec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/file_name.rec -------------------------------------------------------------------------------- /rom/file_name2.rec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/file_name2.rec -------------------------------------------------------------------------------- /rom/games/ADSKOK.ROM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/games/ADSKOK.ROM -------------------------------------------------------------------------------- /rom/games/DFIGHT.ROM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/games/DFIGHT.ROM -------------------------------------------------------------------------------- /rom/games/FATAXCOL.ROM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/games/FATAXCOL.ROM -------------------------------------------------------------------------------- /rom/games/GameNoname_eng.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/games/GameNoname_eng.rom -------------------------------------------------------------------------------- /rom/games/GameNoname_rus.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/games/GameNoname_rus.rom -------------------------------------------------------------------------------- /rom/games/cronex.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/games/cronex.rom -------------------------------------------------------------------------------- /rom/games/exolon.json: -------------------------------------------------------------------------------- 1 | { 2 | "breakpoints": null, 3 | "comments": { 4 | "0x0100": "comment 123" 5 | }, 6 | "consts": null, 7 | "labels": { 8 | "TimerRead": "0x0147", 9 | "WriteTimer1": "0x16A2", 10 | "WriteTimer2": "0x16B2" 11 | }, 12 | "memoryEdits": null, 13 | "watchpoints": null 14 | } 15 | -------------------------------------------------------------------------------- /rom/games/exolon.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/games/exolon.rom -------------------------------------------------------------------------------- /rom/games/maric.json: -------------------------------------------------------------------------------- 1 | { 2 | "breakpoints": [ 3 | { 4 | "addr": "0x06DF", 5 | "autoDel": false, 6 | "comment": "", 7 | "cond": "=ANY", 8 | "memPages": 4294967295, 9 | "operand": "A", 10 | "status": 0, 11 | "value": "0x00" 12 | } 13 | ], 14 | "comments": null, 15 | "consts": null, 16 | "labels": null, 17 | "memoryEdits": null, 18 | "watchpoints": [ 19 | { 20 | "access": "RW", 21 | "active": false, 22 | "comment": "", 23 | "cond": "=ANY", 24 | "globalAddr": "0x00AD24", 25 | "id": 1, 26 | "len": "0x0100", 27 | "type": "LEN", 28 | "value": "0x0000" 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /rom/games/maric.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/games/maric.rom -------------------------------------------------------------------------------- /rom/games/ot.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/games/ot.rom -------------------------------------------------------------------------------- /rom/games/putup.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/games/putup.rom -------------------------------------------------------------------------------- /rom/games/river_raid.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/games/river_raid.rom -------------------------------------------------------------------------------- /rom/games/vetka - Copy.fdd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/games/vetka - Copy.fdd -------------------------------------------------------------------------------- /rom/games/vetka.fdd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/games/vetka.fdd -------------------------------------------------------------------------------- /rom/not_working/.saved.fdd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/not_working/.saved.fdd -------------------------------------------------------------------------------- /rom/not_working/8080EX1.COM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/not_working/8080EX1.COM -------------------------------------------------------------------------------- /rom/not_working/b-ice.fdd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/not_working/b-ice.fdd -------------------------------------------------------------------------------- /rom/not_working/card.fdd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/not_working/card.fdd -------------------------------------------------------------------------------- /rom/not_working/cdpacman.fdd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/not_working/cdpacman.fdd -------------------------------------------------------------------------------- /rom/not_working/pillars.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/not_working/pillars.rom -------------------------------------------------------------------------------- /rom/not_working/t-rex-05.fdd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/not_working/t-rex-05.fdd -------------------------------------------------------------------------------- /rom/ramdisk_test.ROM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/ramdisk_test.ROM -------------------------------------------------------------------------------- /rom/scrltst2/00.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/scrltst2/00.jpg -------------------------------------------------------------------------------- /rom/scrltst2/14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/scrltst2/14.jpg -------------------------------------------------------------------------------- /rom/scrltst2/18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/scrltst2/18.jpg -------------------------------------------------------------------------------- /rom/scrltst2/README.txt: -------------------------------------------------------------------------------- 1 | Тест загрузки регистра прокрутки. Иван Городецкий, Уфа, 2009. 2 | Управление клавишами УС и СС. 3 | 4 | Скриншоты с реала Александра Тимошенко (Tim0xA). 5 | -------------------------------------------------------------------------------- /rom/scrltst2/scrltst2.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/scrltst2/scrltst2.rom -------------------------------------------------------------------------------- /rom/timing_tests/b-ice.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/timing_tests/b-ice.com -------------------------------------------------------------------------------- /rom/timing_tests/b-ice.xor: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/timing_tests/b-ice.xor -------------------------------------------------------------------------------- /rom/timing_tests/b-ice.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/timing_tests/b-ice.zip -------------------------------------------------------------------------------- /rom/timing_tests/hwdit512.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/timing_tests/hwdit512.rom -------------------------------------------------------------------------------- /rom/timing_tests/kittham1.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/timing_tests/kittham1.rom -------------------------------------------------------------------------------- /rom/timing_tests/mineswep.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/timing_tests/mineswep.rom -------------------------------------------------------------------------------- /rom/timing_tests/sunsetb.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/timing_tests/sunsetb.rom -------------------------------------------------------------------------------- /rom/timing_tests/tiedye2.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/timing_tests/tiedye2.rom -------------------------------------------------------------------------------- /rom/v_tests/bord2.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/v_tests/bord2.rom -------------------------------------------------------------------------------- /rom/v_tests/clrspace.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/v_tests/clrspace.rom -------------------------------------------------------------------------------- /rom/v_tests/test512.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/v_tests/test512.rom -------------------------------------------------------------------------------- /rom/v_tests/vst.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/v_tests/vst.rom -------------------------------------------------------------------------------- /rom/v_tests/vst_realV06C.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/v_tests/vst_realV06C.jpg -------------------------------------------------------------------------------- /rom/v_tests/vstvi53.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/v_tests/vstvi53.jpg -------------------------------------------------------------------------------- /rom/v_tests/vstvi53.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/v_tests/vstvi53.rom -------------------------------------------------------------------------------- /rom/v_tests/vstvi53_real6128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/rom/v_tests/vstvi53_real6128.jpg -------------------------------------------------------------------------------- /src/core/audio.cpp: -------------------------------------------------------------------------------- 1 | #include "core/audio.h" 2 | #include 3 | #include "utils/utils.h" 4 | 5 | dev::Audio::Audio(TimerI8253& _timer, AYWrapper& _aywrapper) : 6 | m_timer(_timer), m_aywrapper(_aywrapper) 7 | { 8 | Init(); 9 | } 10 | 11 | dev::Audio::~Audio() 12 | { 13 | Pause(true); 14 | SDL_DestroyAudioStream(m_stream); 15 | } 16 | 17 | void dev::Audio::Pause(bool _pause) 18 | { 19 | if (_pause) 20 | { 21 | SDL_PauseAudioDevice(m_audioDevice); 22 | } 23 | else { 24 | SDL_ResumeAudioDevice(m_audioDevice); 25 | } 26 | } 27 | 28 | void dev::Audio::Mute(const bool _mute) { m_muteMul = _mute ? 0.0f : 1.0f; } 29 | 30 | void dev::Audio::Reset() 31 | { 32 | m_aywrapper.Reset(); 33 | m_timer.Reset(); 34 | m_buffer.fill(0); 35 | m_lastSample = m_readBuffIdx = m_writeBuffIdx = 0; 36 | m_muteMul = 1.0f; 37 | } 38 | 39 | void dev::Audio::Init() 40 | { 41 | const SDL_AudioSpec spec = { SDL_AUDIO_F32, 1, 50000 }; 42 | 43 | SDL_Init(SDL_INIT_AUDIO); 44 | 45 | if (!(SDL_WasInit(SDL_INIT_AUDIO) & SDL_INIT_AUDIO)) { 46 | dev::Log("SDL audio error: SDL_INIT_AUDIO not initialized\n"); 47 | return; 48 | } 49 | 50 | m_stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, Callback, this); 51 | if (m_stream == NULL) { 52 | dev::Log("SDL_OpenAudioDeviceStream: the stream failed to create: {}\n", SDL_GetError()); 53 | } 54 | 55 | m_audioDevice = SDL_GetAudioStreamDevice(m_stream); 56 | if (!m_audioDevice) { 57 | dev::Log("SDL_GetAudioStreamDevice: the device failed to create: {}\n", SDL_GetError()); 58 | } 59 | SDL_ResumeAudioDevice(m_audioDevice); 60 | 61 | m_inited = true; 62 | } 63 | 64 | // _cycles are ticks of the 1.5 Mhz timer. 65 | // Hardware thread 66 | void dev::Audio::Clock(int _cycles, const float _beeper) 67 | { 68 | if (!m_inited) return; 69 | 70 | //covox = covox - 255; 71 | 72 | for (int tick = 0; tick < _cycles; ++tick) 73 | { 74 | float sample = (m_timer.Clock(1) + m_aywrapper.Clock(2) + _beeper) * m_muteMul; 75 | 76 | if (Downsample(sample)) 77 | { 78 | m_buffer[(m_writeBuffIdx++) % BUFFER_SIZE] = sample; 79 | m_lastSample = sample; 80 | } 81 | } 82 | } 83 | 84 | 85 | // resamples to a lower rate using a linear interpolation. 86 | // returns true if the output sample is ready, false otherwise 87 | bool dev::Audio::Downsample(float& _sample) 88 | { 89 | static int sampleCounter = 0; 90 | static float accumulator = 0; 91 | accumulator += _sample; 92 | 93 | if (++sampleCounter > m_downsampleRate) 94 | { 95 | _sample = accumulator / m_downsampleRate; 96 | sampleCounter = 0; 97 | accumulator = 0; 98 | return true; 99 | } 100 | 101 | return false; 102 | } 103 | 104 | // feeds the SDL3 playback buffer. 105 | void dev::Audio::Callback(void* _userdata, SDL_AudioStream* _stream, int _additionalAmount, int _totalAmount) 106 | { 107 | if (_additionalAmount <= 0) return; 108 | 109 | Audio* audioP = (Audio*)_userdata; 110 | if (!audioP->m_inited) return; 111 | 112 | // malloc the SDL buff 113 | Uint8* data = SDL_stack_alloc(Uint8, _additionalAmount); 114 | if (!data) return; 115 | 116 | // convert the plain data to SDL_AUDIO_F32 buff; 117 | float* fstream = (float*)data; 118 | int fstreamLen = _additionalAmount / sizeof(float); 119 | 120 | 121 | int buffering = audioP->m_writeBuffIdx - audioP->m_readBuffIdx; 122 | bool underBuferring = buffering < LOW_BUFFERING; 123 | bool overBuferring = buffering > HIGH_BUFFERING; 124 | 125 | if (underBuferring) 126 | { 127 | // fill in with the lastSample when it's low buffering 128 | auto lastSample = audioP->m_lastSample.load(); 129 | std::fill(fstream, fstream + fstreamLen, lastSample); 130 | 131 | // adjust the resample rate 132 | int downsampleRate = --audioP->m_downsampleRate; 133 | //dev::Log("SDL buffering is too low: {}. Sample rate is adjusted: {}", buffering, downsampleRate); 134 | } 135 | else 136 | { 137 | // copy the samples 138 | for (int i = 0; i < fstreamLen; i++) 139 | { 140 | fstream[i] = audioP->m_buffer[(audioP->m_readBuffIdx++) % BUFFER_SIZE]; 141 | } 142 | 143 | if (overBuferring) 144 | { 145 | audioP->m_readBuffIdx += fstreamLen; 146 | // adjust the resample rate 147 | int downsampleRate = ++audioP->m_downsampleRate; 148 | //dev::Log("SDL buffering is too big: {}. Sample rate is adjusted: {}", buffering, downsampleRate); 149 | } 150 | } 151 | 152 | // memcopy the SDL buff 153 | SDL_PutAudioStreamData(_stream, data, _additionalAmount); 154 | SDL_stack_free(data); 155 | } 156 | -------------------------------------------------------------------------------- /src/core/audio.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "core/timer_i8253.h" 6 | #include "core/sound_ay8910.h" 7 | #include "SDL3/SDL.h" 8 | 9 | namespace dev 10 | { 11 | class Audio 12 | { 13 | private: 14 | static constexpr int INPUT_RATE = 1500000; // 1.5 MHz timer 15 | static constexpr int OUTPUT_RATE = 50000; // 50 KHz 16 | static constexpr int DOWNSAMPLE_RATE = INPUT_RATE / OUTPUT_RATE; 17 | static constexpr int CALLBACKS_PER_SEC = 100; // arbitrary number found while examining the SDL3 callback calls 18 | static constexpr int SDL_BUFFER = OUTPUT_RATE / CALLBACKS_PER_SEC; // the estimated SDL stream buff len 19 | static constexpr int SDL_BUFFERS = 8; // to make sure there is enough available data for audio streaming 20 | static constexpr int BUFFER_SIZE = SDL_BUFFER * SDL_BUFFERS; 21 | static constexpr int TARGET_BUFFERING = SDL_BUFFER * 4; 22 | static constexpr int LOW_BUFFERING = TARGET_BUFFERING - SDL_BUFFER * 2; 23 | static constexpr int HIGH_BUFFERING = TARGET_BUFFERING + SDL_BUFFER * 2; 24 | 25 | TimerI8253& m_timer; 26 | AYWrapper& m_aywrapper; 27 | SDL_AudioDeviceID m_audioDevice = 0; 28 | SDL_AudioStream* m_stream = nullptr; 29 | float m_muteMul = 1.0f; 30 | 31 | std::array m_buffer; // Audio system writes to it, SDL reads from it 32 | std::atomic_uint64_t m_readBuffIdx = 0; // the last sample played by SDL 33 | std::atomic_uint64_t m_writeBuffIdx = 0; // the last sample stored by the Audio system 34 | std::atomic m_lastSample = 0.0f; 35 | 36 | std::atomic_bool m_inited = false; 37 | std::atomic_int m_downsampleRate = DOWNSAMPLE_RATE; 38 | 39 | bool Downsample(float& _sample); 40 | 41 | public: 42 | Audio(TimerI8253& _timer, AYWrapper& _aywrapper); 43 | ~Audio(); 44 | void Init(); 45 | void Pause(bool _pause); 46 | void Mute(const bool _mute); 47 | static void Callback(void* _userdata, SDL_AudioStream* _stream, int _additionalAmount, int _totalAmount); 48 | void Clock(int _cycles, const float _beeper); 49 | void Reset(); 50 | }; 51 | 52 | } -------------------------------------------------------------------------------- /src/core/breakpoint.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "core/breakpoint.h" 8 | #include "utils/str_utils.h" 9 | #include "utils/utils.h" 10 | 11 | dev::Breakpoint::Breakpoint(Data&& _data, const std::string& _comment) 12 | : 13 | data(std::move(_data)), comment(_comment) 14 | { 15 | UpdateAddrMappingS(); 16 | } 17 | 18 | void dev::Breakpoint::Update(Breakpoint&& _bp) 19 | { 20 | data = std::move(_bp.data); 21 | comment = std::move(_bp.comment); 22 | UpdateAddrMappingS(); 23 | } 24 | 25 | auto dev::Breakpoint::GetOperandS() const 26 | -> const char* 27 | { 28 | return bpOperandsS[static_cast(data.structured.operand)]; 29 | } 30 | 31 | auto dev::Breakpoint::GetConditionS() const 32 | -> const std::string 33 | { 34 | std::string condValS = ConditionsS[static_cast(data.structured.cond)]; 35 | condValS += data.structured.cond == Condition::ANY ? "" : std::format(" 0x{:02X}", data.structured.value); 36 | 37 | std::string out = std::format("{}{}{}", 38 | GetOperandS(), 39 | condValS, 40 | data.structured.autoDel ? ":A" : "" 41 | ); 42 | return out; 43 | } 44 | 45 | auto dev::Breakpoint::IsActiveS() const -> const char* { return data.structured.status == Status::ACTIVE ? "X" : "-"; } 46 | 47 | bool dev::Breakpoint::CheckStatus(const CpuI8080::State& _cpuState, const Memory::State& _memState) const 48 | { 49 | auto mapping = _memState.update.mapping.data & Memory::MAPPING_RAM_MODE_MASK ? 1 << (_memState.update.mapping.pageRam + 1 + 4 * _memState.update.ramdiskIdx) : 1; 50 | 51 | bool active = data.structured.status == Status::ACTIVE && mapping & data.structured.memPages.data; 52 | if (!active) return false; 53 | if (data.structured.cond == dev::Condition::ANY) return true; 54 | 55 | uint64_t op; 56 | switch (data.structured.operand) 57 | { 58 | case dev::Breakpoint::Operand::A: 59 | op = _cpuState.regs.psw.a; 60 | break; 61 | case dev::Breakpoint::Operand::F: 62 | op = _cpuState.regs.psw.af.l; 63 | break; 64 | case dev::Breakpoint::Operand::B: 65 | op = _cpuState.regs.bc.h; 66 | break; 67 | case dev::Breakpoint::Operand::C: 68 | op = _cpuState.regs.bc.l; 69 | break; 70 | case dev::Breakpoint::Operand::D: 71 | op = _cpuState.regs.de.h; 72 | break; 73 | case dev::Breakpoint::Operand::E: 74 | op = _cpuState.regs.de.l; 75 | break; 76 | case dev::Breakpoint::Operand::H: 77 | op = _cpuState.regs.hl.h; 78 | break; 79 | case dev::Breakpoint::Operand::L: 80 | op = _cpuState.regs.hl.l; 81 | break; 82 | case dev::Breakpoint::Operand::PSW: 83 | op = _cpuState.regs.psw.af.word; 84 | break; 85 | case dev::Breakpoint::Operand::BC: 86 | op = _cpuState.regs.bc.word; 87 | break; 88 | case dev::Breakpoint::Operand::DE: 89 | op = _cpuState.regs.de.word; 90 | break; 91 | case dev::Breakpoint::Operand::HL: 92 | op = _cpuState.regs.hl.word; 93 | break; 94 | case dev::Breakpoint::Operand::CC: 95 | op = _cpuState.cc; 96 | break; 97 | case dev::Breakpoint::Operand::SP: 98 | op = _cpuState.regs.sp.word; 99 | break; 100 | default: 101 | op = 0; 102 | break; 103 | } 104 | 105 | switch (data.structured.cond) 106 | { 107 | case dev::Condition::EQU: 108 | return op == data.structured.value; 109 | case dev::Condition::LESS: 110 | return op < data.structured.value; 111 | case dev::Condition::GREATER: 112 | return op > data.structured.value; 113 | case dev::Condition::LESS_EQU: 114 | return op <= data.structured.value; 115 | case dev::Condition::GREATER_EQU: 116 | return op >= data.structured.value; 117 | case dev::Condition::NOT_EQU: 118 | return op != data.structured.value; 119 | } 120 | return false; 121 | } 122 | 123 | void dev::Breakpoint::Print() const 124 | { 125 | dev::Log("0x{:04X}, status:{}, memPages: {}, autoDel: {}, op: {}, cond: {}, val: {}", 126 | data.structured.addr, static_cast(data.structured.status), data.structured.memPages.data, data.structured.autoDel, 127 | GetOperandS(), GetConditionS(), data.structured.value); 128 | } 129 | 130 | void dev::Breakpoint::UpdateAddrMappingS() 131 | { 132 | addrMappingS = dev::Uint16ToStrC0x(data.structured.addr); 133 | } 134 | 135 | auto dev::Breakpoint::GetAddrMappingS() const 136 | -> const char* 137 | { 138 | return addrMappingS.c_str(); 139 | }; -------------------------------------------------------------------------------- /src/core/breakpoints.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "breakpoints.h" 4 | #include "utils/str_utils.h" 5 | #include "utils/utils.h" 6 | 7 | void dev::Breakpoints::Clear() 8 | { 9 | m_bps.clear(); 10 | m_updates++; 11 | } 12 | 13 | void dev::Breakpoints::SetStatus(const Addr _addr, const Breakpoint::Status _status) 14 | { 15 | m_updates++; 16 | auto bpI = m_bps.find(_addr); 17 | if (bpI != m_bps.end()) { 18 | bpI->second.data.structured.status = _status; 19 | return; 20 | } 21 | Add(Breakpoint{ _addr }); 22 | } 23 | 24 | void dev::Breakpoints::Add(Breakpoint&& _bp ) 25 | { 26 | m_updates++; 27 | auto bpI = m_bps.find(_bp.data.structured.addr); 28 | if (bpI != m_bps.end()) 29 | { 30 | bpI->second.Update(std::move(_bp)); 31 | return; 32 | } 33 | 34 | m_bps.emplace(static_cast(_bp.data.structured.addr), std::move(_bp)); 35 | } 36 | 37 | void dev::Breakpoints::Add(const nlohmann::json& _bpJ) 38 | { 39 | m_updates++; 40 | 41 | Breakpoint::Data bpData {_bpJ}; 42 | Breakpoint bp{ std::move(bpData), _bpJ["comment"] }; 43 | 44 | auto bpI = m_bps.find(bp.data.structured.addr); 45 | if (bpI != m_bps.end()) 46 | { 47 | bpI->second.Update(std::move(bp)); 48 | return; 49 | } 50 | 51 | m_bps.emplace(static_cast(bp.data.structured.addr), std::move(bp)); 52 | } 53 | 54 | void dev::Breakpoints::Del(const Addr _addr) 55 | { 56 | m_updates++; 57 | auto bpI = m_bps.find(_addr); 58 | if (bpI != m_bps.end()) 59 | { 60 | m_bps.erase(bpI); 61 | } 62 | } 63 | 64 | auto dev::Breakpoints::GetStatus(const Addr _addr) 65 | -> const Breakpoint::Status 66 | { 67 | auto bpI = m_bps.find(_addr); 68 | return bpI == m_bps.end() ? Breakpoint::Status::DELETED : bpI->second.data.structured.status; 69 | } 70 | 71 | bool dev::Breakpoints::Check(const CpuI8080::State& _cpuState, const Memory::State& _memState) 72 | { 73 | auto bpI = m_bps.find(_cpuState.regs.pc.word); 74 | if (bpI == m_bps.end()) return false; 75 | 76 | auto status = bpI->second.CheckStatus(_cpuState, _memState); 77 | if (bpI->second.data.structured.autoDel) 78 | { 79 | m_bps.erase(bpI); 80 | m_updates++; 81 | } 82 | return status; 83 | } 84 | 85 | auto dev::Breakpoints::GetAll() 86 | -> const BpMap& 87 | { 88 | return m_bps; 89 | } 90 | 91 | auto dev::Breakpoints::GetUpdates() 92 | -> const uint32_t 93 | { 94 | return m_updates; 95 | } -------------------------------------------------------------------------------- /src/core/breakpoints.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "utils/types.h" 6 | #include "utils/json_utils.h" 7 | #include "core/breakpoint.h" 8 | 9 | namespace dev 10 | { 11 | struct Breakpoints 12 | { 13 | public: 14 | using BpMap = std::unordered_map; 15 | 16 | void SetStatus(const Addr _addr, const Breakpoint::Status _status); 17 | void Add(Breakpoint&& _bp); 18 | void Add(const nlohmann::json& _bpJ); 19 | void Del(const Addr _addr); 20 | bool Check(const CpuI8080::State& _cpuState, const Memory::State& _memState); 21 | auto GetAll() -> const BpMap&; 22 | auto GetUpdates() -> const uint32_t; 23 | auto GetStatus(const Addr _addr) -> const Breakpoint::Status; 24 | void Clear(); 25 | 26 | private: 27 | 28 | BpMap m_bps; 29 | uint32_t m_updates; // counts number of updates 30 | }; 31 | } -------------------------------------------------------------------------------- /src/core/code_perf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "utils/types.h" 7 | #include "utils/str_utils.h" 8 | #include "utils/json_utils.h" 9 | 10 | namespace dev 11 | { 12 | struct CodePerf 13 | { 14 | static constexpr int TESTS_MAX = 20000; 15 | std::string label; 16 | Addr addrStart = 0; 17 | Addr addrEnd = 0x100; 18 | double averageCcDiff = 0.0f; // average cc (Cpu CLock) difference between it entered the addrStart and exited addrEnd 19 | int64_t tests = 0; // how many testes executed 20 | int64_t cc = 0; // the current perf test cc 21 | bool active = true; 22 | 23 | auto AddrToStr() const -> std::string { 24 | return std::format("0x{:06x}-0x{:06x}: {}, average cc: {}, tests: {}", 25 | addrStart, addrEnd, 26 | active ? "active" : "not active", 27 | static_cast(std::round(averageCcDiff)), 28 | tests); 29 | } 30 | 31 | void Erase() 32 | { 33 | label.clear(); 34 | addrStart = 0; 35 | addrEnd = 0x100; 36 | averageCcDiff = 0; 37 | tests = 0; 38 | cc = 0; 39 | active = true; 40 | } 41 | 42 | void CheckPerf(const Addr _addr, const uint64_t _cc) 43 | { 44 | if (!active || (addrStart != _addr && cc == 0)) return; 45 | 46 | if (addrStart == _addr){ 47 | cc = _cc; 48 | } 49 | else 50 | if (addrEnd == _addr) 51 | { 52 | tests += tests >= TESTS_MAX ? 0 : 1; 53 | auto weight = 1.0 / tests; 54 | int64_t ccDiff = _cc - cc; 55 | averageCcDiff += (ccDiff - averageCcDiff) * weight; 56 | cc = 0; 57 | } 58 | } 59 | 60 | CodePerf() = default; 61 | 62 | CodePerf(const nlohmann::json& _json) 63 | : 64 | label(_json["label"].get()), 65 | addrStart(dev::StrHexToInt(_json["addrStart"].get().c_str())), 66 | addrEnd(dev::StrHexToInt(_json["addrEnd"].get().c_str())), 67 | active(_json["active"].get()) 68 | {} 69 | 70 | auto ToJson() const -> nlohmann::json 71 | { 72 | return { 73 | {"label", label}, 74 | {"addrStart", std::format("0x{:04X}", addrStart)}, 75 | {"addrEnd", std::format("0x{:04X}", addrEnd)}, 76 | {"active", active} 77 | }; 78 | } 79 | }; 80 | } -------------------------------------------------------------------------------- /src/core/debug_data.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "utils/types.h" 9 | #include "utils/str_utils.h" 10 | #include "core/hardware.h" 11 | 12 | #include "core/breakpoints.h" 13 | #include "core/watchpoints.h" 14 | #include "core/code_perf.h" 15 | #include "core/memory_edit.h" 16 | #include "core/scripts.h" 17 | #include "utils/json_utils.h" 18 | 19 | namespace dev 20 | { 21 | class DebugData 22 | { 23 | public: 24 | using LabelList = std::vector; 25 | using Labels = std::unordered_map; 26 | using Comments = std::unordered_map; 27 | 28 | using UpdateId = int; 29 | 30 | using FilteredElements = std::vector>; // name, addr, addrS 31 | 32 | // injects the value into the memory while loading 33 | 34 | using MemoryEdits = std::unordered_map; 35 | using CodePerfs = std::unordered_map; 36 | 37 | DebugData(Hardware& _hardware); 38 | 39 | auto GetLabels(const Addr _addr) const -> const LabelList*; 40 | void SetLabels(const Addr _addr, const LabelList& _labels); 41 | void AddLabel(const Addr _addr, const std::string& _label); 42 | void DelLabel(const Addr _addr, const std::string& _label); 43 | void DelLabels(const Addr _addr); 44 | void DelAllLabels(); 45 | void RenameLabel(const Addr _addr, const std::string& _oldLabel, const std::string& _newLabel); 46 | void GetFilteredLabels(FilteredElements& _out, const std::string& _filter = "") const; 47 | 48 | auto GetConsts(const Addr _addr) const -> const LabelList*; 49 | void SetConsts(const Addr _addr, const LabelList& _consts); 50 | void AddConst(const Addr _addr, const std::string& _const); 51 | void DelConst(const Addr _addr, const std::string& _const); 52 | void DelConsts(const Addr _addr); 53 | void DelAllConsts(); 54 | void RenameConst(const Addr _addr, const std::string& _oldConst, const std::string& _newConst); 55 | void GetFilteredConsts(FilteredElements& _out, const std::string& _filter = "") const; 56 | 57 | auto GetComment(const Addr _addr) const -> const std::string*; 58 | void SetComment(const Addr _addr, const std::string& _comment); 59 | void DelComment(const Addr _addr); 60 | void DelAllComments(); 61 | void GetFilteredComments(FilteredElements& _out, const std::string& _filter = "") const; 62 | 63 | auto GetMemoryEdit(const Addr _addr) const -> const MemoryEdit*; 64 | void SetMemoryEdit(const MemoryEdit& _edit); 65 | void DelMemoryEdit(const Addr _addr); 66 | void DelAllMemoryEdits(); 67 | void GetFilteredMemoryEdits(FilteredElements& _out, const std::string& _filter = "") const; 68 | 69 | auto GetCodePerf(const Addr _addr) const -> const CodePerf*; 70 | void SetCodePerf(const CodePerf& _codePerf); 71 | void DelCodePerf(const Addr _addr); 72 | void DelAllCodePerfs(); 73 | void GetFilteredCodePerfs(FilteredElements& _out, const std::string& _filter = "") const; 74 | auto CheckCodePerfs(const Addr _addrStart, const uint64_t _cc) -> bool; 75 | 76 | void GetFilteredScripts(FilteredElements& _out, const std::string& _filter = ""); 77 | 78 | auto GetCommentsUpdates() const -> UpdateId { return m_commentsUpdates; }; 79 | auto GetLabelsUpdates() const -> UpdateId { return m_labelsUpdates; }; 80 | auto GetConstsUpdates() const -> UpdateId { return m_constsUpdates; }; 81 | auto GetEditsUpdates() const -> UpdateId { return m_editsUpdates; }; 82 | auto GetCodePerfsUpdates() const -> UpdateId { return m_codePerfsUpdates; }; 83 | 84 | auto GetBreakpoints() -> Breakpoints& { return m_breakpoints; }; 85 | auto GetWatchpoints() -> Watchpoints& { return m_watchpoints; }; 86 | auto GetScripts() -> Scripts& { return m_scripts; }; 87 | 88 | void LoadDebugData(const std::string& _path); 89 | void SaveDebugData(); 90 | 91 | void Reset(); 92 | 93 | private: 94 | 95 | Hardware& m_hardware; 96 | 97 | Labels m_labels; // labels 98 | Labels m_consts; // labels used as constants or they point to data 99 | Comments m_comments; 100 | MemoryEdits m_memoryEdits; // code/data modifications 101 | CodePerfs m_codePerfs; 102 | Breakpoints m_breakpoints; 103 | Watchpoints m_watchpoints; 104 | Scripts m_scripts; 105 | 106 | std::string m_debugPath; 107 | 108 | UpdateId m_labelsUpdates = 0; 109 | UpdateId m_constsUpdates = 0; 110 | UpdateId m_commentsUpdates = 0; 111 | UpdateId m_editsUpdates = 0; 112 | UpdateId m_codePerfsUpdates = 0; 113 | }; 114 | } -------------------------------------------------------------------------------- /src/core/debugger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "utils/types.h" 11 | #include "core/hardware.h" 12 | #include "core/disasm.h" 13 | #include "core/debug_data.h" 14 | #include "core/display.h" 15 | #include "core/breakpoint.h" 16 | #include "core/watchpoint.h" 17 | #include "core/trace_log.h" 18 | #include "core/recorder.h" 19 | 20 | namespace dev 21 | { 22 | class Debugger 23 | { 24 | public: 25 | static constexpr int LAST_RW_W = 32; 26 | static constexpr int LAST_RW_H = 32; 27 | static constexpr int LAST_RW_MAX = LAST_RW_W * LAST_RW_H; // should be squared because it is sent to GPU 28 | static constexpr uint32_t LAST_RW_NO_DATA = uint32_t(-1); 29 | using MemLastRW = std::array; 30 | using LastRWAddrs = std::array; 31 | 32 | Debugger(Hardware& _hardware); 33 | ~Debugger(); 34 | 35 | void Reset(bool _resetRecorder, 36 | CpuI8080::State* _cpuStateP, Memory::State* _memStateP, 37 | IO::State* _ioStateP, Display::State* _displayStateP); 38 | 39 | bool Debug(CpuI8080::State* _cpuStateP, Memory::State* _memStateP, 40 | IO::State* _ioStateP, Display::State* _displayStateP); 41 | auto DebugReqHandling(Hardware::Req _req, nlohmann::json _reqDataJ, 42 | CpuI8080::State* _cpuStateP, Memory::State* _memStateP, 43 | IO::State* _ioStateP, Display::State* _displayStateP) -> nlohmann::json; 44 | 45 | void UpdateLastRW(); 46 | auto GetLastRW() -> const MemLastRW* { return &m_memLastRW; } 47 | void UpdateDisasm(const Addr _addr, const size_t _lines, const int _instructionOffset); 48 | auto GetTraceLog() -> TraceLog& { return m_traceLog; }; 49 | auto GetDebugData() -> DebugData& { return m_debugData; }; 50 | auto GetDisasm() -> Disasm& { return m_disasm; }; 51 | auto GetRecorder() -> Recorder& { return m_recorder; }; 52 | 53 | private: 54 | 55 | Hardware& m_hardware; 56 | DebugData m_debugData; 57 | Disasm m_disasm; 58 | TraceLog m_traceLog; 59 | Recorder m_recorder; 60 | 61 | std::mutex m_lastRWMutex; 62 | LastRWAddrs m_lastReadsAddrs; // a circular buffer that contains addresses 63 | LastRWAddrs m_lastWritesAddrs; // ... 64 | LastRWAddrs m_lastReadsAddrsOld; // ... used to clean up m_memLastReads 65 | LastRWAddrs m_lastWritesAddrsOld; // ... ... 66 | LastRWAddrs m_lastRWAddrsOut; // used to sent the data out of this thread 67 | int m_lastReadsIdx = 0; // index to m_memLastReads, points to the least recently read. because it's a circular buffer, that element before it is the most recently read 68 | int m_lastWritesIdx = 0; // ... 69 | MemLastRW m_memLastRW; // low 2 bytes of each element contains the order of readings. 255 is the most recently read, 0 - the least recently read 70 | // high 2 bytes contains the order of writings. 255 is the most recently written, 0 - the least recently written 71 | }; 72 | } -------------------------------------------------------------------------------- /src/core/fdc_wd1793.h: -------------------------------------------------------------------------------- 1 | // Emulation of Soviet KR1818WG93 (КР1818ВГ93) Floppy Disk Controller (WD1793 analog) 2 | 3 | // based on: 4 | // https://github.com/libretro/fmsx-libretro/blob/master/EMULib/WD1793.c 5 | // https://github.com/svofski/vector06sdl/blob/master/src/fd1793.h 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include "core/fdd_consts.h" 13 | 14 | namespace dev 15 | { 16 | struct FDisk 17 | { 18 | uint8_t data[FDD_SIZE]; 19 | public: 20 | 21 | uint8_t header[6]; // current header, result of Seek() 22 | bool updated = false; 23 | std::string path; 24 | bool mounted = false; 25 | 26 | size_t reads = 0; 27 | size_t writes = 0; 28 | 29 | FDisk(); 30 | void Mount(const std::vector& _data, const std::string& _path); 31 | auto GetData() -> uint8_t*; 32 | auto GetDisk() -> FDisk*; 33 | }; 34 | 35 | class Fdc1793 36 | { 37 | public: 38 | enum class Port : int { 39 | COMMAND = 0, 40 | STATUS = 0, 41 | TRACK = 1, 42 | SECTOR = 2, 43 | DATA = 3, 44 | READY = 4, 45 | SYSTEM = 4 46 | }; 47 | 48 | struct Info { 49 | uint8_t drive; // Current disk # 50 | uint8_t side; // Current side # 51 | uint8_t track; // Current track # 52 | uint8_t lastS; // Last STEP direction 53 | uint8_t irq; // 0x80: IRQ pending, 0x40: DRQ pending 54 | uint8_t wait; // Expiration counter 55 | uint8_t cmd; // Last command 56 | 57 | int rwLen; // The length of the transfered data 58 | size_t position; // sector addr 59 | }; 60 | 61 | struct DiskInfo { 62 | std::string path; 63 | bool updated = false; 64 | size_t reads; 65 | size_t writes; 66 | bool mounted = false; 67 | }; 68 | 69 | static constexpr int DRIVES_MAX = 4; 70 | 71 | private: 72 | FDisk m_disks[DRIVES_MAX]; 73 | 74 | uint8_t m_regs[5]; // Registers 75 | uint8_t m_drive = 0;// Current disk # 76 | uint8_t m_side = 0;// Current side # 77 | uint8_t m_track = 0;// Current track # 78 | uint8_t m_lastS = 0;// Last STEP direction 79 | uint8_t m_irq = 0;// 0x80: IRQ pending, 0x40: DRQ pending 80 | uint8_t m_wait = 0;// Expiration counter 81 | uint8_t m_cmd = 0;// Last command 82 | 83 | int m_rwLen = 0; // The length of the transfered data 84 | 85 | uint8_t* m_ptr = nullptr; // Pointer to data 86 | FDisk* m_disk = nullptr; // current disk images 87 | 88 | auto Seek(int _sideID, int _trackID, int _sectorID) -> uint8_t*; 89 | void Reset(); 90 | 91 | public: 92 | Fdc1793(); 93 | void Mount(const int _driveIdx, const std::vector& _data, const std::string& _path); 94 | auto Read(const Port _port) -> uint8_t; 95 | auto Write(const Port _port, uint8_t _val) -> uint8_t; 96 | auto GetFdcInfo() -> Info; 97 | auto GetFddInfo(const int _driveIdx) -> DiskInfo; 98 | auto GetFddImage(const int _driveIdx) -> const std::vector; 99 | void ResetUpdate(const int _driveIdx); 100 | }; 101 | } -------------------------------------------------------------------------------- /src/core/fdd_consts.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | static constexpr int FDD_SIDES = 2; 4 | static constexpr int FDD_TRACKS_PER_SIDE = 82; 5 | static constexpr int FDD_SECTORS_PER_TRACK = 5; 6 | static constexpr int FDD_SECTOR_LEN = 1024; 7 | static constexpr int FDD_SIZE = FDD_SIDES * FDD_TRACKS_PER_SIDE * FDD_SECTORS_PER_TRACK * FDD_SECTOR_LEN; -------------------------------------------------------------------------------- /src/core/hardware.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "utils/types.h" 11 | #include "core/cpu_i8080.h" 12 | #include "core/memory.h" 13 | #include "core/keyboard.h" 14 | #include "core/io.h" 15 | #include "core/display.h" 16 | #include "core/timer_i8253.h" 17 | #include "core/sound_ay8910.h" 18 | #include "core/audio.h" 19 | #include "core/fdc_wd1793.h" 20 | #include "utils/utils.h" 21 | #include "utils/result.h" 22 | #include "utils/tqueue.h" 23 | #include "utils/json_utils.h" 24 | 25 | namespace dev 26 | { 27 | class Hardware 28 | { 29 | CpuI8080 m_cpu; 30 | Memory m_memory; 31 | Keyboard m_keyboard; 32 | IO m_io; 33 | Display m_display; 34 | TimerI8253 m_timer; 35 | SoundAY8910 m_ay; 36 | AYWrapper m_aywrapper; 37 | Audio m_audio; 38 | Fdc1793 m_fdc; 39 | 40 | enum class Status : int { 41 | RUN, 42 | STOP, 43 | EXIT 44 | }; 45 | 46 | public: 47 | //enum class Req 48 | #include "core/hardware_consts.h" 49 | 50 | 51 | using DebugFunc = std::function; 54 | 55 | using DebugReqHandlingFunc = std::function; 58 | 59 | enum class ExecSpeed : int { _1PERCENT = 0, _20PERCENT, HALF, NORMAL, X2, MAX, LEN }; 60 | 61 | 62 | Hardware(const std::string& _pathBootData, const std::string& _pathRamDiskData, 63 | const bool _ramDiskClearAfterRestart); 64 | ~Hardware(); 65 | auto Request(const Req _req, const nlohmann::json& _dataJ = {}) -> Result ; 66 | auto GetFrame(const bool _vsync) -> const Display::FrameBuffer*; 67 | auto GetRam() const -> const Memory::Ram*; 68 | auto GetCpuState() -> const CpuI8080::State& { return m_cpu.GetState(); } 69 | auto GetMemState() -> const Memory::State& { return m_memory.GetState(); } 70 | auto GetIoState() -> const IO::State& { return m_io.GetState(); } 71 | 72 | void AttachDebugFuncs(DebugFunc _debugFunc, DebugReqHandlingFunc _debugReqHandlingFunc); 73 | 74 | 75 | private: 76 | DebugFunc Debug = nullptr; 77 | DebugReqHandlingFunc DebugReqHandling = nullptr; 78 | bool m_debugAttached = false; 79 | 80 | std::thread m_executionThread; 81 | std::thread m_reqHandlingThread; 82 | std::atomic m_status; 83 | TQueue > m_reqs; // request 84 | TQueue m_reqRes; // request's result sent back 85 | 86 | static constexpr std::chrono::microseconds m_reqHandlingTime = 1ms; 87 | ExecSpeed m_execSpeed = ExecSpeed::NORMAL; 88 | std::chrono::microseconds m_execDelays[static_cast(ExecSpeed::LEN)] = { 1996800us/*1%*/, 99840us/*20%*/, 39936us/*HALF*/, 19968us/*NORMAL*/, 9984us/*X2*/, 0us/*MAX*/ }; 89 | 90 | void Init(); 91 | void Execution(); 92 | bool ExecuteInstruction(); 93 | void ExecuteFrameNoBreaks(); 94 | void ReqHandling(const std::chrono::duration _waitTime = -1ns); 95 | void Reset(); 96 | void Restart(); 97 | void Stop(); 98 | void Run(); 99 | auto GetRegs() const -> nlohmann::json; 100 | auto GetByteGlobal(const nlohmann::json _globalAddrJ) -> nlohmann::json; 101 | auto GetByte(const nlohmann::json _addrJ, const Memory::AddrSpace _addrSpace) -> nlohmann::json; 102 | auto Get3Bytes(const nlohmann::json _addrJ, const Memory::AddrSpace _addrSpace) -> nlohmann::json; 103 | auto GetMemString(const nlohmann::json _dataJ, const Memory::AddrSpace _addrSpace = Memory::AddrSpace::RAM) -> nlohmann::json; 104 | auto GetWord(const nlohmann::json _addrJ, const Memory::AddrSpace _addrSpace) -> nlohmann::json; 105 | auto GetStackSample(const nlohmann::json _addrJ) -> nlohmann::json; 106 | auto GetFddInfo(const int _driveIdx) -> Fdc1793::DiskInfo; 107 | auto GetFddImage(const int _driveIdx) -> const std::vector; 108 | auto GetStepOverAddr() -> const Addr; 109 | }; 110 | } -------------------------------------------------------------------------------- /src/core/hardware_consts.h: -------------------------------------------------------------------------------- 1 | // kept separated because it is used in the c++ and c++/clr sides 2 | enum class Req: int { 3 | NONE = 0, 4 | RUN, 5 | STOP, 6 | IS_RUNNING, 7 | EXIT, 8 | RESET, // reboot the pc, enable the ROM 9 | RESTART, // reboot the pc, disable the ROM 10 | EXECUTE_INSTR, 11 | EXECUTE_FRAME, 12 | EXECUTE_FRAME_NO_BREAKS, 13 | GET_CC, 14 | GET_REGS, 15 | GET_REG_PC, 16 | GET_BYTE_GLOBAL, 17 | GET_BYTE_RAM, 18 | GET_THREE_BYTES_RAM, 19 | GET_MEM_STRING_GLOBAL, 20 | GET_WORD_STACK, 21 | GET_STACK_SAMPLE, 22 | GET_DISPLAY_DATA, 23 | GET_MEMORY_MAPPING, 24 | GET_MEMORY_MAPPINGS, 25 | GET_GLOBAL_ADDR_RAM, 26 | GET_FDC_INFO, 27 | GET_FDD_INFO, 28 | GET_FDD_IMAGE, 29 | GET_RUSLAT_HISTORY, 30 | GET_SCROLL_VERT, 31 | GET_STEP_OVER_ADDR, 32 | GET_IO_PORTS, 33 | GET_IO_PORTS_IN_DATA, 34 | GET_IO_PORTS_OUT_DATA, 35 | GET_IO_DISPLAY_MODE, 36 | GET_IO_PALETTE, 37 | GET_IO_PALETTE_COMMIT_TIME, 38 | SET_IO_PALETTE_COMMIT_TIME, 39 | GET_DISPLAY_BORDER_LEFT, 40 | SET_DISPLAY_BORDER_LEFT, 41 | GET_DISPLAY_IRQ_COMMIT_PXL, 42 | SET_DISPLAY_IRQ_COMMIT_PXL, 43 | SET_MEM, 44 | SET_BYTE_GLOBAL, 45 | SET_CPU_SPEED, 46 | GET_HW_MAIN_STATS, 47 | IS_MEMROM_ENABLED, 48 | KEY_HANDLING, 49 | LOAD_FDD, 50 | RESET_UPDATE_FDD, 51 | DEBUG_ATTACH, 52 | DEBUG_RESET, 53 | 54 | DEBUG_RECORDER_RESET, 55 | DEBUG_RECORDER_PLAY_FORWARD, 56 | DEBUG_RECORDER_PLAY_REVERSE, 57 | DEBUG_RECORDER_GET_STATE_RECORDED, 58 | DEBUG_RECORDER_GET_STATE_CURRENT, 59 | DEBUG_RECORDER_SERIALIZE, 60 | DEBUG_RECORDER_DESERIALIZE, 61 | 62 | DEBUG_BREAKPOINT_ADD, 63 | DEBUG_BREAKPOINT_DEL, 64 | DEBUG_BREAKPOINT_DEL_ALL, 65 | DEBUG_BREAKPOINT_GET_STATUS, 66 | DEBUG_BREAKPOINT_SET_STATUS, 67 | DEBUG_BREAKPOINT_ACTIVE, 68 | DEBUG_BREAKPOINT_DISABLE, 69 | DEBUG_BREAKPOINT_GET_ALL, 70 | DEBUG_BREAKPOINT_GET_UPDATES, 71 | 72 | DEBUG_WATCHPOINT_ADD, 73 | DEBUG_WATCHPOINT_DEL_ALL, 74 | DEBUG_WATCHPOINT_DEL, 75 | DEBUG_WATCHPOINT_GET_UPDATES, 76 | DEBUG_WATCHPOINT_GET_ALL, 77 | 78 | DEBUG_MEMORY_EDIT_ADD, 79 | DEBUG_MEMORY_EDIT_DEL_ALL, 80 | DEBUG_MEMORY_EDIT_DEL, 81 | DEBUG_MEMORY_EDIT_GET, 82 | DEBUG_MEMORY_EDIT_EXISTS, 83 | 84 | DEBUG_CODE_PERF_ADD, 85 | DEBUG_CODE_PERF_DEL_ALL, 86 | DEBUG_CODE_PERF_DEL, 87 | DEBUG_CODE_PERF_GET, 88 | DEBUG_CODE_PERF_EXISTS, 89 | 90 | DEBUG_SCRIPT_ADD, 91 | DEBUG_SCRIPT_DEL_ALL, 92 | DEBUG_SCRIPT_DEL, 93 | DEBUG_SCRIPT_GET_ALL, 94 | DEBUG_SCRIPT_GET_UPDATES, 95 | }; -------------------------------------------------------------------------------- /src/core/keyboard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "utils/types.h" 10 | #include "core/memory.h" 11 | 12 | namespace dev 13 | { 14 | class Keyboard 15 | { 16 | private: 17 | uint8_t m_encodingMatrix[8]; 18 | using KeyCode = int; 19 | using RowColumnCode = int; 20 | std::unordered_map m_keymap; 21 | 22 | public: 23 | enum class Operation { 24 | NONE = 0, 25 | RESET, 26 | RESTART 27 | }; 28 | bool m_keySS = false; 29 | bool m_keyUS = false; 30 | bool m_keyRus = false; 31 | Operation m_rebootType = Operation::NONE; 32 | 33 | Keyboard(); 34 | 35 | auto KeyHandling(int _scancode, int _action) -> Operation; 36 | auto Read(int _rows) -> uint8_t; 37 | 38 | private: 39 | void InitMapping(); 40 | }; 41 | } -------------------------------------------------------------------------------- /src/core/memory_consts.h: -------------------------------------------------------------------------------- 1 | #include "utils/types.h" 2 | 3 | enum class AddrSpace : uint8_t { RAM = 0, STACK = 1 }; 4 | enum class MemType : uint8_t { ROM = 0, RAM }; 5 | 6 | static constexpr dev::GlobalAddr ROM_LOAD_ADDR = 0x100; 7 | 8 | static constexpr size_t MEM_64K = 64 * 1024; 9 | static constexpr size_t RAM_DISK_PAGE_LEN = MEM_64K; 10 | static constexpr size_t MEMORY_RAMDISK_LEN = 4 * MEM_64K; 11 | static constexpr size_t RAM_DISK_MAX = 8; 12 | 13 | static constexpr size_t MEMORY_MAIN_LEN = MEM_64K; 14 | static constexpr size_t MEMORY_GLOBAL_LEN = MEMORY_MAIN_LEN + MEMORY_RAMDISK_LEN * RAM_DISK_MAX; 15 | 16 | static constexpr uint8_t MAPPING_RAM_MODE_MASK = 0b11100000; 17 | static constexpr uint8_t MAPPING_MODE_MASK = 0b11110000; -------------------------------------------------------------------------------- /src/core/memory_edit.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "utils/types.h" 7 | #include "utils/str_utils.h" 8 | #include "utils/json_utils.h" 9 | 10 | namespace dev 11 | { 12 | struct MemoryEdit 13 | { 14 | std::string comment; 15 | GlobalAddr globalAddr = 0; 16 | uint8_t value = 0; 17 | bool readonly = true; // if true, memory is not modified 18 | bool active = true; 19 | 20 | auto AddrToStr() const -> std::string { return std::format("0x{:06x}: 0x{:02x} {}, {}", globalAddr, value, readonly ? "read-only" : "", active ? "active" : "not active"); } 21 | void Erase() 22 | { 23 | comment.clear(); 24 | globalAddr = 0; 25 | value = 0; 26 | readonly = true; 27 | active = true; 28 | } 29 | 30 | auto ToJson() const -> nlohmann::json 31 | { 32 | return { 33 | {"comment", comment}, 34 | {"globalAddr", std::format("0x{:06X}", globalAddr)}, 35 | {"value", std::format("0x{:02X}", value)}, 36 | {"readonly", readonly}, 37 | {"active", active} 38 | }; 39 | } 40 | 41 | MemoryEdit() = default; 42 | 43 | MemoryEdit(const nlohmann::json& _json) 44 | : 45 | comment(_json["comment"].get()), 46 | globalAddr(dev::StrHexToInt(_json["globalAddr"].get().c_str())), 47 | value(dev::StrHexToInt(_json["value"].get().c_str())), 48 | readonly(_json["readonly"].get()), 49 | active(_json["active"].get()) 50 | {} 51 | 52 | MemoryEdit(GlobalAddr _globalAddr, uint8_t _value, const std::string& _comment = "", bool _readonly = true, bool _active = true) 53 | : 54 | comment(_comment), 55 | globalAddr(_globalAddr), 56 | value(_value), 57 | readonly(_readonly), 58 | active(_active) {} 59 | }; 60 | } -------------------------------------------------------------------------------- /src/core/recorder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "utils/types.h" 6 | #include "core/cpu_i8080.h" 7 | #include "core/memory.h" 8 | #include "core/io.h" 9 | #include "core/display.h" 10 | #include "core/fdc_wd1793.h" 11 | 12 | namespace dev 13 | { 14 | class Recorder 15 | { 16 | public: 17 | static constexpr int FRAMES_PER_SEC = 50; 18 | static constexpr int STATES_LEN = FRAMES_PER_SEC * 600; 19 | using MemUpdates = std::vector; 20 | using GlobalAddrs = std::vector; 21 | 22 | static constexpr int STATUS_RESET = 0; // erase the data, stores the first state 23 | static constexpr int STATUS_UPDATE = 1; // enables updating 24 | static constexpr int STATUS_RESTORE = 2; // restore the last state 25 | // file format version 26 | static constexpr uint32_t VERSION = 1; 27 | // it checks only first 8 bits of a version 28 | static constexpr uint32_t VERSION_MASK = 0xff; 29 | 30 | #pragma pack(push, 1) 31 | struct HwState 32 | { 33 | CpuI8080::State cpuState; 34 | Memory::Update memState; 35 | MemUpdates memBeforeWrites; // what was in memory before writes 36 | MemUpdates memWrites; // memory after writes 37 | GlobalAddrs globalAddrs; // the global addresses where to restore memory 38 | IO::State ioState; 39 | Display::Update displayState; 40 | }; 41 | #pragma pack(pop) 42 | 43 | using HwStates = std::array; // one state per frame 44 | 45 | void Update(CpuI8080::State* _cpuStateP, Memory::State* _memStateP, 46 | IO::State* _ioStateP, Display::State* _displayStateP); 47 | void Reset(CpuI8080::State* _cpuStateP, Memory::State* _memStateP, 48 | IO::State* _ioStateP, Display::State* _displayStateP); 49 | void PlayForward(const int _frames, CpuI8080::State* _cpuStateP, Memory::State* _memStateP, 50 | IO::State* _ioStateP, Display::State* _displayStateP); 51 | void PlayReverse(const int _frames, CpuI8080::State* _cpuStateP, Memory::State* _memStateP, 52 | IO::State* _ioStateP, Display::State* _displayStateP); 53 | void CleanMemUpdates(Display::State* _displayStateP); 54 | auto GetStateRecorded() const -> size_t { return m_stateRecorded; }; 55 | auto GetStateCurrent() const -> size_t { return m_stateCurrent; }; 56 | void Deserialize(const std::vector& _data, 57 | CpuI8080::State* _cpuStateP, Memory::State* _memStateP, 58 | IO::State* _ioStateP, Display::State* _displayStateP); 59 | auto Serialize() const -> const std::vector; 60 | 61 | private: 62 | void StoreState(const CpuI8080::State& _cpuState, const Memory::State& _memState, 63 | const IO::State& _ioState, const Display::State& _displayState); 64 | void StoreMemoryDiff(const Memory::State& _memState); 65 | void RestoreState(CpuI8080::State* _cpuStateP, Memory::State* _memStateP, 66 | IO::State* _ioStateP, Display::State* _displayStateP); 67 | void GetStatesSize(); 68 | 69 | size_t m_stateIdx = 0; // idx of the last stored state in a circular buffer 70 | size_t m_stateRecorded = 0; // the amount of recorded states from 1 to STATES_LEN 71 | size_t m_stateCurrent = 0; // the number of current state from 1 to m_stateRecorded included 72 | bool m_lastRecord = true; // false means we at the end of recorded state + memory writes 73 | HwStates m_states; 74 | size_t m_statesMemSize = 0; // m_states memory consumption 75 | size_t m_frameNum = 0; 76 | Memory::Ram m_ram; 77 | uint32_t m_version = VERSION; 78 | }; 79 | } -------------------------------------------------------------------------------- /src/core/script.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "core/script.h" 8 | #include "utils/str_utils.h" 9 | #include "utils/utils.h" 10 | 11 | dev::Script::Script(const Id _id, const bool _active, const std::string& _code, const std::string& _comment) 12 | : 13 | id(_id), active(_active), code(_code), comment(_comment) 14 | {} 15 | 16 | dev::Script::Script(const nlohmann::json& _scriptJ) 17 | : id(_scriptJ.value("id", scriptId++)), 18 | active(_scriptJ.value("active", true)), 19 | code(_scriptJ.value("code", "")), 20 | comment(_scriptJ.value("comment", "")) 21 | {} 22 | 23 | void dev::Script::Update(Script&& _script) 24 | { 25 | id = _script.id; 26 | active = _script.active; 27 | code = _script.code; 28 | comment = _script.comment; 29 | } 30 | 31 | void dev::Script::Check(lua_State* _luaState) 32 | { 33 | if (active) RunScript(_luaState); 34 | } 35 | 36 | void dev::Script::Reset() 37 | { 38 | } 39 | 40 | void dev::Script::Print(bool _printCode) const 41 | { 42 | if (_printCode){ 43 | dev::Log("Script id: {}, comment: {}, active: {} \n code: \n{}", 44 | id, comment.c_str(), active, code.c_str()); 45 | } 46 | else{ 47 | dev::Log("Script id: {}, comment: {}, active: {}", 48 | id, comment.c_str(), active); 49 | } 50 | } 51 | 52 | auto dev::Script::ToStr(bool _printId, bool _printComment) const 53 | -> const std::string 54 | { 55 | std::string out; 56 | if (_printId) out += std::format("Id: {}, ", id); 57 | if (_printComment) out += std::format("Comment: {}, ", comment); 58 | out += std::format("Active: {}, code {}", active ? "true" : "false", code); 59 | return out; 60 | } 61 | 62 | auto dev::Script::GetCode(const int _lines) const -> const std::string 63 | { 64 | if (_lines <= 0) return code; 65 | 66 | std::string out; 67 | size_t line = 0; 68 | std::istringstream iss(code); 69 | std::string lineS; 70 | 71 | while (std::getline(iss, lineS) && line < _lines) { 72 | out += lineS + "\n"; 73 | line++; 74 | } 75 | const auto total_lines = std::count(std::begin(code), std::end(code), '\n'); 76 | if (line < total_lines) out += "...\n"; 77 | 78 | return out; 79 | } 80 | 81 | void dev::Script::CompileScript(lua_State* _luaState) 82 | { 83 | int status = luaL_loadstring(_luaState, code.c_str()); 84 | if (status != LUA_OK) { 85 | dev::Log("Scripts: compilation error. Script id: {}, comment: {},\n error: {}", 86 | id, comment, lua_tostring(_luaState, -1)); 87 | lua_pop(_luaState, 1); 88 | active = false; 89 | return; 90 | } 91 | 92 | // Store the compiled function in the Lua registry and get a reference 93 | ref = luaL_ref(_luaState, LUA_REGISTRYINDEX); 94 | } 95 | 96 | void dev::Script::RunScript(lua_State* _luaState) 97 | { 98 | if (ref == LUA_NOREF) { 99 | dev::Log("Scripts: Invalid script reference: {}. Script is disabled.", ref); 100 | active = false; 101 | } 102 | 103 | // Retrieve the compiled function from the registry 104 | lua_rawgeti(_luaState, LUA_REGISTRYINDEX, ref); 105 | 106 | // Execute the function 107 | int status = lua_pcall(_luaState, 0, LUA_MULTRET, 0); 108 | if (status != LUA_OK) { 109 | dev::Log("Script: Lua execution error: {}", lua_tostring(_luaState, -1)); 110 | lua_pop(_luaState, 1); 111 | active = false; 112 | } 113 | } -------------------------------------------------------------------------------- /src/core/script.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include "utils/types.h" 12 | #include "utils/str_utils.h" 13 | #include "utils/utils.h" 14 | #include "core/cpu_i8080.h" 15 | #include "core/memory.h" 16 | #include "core/io.h" 17 | #include "core/display.h" 18 | #include "utils/json_utils.h" 19 | 20 | namespace dev 21 | { 22 | static Id scriptId = 0; 23 | 24 | struct Script 25 | { 26 | Script(const Id _id, const bool _active, const std::string& _code, const std::string& _comment = ""); 27 | Script() : Script(scriptId++, true, "", "") {} 28 | Script(const nlohmann::json& _scriptJ); 29 | void CompileScript(lua_State* _luaState); 30 | void RunScript(lua_State* _luaState); 31 | void Update(Script&& _script); 32 | void Check(lua_State* _luaState); 33 | auto GetComment() const -> const std::string& { return comment; }; 34 | void Reset(); 35 | void Print(bool _printCode = false) const; 36 | auto ToStr(bool _printId, bool _printComment) const -> const std::string; 37 | auto GetCode(const int _lines) const -> const std::string; 38 | auto ToJson() const -> nlohmann::json 39 | { 40 | return { 41 | {"id", id}, 42 | {"active", active}, 43 | {"code", code}, 44 | {"comment", comment}, 45 | }; 46 | }; 47 | 48 | Id id; 49 | bool active; 50 | std::string code; 51 | std::string comment; 52 | int ref = LUA_NOREF; 53 | }; 54 | } -------------------------------------------------------------------------------- /src/core/scripts.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "utils/json_utils.h" 10 | #include "utils/types.h" 11 | #include "core/script.h" 12 | #include "core/cpu_i8080.h" 13 | #include "core/memory.h" 14 | #include "core/io.h" 15 | #include "core/display.h" 16 | 17 | 18 | namespace dev 19 | { 20 | struct Scripts 21 | { 22 | public: 23 | enum UIType { 24 | NONE = 0, 25 | TEXT, 26 | RECT, 27 | RECT_FILLED, 28 | }; 29 | struct UIItem{ 30 | UIType type = NONE; 31 | float x = 0; 32 | float y = 0; 33 | float width = 0; 34 | float height = 0; 35 | std::string text = ""; 36 | uint32_t color = 0xFFFFFFFF; 37 | bool vectorScreenCoords = true; 38 | }; 39 | using UIReqs = std::unordered_map; // for UI rendering, this is used by Lua to request a render UI items in the UI thread 40 | using ScriptMap = std::unordered_map; 41 | 42 | Scripts(); 43 | ~Scripts(); 44 | void Add(Script&& _script); 45 | void Add(const nlohmann::json& _scriptJ); 46 | auto Find(const dev::Id _id) -> const Script*; 47 | void Del(const dev::Id _id); 48 | bool Check(const CpuI8080::State* _cpuStateP, const Memory::State* _memStateP, 49 | const IO::State* _ioStateP, const Display::State* _displayStateP); 50 | auto GetAll() -> const ScriptMap&; 51 | auto GetUpdates() -> const uint32_t; 52 | void Clear(); 53 | auto GetUIItems() -> const UIReqs 54 | { 55 | std::lock_guard mlock(m_uiReqsMutex); 56 | UIReqs uiReqs; 57 | uiReqs.reserve(m_uiReqs.size()); 58 | for (const auto& [id, item] : m_uiReqs) 59 | { 60 | uiReqs[id] = item; 61 | } 62 | return uiReqs; 63 | } 64 | 65 | private: 66 | void RegisterCppFunctions(); 67 | void CompileScript(Script& _script); 68 | void RunScript(int _scriptRef); 69 | 70 | ScriptMap m_scripts; 71 | uint32_t m_updates = 0; // counts number of updates 72 | lua_State* m_luaState; 73 | bool m_enabled = false; 74 | 75 | const CpuI8080::State* m_cpuStateP = nullptr; 76 | const Memory::State* m_memStateP = nullptr; 77 | const IO::State* m_ioStateP = nullptr; 78 | const Display::State* m_displayStateP = nullptr; 79 | bool m_break = false; 80 | 81 | UIReqs m_uiReqs; 82 | std::mutex m_uiReqsMutex; 83 | }; 84 | } -------------------------------------------------------------------------------- /src/core/sound_ay8910.cpp: -------------------------------------------------------------------------------- 1 | #include "core/sound_ay8910.h" 2 | 3 | -------------------------------------------------------------------------------- /src/core/timer_i8253.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // from vector06sdl (c) 2018 Viacheslav Slavinsky 4 | // https://github.com/svofski/vector06sdl/blob/master/src/8253.h 5 | 6 | #include 7 | 8 | namespace dev 9 | { 10 | class CounterUnit 11 | { 12 | int m_latchValue = -1; 13 | int m_writeState = 0; 14 | int m_latchMode = 0; 15 | int m_out = 0; 16 | int m_value = 0; 17 | int m_modeInt = 0; 18 | 19 | uint8_t m_writeLsb = 0; 20 | uint8_t m_writeMsb = 0; 21 | uint16_t m_loadValue = 0; 22 | 23 | int m_delay; 24 | 25 | union { 26 | uint32_t m_flags = 0; 27 | struct { 28 | bool m_flagArmed : 1; 29 | bool m_flagLoad : 1; 30 | bool m_flagEnabled : 1; 31 | bool m_flagBcd : 1; 32 | }; 33 | }; 34 | 35 | public: 36 | CounterUnit() { Reset(); } 37 | void Reset(); 38 | void SetMode(int _mode, int _latchMode, bool _flagBcd); 39 | void Latch(); 40 | int Clock(int _cycles); 41 | void Write(uint8_t _w8); 42 | int Read(); 43 | static uint16_t ToBcd(uint16_t _x); 44 | static uint16_t FromBcd(uint16_t _x); 45 | }; 46 | 47 | 48 | class TimerI8253 49 | { 50 | private: 51 | CounterUnit m_counters[3]; 52 | uint8_t m_controlWord = 0; 53 | 54 | public: 55 | void Reset(); 56 | void write_cw(uint8_t _w8); 57 | void Write(int _addr, uint8_t _w8); 58 | auto Read(int _addr) -> int; 59 | auto Clock(int _cycles) -> float; 60 | }; 61 | } -------------------------------------------------------------------------------- /src/core/trace_log.cpp: -------------------------------------------------------------------------------- 1 | #include "core/trace_log.h" 2 | 3 | 4 | dev::TraceLog::TraceLog(const DebugData& _debugData) 5 | : 6 | m_debugData(_debugData) 7 | {} 8 | 9 | // Hardware thread 10 | void dev::TraceLog::Update(const CpuI8080::State& _cpuState, const Memory::State& _memState) 11 | { 12 | uint8_t opcode = _memState.debug.instr[0]; 13 | uint8_t dataL = _memState.debug.instr[1]; 14 | uint8_t dataH = _memState.debug.instr[2]; 15 | 16 | // skip repeataive HLT 17 | if (opcode == CpuI8080::OPCODE_HLT && 18 | m_log[m_logIdx].opcode == CpuI8080::OPCODE_HLT) { 19 | return; 20 | } 21 | 22 | m_logIdx = --m_logIdx % TRACE_LOG_SIZE; 23 | m_log[m_logIdx].globalAddr = _memState.debug.instrGlobalAddr; 24 | m_log[m_logIdx].opcode = opcode; 25 | m_log[m_logIdx].imm.l = opcode != CpuI8080::OPCODE_PCHL ? dataL : _cpuState.regs.hl.l; 26 | m_log[m_logIdx].imm.h = opcode != CpuI8080::OPCODE_PCHL ? dataH : _cpuState.regs.hl.h; 27 | } 28 | 29 | auto dev::TraceLog::GetDisasm(const size_t _lines, const uint8_t _filter) 30 | -> const Lines* 31 | { 32 | size_t idxLast = m_logIdx + TRACE_LOG_SIZE - 1; 33 | m_disasmLinesLen = 0; 34 | auto idx = m_logIdx; 35 | int line = 0; 36 | 37 | for (; idx <= idxLast && line < _lines; idx++) 38 | { 39 | auto& item = m_log[idx % TRACE_LOG_SIZE]; 40 | auto globalAddr = item.globalAddr; 41 | 42 | if (globalAddr == EMPTY_ITEM) { break; } 43 | 44 | if (GetOpcodeType(item.opcode) <= _filter) 45 | { 46 | AddCode(item, m_disasmLines[m_disasmLinesLen++]); 47 | line++; 48 | } 49 | } 50 | 51 | return &m_disasmLines; 52 | } 53 | 54 | void dev::TraceLog::AddCode(const Item& _item, Disasm::Line& _line) 55 | { 56 | auto immType = GetImmediateType(_item.opcode); 57 | 58 | _line.Init(); 59 | 60 | _line.opcode = _item.opcode; 61 | switch (GetCmdLen(_item.opcode)) 62 | { 63 | case 1: 64 | _line.imm = immType == CMD_IB_OFF0 ? _item.opcode : 0; 65 | break; 66 | case 2: 67 | _line.imm = _item.imm.l; 68 | break; 69 | case 3: 70 | _line.imm = _item.imm.word; 71 | break; 72 | }; 73 | 74 | if (immType != CMD_IM_NONE) 75 | { 76 | auto labelsP = m_debugData.GetLabels(_line.imm); 77 | _line.labels = labelsP ? *labelsP : Disasm::LabelList(); 78 | auto constsP = m_debugData.GetConsts(_line.imm); 79 | _line.consts = constsP ? *constsP : Disasm::LabelList(); 80 | } 81 | 82 | _line.type = Disasm::Line::Type::CODE; 83 | _line.addr = (Addr)_item.globalAddr; 84 | } 85 | 86 | void dev::TraceLog::Reset() 87 | { 88 | m_disasmLinesLen = m_logIdx = 0; 89 | m_log[m_logIdx].globalAddr = EMPTY_ITEM; 90 | } 91 | 92 | -------------------------------------------------------------------------------- /src/core/trace_log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "utils/types.h" 8 | #include "core/breakpoint.h" 9 | #include "core/cpu_i8080.h" 10 | #include "core/memory.h" 11 | #include "core/disasm.h" 12 | 13 | namespace dev 14 | { 15 | class TraceLog 16 | { 17 | public: 18 | static const constexpr size_t TRACE_LOG_SIZE = 300000; 19 | static const constexpr int32_t EMPTY_ITEM = -1; 20 | 21 | struct Item 22 | { 23 | int32_t globalAddr = EMPTY_ITEM; 24 | uint8_t opcode = 0; 25 | CpuI8080::RegPair imm = 0; // immediate operand 26 | }; 27 | 28 | using Lines = std::array; 29 | 30 | std::array m_log; 31 | size_t m_logIdx = 0; 32 | Lines m_disasmLines; 33 | size_t m_disasmLinesLen = 0; 34 | 35 | TraceLog(const DebugData& _debugData); 36 | void AddCode(const Item& _item, Disasm::Line& _line); 37 | void Update(const CpuI8080::State& _cpuState, const Memory::State& _memState); 38 | auto GetDisasm(const size_t _lines, const uint8_t _filter) -> const Lines*; 39 | auto GetDisasmLen() -> const size_t { return m_disasmLinesLen; }; 40 | void Reset(); 41 | 42 | private: 43 | const DebugData& m_debugData; 44 | }; 45 | 46 | 47 | } -------------------------------------------------------------------------------- /src/core/watchpoint.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "core/watchpoint.h" 8 | #include "utils/str_utils.h" 9 | #include "utils/utils.h" 10 | 11 | dev::Watchpoint::Watchpoint(Data&& _data, const std::string& _comment) 12 | : 13 | data(std::move(_data)), comment(_comment) 14 | {} 15 | 16 | void dev::Watchpoint::Update(Watchpoint&& _wp) 17 | { 18 | data = std::move(_wp.data); 19 | comment = std::move(_wp.comment); 20 | } 21 | 22 | auto dev::Watchpoint::Check(const Access _access, const GlobalAddr _globalAddr, const uint8_t _value) 23 | ->const bool 24 | { 25 | if (!data.active) return false; 26 | if (data.access != Access::RW && data.access != _access) return false; 27 | if (_globalAddr < data.globalAddr || _globalAddr >= data.globalAddr + data.len) return false; 28 | 29 | bool break_; 30 | bool low = true; 31 | 32 | uint8_t value_byte; 33 | 34 | if (data.type == Type::LEN) 35 | { 36 | value_byte = data.value & 0xff; 37 | } 38 | else // check the hi byte of a word 39 | if (data.globalAddr + 1 != _globalAddr) { 40 | return false; 41 | } 42 | else{ 43 | low = false; 44 | value_byte = data.value >> 8 & 0xff; 45 | } 46 | 47 | switch (data.cond) 48 | { 49 | case Condition::ANY: 50 | break_ = true; 51 | break; 52 | case Condition::EQU: 53 | break_ = _value == value_byte; 54 | break; 55 | case Condition::LESS: 56 | break_ = _value < value_byte; 57 | break; 58 | case Condition::GREATER: 59 | break_ = _value > value_byte; 60 | break; 61 | case Condition::LESS_EQU: 62 | break_ = _value <= value_byte; 63 | break; 64 | case Condition::GREATER_EQU: 65 | break_ = _value >= value_byte; 66 | break; 67 | case Condition::NOT_EQU: 68 | break_ = _value != value_byte; 69 | break; 70 | default: 71 | return false; 72 | }; 73 | 74 | if (low) { 75 | data.breakL = break_; 76 | } 77 | else { 78 | data.breakH = break_; 79 | } 80 | 81 | return data.breakL && (data.type == Type::LEN || data.breakH); 82 | } 83 | 84 | auto dev::Watchpoint::GetAccessI() const -> int { return static_cast(data.access); } 85 | auto dev::Watchpoint::GetAccessS() const -> const char* { return wpAccessS[static_cast(data.access)]; } 86 | auto dev::Watchpoint::GetConditionS() const -> const char* { return ConditionsS[static_cast(data.cond)];} 87 | auto dev::Watchpoint::GetTypeS() const -> const char* { return wpTypesS[static_cast(data.type)]; } 88 | 89 | void dev::Watchpoint::Reset() 90 | { 91 | data.breakL = false; 92 | data.breakH = false; 93 | } 94 | 95 | void dev::Watchpoint::Print() const 96 | { 97 | std::printf("0x%05x, access: %s, cond: %s, value: 0x%04x, type: %s, len: %d, active: %d \n", 98 | data.globalAddr, GetAccessS(), GetConditionS(), 99 | data.value, GetTypeS(), data.len, data.active); 100 | } -------------------------------------------------------------------------------- /src/core/watchpoint.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "utils/types.h" 10 | #include "utils/str_utils.h" 11 | #include "utils/utils.h" 12 | #include "core/cpu_i8080.h" 13 | #include "core/memory.h" 14 | #include "utils/json_utils.h" 15 | 16 | namespace dev 17 | { 18 | static Id watchpointId = 0; 19 | static const char* wpAccessS[] = { "R", "W", "RW" }; 20 | static const char* wpTypesS[] = { "LEN", "WORD" }; 21 | 22 | struct Watchpoint 23 | { 24 | // LEN - breaks if the condition succeds for any bytes in m_len range 25 | // WORD - breaks if the condition succeds for a word 26 | enum class Type : uint8_t { LEN = 0, WORD, COUNT }; 27 | static constexpr int TYPE_BIT_WIDTH = std::bit_width(static_cast(Type::COUNT) - 1); 28 | enum class Access : uint8_t { R = 0, W, RW, COUNT }; 29 | static constexpr int ACCESS_BIT_WIDTH = std::bit_width(static_cast(Access::COUNT) - 1); 30 | 31 | static auto GetAccess(const std::string _accessS) 32 | -> Access 33 | { 34 | for (int i = 0; i < static_cast(Access::COUNT); i++) 35 | { 36 | if (std::string(wpAccessS[i]) == _accessS) 37 | { 38 | return static_cast(i); 39 | } 40 | } 41 | return Access::COUNT; 42 | } 43 | 44 | static auto GetType(const std::string _typeS) 45 | -> Type 46 | { 47 | for (int i = 0; i < static_cast(Type::COUNT); i++) 48 | { 49 | if (std::string(wpTypesS[i]) == _typeS) 50 | { 51 | return static_cast(i); 52 | } 53 | } 54 | return Type::COUNT; 55 | } 56 | 57 | #pragma pack(push, 1) 58 | union Data { 59 | struct { 60 | GlobalAddr globalAddr; 61 | Id id; 62 | GlobalAddr len; 63 | uint16_t value; 64 | 65 | Access access : ACCESS_BIT_WIDTH; 66 | Condition cond : CONDITION_BIT_WIDTH + 1; 67 | Type type : TYPE_BIT_WIDTH + 1; 68 | 69 | bool active : 1; 70 | bool breakL : 1; 71 | bool breakH : 1; 72 | }; 73 | struct { 74 | uint64_t data0; 75 | uint64_t data1; 76 | }; 77 | 78 | Data( 79 | const Id _id, const Access _access, const GlobalAddr _globalAddr, const Condition _cond, 80 | const uint16_t _value, const Type _type = Type::LEN, const GlobalAddr _len = 1, 81 | const bool _active = true, 82 | const bool _breakH = false, const bool _breakL = false 83 | ) : 84 | id(_id == -1 ? watchpointId++ : _id), access(_access), globalAddr(_globalAddr), 85 | cond(_cond), value(_value), type(_type), len(_len), active(_active), breakH(_breakH), breakL(_breakL) 86 | {}; 87 | Data(const uint64_t _data0, const uint64_t _data1) 88 | : 89 | data0(_data0), data1(_data1) 90 | {} 91 | Data(const nlohmann::json& _wpJ) : 92 | Data(_wpJ["id"], 93 | GetAccess(_wpJ["access"].get()), 94 | dev::StrHexToInt(_wpJ["globalAddr"].get().c_str()), 95 | GetCondition(_wpJ["cond"].get()), 96 | dev::StrHexToInt(_wpJ["value"].get().c_str()), 97 | GetType(_wpJ["type"].get()), 98 | dev::StrHexToInt(_wpJ["len"].get().c_str()), 99 | _wpJ["active"]) 100 | {}; 101 | }; 102 | #pragma pack(pop) 103 | 104 | Watchpoint(Data&& _data, const std::string& _comment = ""); 105 | 106 | void Update(Watchpoint&& _wp); 107 | 108 | auto Check(const Access _access, const GlobalAddr _globalAddr, const uint8_t _value) -> const bool; 109 | auto GetAccessI() const -> int; 110 | auto GetComment() const -> const std::string& { return comment; }; 111 | auto GetConditionS() const -> const char*; 112 | auto GetAccessS() const -> const char*; 113 | auto GetTypeS() const -> const char*; 114 | void Reset(); 115 | void Print() const; 116 | auto ToJson() const -> nlohmann::json 117 | { 118 | return { 119 | {"id", data.id}, 120 | {"access", GetAccessS()}, 121 | {"globalAddr", std::format("0x{:06X}", data.globalAddr)}, 122 | {"cond", GetConditionS()}, 123 | {"value", std::format("0x{:04X}", data.value)}, 124 | {"type", GetTypeS()}, 125 | {"len", std::format("0x{:04X}", data.len)}, 126 | {"active", data.active}, 127 | {"comment", comment} 128 | }; 129 | }; 130 | 131 | Data data; 132 | std::string comment; 133 | }; 134 | } -------------------------------------------------------------------------------- /src/core/watchpoints.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include "core/watchpoints.h" 5 | #include "utils/str_utils.h" 6 | #include "utils/utils.h" 7 | 8 | // Hardware thread 9 | void dev::Watchpoints::Clear() 10 | { 11 | m_wps.clear(); 12 | m_updates++; 13 | } 14 | 15 | // Hardware thread 16 | void dev::Watchpoints::Add(Watchpoint&& _wp) 17 | { 18 | m_updates++; 19 | 20 | auto wpI = m_wps.find(_wp.data.id); 21 | if (wpI != m_wps.end()) 22 | { 23 | wpI->second.Update(std::move(_wp)); 24 | return; 25 | } 26 | 27 | m_wps.emplace(_wp.data.id, std::move(_wp)); 28 | } 29 | 30 | void dev::Watchpoints::Add(const nlohmann::json& _wpJ) 31 | { 32 | m_updates++; 33 | 34 | Watchpoint::Data wpData {_wpJ}; 35 | Watchpoint wp{ std::move(wpData), _wpJ["comment"] }; 36 | 37 | auto wpI = m_wps.find(wp.data.id); 38 | if (wpI != m_wps.end()) 39 | { 40 | wpI->second.Update(std::move(wp)); 41 | return; 42 | } 43 | 44 | m_wps.emplace(wp.data.id, std::move(wp)); 45 | } 46 | 47 | // Hardware thread 48 | void dev::Watchpoints::Del(const dev::Id _id) 49 | { 50 | m_updates++; 51 | auto bpI = m_wps.find(_id); 52 | if (bpI != m_wps.end()) 53 | { 54 | m_wps.erase(bpI); 55 | } 56 | } 57 | 58 | // Hardware thread 59 | void dev::Watchpoints::Check(const Watchpoint::Access _access, const GlobalAddr _globalAddr, const uint8_t _value) 60 | { 61 | auto wpI = std::find_if(m_wps.begin(), m_wps.end(), 62 | [_access, _globalAddr, _value](WpMap::value_type& pair) 63 | { 64 | return pair.second.Check(_access, _globalAddr, _value); 65 | }); 66 | 67 | m_wpBreak |= wpI != m_wps.end(); 68 | } 69 | 70 | // Hardware thread 71 | auto dev::Watchpoints::GetAll() 72 | -> const WpMap& 73 | { 74 | return m_wps; 75 | } 76 | 77 | // Hardware thread 78 | auto dev::Watchpoints::GetUpdates() 79 | -> const uint32_t 80 | { 81 | return m_updates; 82 | } 83 | 84 | bool dev::Watchpoints::CheckBreak() 85 | { 86 | if (!m_wpBreak) return false; 87 | 88 | m_wpBreak = false; 89 | 90 | // reset wps break status 91 | for (auto& [id, watchpoint] : m_wps) 92 | { 93 | watchpoint.Reset(); 94 | } 95 | 96 | return true; 97 | } -------------------------------------------------------------------------------- /src/core/watchpoints.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "utils/types.h" 6 | #include "core/watchpoint.h" 7 | 8 | namespace dev 9 | { 10 | struct Watchpoints 11 | { 12 | public: 13 | using WpMap = std::unordered_map; 14 | 15 | void Add(Watchpoint&& _bp); 16 | void Add(const nlohmann::json& _wpJ); 17 | void Del(const dev::Id _id); 18 | void Check(const Watchpoint::Access _access, const GlobalAddr _globalAddr, const uint8_t _value); 19 | auto GetAll() -> const WpMap&; 20 | auto GetUpdates() -> const uint32_t; 21 | void Clear(); 22 | bool CheckBreak(); 23 | 24 | private: 25 | 26 | WpMap m_wps; 27 | uint32_t m_updates = 0; // counts number of updates 28 | bool m_wpBreak = false; 29 | }; 30 | } -------------------------------------------------------------------------------- /src/main_imgui/main/imgui_app.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "utils/gl_utils.h" 10 | #include "imgui.h" 11 | #include "imgui_impl_sdl3.h" 12 | #include "imgui_impl_opengl3.h" 13 | #include 14 | #if defined(IMGUI_IMPL_OPENGL_ES2) 15 | #include 16 | #else 17 | #include 18 | #endif 19 | 20 | #include "utils/json_utils.h" 21 | 22 | namespace dev { 23 | 24 | class ImGuiApp 25 | { 26 | public: 27 | enum class AppStatus { 28 | NOT_INITED = 0, // ImGui not initialized 29 | INITED, // ImGui initialized 30 | RUN, // app is running 31 | REQ_PREPARE_FOR_EXIT, 32 | PREPARE_FOR_EXIT, 33 | EXIT, 34 | }; 35 | 36 | ImGuiApp(nlohmann::json _settingsJ, const std::string& _settingsPath, const std::string& _title = "New Window"); 37 | ~ImGuiApp(); 38 | 39 | void Run(); 40 | bool IsInited() const { return m_status == AppStatus::INITED || m_status == AppStatus::RUN; }; 41 | auto GetStatus() const -> AppStatus { return m_status; }; 42 | auto GetError() const -> ErrCode { return m_error; }; 43 | 44 | virtual void Update() {}; 45 | 46 | protected: 47 | const std::string m_settingsPath; 48 | int m_width; 49 | int m_height; 50 | int m_posX; 51 | int m_posY; 52 | std::string m_title; 53 | ImVec4 m_backColor = ImVec4(0.25f, 0.25f, 0.25f, 1.0f); 54 | AppStatus m_status = AppStatus::NOT_INITED; 55 | dev::ErrCode m_error = dev::ErrCode::NO_ERRORS; 56 | 57 | static void glfw_error_callback(int _error, const char* _description); 58 | SDL_Window* m_window = nullptr; 59 | SDL_GLContext m_gl_context = nullptr; 60 | ImGuiIO* m_ioP = nullptr; 61 | 62 | static constexpr double AUTO_UPDATE_COOLDOWN = 2.0; 63 | 64 | ImFont* m_font = nullptr; 65 | ImFont* m_fontItalic = nullptr; 66 | float m_dpiScale = 1.0f; 67 | 68 | enum class Req { LOAD_FONT, CHECK_WINDOW_SIZE_POS, }; 69 | TQueue > m_reqs; // request 70 | std::thread m_autoUpdateThread; 71 | 72 | bool m_prepare_for_exit = false; 73 | 74 | // reqs 75 | void AutoUpdate(); 76 | void Request(const Req _req, const int64_t _val = 0); 77 | void ReqHandling(); 78 | void LoadFonts(); 79 | void SettingsUpdate(const std::string& _fieldName, nlohmann::json _json); 80 | void SettingsSave(const std::string& _path); 81 | auto GetSettingsString(const std::string& _fieldName, const std::string& _defaultValue) -> std::string; 82 | auto GetSettingsObject(const std::string& _fieldName ) -> nlohmann::json; 83 | int GetSettingsInt(const std::string& _fieldName, int _defaultValue); 84 | bool GetSettingsBool(const std::string& _fieldName, bool _defaultValue); 85 | float GetDpiScale(); 86 | 87 | private: 88 | std::mutex m_settingsMutex; 89 | nlohmann::json m_settingsJ; 90 | }; 91 | } -------------------------------------------------------------------------------- /src/main_imgui/main/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "utils/args_parser.h" 4 | #include "utils/consts.h" 5 | #include "utils/utils.h" 6 | #include "utils/str_utils.h" 7 | #include "utils/json_utils.h" 8 | #include "utils/consts.h" 9 | #include "devector_app.h" 10 | 11 | int main(int argc, char** argv) 12 | { 13 | std::string rom_fdd_recPath = ""; 14 | auto executableDir = dev::GetExecutableDir(); 15 | auto settingsPath = executableDir + "settings.json"; 16 | 17 | // if it's only one valid path as an argument, use it as a path to the rom/fdd/rec file 18 | if (argc == 2) 19 | { 20 | auto path = std::string(argv[1]); 21 | if (dev::IsFileExist(path)) 22 | { 23 | rom_fdd_recPath = path; 24 | } 25 | } 26 | 27 | if (rom_fdd_recPath.empty()) 28 | { 29 | dev::ArgsParser argsParser(argc, argv, 30 | "This is an emulator of the Soviet personal computer Vector06C. It has built-in debugger functionality."); 31 | 32 | auto settingsPath = argsParser.GetString("settingsPath", 33 | "The path to the settings.", false, executableDir + "settings.json"); 34 | 35 | rom_fdd_recPath = argsParser.GetString("path", 36 | "The path to the rom/fdd/rec file.", false, ""); 37 | 38 | if (!rom_fdd_recPath.empty() && !dev::IsFileExist(rom_fdd_recPath)){ 39 | dev::Log("A path is invalid: {}", rom_fdd_recPath); 40 | rom_fdd_recPath = ""; 41 | } 42 | 43 | if (!argsParser.IsRequirementSatisfied()) 44 | { 45 | dev::Log("---Settings parameters are missing"); 46 | } 47 | } 48 | 49 | nlohmann::json settingsJ; 50 | if (dev::IsFileExist(settingsPath) == false) 51 | { 52 | dev::Log("The settings wasn't found. Created new default settings: {}", settingsPath); 53 | } 54 | else { 55 | try 56 | { 57 | settingsJ = dev::LoadJson(settingsPath); 58 | } 59 | catch (const std::exception& e) 60 | { 61 | dev::Log("The settings file is corrupted. Created new default settings: {}", settingsPath); 62 | } 63 | } 64 | 65 | auto app = dev::DevectorApp(settingsPath, settingsJ, rom_fdd_recPath); 66 | if (!app.IsInited()) return (int)app.GetError(); 67 | app.Run(); 68 | 69 | return (int)dev::ErrCode::NO_ERRORS; 70 | } -------------------------------------------------------------------------------- /src/main_imgui/main/ui/about_window.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ui/about_window.h" 3 | #include "utils/str_utils.h" 4 | 5 | dev::AboutWindow::AboutWindow(const float* const _dpiScaleP) 6 | : 7 | BaseWindow("About Devector", DEFAULT_WINDOW_W, DEFAULT_WINDOW_H, _dpiScaleP) 8 | {} 9 | 10 | void dev::AboutWindow::Update(bool& _visible, const bool _isRunning) 11 | { 12 | BaseWindow::Update(); 13 | 14 | if (_visible) 15 | { 16 | ImVec2 center = ImGui::GetMainViewport()->GetCenter(); // Always center this window when appearing 17 | ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); 18 | 19 | if (ImGui::Begin(m_name.c_str(), &_visible, 20 | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking | 21 | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoCollapse)) 22 | { 23 | Draw(); 24 | ImGui::End(); 25 | } 26 | } 27 | } 28 | 29 | void dev::AboutWindow::Draw() 30 | { 31 | ImGui::BeginChild("##aboutchframe", { DEFAULT_WINDOW_W, 205}, ImGuiChildFlags_FrameStyle); 32 | 33 | ImGui::Text("Devector is an emulator of the Soviet personal computer\nVector 06C, offering advanced debugging options to enhance \nyour development experience."); 34 | ImGui::Dummy({1, 5}); 35 | ImGui::Text("Your feedback is invaluable, whether positive or negative. \nPlease share your thoughts using the Feedback window. \nYour contributions and support help improve this emulator."); 36 | ImGui::Dummy({ 1, 20 }); 37 | ImGui::Text("Please join our Telegram channel"); 38 | ImGui::SameLine(); 39 | if (dev::HyperLink("http://t.me/devector06C")) 40 | { 41 | dev::OsOpenInShell("http://t.me/devector06C"); 42 | } 43 | ImGui::Text("for updates and discussions."); 44 | 45 | //ImGui::Separator(); 46 | 47 | //ImGui::Text("Devector - эмулятор советского персонального компьютера\nVector 06Ц, со встроенными возможностями отладки \nдля улучшения вашего опыта разработки."); 48 | //ImGui::Dummy({ 1, 5 }); 49 | //ImGui::Text("Ваши положительные и даже отрицательные отзывы бесценны. \nПожалуйста, поделитесь вашими предложениями в окне Feedback. \nЭто поможет сделать эмулятор лучше."); 50 | //ImGui::Dummy({ 1, 20 }); 51 | //ImGui::Text("Подключайтесь в"); 52 | //ImGui::SameLine(); 53 | //if (dev::HyperLink("Telegram канал")) 54 | //{ 55 | // dev::OsOpenInShell("http://t.me/devector06C"); 56 | //} 57 | //ImGui::SameLine(); ImGui::Text("для дальнейших обновлений и обсуждений."); 58 | 59 | ImGui::EndChild(); 60 | 61 | ImGui::Separator(); 62 | ImGui::Dummy({ 1, 5 }); 63 | ImGui::Text("Developed by Alexander Fedotovskikh"); 64 | ImGui::Text("Build details: %s", compilation_date.c_str()); 65 | } -------------------------------------------------------------------------------- /src/main_imgui/main/ui/about_window.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "utils/imgui_utils.h" 4 | #include "ui/base_window.h" 5 | 6 | namespace dev 7 | { 8 | class AboutWindow : public BaseWindow 9 | { 10 | static constexpr int DEFAULT_WINDOW_W = 500; 11 | static constexpr int DEFAULT_WINDOW_H = 300; 12 | 13 | const std::string compilation_date = __DATE__; 14 | 15 | public: 16 | AboutWindow(const float* const _dpiScaleP); 17 | void Update(bool& _visible, const bool _isRunning); 18 | void Draw(); 19 | }; 20 | }; -------------------------------------------------------------------------------- /src/main_imgui/main/ui/base_window.cpp: -------------------------------------------------------------------------------- 1 | #include "ui/base_window.h" 2 | #include "utils/imgui_utils.h" 3 | 4 | void dev::BaseWindow::Update() 5 | { 6 | SetWindowDefaultPosSize(); 7 | } 8 | 9 | void dev::BaseWindow::SetWindowDefaultPosSize() 10 | { 11 | auto windowPos = ImGui::GetWindowPos(); 12 | ImGui::SetNextWindowPos(ImVec2(windowPos.x, windowPos.y), ImGuiCond_FirstUseEver); 13 | ImGui::SetNextWindowSize(ImVec2((float)m_defaultW, (float)m_defaultH), ImGuiCond_FirstUseEver); 14 | } 15 | -------------------------------------------------------------------------------- /src/main_imgui/main/ui/base_window.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #pragma once 4 | 5 | namespace dev 6 | { 7 | class BaseWindow 8 | { 9 | int m_defaultW; 10 | int m_defaultH; 11 | 12 | protected: 13 | const float* const m_dpiScaleP = nullptr; 14 | 15 | public: 16 | const std::string m_name; 17 | 18 | BaseWindow(const std::string& _name, 19 | const int _defaultW, const int _defaultH, 20 | const float* const _dpiScaleP) 21 | : 22 | m_name(_name), m_defaultW(_defaultW), m_defaultH(_defaultH), 23 | m_dpiScaleP(_dpiScaleP) 24 | {}; 25 | 26 | void Update(); 27 | void SetWindowDefaultPosSize(); 28 | }; 29 | } -------------------------------------------------------------------------------- /src/main_imgui/main/ui/breakpoints_window.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "utils/imgui_utils.h" 6 | #include "utils/consts.h" 7 | #include "ui/base_window.h" 8 | #include "core/debugger.h" 9 | 10 | namespace dev 11 | { 12 | class BreakpointsWindow : public BaseWindow 13 | { 14 | static constexpr int DEFAULT_WINDOW_W = 600; 15 | static constexpr int DEFAULT_WINDOW_H = 300; 16 | 17 | Hardware& m_hardware; 18 | ReqUI& m_reqUI; 19 | Breakpoints::BpMap m_breakpoints; 20 | size_t m_updates = 0; // stores the updates to prevent extra Debug data fetching 21 | 22 | void DrawTable(); 23 | void DrawPopup(ReqPopup& _reqPopup, const Breakpoints::BpMap& _pbs, int _addr); 24 | void CheckIfItemClicked(const ImVec2& _rowMin, bool& _showItemContextMenu, 25 | const int _addr, int& _editedBreakpointAddr, ReqPopup& _reqPopup); 26 | void UpdateBreakpoints(); 27 | 28 | public: 29 | BreakpointsWindow(Hardware& _hardware, 30 | const float* const _dpiScaleP, ReqUI& _reqUI); 31 | void Update(bool& _visible, const bool _isRunning); 32 | void DrawProperty(const std::string& _name, const ImVec2& _aligment = { 0.0f, 0.5f }); 33 | }; 34 | 35 | }; -------------------------------------------------------------------------------- /src/main_imgui/main/ui/debugdata_window.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "utils/imgui_utils.h" 4 | #include "ui/base_window.h" 5 | #include "core/hardware.h" 6 | 7 | namespace dev 8 | { 9 | class DebugDataWindow : public BaseWindow 10 | { 11 | static constexpr int DEFAULT_WINDOW_W = 500; 12 | static constexpr int DEFAULT_WINDOW_H = 300; 13 | 14 | Hardware& m_hardware; 15 | Debugger& m_debugger; 16 | ReqUI& m_reqUI; 17 | 18 | int64_t m_ccLast = -1; // to force the first stats update 19 | 20 | DebugData::UpdateId m_labelsUpdates = 0; 21 | DebugData::UpdateId m_constsUpdates = 0; 22 | DebugData::UpdateId m_commentsUpdates = 0; 23 | DebugData::UpdateId m_editsUpdates = 0; 24 | DebugData::UpdateId m_codePerfsUpdates = 0; 25 | DebugData::UpdateId m_scriptsUpdates = 0; 26 | 27 | DebugData::FilteredElements m_filteredLabels; 28 | DebugData::FilteredElements m_filteredConsts; 29 | DebugData::FilteredElements m_filteredComments; 30 | DebugData::FilteredElements m_filteredEdits; 31 | DebugData::FilteredElements m_filteredCodePerfs; 32 | DebugData::FilteredElements m_filteredScripts; 33 | 34 | std::string m_labelFilter; 35 | std::string m_constFilter; 36 | std::string m_commentFilter; 37 | std::string m_editFilter; 38 | std::string m_codePerfFilter; 39 | std::string m_scriptFilter; 40 | 41 | std::string m_tempFilter; 42 | 43 | int m_selectedLineIdx = 0; 44 | 45 | enum class ElementType { LABEL = 0, CONST, COMMENT, MEMORY_EDIT, CODE_PERFS, SCRIPTS }; 46 | 47 | struct ContextMenu { 48 | bool openPopup = false; 49 | ElementType elementType = ElementType::LABEL; 50 | int addr = 0; 51 | int oldAddr = 0; 52 | std::string elementName = ""; 53 | std::string oldElementName = ""; 54 | bool itemHovered = false; 55 | const char* contextMenuName = "DebugdataMenu"; 56 | 57 | void Init(Addr _addr, const std::string& _elementName, const ElementType _elementType, const bool _itemHovered = true) 58 | { 59 | openPopup = true; 60 | elementType = _elementType; 61 | addr = _addr; 62 | oldAddr = _addr; 63 | elementName = _elementName; 64 | oldElementName = _elementName; 65 | itemHovered = _itemHovered; 66 | } 67 | 68 | bool BeginPopup(){ 69 | if (openPopup) { 70 | ImGui::OpenPopup(contextMenuName); 71 | openPopup = false; 72 | } 73 | 74 | return ImGui::BeginPopup(contextMenuName); 75 | } 76 | }; 77 | ContextMenu m_contextMenu; 78 | 79 | void UpdateData(const bool _isRunning); 80 | 81 | void UpdateAndDrawFilteredElements(DebugData::FilteredElements& _filteredElements, 82 | DebugData::UpdateId& _filteredUpdateId, 83 | const DebugData::UpdateId& _updateId, 84 | std::string& _filter, 85 | ElementType _elementType); 86 | 87 | void DrawContextMenu(ContextMenu& _contextMenu); 88 | 89 | public: 90 | DebugDataWindow(Hardware& _hardware, Debugger& _debugger, 91 | const float* const _dpiScaleP, 92 | ReqUI& _reqUI); 93 | void Update(bool& _visible, const bool _isRunning); 94 | void Draw(const bool _isRunning); 95 | }; 96 | }; -------------------------------------------------------------------------------- /src/main_imgui/main/ui/display_window.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "utils/types.h" 8 | #include "utils/consts.h" 9 | #include "ui/base_window.h" 10 | #include "utils/result.h" 11 | #include "core/hardware.h" 12 | #include "core/scripts.h" 13 | #include "utils/gl_utils.h" 14 | #include "imgui_app.h" 15 | 16 | namespace dev 17 | { 18 | class DisplayWindow : public BaseWindow 19 | { 20 | static constexpr float WINDOW_ASPECT = 3.0f / 4.0f; 21 | static constexpr int DEFAULT_WINDOW_W = 800; 22 | static constexpr int DEFAULT_WINDOW_H = static_cast(DEFAULT_WINDOW_W * WINDOW_ASPECT); 23 | static constexpr float SCANLINE_HIGHLIGHT_MUL = 0.3f; 24 | static constexpr float FRAME_PXL_SIZE_W = 1.0f / Display::FRAME_W; 25 | static constexpr float FRAME_PXL_SIZE_H = 1.0f / Display::FRAME_H; 26 | 27 | GLuint m_frameTextureId = 0; 28 | Hardware& m_hardware; 29 | int64_t m_ccLast = -1; // to force the first stats update 30 | int64_t m_ccLastRun = 0; 31 | std::atomic_bool m_windowFocused = false; 32 | int m_rasterPixel = 0; 33 | int m_rasterLine = 0; 34 | enum class BorderType : int { NONE = 0, NORMAL, FULL, LEN}; 35 | BorderType m_borderType = BorderType::NORMAL; 36 | enum class DisplaySize : int { R256_256 = 0, R512_256, R512_512, MAX, LEN }; 37 | DisplaySize m_displaySize = DisplaySize::MAX; 38 | const char* m_borderTypeS = " None\0 Normal\0 Full\0\0"; 39 | const char* m_displaySizeS = " 256x256\0 512x256\0 512x512\0 Maximize\0\0"; 40 | const char* m_borderTypeAS[3] = { "Border: None", "Border: Normal", "Border: Full" }; 41 | const char* m_displaySizeAS[4] = { "Display Size: 256x256", "Display Size: 512x256", "Display Size: 512x512", "Display Size: Maximize" }; 42 | Hardware::ExecSpeed m_execSpeed = Hardware::ExecSpeed::NORMAL; 43 | const char* m_execSpeedsS = " 1%\0 20%\0 50%\0 100%\0 200%\0 MAX\0\0"; 44 | 45 | GLUtils& m_glUtils; 46 | GLUtils::Vec4 m_activeArea_pxlSize = { Display::ACTIVE_AREA_W, Display::ACTIVE_AREA_H, FRAME_PXL_SIZE_W, FRAME_PXL_SIZE_H}; 47 | GLUtils::Vec4 m_scrollV_crtXY_highlightMul = { 255.0f * FRAME_PXL_SIZE_H, 0.0f, 0.0f, 1.0f}; 48 | GLUtils::Vec4 m_bordsLRTB = { 49 | static_cast(0), // inited in the constructor 50 | static_cast(0), // inited in the constructor 51 | static_cast(Display::SCAN_ACTIVE_AREA_TOP * FRAME_PXL_SIZE_H), 52 | static_cast(Display::SCAN_ACTIVE_AREA_TOP + Display::ACTIVE_AREA_H) * FRAME_PXL_SIZE_H }; 53 | 54 | dev::Id m_matParamId_scrollV_crtXY_highlightMul = -1; 55 | dev::Id m_matParamId_activeArea_pxlSize = -1; 56 | dev::Id m_matParamId_bordsLRTB = -1; 57 | 58 | dev::Id m_vramShaderId = -1; 59 | dev::Id m_vramTexId = -1; 60 | dev::Id m_vramMatId = -1; 61 | bool m_isGLInited = false; 62 | bool m_displayIsHovered = false; 63 | const char* m_contextMenuName = "##displayCMenu"; 64 | ReqUI& m_reqUI; 65 | Scripts& m_scripts; 66 | 67 | void DrawDisplay(); 68 | void DrawContextMenu(); 69 | void CreateTexture(const bool _vsync); 70 | void UpdateData(const bool _isRunning); 71 | bool Init(); 72 | void DrawScriptsUIItems(const ImVec2& _pos, const ImVec2& _displaySize); 73 | 74 | public: 75 | DisplayWindow(Hardware& _hardware, 76 | const float* const _dpiScaleP, GLUtils& _glUtils, ReqUI& _reqUI, 77 | Scripts& _scripts, const Hardware::ExecSpeed _execSpeed); 78 | void Update(bool& _visible, const bool _isRunning); 79 | bool IsFocused() const; 80 | auto GetExecutionSpeed() const { return m_execSpeed; }; 81 | void SetExecutionSpeed(const Hardware::ExecSpeed _execSpeed); 82 | }; 83 | 84 | }; -------------------------------------------------------------------------------- /src/main_imgui/main/ui/feedback_window.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ui/feedback_window.h" 3 | #include "utils/str_utils.h" 4 | 5 | dev::FeedbackWindow::FeedbackWindow(const float* const _dpiScaleP) 6 | : 7 | BaseWindow("Send Feedback", DEFAULT_WINDOW_W, DEFAULT_WINDOW_H, _dpiScaleP) 8 | { 9 | m_userFeedback = m_defaultFeedback; 10 | } 11 | 12 | 13 | void dev::FeedbackWindow::Update(bool& _visible, const bool _isRunning) 14 | { 15 | BaseWindow::Update(); 16 | 17 | if (_visible) 18 | { 19 | ImVec2 center = ImGui::GetMainViewport()->GetCenter(); // Always center this window when appearing 20 | ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); 21 | 22 | if (ImGui::Begin(m_name.c_str(), &_visible, 23 | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking | 24 | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoCollapse)) 25 | { 26 | Draw(); 27 | DrawConfirmation(); 28 | ImGui::End(); 29 | } 30 | } 31 | } 32 | 33 | void dev::FeedbackWindow::Draw() 34 | { 35 | dev::DrawHelpMarker("Please, use english alphabet only, \nbecause the current font does not support \ncyrillic in the current version."); 36 | 37 | ImGui::InputTextMultiline("##feedback", m_userFeedback.data(), FEEDBACK_LEN_MAX, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), ImGuiInputTextFlags_AllowTabInput); 38 | ImGui::Separator(); 39 | 40 | ImGui::Dummy({ 1, 5 }); 41 | if (ImGui::Button("Send Feedback")) 42 | { 43 | std::string info = __DATE__; 44 | std::copy(info.begin(), info.end() - 1, m_sysInfo.data()); 45 | ImGui::OpenPopup(POPUP_CONFIRMATION_NAME); 46 | } 47 | ImGui::Dummy({ 1, 5 }); 48 | } 49 | 50 | // Popup window. Display the full feedback message and ask for confirmation to send it 51 | void dev::FeedbackWindow::DrawConfirmation() 52 | { 53 | ImVec2 center = ImGui::GetMainViewport()->GetCenter(); // Always center this window when appearing 54 | ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); 55 | if (ImGui::BeginPopupModal(POPUP_CONFIRMATION_NAME, NULL, ImGuiWindowFlags_AlwaysAutoResize)) 56 | { 57 | ImGui::Text("Full message:"); 58 | ImGui::Separator(); 59 | ImGui::InputTextMultiline("##feedbackconf1", m_userFeedback.data(), FEEDBACK_LEN_MAX, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 10) ); 60 | ImGui::InputTextMultiline("##feedbackconf2", m_sysInfo.data(), FEEDBACK_LEN_MAX, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 6)); 61 | 62 | ImGui::Separator(); 63 | ImGui::Dummy({ DEFAULT_WINDOW_W, 5 }); 64 | 65 | if (ImGui::Button("Confirm", ImVec2(120, 0))) 66 | { 67 | m_userFeedback = m_defaultFeedback; 68 | ImGui::CloseCurrentPopup(); 69 | } 70 | ImGui::SameLine(); 71 | ImGui::Dummy({ 10, 1 }); 72 | ImGui::SameLine(); 73 | if (ImGui::Button("Cancel", ImVec2(120, 0))) 74 | { 75 | ImGui::CloseCurrentPopup(); 76 | } 77 | ImGui::Dummy({ 1, 5 }); 78 | 79 | ImGui::EndPopup(); 80 | } 81 | } -------------------------------------------------------------------------------- /src/main_imgui/main/ui/feedback_window.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "utils/imgui_utils.h" 3 | 4 | #include "ui/base_window.h" 5 | //#include "utils/telegramBot.h" 6 | #include 7 | 8 | namespace dev 9 | { 10 | class FeedbackWindow : public BaseWindow 11 | { 12 | static constexpr int DEFAULT_WINDOW_W = 500; 13 | static constexpr int DEFAULT_WINDOW_H = 300; 14 | static constexpr int FEEDBACK_LEN_MAX = 1024; 15 | const char* POPUP_CONFIRMATION_NAME = "Confirmation"; 16 | 17 | const std::array m_defaultFeedback = { 18 | "Describe the steps to repro the issue:\n" 19 | "...\n\n" 20 | "What workaround/solution/suggetion do you have if any?\n" 21 | "...\n\n" 22 | "Thank you!\n" 23 | }; 24 | std::array m_userFeedback; 25 | std::array m_sysInfo; 26 | 27 | //TelegramBot m_telegramBot; 28 | 29 | public: 30 | FeedbackWindow(const float* const _dpiScaleP); 31 | void Update(bool& _visible, const bool _isRunning); 32 | void Draw(); 33 | void DrawConfirmation(); 34 | }; 35 | }; -------------------------------------------------------------------------------- /src/main_imgui/main/ui/hardware_stats_window.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "utils/consts.h" 4 | #include "ui/base_window.h" 5 | #include "core/hardware.h" 6 | #include "core/cpu_i8080.h" 7 | #include "utils/imgui_utils.h" 8 | 9 | namespace dev 10 | { 11 | class HardwareStatsWindow : public BaseWindow 12 | { 13 | static constexpr int DEFAULT_WINDOW_W = 600; 14 | static constexpr int DEFAULT_WINDOW_H = 400; 15 | 16 | int64_t m_ccLast = -1; // to force the first stats update 17 | int64_t m_ccLastRun = 0; 18 | Hardware& m_hardware; 19 | bool& m_ruslat; 20 | 21 | //////////////////// 22 | // stats 23 | std::string m_dataAddrN10S; 24 | std::string m_dataAddrN8S; 25 | std::string m_dataAddrN6S; 26 | std::string m_dataAddrN4S; 27 | std::string m_dataAddrN2S; 28 | std::string m_dataAddr0S; 29 | std::string m_dataAddrP2S; 30 | std::string m_dataAddrP4S; 31 | std::string m_dataAddrP6S; 32 | std::string m_dataAddrP8S; 33 | std::string m_dataAddrP10S; 34 | 35 | std::string m_ccS; 36 | std::string m_ccLastRunS; 37 | std::string m_crtS; 38 | std::string m_frameCCS; 39 | std::string m_frameNumS; 40 | std::string m_mappingRamModeS; 41 | std::string m_mappingPageRamS; 42 | std::string m_mappingModeStackS; 43 | std::string m_mappingPageStackS; 44 | std::string m_ramdiskIdxS; 45 | std::string m_fdcDrive; 46 | std::string m_fdcSide; 47 | std::string m_fdcTrack; 48 | std::string m_fdcPosition; 49 | std::string m_fdcRwLen; 50 | std::string m_fdcStats; 51 | std::string m_fddStats[Fdc1793::DRIVES_MAX]; 52 | std::string m_fddPaths[Fdc1793::DRIVES_MAX]; 53 | std::string m_ruslatS; 54 | std::string m_displayModeS; 55 | 56 | CpuI8080::State m_cpuState; 57 | int m_cpuRegM = 0; 58 | const ImVec4* m_regAFColor = &DASM_CLR_NUMBER; 59 | const ImVec4* m_regBCColor = &DASM_CLR_NUMBER; 60 | const ImVec4* m_regDEColor = &DASM_CLR_NUMBER; 61 | const ImVec4* m_regHLColor = &DASM_CLR_NUMBER; 62 | const ImVec4* m_regSPColor = &DASM_CLR_NUMBER; 63 | const ImVec4* m_regPCColor = &DASM_CLR_NUMBER; 64 | 65 | const ImVec4* m_flagCColor = &DASM_CLR_NUMBER; 66 | const ImVec4* m_flagZColor = &DASM_CLR_NUMBER; 67 | const ImVec4* m_flagPColor = &DASM_CLR_NUMBER; 68 | const ImVec4* m_flagSColor = &DASM_CLR_NUMBER; 69 | const ImVec4* m_flagACColor = &DASM_CLR_NUMBER; 70 | 71 | IO::Palette m_palette; 72 | IO::PortsData m_portsInData; 73 | IO::PortsData m_portsOutData; 74 | using PortsDataColors = std::array; 75 | PortsDataColors m_portsInDataColor; 76 | PortsDataColors m_portsOutDataColor; 77 | 78 | std::string m_upTimeS; 79 | uint8_t m_scrollVert = 0; 80 | 81 | // stats end 82 | //////////////////// 83 | 84 | void DrawStats(const bool _isRunning); 85 | void DrawRegs() const; 86 | void DrawStack() const; 87 | void DrawHardware(const bool _isRunning) const; 88 | void DrawPeripheral() const; 89 | void DrawPortsDataProperty(const char* _name, 90 | const IO::PortsData& _portsData, const bool _isRunning, 91 | const PortsDataColors& _colors, 92 | const char* _hint = nullptr) const; 93 | void UpdateData(const bool _isRunning); 94 | void UpdateDataRuntime(); 95 | void Init(); 96 | void UpdateUpTime(); 97 | 98 | public: 99 | HardwareStatsWindow(Hardware& _hardware, 100 | const float* const _dpiScaleP, 101 | bool& _ruslat); 102 | 103 | void Update(bool& _visible, const bool _isRunning); 104 | 105 | }; 106 | 107 | }; -------------------------------------------------------------------------------- /src/main_imgui/main/ui/hex_viewer_window.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "utils/types.h" 6 | #include "utils/consts.h" 7 | #include "utils/imgui_utils.h" 8 | #include "ui/base_window.h" 9 | #include "core/hardware.h" 10 | #include "core/debugger.h" 11 | 12 | namespace dev 13 | { 14 | class HexViewerWindow : public BaseWindow 15 | { 16 | static constexpr int DEFAULT_WINDOW_W = 512; 17 | static constexpr int DEFAULT_WINDOW_H = 300; 18 | 19 | static constexpr ImU32 BG_COLOR_ADDR = dev::IM_U32(0x303030FF); 20 | static constexpr ImU32 BG_COLOR_ADDR_HOVER = dev::IM_U32(0x1E4D8CFF); 21 | 22 | static constexpr ImVec4 COLOR_ADDR = dev::IM_VEC4(0x909090FF); 23 | static constexpr ImVec4 COLOR_VALUE = dev::IM_VEC4(0xD4D4D4FF); 24 | 25 | static constexpr ImU32 BG_COLOR_BYTE_HOVER = IM_COL32(100, 10, 150, 255); 26 | 27 | Hardware& m_hardware; 28 | Debugger& m_debugger; 29 | ReqUI& m_reqUI; 30 | 31 | int64_t m_ccLast = -1; // to force the first stats update 32 | std::array m_ram; 33 | char m_searchAddrS[255] = ""; 34 | 35 | enum class Status { NONE = 0, HIGHLIGHT }; 36 | Status m_status = Status::NONE; 37 | int m_memPageIdx = 0; 38 | GlobalAddr m_highlightAddr = 0; 39 | GlobalAddr m_highlightAddrLen = 0; 40 | 41 | void UpdateData(const bool _isRunning); 42 | void DrawHex(const bool _isRunning); 43 | 44 | public: 45 | HexViewerWindow(Hardware& _hardware, Debugger& _debugger, 46 | const float* const _dpiScaleP, ReqUI& _reqUI); 47 | void Update(bool& _visible, const bool _isRunning); 48 | }; 49 | }; -------------------------------------------------------------------------------- /src/main_imgui/main/ui/keyboard_window.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "core/hardware.h" 4 | #include "utils/imgui_utils.h" 5 | #include "ui/base_window.h" 6 | #include "utils/gl_utils.h" 7 | 8 | namespace dev 9 | { 10 | class KeyboardWindow : public BaseWindow 11 | { 12 | static constexpr int DEFAULT_WINDOW_W = 600; 13 | static constexpr int DEFAULT_WINDOW_H = 250; 14 | 15 | static constexpr float KEYBOARD_IMG_ASPECT = 682.0f / 1280.0f; 16 | 17 | Hardware& m_hardware; 18 | ReqUI& m_reqUI; 19 | std::string m_pathImgKeyboard; 20 | 21 | bool m_isGLInited = false; 22 | GLUtils& m_glUtils; 23 | GLUtils::Vec4 m_pressedKeyImgIdx_scaleXY = { 0, 1.0f, 1.0f, 0}; 24 | GLuint m_vramShaderId = -1; 25 | dev::Id m_vramMatId; 26 | GLuint m_vramTexId = -1; 27 | int m_imgKeyboardH; 28 | int m_imgKeyboardW; 29 | int m_imgKeyboardCh; 30 | bool m_displayIsHovered = false; 31 | const char* m_contextMenuName = "##keyboardCMenu"; 32 | bool m_windowFocused = false; 33 | 34 | bool Init(); 35 | 36 | public: 37 | KeyboardWindow(Hardware& _hardware, const float* const _dpiScaleP, 38 | GLUtils& _glUtils, ReqUI& _reqUI, const std::string& _pathImgKeyboard); 39 | void Update(bool& _visible, const bool _isRunning); 40 | void Draw(const bool _isRunning); 41 | bool IsFocused() const; 42 | }; 43 | }; -------------------------------------------------------------------------------- /src/main_imgui/main/ui/mem_display_window.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "utils/types.h" 6 | #include "utils/consts.h" 7 | #include "ui/base_window.h" 8 | #include "utils/result.h" 9 | #include "core/hardware.h" 10 | #include "core/debugger.h" 11 | #include "utils/gl_utils.h" 12 | 13 | namespace dev 14 | { 15 | class MemDisplayWindow : public BaseWindow 16 | { 17 | static constexpr int FRAME_BUFFER_W = 1024; 18 | static constexpr int FRAME_BUFFER_H = 512; 19 | 20 | static constexpr int DEFAULT_WINDOW_W = 1024; 21 | static constexpr int DEFAULT_WINDOW_H = 512; 22 | 23 | static constexpr float SCALE_MAX = 5.0f; 24 | static constexpr float SCALE_MIN = 0.3f; 25 | static constexpr float SCALE_INC = 0.2f; 26 | 27 | static constexpr int RAM_TEXTURES = Memory::MEMORY_GLOBAL_LEN / Memory::MEM_64K; 28 | static constexpr int RAM_TEXTURE_W = 256; 29 | static constexpr int RAM_TEXTURE_H = Memory::MEMORY_MAIN_LEN / 256; 30 | 31 | Hardware& m_hardware; 32 | Debugger& m_debugger; 33 | ReqUI& m_reqUI; 34 | 35 | int64_t m_ccLast = -1; // to force the first stats update 36 | float m_scale = 1.0f; 37 | 38 | GLUtils& m_glUtils; 39 | GLUtils::Vec4 m_globalColorBg = { 0.2f, 0.2f, 0.2f, 1.0f }; 40 | GLUtils::Vec4 m_globalColorFg = { 1.0f, 1.0f, 1.0f, 1.0f }; 41 | GLUtils::Vec4 m_highlightRead = { 0.078f, 0.078f, 1.0f, 0.8f }; 42 | GLUtils::Vec4 m_highlightWrite = { 1.0f, 0.078f, 0.078f, 0.8f }; 43 | GLUtils::Vec4 m_highlightIdxMax = {Debugger::LAST_RW_MAX, 0.0f, 0.0f, 0.0f}; 44 | dev::Id m_paramId_globalColorBg = -1; 45 | dev::Id m_paramId_globalColorFg = -1; 46 | dev::Id m_paramId_highlightRead = -1; 47 | dev::Id m_paramId_highlightWrite = -1; 48 | dev::Id m_paramId_highlightIdxMax = -1; 49 | 50 | dev::Id m_memViewShaderId = -1; 51 | dev::Id m_highlightShaderId = -1; 52 | std::array m_memViewMatIds; 53 | std::array m_memViewTexIds; 54 | std::array m_lastRWTexIds; 55 | Debugger::MemLastRW* m_lastRWIdxsP; 56 | bool m_isGLInited = false; 57 | 58 | void DrawDisplay(); 59 | void UpdateData(const bool _isRunning); 60 | void ScaleView(); 61 | bool Init(); 62 | 63 | public: 64 | MemDisplayWindow(Hardware& _hardware, Debugger& _debugger, 65 | const float* const _dpiScaleP, GLUtils& _glUtils, ReqUI& _reqUI); 66 | void Update(bool& _visible, const bool _isRunning); 67 | }; 68 | 69 | }; -------------------------------------------------------------------------------- /src/main_imgui/main/ui/recorder_window.cpp: -------------------------------------------------------------------------------- 1 | #include "ui/recorder_window.h" 2 | 3 | #include 4 | #include "utils/str_utils.h" 5 | 6 | dev::RecorderWindow::RecorderWindow(Hardware& _hardware, Debugger& _debugger, 7 | const float* const _dpiScaleP, 8 | ReqUI& _reqUI) 9 | : 10 | BaseWindow("Recorder", DEFAULT_WINDOW_W, DEFAULT_WINDOW_H, _dpiScaleP), 11 | m_hardware(_hardware), m_debugger(_debugger), 12 | m_reqUI(_reqUI) 13 | {} 14 | 15 | void dev::RecorderWindow::Update(bool& _visible, const bool _isRunning) 16 | { 17 | BaseWindow::Update(); 18 | 19 | if (_visible && ImGui::Begin(m_name.c_str(), &_visible, ImGuiWindowFlags_NoCollapse)) 20 | { 21 | UpdateData(_isRunning); 22 | Draw(_isRunning); 23 | 24 | ImGui::End(); 25 | } 26 | } 27 | 28 | void dev::RecorderWindow::Draw(const bool _isRunning) 29 | { 30 | 31 | ImGui::Text("State current / recorded: %d / %d", m_stateCurrent, m_stateRecorded); 32 | 33 | ImGui::Separator(); 34 | 35 | if (ImGui::Button(_isRunning ? "Break" : " Run ")) 36 | { 37 | m_hardware.Request(_isRunning ? Hardware::Req::STOP : Hardware::Req::RUN); 38 | } 39 | 40 | if (_isRunning) ImGui::BeginDisabled(); 41 | 42 | ImGui::SameLine(); 43 | if (ImGui::Button("Clear")) 44 | { 45 | m_hardware.Request(Hardware::Req::DEBUG_RECORDER_RESET); 46 | m_stateRecorded = m_hardware.Request(Hardware::Req::DEBUG_RECORDER_GET_STATE_RECORDED)->at("states"); 47 | m_stateCurrent = m_hardware.Request(Hardware::Req::DEBUG_RECORDER_GET_STATE_CURRENT)->at("states"); 48 | } 49 | if (_isRunning) ImGui::EndDisabled(); 50 | 51 | ImGui::SameLine(); 52 | dev::DrawHelpMarker("Left Ctrl + R - reverse playback. Works runtime and while break\n" 53 | "Left Ctrl + F - forward playback. Works while break only"); 54 | 55 | ImGui::Dummy({ 1, 5 }); 56 | 57 | // Frame slider 58 | dev::PushStyleCompact(0.5f); 59 | int stateCurrentOld = m_stateCurrent; 60 | ImGui::SetNextItemWidth(-70.0f); 61 | if (ImGui::SliderInt("##recTimeline", &m_stateCurrent, 1, m_stateRecorded, "%d", ImGuiSliderFlags_AlwaysClamp)) 62 | { 63 | int diff = m_stateCurrent - stateCurrentOld; 64 | if (diff < 0) { 65 | m_hardware.Request(Hardware::Req::DEBUG_RECORDER_PLAY_REVERSE, { {"frames", abs(diff)} }); 66 | } 67 | else { 68 | m_hardware.Request(Hardware::Req::DEBUG_RECORDER_PLAY_FORWARD, { {"frames", abs(diff)} }); 69 | } 70 | 71 | m_stateCurrent = m_hardware.Request(Hardware::Req::DEBUG_RECORDER_GET_STATE_CURRENT)->at("states"); 72 | } 73 | 74 | ImGui::SameLine(); 75 | if (ImGui::Button(" - ") || 76 | (ImGui::IsKeyPressed(ImGuiKey_R) && ImGui::IsKeyPressed(ImGuiKey_LeftCtrl))) 77 | { 78 | m_hardware.Request(Hardware::Req::DEBUG_RECORDER_PLAY_REVERSE, { {"frames", 1}}); 79 | m_stateCurrent = m_hardware.Request(Hardware::Req::DEBUG_RECORDER_GET_STATE_CURRENT)->at("states"); 80 | } 81 | 82 | ImGui::SameLine(); 83 | if (ImGui::Button(" + ")) 84 | { 85 | m_hardware.Request(Hardware::Req::DEBUG_RECORDER_PLAY_FORWARD, { {"frames", 1} }); 86 | m_stateCurrent = m_hardware.Request(Hardware::Req::DEBUG_RECORDER_GET_STATE_CURRENT)->at("states"); 87 | } 88 | dev::PopStyleCompact(); 89 | } 90 | 91 | void dev::RecorderWindow::UpdateData(const bool _isRunning) 92 | { 93 | // check if the hardware updated its state 94 | uint64_t cc = m_hardware.Request(Hardware::Req::GET_CC)->at("cc"); 95 | auto ccDiff = cc - m_ccLast; 96 | if (ccDiff == 0) return; 97 | m_ccLast = cc; 98 | 99 | // update 100 | m_stateRecorded = m_hardware.Request(Hardware::Req::DEBUG_RECORDER_GET_STATE_RECORDED)->at("states"); 101 | m_stateCurrent = m_hardware.Request(Hardware::Req::DEBUG_RECORDER_GET_STATE_CURRENT)->at("states"); 102 | } -------------------------------------------------------------------------------- /src/main_imgui/main/ui/recorder_window.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "utils/imgui_utils.h" 4 | #include "ui/base_window.h" 5 | #include "core/hardware.h" 6 | 7 | namespace dev 8 | { 9 | class RecorderWindow : public BaseWindow 10 | { 11 | static constexpr int DEFAULT_WINDOW_W = 500; 12 | static constexpr int DEFAULT_WINDOW_H = 300; 13 | 14 | Hardware& m_hardware; 15 | Debugger& m_debugger; 16 | ReqUI& m_reqUI; 17 | 18 | int64_t m_ccLast = -1; // to force the first stats update 19 | int m_stateRecorded = 0; 20 | int m_stateCurrent = 0; 21 | 22 | void UpdateData(const bool _isRunning); 23 | 24 | public: 25 | RecorderWindow(Hardware& _hardware, Debugger& _debugger, 26 | const float* const _dpiScaleP, 27 | ReqUI& _reqUI); 28 | void Update(bool& _visible, const bool _isRunning); 29 | void Draw(const bool _isRunning); 30 | }; 31 | }; -------------------------------------------------------------------------------- /src/main_imgui/main/ui/search_window.cpp: -------------------------------------------------------------------------------- 1 | #include "ui/search_window.h" 2 | 3 | #include 4 | #include "utils/str_utils.h" 5 | 6 | dev::SearchWindow::SearchWindow(Hardware& _hardware, Debugger& _debugger, 7 | const float* const _dpiScaleP, 8 | ReqUI& _reqUI) 9 | : 10 | BaseWindow("Search", DEFAULT_WINDOW_W, DEFAULT_WINDOW_H, _dpiScaleP), 11 | m_hardware(_hardware), m_debugger(_debugger), 12 | m_reqUI(_reqUI) 13 | {} 14 | 15 | void dev::SearchWindow::Update(bool& _visible, const bool _isRunning) 16 | { 17 | BaseWindow::Update(); 18 | 19 | if (_visible && ImGui::Begin(m_name.c_str(), &_visible, ImGuiWindowFlags_NoCollapse)) 20 | { 21 | UpdateData(_isRunning); 22 | Draw(_isRunning); 23 | 24 | ImGui::End(); 25 | } 26 | } 27 | 28 | void dev::SearchWindow::Draw(const bool _isRunning) 29 | { 30 | if (m_searchEnabled) ImGui::BeginDisabled(); 31 | 32 | if (ImGui::InputInt("Start Address", &m_searchStartAddr, 1, 100, ImGuiInputTextFlags_CharsHexadecimal)) 33 | { 34 | m_searchStartAddr = dev::Max(0, m_searchStartAddr); 35 | m_searchStartAddr = dev::Min(m_searchStartAddr, Memory::MEMORY_GLOBAL_LEN - 1); 36 | }; 37 | 38 | if (ImGui::InputInt("End Address", &m_searchEndAddr, 1, 100, ImGuiInputTextFlags_CharsHexadecimal)) 39 | { 40 | m_searchEndAddr = dev::Max(0, m_searchEndAddr); 41 | m_searchEndAddr = dev::Min(m_searchEndAddr, Memory::MEMORY_GLOBAL_LEN - 1); 42 | } 43 | 44 | if (m_searchEnabled) ImGui::EndDisabled(); 45 | 46 | if (ImGui::InputInt("Search Value", &m_searchVal, 1, 100, ImGuiInputTextFlags_CharsHexadecimal)) 47 | { 48 | m_searchVal = dev::Max(0, m_searchVal); 49 | m_searchVal = dev::Min(m_searchVal, 0xFF); 50 | } 51 | 52 | if (ImGui::Checkbox("Start Search", &m_searchEnabled)) 53 | { 54 | // search started, so clean the results 55 | m_searchResults.clear(); 56 | 57 | if (m_searchEnabled){ 58 | const auto& memP = *m_hardware.GetRam(); 59 | 60 | for (int addr = m_searchStartAddr; addr <= m_searchEndAddr; addr++) 61 | { 62 | if (memP[addr] == m_searchVal) 63 | { 64 | m_searchResults.push_back(addr); 65 | } 66 | } 67 | } 68 | } 69 | 70 | if (!m_searchEnabled) ImGui::BeginDisabled(); 71 | 72 | if (ImGui::Button("Update Search")) 73 | { 74 | const auto& memP = *m_hardware.GetRam(); 75 | 76 | auto m_searchResultsIt = m_searchResults.begin(); 77 | 78 | while (m_searchResultsIt != m_searchResults.end()) 79 | { 80 | auto addr = *m_searchResultsIt; 81 | 82 | if (memP[addr] != m_searchVal) 83 | { 84 | m_searchResultsIt = m_searchResults.erase(m_searchResultsIt); 85 | } 86 | else 87 | { 88 | m_searchResultsIt++; 89 | } 90 | } 91 | } 92 | 93 | ImGui::Separator(); 94 | 95 | if (m_searchResults.empty()) 96 | { 97 | ImGui::Text("No results"); 98 | } 99 | else if (m_searchResults.size() > 100) 100 | { 101 | ImGui::Text("Too many results: %d", (int)m_searchResults.size()); 102 | } 103 | else if (ImGui::BeginListBox("##searchResults", ImVec2(-FLT_MIN, 100))) 104 | { 105 | for (auto addr : m_searchResults) 106 | { 107 | ImGui::PushID(addr); 108 | if (ImGui::Selectable(std::format("0x{:04X}", addr).c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) 109 | { 110 | //m_hardware.Request(Hardware::Req::DEBUGGER_SET_PC, addr); 111 | } 112 | ImGui::PopID(); 113 | } 114 | ImGui::EndListBox(); 115 | } 116 | 117 | if (!m_searchEnabled) ImGui::EndDisabled(); 118 | } 119 | 120 | void dev::SearchWindow::UpdateData(const bool _isRunning) 121 | { 122 | // check if the hardware updated its state 123 | uint64_t cc = m_hardware.Request(Hardware::Req::GET_CC)->at("cc"); 124 | auto ccDiff = cc - m_ccLast; 125 | if (ccDiff == 0) return; 126 | m_ccLast = cc; 127 | 128 | // update 129 | } -------------------------------------------------------------------------------- /src/main_imgui/main/ui/search_window.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "utils/imgui_utils.h" 4 | #include "ui/base_window.h" 5 | #include "core/hardware.h" 6 | 7 | namespace dev 8 | { 9 | class SearchWindow : public BaseWindow 10 | { 11 | static constexpr int DEFAULT_WINDOW_W = 500; 12 | static constexpr int DEFAULT_WINDOW_H = 300; 13 | 14 | Hardware& m_hardware; 15 | Debugger& m_debugger; 16 | ReqUI& m_reqUI; 17 | 18 | int64_t m_ccLast = -1; // to force the first stats update 19 | 20 | bool m_searchEnabled = false; 21 | int m_searchStartAddr = 0x0; 22 | int m_searchEndAddr = 0xFFFF; 23 | int m_searchVal = 0x0; 24 | 25 | std::vector m_searchResults; 26 | 27 | void UpdateData(const bool _isRunning); 28 | 29 | public: 30 | SearchWindow(Hardware& _hardware, Debugger& _debugger, 31 | const float* const _dpiScaleP, 32 | ReqUI& _reqUI); 33 | void Update(bool& _visible, const bool _isRunning); 34 | void Draw(const bool _isRunning); 35 | }; 36 | }; -------------------------------------------------------------------------------- /src/main_imgui/main/ui/trace_log_window.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "utils/types.h" 6 | #include "utils/consts.h" 7 | #include "ui/base_window.h" 8 | #include "utils/imgui_utils.h" 9 | #include "utils/result.h" 10 | #include "core/hardware.h" 11 | #include "core/debugger.h" 12 | 13 | namespace dev 14 | { 15 | class TraceLogWindow : public BaseWindow 16 | { 17 | static constexpr int DEFAULT_WINDOW_W = 512; 18 | static constexpr int DEFAULT_WINDOW_H = 300; 19 | static constexpr float ADDR_W = 50.0f; 20 | static constexpr float CODE_W = 200.0f; 21 | 22 | static constexpr int MAX_DISASM_LABELS = 4; 23 | 24 | struct ContextMenu { 25 | enum class Status { NONE = 0, INIT_CONTEXT_MENU, INIT_COMMENT_EDIT, INIT_LABEL_EDIT, INIT_CONST_EDIT }; 26 | Status status = Status::NONE; 27 | Addr addr = 0; 28 | std::string str; 29 | bool immHovered = false; // the context menu was opened on the immediate operand 30 | const char* contextMenuName = "DisasmItemMenu"; 31 | 32 | void Init(Addr _addr, const std::string& _lineS, const bool _immHovered = false) 33 | { 34 | immHovered = _immHovered; 35 | status = Status::INIT_CONTEXT_MENU; 36 | addr = _addr; 37 | str = _lineS; 38 | } 39 | }; 40 | ContextMenu m_contextMenu; 41 | 42 | struct AddrHighlight 43 | { 44 | int addr = -1; // -1 means disabled 45 | 46 | void Init(const Addr _addr) { 47 | addr = _addr; 48 | } 49 | bool IsEnabled(const Addr _addr) 50 | { 51 | bool out = _addr == addr; 52 | if (_addr == addr) addr = -1; // disable after use 53 | return out; 54 | } 55 | }; 56 | AddrHighlight m_addrHighlight; 57 | 58 | Hardware& m_hardware; 59 | Debugger& m_debugger; 60 | ReqUI& m_reqUI; 61 | int64_t m_ccLast = -1; // to force the first stats update 62 | int64_t m_ccLastRun = 0; 63 | const TraceLog::Lines* m_traceLogP = nullptr; 64 | uint8_t m_disasmFilter = 0; 65 | int m_selectedLineIdx = 0; 66 | size_t m_disasmLinesLen = 0; 67 | bool m_visible = false; 68 | 69 | void UpdateData(const bool _isRunning); 70 | void DrawLog(const bool _isRunning); 71 | void DrawContextMenu(const Addr _regPC, ContextMenu& _contextMenu); 72 | void DrawDisasmCode(const bool _isRunning, const Disasm::Line& _line, 73 | ReqUI& _reqUI, ContextMenu& _contextMenu, AddrHighlight& _addrHighlight); 74 | void DrawDisasmAddr(const bool _isRunning, const Disasm::Line& _line, 75 | ReqUI& _reqUI, ContextMenu& _contextMenu, AddrHighlight& _addrHighlight); 76 | 77 | public: 78 | TraceLogWindow(Hardware& _hardware, Debugger& _debugger, 79 | const float* const _dpiScaleP, ReqUI& _reqUI); 80 | void Update(bool& _visible, const bool _isRunning); 81 | }; 82 | }; -------------------------------------------------------------------------------- /src/main_imgui/main/ui/watchpoints_window.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "utils/imgui_utils.h" 4 | #include "utils/types.h" 5 | #include "utils/consts.h" 6 | #include "ui/base_window.h" 7 | #include "core/debugger.h" 8 | 9 | namespace dev 10 | { 11 | class WatchpointsWindow : public BaseWindow 12 | { 13 | static constexpr int DEFAULT_WINDOW_W = 600; 14 | static constexpr int DEFAULT_WINDOW_H = 300; 15 | 16 | Hardware& m_hardware; 17 | ReqUI& m_reqUI; 18 | Watchpoints::WpMap m_watchpoints; 19 | size_t m_updates = 0; // stores the watchpoint data updates to prevent extra Debug data fetching 20 | 21 | void DrawTable(); 22 | void DrawPopup(ReqPopup& _reqPopup, const Watchpoints::WpMap& _wps, int _id = -1); 23 | void CheckIfItemClicked(const ImVec2& _rowMin, bool& _showItemContextMenu, 24 | const int _id, int& _editedWatchpointId, ReqPopup& _reqPopup); 25 | void UpdateWatchpoints(); 26 | 27 | public: 28 | WatchpointsWindow(Hardware& _hardware, 29 | const float* const _dpiScaleP, ReqUI& _reqUI); 30 | void Update(bool& _visible, const bool _isRunning); 31 | void DrawProperty(const std::string& _name, const ImVec2& _aligment = { 0.0f, 0.5f }); 32 | }; 33 | 34 | }; -------------------------------------------------------------------------------- /src/main_wpf/Devector/About.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/About.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Devector 2 | { 3 | /// 4 | /// Interaction logic for About.xaml 5 | /// 6 | public partial class About : DevectorWindow 7 | { 8 | public About() 9 | { 10 | InitializeComponent(); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/App.xaml: -------------------------------------------------------------------------------- 1 |  7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/ArgsParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | 8 | namespace Devector 9 | { 10 | public class ArgsParser 11 | { 12 | private static string m_help = ""; 13 | private Dictionary m_args = new Dictionary(); 14 | bool m_requirementSatisfied = true; 15 | 16 | public ArgsParser(string[] args, string description) 17 | { 18 | AddDescriptionToHelp(description); 19 | 20 | for (int i = 0; i < args.Length; i++) 21 | { 22 | // wait for the first param name 23 | if (args[i][0] == '-') 24 | { 25 | string paramName = args[i].Substring(1); 26 | string value = ""; 27 | if (i + 1 < args.Length && args[i + 1][0] != '-') 28 | { 29 | i++; 30 | value = args[i]; 31 | } 32 | 33 | m_args[paramName] = value; 34 | } 35 | } 36 | } 37 | 38 | public enum ArgType : uint 39 | { 40 | INT = 0, 41 | DOUBLE, 42 | STRING, 43 | END 44 | }; 45 | 46 | private static readonly string[] ArgTypeStr = 47 | { 48 | "int", 49 | "double", 50 | "string" 51 | }; 52 | 53 | public void AddParamToHelp(string _arg, ArgType _type, bool _required, object _default, string _help) 54 | { 55 | string defaultStr = ""; 56 | if (_type == ArgType.DOUBLE) defaultStr = Convert.ToString((double)_default); 57 | if (_type == ArgType.INT) defaultStr = Convert.ToString((int)_default); 58 | if (_type == ArgType.STRING) defaultStr = (string)_default; 59 | 60 | m_help += string.Format("-{0} \n\ttype: {1}, required: {2}, default: {3}\n{4}\n\n", 61 | _arg, 62 | ArgTypeStr[(int)_type], 63 | _required ? "true" : "false", 64 | _required ? "no default" : defaultStr, 65 | ("\t" + _help)); 66 | } 67 | private void AddDescriptionToHelp(string _description) 68 | { 69 | m_help += "Help:\n"; 70 | m_help += $"Description: {_description}\n"; 71 | m_help += "format: -paramName or -h, -help to show this guide.\n"; 72 | m_help += "Parameters:\n"; 73 | } 74 | 75 | private void RequirementMsg(string _arg) 76 | { 77 | Console.WriteLine($"Required parameter \"{_arg}\" or its value was not provided."); 78 | m_requirementSatisfied = false; 79 | } 80 | 81 | public string GetString(string _arg, string _help, bool _required, string _defaultV = "") 82 | { 83 | AddParamToHelp(_arg, ArgType.STRING, _required, _defaultV, _help); 84 | 85 | if (!m_args.TryGetValue(_arg, out string v) || string.IsNullOrEmpty(v)) 86 | { 87 | if (_required) RequirementMsg(_arg); 88 | return _defaultV; 89 | } 90 | 91 | return v; 92 | } 93 | 94 | public double GetDouble(string _arg, string _help, bool _required, double _defaultV) 95 | { 96 | AddParamToHelp(_arg, ArgType.DOUBLE, _required, _defaultV, _help); 97 | 98 | if (!m_args.TryGetValue(_arg, out string v) || string.IsNullOrEmpty(v)) 99 | { 100 | if (_required) RequirementMsg(_arg); 101 | return _defaultV; 102 | } 103 | 104 | return double.Parse(v); 105 | } 106 | 107 | public int GetInt(string _arg, string _help, bool _required, int _defaultV) 108 | { 109 | AddParamToHelp(_arg, ArgType.INT, _required, _defaultV, _help); 110 | 111 | if (!m_args.TryGetValue(_arg, out string v) || string.IsNullOrEmpty(v)) 112 | { 113 | if (_required) RequirementMsg(_arg); 114 | return _defaultV; 115 | } 116 | 117 | return int.Parse(v); 118 | } 119 | private void PrintHelp() 120 | { 121 | if (!m_args.ContainsKey("help") && 122 | !m_args.ContainsKey("h") && 123 | m_args.Count > 0 && 124 | m_requirementSatisfied) return; 125 | 126 | Console.WriteLine($"\n{m_help}"); 127 | } 128 | 129 | public bool IsRequirementSatisfied() 130 | { 131 | PrintHelp(); 132 | return m_requirementSatisfied; 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | [assembly: ThemeInfo( 4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 5 | //(used if a resource is not found in the page, 6 | // or application resource dictionaries) 7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 8 | //(used if a resource is not found in the page, 9 | // app, or any theme specific resource dictionaries) 10 | )] 11 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/Breakpoints.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/Breakpoints.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Shapes; 14 | 15 | namespace Devector 16 | { 17 | /// 18 | /// Interaction logic for Breakpoints.xaml 19 | /// 20 | public partial class Breakpoints : DevectorWindow 21 | { 22 | public Breakpoints() 23 | { 24 | InitializeComponent(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/Consts.cs: -------------------------------------------------------------------------------- 1 | namespace Devector 2 | { 3 | public static class Consts 4 | { 5 | public const string DEFAULT_SETTING_PATH = "settings.json"; 6 | 7 | public const int INVALID_ID = -1; 8 | 9 | public enum ErrCode 10 | { 11 | UNSPECIFIED = -1, 12 | NO_ERRORS = 0, 13 | NO_FILES, 14 | FAILED_SDL_INIT, 15 | FAILED_CREATION_WINDOW, 16 | FAILED_SDL_GET_DISPLAY_BOUNDS, 17 | FAILED_OPENGL_INIT, 18 | UNRECOGNIZED_CPU_INSTR, 19 | WARNING_FDD_IMAGE_TOO_BIG, 20 | } 21 | 22 | 23 | public const int FDD_SIDES = 2; 24 | public const int FDD_TRACKS_PER_SIDE = 82; 25 | public const int FDD_SECTORS_PER_TRACK = 5; 26 | public const int FDD_SECTOR_LEN = 1024; 27 | public const int FDD_SIZE = FDD_SIDES * FDD_TRACKS_PER_SIDE * FDD_SECTORS_PER_TRACK * FDD_SECTOR_LEN; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/DarkTheme.xaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 6 | 34 | 35 | #CC353819 36 | #FF353819 37 | #FF535350 38 | #FF787878 39 | #FF353819 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/Devector.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | net8.0-windows 6 | enable 7 | enable 8 | true 9 | $(SolutionDir)build\wpf\out\ 10 | $(SolutionDir)build\main_wpf\hal\obj\$(Configuration)\$(Platform)\ 11 | false 12 | false 13 | False 14 | OnBuildSuccess 15 | x64 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | True 32 | True 33 | Resources.resx 34 | 35 | 36 | True 37 | True 38 | Settings.settings 39 | 40 | 41 | 42 | 43 | 44 | ResXFileCodeGenerator 45 | Resources.Designer.cs 46 | 47 | 48 | 49 | 50 | 51 | SettingsSingleFileGenerator 52 | Settings.Designer.cs 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/DevectorWindow.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using dev; 3 | 4 | namespace Devector 5 | { 6 | public abstract class DevectorWindow : Window 7 | { 8 | protected HAL? Hal; 9 | 10 | public DevectorWindow() 11 | { 12 | var app = (Devector.App)System.Windows.Application.Current; 13 | Hal = app.Hal; 14 | 15 | LocationChanged += WindowLocationChanged; 16 | SizeChanged += WindowSizeChanged; 17 | } 18 | 19 | private void WindowLocationChanged(object? sender, EventArgs e) 20 | { 21 | // TODO: store the location to settings 22 | } 23 | 24 | private void WindowSizeChanged(object sender, SizeChangedEventArgs e) 25 | { 26 | // TODO: store the size to settings 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/Disasm.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/Disasm.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Shapes; 14 | 15 | namespace Devector 16 | { 17 | /// 18 | /// Interaction logic for Disasm.xaml 19 | /// 20 | public partial class Disasm : DevectorWindow 21 | { 22 | public Disasm() 23 | { 24 | InitializeComponent(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/HexViewer.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/HexViewer.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Shapes; 14 | 15 | namespace Devector 16 | { 17 | /// 18 | /// Interaction logic for HexViewer.xaml 19 | /// 20 | public partial class HexViewer : DevectorWindow 21 | { 22 | public HexViewer() 23 | { 24 | InitializeComponent(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/MemoryDisplay.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/MemoryDisplay.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Shapes; 14 | 15 | namespace Devector 16 | { 17 | /// 18 | /// Interaction logic for MemoryDisplay.xaml 19 | /// 20 | public partial class MemoryDisplay : DevectorWindow 21 | { 22 | public MemoryDisplay() 23 | { 24 | InitializeComponent(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Devector.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Devector.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | text/microsoft-resx 91 | 92 | 93 | 1.3 94 | 95 | 96 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 97 | 98 | 99 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 100 | 101 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Devector.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.11.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Devector": { 4 | "commandName": "Project", 5 | "commandLineArgs": "-path ../../rom/games/putup.rom", 6 | "workingDirectory": "$(SolutionDir)bin\\$(Configuration)", 7 | "nativeDebugging": true 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/main_wpf/Devector/RamMappingViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Windows.Media; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using static Devector.HardwareStats; 9 | using System.Collections.ObjectModel; 10 | using System.Runtime.CompilerServices; 11 | using dev; 12 | 13 | namespace Devector 14 | { 15 | public class RamMappingViewModel : INotifyPropertyChanged 16 | { 17 | public struct MappingData 18 | { 19 | public int idx; 20 | public int pageRam; // Ram-Disk 64k page idx accesssed via non-stack instructions (all instructions except mentioned below) 21 | public int pageStack; // Ram-Disk 64k page idx accesssed via the stack instructions (Push, Pop, XTHL, Call, Ret, C*, R*, RST) 22 | public bool modeStack; // enabling stack mapping 23 | public bool modeRamA; // enabling ram [0xA000-0xDFFF] mapped into the the Ram-Disk 24 | public bool modeRam8; // enabling ram [0x8000-0x9FFF] mapped into the the Ram-Disk 25 | public bool modeRamE; // enabling ram [0xE000-0xFFFF] mapped into the the Ram-Disk 26 | 27 | public MappingData(int ramDiskIdx, int data = 0) 28 | { 29 | idx = ramDiskIdx; 30 | pageRam = data & 0x2; 31 | pageStack = (data >> 2) & 0x2; 32 | modeStack = ((data >> 4) & 0x1) != 0; 33 | modeRamA = ((data >> 5) & 0x1) != 0; 34 | modeRam8 = ((data >> 6) & 0x1) != 0; 35 | modeRamE = ((data >> 7) & 0x1) != 0; 36 | } 37 | public string ModeRamToString() 38 | { 39 | string mapping = modeRam8 ? "8" : "-"; 40 | mapping += modeRam8 ? "AC" : "-"; 41 | mapping += modeRam8 ? "E" : "-"; 42 | return mapping; 43 | } 44 | public string ModeStackToString() 45 | { 46 | return modeStack ? "On" : "Off"; 47 | } 48 | 49 | public string MappingRam { get => ModeRamToString() + " / " + pageRam.ToString(); } 50 | public string MappingStack { get => ModeStackToString() + " / " + pageStack.ToString(); } 51 | 52 | public int Idx { get => idx; } 53 | } 54 | 55 | private ObservableCollection _mappingDataList; 56 | public ObservableCollection MappingDataList 57 | { 58 | get => _mappingDataList; 59 | set 60 | { 61 | _mappingDataList = value; 62 | OnPropertyChanged(); 63 | } 64 | } 65 | 66 | public RamMappingViewModel() 67 | { 68 | // Initialize with sample data 69 | MappingDataList = new ObservableCollection(); 70 | for (int i = 0; i < (int)HAL.RAM_DISK_MAX; i++) 71 | { 72 | MappingDataList.Add(new MappingData(i)); 73 | } 74 | } 75 | 76 | // INotifyPropertyChanged Implementation 77 | public event PropertyChangedEventHandler PropertyChanged; 78 | protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 79 | { 80 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /src/main_wpf/Devector/Recorder.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/Recorder.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Shapes; 14 | 15 | namespace Devector 16 | { 17 | /// 18 | /// Interaction logic for Recorder.xaml 19 | /// 20 | public partial class Recorder : DevectorWindow 21 | { 22 | public Recorder() 23 | { 24 | InitializeComponent(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/RelayCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Input; 7 | 8 | namespace Devector 9 | { 10 | public class RelayCommand : ICommand 11 | { 12 | private readonly Action _execute; 13 | private readonly Predicate? _canExecute; 14 | 15 | public RelayCommand(Action execute, Predicate? canExecute = null) 16 | { 17 | _execute = execute ?? throw new ArgumentNullException(nameof(execute)); 18 | _canExecute = canExecute; 19 | } 20 | 21 | public bool CanExecute(object? parameter) => _canExecute?.Invoke((T?)parameter) ?? true; 22 | 23 | public void Execute(object? parameter) => _execute((T?)parameter); 24 | 25 | public event EventHandler? CanExecuteChanged 26 | { 27 | add => CommandManager.RequerySuggested += value; 28 | remove => CommandManager.RequerySuggested -= value; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/ScreenKeyboard.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/ScreenKeyboard.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Shapes; 14 | 15 | namespace Devector 16 | { 17 | /// 18 | /// Interaction logic for Keyboard.xaml 19 | /// 20 | public partial class ScreenKeyboard : DevectorWindow 21 | { 22 | public ScreenKeyboard() 23 | { 24 | InitializeComponent(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/Shaders.cs: -------------------------------------------------------------------------------- 1 | namespace Devector 2 | { 3 | public static class Shaders 4 | { 5 | public const string vtxShaderDisplay = @" 6 | #version 330 core 7 | precision highp float; 8 | 9 | layout (location = 0) in vec3 pos; 10 | layout (location = 1) in vec2 uv; 11 | 12 | uniform vec4 m_uvMinMax; 13 | 14 | out vec2 uv0; 15 | 16 | void main() 17 | { 18 | // remap 0-1 to m_uvMinMax 19 | uv0 = mix(m_uvMinMax.xy, m_uvMinMax.zw, uv); 20 | 21 | gl_Position = vec4(pos.xyz, 1.0f); 22 | } 23 | "; 24 | public const string fragShaderDisplay = @" 25 | #version 330 core 26 | precision highp float; 27 | precision highp int; 28 | 29 | in vec2 uv0; 30 | 31 | uniform sampler2D texture0; 32 | uniform vec4 m_activeArea_pxlSize; 33 | uniform vec4 m_bordsLRTB; 34 | uniform vec4 m_scrollV_crtXY_highlightMul; 35 | 36 | layout (location = 0) out vec4 out0; 37 | 38 | void main() 39 | { 40 | vec2 uv = uv0; 41 | float bordL = m_bordsLRTB.x; 42 | float bordR = m_bordsLRTB.y; 43 | float bordT = m_bordsLRTB.z; 44 | float bordB = m_bordsLRTB.w; 45 | float highlightMul = m_scrollV_crtXY_highlightMul.w; 46 | vec2 crt = m_scrollV_crtXY_highlightMul.yz; 47 | vec2 pxlSize = m_activeArea_pxlSize.zw; 48 | 49 | // vertical scrolling 50 | if (uv.x >= bordL && 51 | uv.x < bordR && 52 | uv.y >= bordT && 53 | uv.y < bordB) 54 | { 55 | uv.y -= m_scrollV_crtXY_highlightMul.x; 56 | // wrap V 57 | uv.y += uv.y < bordT ? m_activeArea_pxlSize.y * pxlSize.y : 0.0f; 58 | } 59 | 60 | vec3 color = texture(texture0, uv).rgb; 61 | 62 | // crt scanline highlight 63 | if (highlightMul < 1.0f) 64 | { 65 | if (uv.y >= crt.y && 66 | uv.y < crt.y + pxlSize.y && 67 | uv.x < crt.x + pxlSize.x ) 68 | { 69 | // highlight the rasterized pixels of the current crt line 70 | color.xyz = vec3(0.3f, 0.3f, 0.3f) + color.xyz * 2.0f; 71 | } 72 | else 73 | if ((uv.y >= crt.y && 74 | uv.y < crt.y + pxlSize.y && 75 | uv.x >= crt.x + pxlSize.x ) || uv.y > crt.y + pxlSize.y) 76 | { 77 | // renders not rasterized pixels yet 78 | color.xyz *= m_scrollV_crtXY_highlightMul.w; 79 | } 80 | } 81 | 82 | out0 = vec4(color, 1.0f); 83 | } 84 | "; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/TraceLog.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/TraceLog.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Shapes; 14 | 15 | namespace Devector 16 | { 17 | /// 18 | /// Interaction logic for TraceLog.xaml 19 | /// 20 | public partial class TraceLog : DevectorWindow 21 | { 22 | public TraceLog() 23 | { 24 | InitializeComponent(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/Types.cs: -------------------------------------------------------------------------------- 1 | namespace Devector 2 | { 3 | // TODO: move type aliases over here 4 | } 5 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/Viewport.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Windows.Interop; 4 | 5 | namespace Devector; 6 | 7 | public class Viewport : HwndHost 8 | { 9 | private IntPtr _hwnd; 10 | public new IntPtr Handle => _hwnd; 11 | //public event EventHandler? HwndReady; 12 | 13 | protected override HandleRef BuildWindowCore(HandleRef hwndParent) 14 | { 15 | _hwnd = CreateWindowEx( 16 | 0, 17 | "static", 18 | "", 19 | WS_CHILD | WS_VISIBLE, 20 | 0, 0, 21 | (int)Width, (int)Height, 22 | hwndParent.Handle, 23 | IntPtr.Zero, 24 | IntPtr.Zero, 25 | 0); 26 | 27 | //HwndReady?.Invoke(this, _hwnd); 28 | 29 | return new HandleRef(this, _hwnd); 30 | } 31 | 32 | protected override void DestroyWindowCore(HandleRef hwnd) 33 | { 34 | DestroyWindow(hwnd.Handle); 35 | } 36 | 37 | [DllImport("user32.dll", SetLastError = true)] 38 | private static extern IntPtr CreateWindowEx( 39 | uint dwExStyle, 40 | string lpClassName, 41 | string lpWindowName, 42 | uint dwStyle, 43 | int x, 44 | int y, 45 | int nWidth, 46 | int nHeight, 47 | IntPtr hWndParent, 48 | IntPtr hMenu, 49 | IntPtr hInstance, 50 | uint lParam); 51 | 52 | [DllImport("user32.dll", SetLastError = true)] 53 | private static extern bool DestroyWindow(IntPtr hwnd); 54 | 55 | private const int WS_CHILD = 0x40000000; 56 | private const int WS_VISIBLE = 0x10000000; 57 | } -------------------------------------------------------------------------------- /src/main_wpf/Devector/Watchpoints.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main_wpf/Devector/Watchpoints.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Shapes; 14 | 15 | namespace Devector 16 | { 17 | /// 18 | /// Interaction logic for Watchpoints.xaml 19 | /// 20 | public partial class Watchpoints : DevectorWindow 21 | { 22 | public Watchpoints() 23 | { 24 | InitializeComponent(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main_wpf/GLAD/GLAD.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {c052f34e-76b8-4ec8-b0a8-ba387fe70d87} 6 | 7 | 8 | {2e3e6c60-5480-4778-940b-a7278d55e428} 9 | 10 | 11 | {058b5108-5123-4c93-a894-74c727b27e75} 12 | 13 | 14 | 15 | 16 | src\glad 17 | 18 | 19 | src\KHR 20 | 21 | 22 | 23 | 24 | src 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/main_wpf/HAL/halwrapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "utils/types.h" 11 | #include "utils/consts.h" 12 | #include "utils/json_utils.h" 13 | 14 | #include "core/hardware.h" 15 | #include "core/debugger.h" 16 | 17 | #include "win_gl_utils.h" 18 | 19 | namespace dev 20 | { 21 | 22 | public ref class HAL 23 | { 24 | Hardware* m_hardwareP; 25 | Debugger* m_debuggerP; 26 | WinGlUtils* m_winGlUtilsP; 27 | 28 | public: 29 | literal float FRAME_PXL_SIZE_W = 1.0f / Display::FRAME_W; 30 | literal float FRAME_PXL_SIZE_H = 1.0f / Display::FRAME_H; 31 | literal float SCANLINE_HIGHLIGHT_MUL = 0.3f; 32 | 33 | literal float ACTIVE_AREA_W = Display::ACTIVE_AREA_W; 34 | literal float ACTIVE_AREA_H = Display::ACTIVE_AREA_H; 35 | literal float SCAN_ACTIVE_AREA_TOP = Display::SCAN_ACTIVE_AREA_TOP; 36 | literal float BORDER_VISIBLE = Display::BORDER_VISIBLE; 37 | 38 | //enum class Req 39 | #include "core/hardware_consts.h" 40 | 41 | #include "core/memory_consts.h" 42 | 43 | bool CreateGfxContext(System::IntPtr hwnd, GLsizei _viewportW, GLsizei _viewportH); 44 | 45 | 46 | HAL(System::String^ _pathBootData, System::String^ _pathRamDiskData, 47 | const bool _ramDiskClearAfterRestart); 48 | 49 | ~HAL(); 50 | !HAL(); 51 | 52 | auto InitShader(System::IntPtr _hWnd, 53 | System::String^ _vtxShaderS, System::String^ _fragShaderS) 54 | -> Id; 55 | 56 | auto InitMaterial( 57 | System::IntPtr _hWnd, 58 | Id _shaderId, 59 | cli::array^ _textureIds, 60 | cli::array^ _shaderParamNames, 61 | cli::array^ _shaderParamValues, 62 | int _framebufferW, int _framebufferH) 63 | -> Id; 64 | 65 | auto InitTexture(System::IntPtr _hWnd, const GLsizei _w, const GLsizei _h) 66 | -> Id; 67 | 68 | void UpdateFrameTexture(System::IntPtr _hWnd, 69 | Id _textureId, const bool _vsync); 70 | 71 | auto Draw(System::IntPtr _hWnd, const Id _materialId, 72 | const GLsizei _viewportW, const GLsizei _viewportH) 73 | ->int; 74 | 75 | auto GetMaterialParamId(System::IntPtr _hWnd, 76 | const Id _materialId, System::String^ _paramName) 77 | -> Id; 78 | 79 | auto UpdateMaterialParam(System::IntPtr _hWnd, 80 | const Id _materialId, const Id _paramId, 81 | const System::Numerics::Vector4^ _paramVal) 82 | -> int; 83 | 84 | //////////////////////////////////////////////////////////// 85 | // 86 | // Requests 87 | // 88 | //////////////////////////////////////////////////////////// 89 | auto Request(const Req _req, System::String^ _dataS) 90 | -> System::Text::Json::JsonDocument^; 91 | 92 | auto ReqCC() -> uint64_t; 93 | bool ReqIsRunning(); 94 | void ReqRun(); 95 | int LoadRom(System::String^ _path); 96 | int LoadFdd(System::String^ _path, const int _driveIdx, const bool _autoBoot); 97 | int LoadRecording(System::String^ _path); 98 | }; 99 | } 100 | 101 | -------------------------------------------------------------------------------- /src/main_wpf/HAL/win_gl_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifdef WPF 3 | #include 4 | #include 5 | 6 | #ifdef APIENTRY 7 | #undef APIENTRY 8 | #endif 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "utils/consts.h" 16 | #include "core/hardware.h" 17 | #include "utils/gl_utils.h" 18 | 19 | namespace dev 20 | { 21 | class WinGlUtils 22 | { 23 | 24 | public: 25 | enum class Status { NOT_INITED, INITED, 26 | FAILED_DC, // Failed to get device context 27 | FAILED_PIXEL_FORMAT, // Failed to choose pixel format 28 | FAILED_SET_PIXEL_FORMAT, //Failed to set pixel format 29 | FAILED_GL_CONTEXT, //Failed to create OpenGL context 30 | FAILED_GLAD, // Initialize to load GLAD lib 31 | FAILED_INIT_GL_UTILS, 32 | FAILED_INIT_BLIT_SHADER, 33 | FAILET_INIT_BLIT_TEX, 34 | FAILED_INIT_BLIT_MAT, 35 | }; 36 | 37 | private: 38 | 39 | struct GfxContext 40 | { 41 | HWND hWnd = nullptr; // window handle 42 | HDC hdc = nullptr; // digital context 43 | HGLRC* hglrcP = nullptr; // shared gl render context 44 | }; 45 | 46 | std::unordered_map m_gfxContexts; 47 | HGLRC m_hglrc = nullptr; // shared opengl render context between WPF controls 48 | 49 | std::shared_ptr m_gLUtilsP; 50 | 51 | void CleanGfxContext(GfxContext& _gfxContext); 52 | auto InitRenderObjects(const GfxContext& _gfxContext, 53 | const GLsizei _viewportW, const GLsizei _viewportH) -> Status; 54 | 55 | // helper class to auto-release the gfx context when it's out of scope 56 | struct CurrentGfxContext 57 | { 58 | const GfxContext& gfxContext; 59 | 60 | CurrentGfxContext(const GfxContext& _gfxContext) 61 | : gfxContext(_gfxContext) 62 | { Refresh(); } 63 | 64 | void Refresh() { 65 | wglMakeCurrent(gfxContext.hdc, *gfxContext.hglrcP); 66 | } 67 | 68 | ~CurrentGfxContext() { 69 | wglMakeCurrent(nullptr, nullptr); 70 | } 71 | }; 72 | 73 | public: 74 | ~WinGlUtils(); 75 | 76 | // called by a wpf window when it's created or its resolution has changed 77 | auto CreateGfxContext(HWND _hWnd, 78 | const int _framebufferW, const int _framebufferH) -> Status; 79 | 80 | // called by a wpf window when it's about to close 81 | void DeleteGfxContext(HWND _hWnd); 82 | 83 | 84 | auto InitShader(HWND _hWnd, 85 | const char* _vtxShaderS, const char* _fragShaderS) 86 | -> Id; 87 | 88 | auto InitMaterial(const HWND _hWnd, const Id _shaderId, 89 | const GLUtils::TextureIds& _textureIds, const GLUtils::ShaderParams& _shaderParams, 90 | const int _framebufferW = 0, const int _framebufferH = 0, 91 | const bool _renderToTexture = false, 92 | const int _framebufferTextureFilter = GL_NEAREST) 93 | -> Id; 94 | 95 | auto InitTexture(const HWND _hWnd, const GLsizei _w, const GLsizei _h, 96 | const GLUtils::Texture::Format _format = GLUtils::Texture::Format::RGBA, 97 | const GLint _textureFilter = GL_NEAREST) 98 | -> Id; 99 | 100 | void UpdateTexture(const HWND _hWnd, const Id _texureId, const uint8_t* _memP); 101 | 102 | auto Draw(const HWND _hWnd, const Id _materialId, 103 | const GLsizei _viewportW, const GLsizei _viewportH) const 104 | -> dev::ErrCode; 105 | 106 | auto GetMaterialParamId(const HWND _hWnd, 107 | const Id _materialId, const std::string& _paramName) 108 | -> Id; 109 | 110 | auto UpdateMaterialParam(const HWND _hWnd, 111 | const Id _materialId, const Id _paramId, const GLUtils::Vec4& _paramVal) 112 | ->ErrCode; 113 | }; 114 | } 115 | #endif // end WPF -------------------------------------------------------------------------------- /src/main_wpf/SDL/dll/x64/SDL3.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/src/main_wpf/SDL/dll/x64/SDL3.dll -------------------------------------------------------------------------------- /src/main_wpf/SDL/lib/x64/SDL3.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallelno/Devector/9ef02383eb3284c349532ea1905ef7963eff31d9/src/main_wpf/SDL/lib/x64/SDL3.lib -------------------------------------------------------------------------------- /src/utils/args_parser.cpp: -------------------------------------------------------------------------------- 1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it. 2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com 3 | #include 4 | #include 5 | 6 | #include "utils/args_parser.h" 7 | #include "utils/utils.h" 8 | 9 | dev::ArgsParser::ArgsParser(int& _argc, char** _argv, 10 | const std::string& _description) 11 | { 12 | AddDescriptionToHelp(_description); 13 | 14 | auto argc = static_cast(_argc); 15 | 16 | for (size_t i = 1; i < argc; i++) 17 | { 18 | // wait for the first param name 19 | if (_argv[i][0] == '-') 20 | { 21 | const std::string paramName = _argv[i]+1; 22 | std::string value; 23 | 24 | if (i + 1 < argc && _argv[i+1][0] != '-') 25 | { 26 | i++; 27 | value = _argv[i]; 28 | } 29 | 30 | m_args.emplace(paramName, value); 31 | } 32 | } 33 | } 34 | 35 | void dev::ArgsParser::RequirementMsg(const std::string& _arg) 36 | { 37 | std::cout << std::format("Required parameter \"{}\" or its value was not provided.\n", _arg); 38 | m_requirementSatisfied = false; 39 | } 40 | 41 | auto dev::ArgsParser::GetString(const std::string& _arg, 42 | const ArgHelp& _help, const bool _required, const std::string& _defaultV) 43 | ->const std::string 44 | { 45 | AddParamToHelp(_arg, ArgType::STRING, _required, _defaultV, _help ); 46 | 47 | if (!m_args.contains(_arg) || m_args[_arg].empty()) 48 | { 49 | if (_required) ArgsParser::RequirementMsg(_arg); 50 | return _defaultV; 51 | } 52 | 53 | return m_args[_arg]; 54 | } 55 | 56 | double dev::ArgsParser::GetDouble(const std::string& _arg, 57 | const ArgHelp& _help, const bool _required, const double _defaultV) 58 | { 59 | AddParamToHelp(_arg, ArgType::DOUBLE, _required, _defaultV, _help ); 60 | 61 | if (!m_args.contains(_arg) || m_args[_arg].empty()) 62 | { 63 | if (_required) ArgsParser::RequirementMsg(_arg); 64 | return _defaultV; 65 | } 66 | 67 | return strtod(m_args[_arg].c_str(), nullptr); 68 | } 69 | 70 | int dev::ArgsParser::GetInt(const std::string& _arg, 71 | const ArgHelp& _help, const bool _required, const int _defaultV) 72 | { 73 | AddParamToHelp(_arg, ArgType::INT, _required, _defaultV, _help ); 74 | 75 | if (!m_args.contains(_arg) || m_args[_arg].empty()) 76 | { 77 | if (_required) ArgsParser::RequirementMsg(_arg); 78 | return _defaultV; 79 | } 80 | return strtol(m_args[_arg].c_str(), nullptr, 10); 81 | } 82 | 83 | void dev::ArgsParser::AddDescriptionToHelp(const std::string& _description) 84 | { 85 | m_help += "Help:\n"; 86 | m_help += std::format("Description: {}\n", _description); 87 | m_help += "format: -paramName or -h, -help to show this guide.\n"; 88 | m_help += "Parameters:\n"; 89 | } 90 | 91 | void dev::ArgsParser::AddParamToHelp(const std::string& _arg, 92 | ArgType _type, Required _required, std::any _default, const ArgHelp& _help) 93 | { 94 | std::string defaultStr; 95 | if (_type == ArgType::DOUBLE) defaultStr = std::to_string(std::any_cast(_default)); 96 | if (_type == ArgType::INT) defaultStr = std::to_string(std::any_cast(_default)); 97 | if (_type == ArgType::STRING) defaultStr = std::any_cast(_default); 98 | 99 | m_help += std::format("-{} \n\ttype: {}, required: {}, default: {}\n{}\n\n", 100 | _arg, 101 | ArgTypeStr[static_cast(_type)], 102 | _required ? "true" : "false", 103 | _required ? "no default" : defaultStr, 104 | ("\t" + _help)); 105 | } 106 | 107 | void dev::ArgsParser::PrintHelp() const 108 | { 109 | if (!m_args.contains("help") && 110 | !m_args.contains("h") && 111 | !m_args.empty() && 112 | m_requirementSatisfied) return; 113 | 114 | std::cout << std::format("\n{}", m_help); 115 | } 116 | 117 | bool dev::ArgsParser::IsRequirementSatisfied() const 118 | { 119 | PrintHelp(); 120 | return m_requirementSatisfied; 121 | } -------------------------------------------------------------------------------- /src/utils/args_parser.h: -------------------------------------------------------------------------------- 1 | // This is an independent project of an individual developer. Dear PVS-Studio, please check it. 2 | // PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace dev 10 | { 11 | 12 | class ArgsParser 13 | { 14 | private: 15 | using ArgName = std::string; 16 | using ArgHelp = std::string; 17 | enum class ArgType : unsigned { 18 | INT = 0, 19 | DOUBLE, 20 | STRING, 21 | END 22 | }; 23 | const char* ArgTypeStr[static_cast(ArgType::END)] = { 24 | "int", 25 | "double", 26 | "string" 27 | }; 28 | using Required = bool; 29 | 30 | std::map m_args; 31 | std::string m_help; 32 | bool m_requirementSatisfied = true; 33 | 34 | public: 35 | ArgsParser(int& _argc, char** _argv, const std::string& _description); 36 | 37 | auto GetString(const std::string& _arg, 38 | const ArgHelp&, 39 | const bool _required = true, 40 | const std::string& _defaultV = "") 41 | -> const std::string; 42 | 43 | double GetDouble(const std::string& _arg, 44 | const ArgHelp&, 45 | const bool _required = true, 46 | const double _defaultV = 0.0); 47 | 48 | int GetInt(const std::string& _arg, 49 | const ArgHelp&, 50 | const bool _required = true, 51 | const int _defaultV = 0); 52 | 53 | void RequirementMsg(const std::string& _arg); 54 | 55 | void AddParamToHelp(const std::string& _arg, 56 | ArgType _type, Required _required, std::any _default, 57 | const ArgHelp& _help); 58 | 59 | void AddDescriptionToHelp(const std::string& _description); 60 | 61 | void PrintHelp() const; 62 | 63 | bool IsRequirementSatisfied() const; 64 | 65 | // deleted to prevent implicit convertion into bool type of the _required parameter in case thee user mixed up the parameters 66 | template 67 | double GetDouble(const std::string& _arg, 68 | const T _required = true, 69 | const double _defaultV = 0.0) = delete; 70 | 71 | // deleted to prevent implicit convertion into bool type of the _required parameter in case thee user mixed up the parameters 72 | template 73 | int GetInt(const std::string& _arg, 74 | const T _required = true, 75 | const int _defaultV = 0) = delete; 76 | }; 77 | 78 | } -------------------------------------------------------------------------------- /src/utils/consts.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "utils/types.h" 4 | 5 | namespace dev 6 | { 7 | static constexpr int MAIN_WINDOW_W = 820; 8 | static constexpr int MAIN_WINDOW_H = 670; 9 | static constexpr int MAIN_WINDOW_X = 0; 10 | static constexpr int MAIN_WINDOW_Y = 32; 11 | static constexpr int DEFAULT_FONT_SIZE = 18; 12 | static constexpr int DEFAULT_FONT_ITALIC_SIZE = 18; 13 | static const char* DEFAULT_FONT_PATH = "fonts//medium.ttf"; 14 | static const char* DEFAULT_FONT_ITALIC_PATH = "fonts//medium_italic.ttf"; 15 | 16 | static const char* ConditionsS[] = { 17 | "=ANY", "=", "<", ">", 18 | "<=", ">=", "!=" }; 19 | 20 | 21 | enum class ErrCode : int { 22 | UNSPECIFIED = -1, 23 | NO_ERRORS = 0, 24 | NO_FILES, 25 | FAILED_SDL_INIT, 26 | FAILED_CREATION_WINDOW, 27 | FAILED_SDL_GET_DISPLAY_BOUNDS, 28 | FAILED_OPENGL_INIT, 29 | UNRECOGNIZED_CPU_INSTR, 30 | INVALID_ID, 31 | WARNING_FDD_IMAGE_TOO_BIG, 32 | }; 33 | 34 | static constexpr int DELAYED_SELECTION_TIME = 6; 35 | 36 | static constexpr Id INVALID_ID = -1; 37 | 38 | } -------------------------------------------------------------------------------- /src/utils/gl_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #ifdef APIENTRY 6 | #undef APIENTRY 7 | #endif 8 | 9 | #include 10 | #include 11 | 12 | #include "utils/consts.h" 13 | #include "core/hardware.h" 14 | 15 | 16 | namespace dev 17 | { 18 | class GLUtils 19 | { 20 | public: 21 | struct Vec4 { 22 | float x, y, z, w; 23 | Vec4() : x(0.0f), y(0.0f), z(0.0f), w(1.0f) {}; 24 | Vec4(float _x, float _y, float _z, float _w) : x(_x), y(_y), z(_z), w(_w) {}; 25 | }; 26 | 27 | using ShaderParamIds = std::unordered_map ; 28 | using ShaderParamData = std::unordered_map ; 29 | using ShaderParams = std::unordered_map ; 30 | using ShaderTextureParams = std::unordered_map; 31 | using TextureIds = std::vector; 32 | 33 | struct Texture 34 | { 35 | enum class Format { RGB, RGBA, R8, R32, }; 36 | Format format; 37 | GLsizei w, h; 38 | GLuint id; 39 | GLint internalFormat; 40 | GLenum type; 41 | GLint filter; 42 | 43 | Texture(GLsizei _w, GLsizei _h, Texture::Format _format, GLint _filter); 44 | }; 45 | 46 | struct Material 47 | { 48 | Id shaderId = 0; 49 | bool renderToTexture; 50 | GLuint framebufferTexture; 51 | GLuint framebuffer; 52 | int viewportW; 53 | int viewportH; 54 | Vec4 backColor; 55 | ShaderParamData params; 56 | ShaderParamIds paramIds; 57 | ShaderTextureParams textureParams; 58 | 59 | Material(Id _shaderId, 60 | const ShaderParams& _shaderParams, 61 | const int _framebufferW, const int _framebufferH, 62 | const bool _renderToTexture = true, 63 | const Vec4& _backColor = Vec4(0.0f, 0.0f, 0.0f, 1.0f)); 64 | Material() = delete; 65 | auto GetParamId(const std::string& _paramName) -> Id; 66 | auto SetParam(const Id _id, const Vec4& _data) -> ErrCode; 67 | }; 68 | 69 | private: 70 | Id m_materialId = 0; 71 | std::unordered_map m_materials; 72 | GLuint vtxArrayObj = 0; 73 | GLuint vtxBufferObj = 0; 74 | std::unordered_map m_textures; 75 | std::vector m_shaders; 76 | 77 | GLenum m_gladInited = 0; 78 | 79 | void InitGeometry(); 80 | auto CompileShader(GLenum _shaderType, const char* _source) -> Id; 81 | auto GLCheckError(Id _id, const std::string& _txt) -> Id; 82 | 83 | public: 84 | GLUtils(bool _init); 85 | ~GLUtils(); 86 | 87 | auto InitShader(const char* _vtxShaderS, const char* _fragShaderS) -> Id; 88 | 89 | auto InitMaterial(Id _shaderId, 90 | const TextureIds& _textureIds, const ShaderParams& _shaderParams, 91 | const int _framebufferW, const int _framebufferH, 92 | const bool _renderToTexture = true, 93 | const int _framebufferTextureFilter = GL_NEAREST) 94 | -> Id; 95 | auto InitTexture(GLsizei _w, GLsizei _h, Texture::Format _format, 96 | const GLint textureFilter = GL_NEAREST) 97 | -> Id; 98 | 99 | auto Draw(const Id _renderDataId) const -> ErrCode; 100 | 101 | auto GetMaterialParamId(const Id _materialId, const std::string& _paramName) -> Id; 102 | auto UpdateMaterialParam(const Id _materialId, const Id _paramId, const Vec4& _param) 103 | -> ErrCode; 104 | 105 | void UpdateTexture(const Id _texureId, const uint8_t* _memP); 106 | auto GetFramebufferTexture(const Id _materialId) const -> Id; 107 | auto GetMaterial(const Id _matId) -> Material*; 108 | auto GetVtxArrayObj() const -> Id { return vtxArrayObj; }; 109 | auto GetVtxBufferObj() const -> Id { return vtxBufferObj; }; 110 | auto IsInited() const -> GLenum { return m_gladInited; }; 111 | bool IsMaterialReady(const Id _materialId) const; 112 | }; 113 | } -------------------------------------------------------------------------------- /src/utils/json_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "njson/json.hpp" 4 | 5 | namespace dev 6 | { 7 | #define JSON_SET(jsonObj, Var) (jsonObj[#Var] = (Var)) 8 | 9 | #define JSON_SET_ENUM(jsonObj, EmunType, Var) \ 10 | case EmunType::##Var : \ 11 | jsonObj[#EmunType] = #Var; \ 12 | break; 13 | #define JSON_GET(jsonObj, Var) ( Var = jsonObj[#Var] ) 14 | #define JSON_GET_C(jsonObj, Var) const auto Var = jsonObj[#Var]; 15 | #define JSON_GET_I(jsonObj, Var) Var(jsonObj[#Var]) 16 | 17 | #define JSON_GET_EX(jsonObj, Parent, Var) (jsonObj[#Var]) 18 | 19 | auto LoadJson(const std::string& _path) ->nlohmann::json; 20 | void SaveJson(const std::string& _path, const nlohmann::json& _json); 21 | 22 | void JsonParsingExit(const std::string& _fieldName); 23 | void JsonParsingTypeMissmatchExit( 24 | const nlohmann::json& _json, 25 | const std::string& _fieldName, 26 | const std::string& _expectedType); 27 | 28 | int GetJsonInt( 29 | nlohmann::json& _json, 30 | const std::string& _fieldName, 31 | const bool _exit = true, 32 | int _defaultValue = 0); 33 | 34 | /* 35 | template 36 | int GetJsonInt( 37 | nlohmann::json& _json, 38 | const std::string& _fieldName, 39 | const T _exit = true, 40 | int _defaultValue = 0) = delete; 41 | */ 42 | double GetJsonDouble( 43 | nlohmann::json& _json, 44 | const std::string& _fieldName, 45 | const bool _exit = true, 46 | double _defaultValue = 0.0); 47 | /* 48 | template 49 | double GetJsonDouble( 50 | const nlohmann::json& _json, 51 | const std::string& _fieldName, 52 | const T _exit = true, 53 | double _defaultValue = 0.0) = delete; 54 | */ 55 | bool GetJsonBool( 56 | nlohmann::json& _json, 57 | const std::string& _fieldName, 58 | const bool _exit = true, 59 | bool _defaultValue = false); 60 | 61 | auto GetJsonString( 62 | nlohmann::json& _json, 63 | const std::string& _fieldName, 64 | bool _exit = true, 65 | const std::string& _defaultValue = "") 66 | -> std::string; 67 | 68 | auto GetJsonObject( 69 | nlohmann::json& _json, 70 | const std::string& _fieldName, 71 | const bool _exit = true) 72 | -> nlohmann::json; 73 | 74 | auto GetJsonVectorUint8( 75 | nlohmann::json& _json, 76 | const std::string& _fieldName, 77 | const bool _exit = true, 78 | const std::vector& _defaultValue = {}) 79 | -> const std::vector; 80 | 81 | } -------------------------------------------------------------------------------- /src/utils/result.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "utils/consts.h" 7 | 8 | namespace dev 9 | { 10 | template 11 | class Result 12 | { 13 | std::optional m_result; 14 | dev::ErrCode m_error = dev::ErrCode::NO_ERRORS; 15 | 16 | public: 17 | Result() 18 | : m_error(dev::ErrCode::UNSPECIFIED) 19 | {} 20 | Result(const ErrCode _error) 21 | : 22 | m_error(_error) 23 | {} 24 | Result(T&& _res, 25 | const dev::ErrCode _error = dev::ErrCode::NO_ERRORS) 26 | : 27 | m_result(std::move(_res)), 28 | m_error(_error) 29 | {} 30 | Result(Result&& _other) 31 | : 32 | m_error(_other.m_error), 33 | m_result(std::move(_other.m_result)) 34 | {} 35 | /* 36 | template>> 37 | Result(U&& _res, const dev::ErrCode _error = dev::NO_ERRORS) 38 | : 39 | m_result(_res), 40 | m_error(_error) 41 | {} 42 | */ 43 | inline auto HasValue() const 44 | ->const bool 45 | { 46 | return m_result.has_value(); 47 | } 48 | operator bool() const 49 | { 50 | return m_result.has_value(); 51 | } 52 | inline auto Error() const 53 | ->const dev::ErrCode 54 | { 55 | return m_error; 56 | } 57 | 58 | inline bool operator==(const dev::ErrCode _err) const 59 | { 60 | return m_error == _err; 61 | } 62 | inline bool operator!=(const dev::ErrCode _err) const 63 | { 64 | return m_error != _err; 65 | } 66 | 67 | inline T&& operator*() 68 | { 69 | return std::move(m_result.value()); 70 | } 71 | /* 72 | template>> 73 | inline U&& operator*() 74 | { 75 | return m_result.value(); 76 | } 77 | */ 78 | inline T* operator->() 79 | { 80 | return &m_result.value(); 81 | } 82 | 83 | inline Result& operator= (const Result& _other) noexcept 84 | { 85 | if (this == &_other) return *this; 86 | 87 | m_error = _other.m_error; 88 | m_result = _other.m_result; 89 | 90 | return *this; 91 | } 92 | inline Result& operator= (Result&& _other) noexcept 93 | { 94 | if (this == &_other) return *this; 95 | 96 | m_error = _other.m_error; 97 | m_result = std::move(_other.m_result); 98 | 99 | return *this; 100 | } 101 | }; 102 | } -------------------------------------------------------------------------------- /src/utils/str_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace dev 7 | { 8 | auto fast_atof(const char* _s) 9 | -> double; 10 | auto fast_atoi(const char* _s) 11 | -> int; 12 | 13 | auto Split(const std::string& _s, char _delim) 14 | -> std::vector; 15 | 16 | auto StrToStrW(const std::string& _s) -> const std::wstring; 17 | auto Utf8ToStrW(const std::string& _s) -> std::wstring; 18 | auto StrWToStr(const std::wstring& _s) -> const std::string; 19 | auto BoolToStrC(const bool _val, int _mode = 0) -> const char*; 20 | auto StrHexToInt(const char* _str) -> int; 21 | auto GetSubstringCount(const std::string& _str, const std::string& _substr) -> int; 22 | auto StrToUpperW(const std::wstring _str) -> std::wstring; 23 | auto StrToUpper(const std::string _str) -> std::string; 24 | inline auto TrimSpacesRight(std::wstring _str) -> std::wstring; 25 | auto Uint16ToStrC0x(const uint16_t _addr) -> const char*; 26 | auto Uint8ToStrC0x(const uint8_t _addr) -> const char*; 27 | auto Uint16ToStrC(const uint16_t _addr) -> const char*; 28 | auto Uint8ToStrC(const uint8_t _addr) -> const char*; 29 | } 30 | -------------------------------------------------------------------------------- /src/utils/tqueue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "utils/result.h" 10 | #include "utils/utils.h" 11 | #include "utils/consts.h" 12 | 13 | using namespace std::chrono_literals; 14 | 15 | namespace dev { 16 | 17 | template 18 | class TQueue 19 | { 20 | std::queue m_queue; 21 | std::mutex m_mutex; 22 | std::condition_variable m_condition; 23 | size_t m_maxLegth; 24 | 25 | public: 26 | TQueue(size_t _maxLegth = 10) : m_maxLegth(_maxLegth) {} 27 | TQueue(const TQueue&) = delete; // disable copying 28 | TQueue& operator=(const TQueue&) = delete; // disable assignment 29 | 30 | // _waitTime is in nanoseconds 31 | // _waitTime < 0 : wait until data received 32 | // _waitTime = 0 : no wait 33 | // _waitTime > 0 : wait until data received or time is over 34 | Result pop(const std::chrono::duration _waitTime = -1ns) 35 | { 36 | std::unique_lock mlock(m_mutex); 37 | 38 | if (_waitTime == 0ns) //-V550 39 | { 40 | if (m_queue.empty()) return {}; 41 | } 42 | else if (_waitTime < 0ns) { 43 | while (m_queue.empty()) 44 | { 45 | m_condition.wait(mlock); 46 | } 47 | } 48 | else if (m_queue.empty()) 49 | { 50 | m_condition.wait_for(mlock, _waitTime); 51 | if (m_queue.empty()) return {}; 52 | } 53 | auto value = m_queue.front(); 54 | m_queue.pop(); 55 | return { std::move(value) }; 56 | } 57 | 58 | void push(const T& _item) 59 | { 60 | std::unique_lock mlock(m_mutex); 61 | if (m_queue.size() > m_maxLegth) { 62 | m_queue.pop(); 63 | } 64 | m_queue.push(_item); 65 | mlock.unlock(); 66 | m_condition.notify_one(); 67 | } 68 | 69 | void emplace(const T& _item) 70 | { 71 | std::unique_lock mlock(m_mutex); 72 | if (m_queue.size() > m_maxLegth) { 73 | m_queue.pop(); 74 | } 75 | m_queue.emplace(std::move(_item)); 76 | mlock.unlock(); 77 | m_condition.notify_one(); 78 | } 79 | 80 | inline void clear() 81 | { 82 | std::unique_lock mlock(m_mutex); 83 | m_queue = {}; 84 | } 85 | 86 | inline bool empty() 87 | { 88 | std::unique_lock mlock(m_mutex); 89 | return m_queue.empty(); 90 | } 91 | }; 92 | } -------------------------------------------------------------------------------- /src/utils/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace dev 7 | { 8 | using GlobalAddr = uint32_t; 9 | using Addr = uint16_t; 10 | using ColorI = uint32_t; 11 | using Id = int; 12 | 13 | // The User initiated requests in the UI thread 14 | // for window-to-window communication 15 | struct ReqUI { 16 | enum class Type : int { 17 | NONE = 0, 18 | DISASM_UPDATE, // redraw disasm 19 | DISASM_UPDATE_ADDR, 20 | DISASM_NAVIGATE_TO_ADDR, 21 | DISASM_NAVIAGATE_NEXT, 22 | DISASM_NAVIAGATE_PREV, 23 | HEX_HIGHLIGHT_ON, 24 | HEX_HIGHLIGHT_OFF, 25 | RELOAD_ROM_FDD_REC, 26 | DISPLAY_FRAME_BUFF_UPDATE, 27 | LOAD_RECENT_FDD_IMG, 28 | 29 | LABEL_EDIT_WINDOW_ADD, 30 | LABEL_EDIT_WINDOW_EDIT, 31 | CONST_EDIT_WINDOW_ADD, 32 | CONST_EDIT_WINDOW_EDIT, 33 | COMMENT_EDIT_WINDOW_ADD, 34 | COMMENT_EDIT_WINDOW_EDIT, 35 | MEMORY_EDIT_EDIT_WINDOW_ADD, 36 | MEMORY_EDIT_EDIT_WINDOW_EDIT, 37 | CODE_PERFS_EDIT_WINDOW_ADD, 38 | CODE_PERFS_EDIT_WINDOW_EDIT, 39 | SCRIPTS_EDIT_WINDOW_ADD, 40 | SCRIPTS_EDIT_WINDOW_EDIT, 41 | }; 42 | 43 | Type type = Type::NONE; 44 | GlobalAddr globalAddr = 0; 45 | uint16_t len = 0; 46 | }; 47 | 48 | enum class UIItemMouseAction { NONE = 0, HOVERED, LEFT, RIGHT, MIDDLE }; 49 | enum class Condition : uint8_t { ANY = 0, EQU, LESS, GREATER, LESS_EQU, GREATER_EQU, NOT_EQU, INVALID, COUNT }; 50 | static constexpr int CONDITION_BIT_WIDTH = std::bit_width(static_cast(Condition::COUNT) - 1); 51 | } --------------------------------------------------------------------------------