├── .clang-format ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ └── cmake.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── CONTRIBUTING.md ├── CREDITS.md ├── LICENSE ├── README.md ├── benchmark └── bench1.cpp ├── cmake └── PlatformGlob.cmake ├── core ├── CMakeLists.txt ├── bitops.h ├── coresignal.h ├── hostevents.h ├── hostevents_sdl.cpp ├── mathutils.h ├── timermanager.cpp └── timermanager.h ├── cpu └── ppc │ ├── CMakeLists.txt │ ├── poweropcodes.cpp │ ├── ppcdisasm.cpp │ ├── ppcdisasm.h │ ├── ppcemu.h │ ├── ppcexceptions.cpp │ ├── ppcexec.cpp │ ├── ppcfpopcodes.cpp │ ├── ppcmacros.h │ ├── ppcmmu.cpp │ ├── ppcmmu.h │ ├── ppcopcodes.cpp │ └── test │ ├── genppctests.py │ ├── ppcdisasmtest.csv │ ├── ppcfloattest.txt │ ├── ppcfloattests.csv │ ├── ppcinttest.txt │ ├── ppcinttests.csv │ ├── ppctests.cpp │ └── testdisasm.cpp ├── debugger ├── CMakeLists.txt ├── debugger.cpp └── debugger.h ├── devices ├── CMakeLists.txt ├── common │ ├── adb │ │ ├── adbapplejack.cpp │ │ ├── adbapplejack.h │ │ ├── adbbus.cpp │ │ ├── adbbus.h │ │ ├── adbdevice.cpp │ │ ├── adbdevice.h │ │ ├── adbkeyboard.cpp │ │ ├── adbkeyboard.h │ │ ├── adbmouse.cpp │ │ └── adbmouse.h │ ├── ata │ │ ├── atabasedevice.cpp │ │ ├── atabasedevice.h │ │ ├── atadefs.h │ │ ├── atahd.cpp │ │ ├── atahd.h │ │ ├── atapibasedevice.cpp │ │ ├── atapibasedevice.h │ │ ├── atapicdrom.cpp │ │ ├── atapicdrom.h │ │ ├── cmd646.cpp │ │ ├── cmd646.h │ │ ├── idechannel.cpp │ │ └── idechannel.h │ ├── clockgen │ │ ├── athens.cpp │ │ └── athens.h │ ├── dbdma.cpp │ ├── dbdma.h │ ├── dmacore.h │ ├── hwcomponent.h │ ├── hwinterrupt.h │ ├── i2c │ │ ├── i2c.h │ │ ├── i2cprom.cpp │ │ └── i2cprom.h │ ├── machineid.h │ ├── mmiodevice.h │ ├── nubus │ │ ├── nubusutils.cpp │ │ └── nubusutils.h │ ├── nvram.cpp │ ├── nvram.h │ ├── ofnvram.cpp │ ├── ofnvram.h │ ├── pci │ │ ├── bandit.cpp │ │ ├── bandit.h │ │ ├── dec21154.cpp │ │ ├── dec21154.h │ │ ├── pcibase.cpp │ │ ├── pcibase.h │ │ ├── pcibridge.cpp │ │ ├── pcibridge.h │ │ ├── pcibridgebase.cpp │ │ ├── pcibridgebase.h │ │ ├── pcicardbusbridge.cpp │ │ ├── pcicardbusbridge.h │ │ ├── pcidevice.cpp │ │ ├── pcidevice.h │ │ ├── pcihost.cpp │ │ └── pcihost.h │ ├── scsi │ │ ├── mesh.cpp │ │ ├── mesh.h │ │ ├── sc53c94.cpp │ │ ├── sc53c94.h │ │ ├── scsi.h │ │ ├── scsibus.cpp │ │ ├── scsibusctrl.cpp │ │ ├── scsibusctrl.h │ │ ├── scsicdrom.cpp │ │ ├── scsicdrom.h │ │ ├── scsidevice.cpp │ │ ├── scsihd.cpp │ │ └── scsihd.h │ ├── viacuda.cpp │ └── viacuda.h ├── deviceregistry.cpp ├── deviceregistry.h ├── ethernet │ ├── bigmac.cpp │ ├── bigmac.h │ ├── mace.cpp │ └── mace.h ├── floppy │ ├── floppyimg.cpp │ ├── floppyimg.h │ ├── superdrive.cpp │ ├── superdrive.h │ ├── swim3.cpp │ └── swim3.h ├── ioctrl │ ├── amic.cpp │ ├── amic.h │ ├── grandcentral.cpp │ ├── heathrow.cpp │ ├── macio.h │ └── ohare.cpp ├── memctrl │ ├── aspen.cpp │ ├── aspen.h │ ├── hammerhead.cpp │ ├── hammerhead.h │ ├── hmc.cpp │ ├── hmc.h │ ├── memctrlbase.cpp │ ├── memctrlbase.h │ ├── mpc106.cpp │ ├── mpc106.h │ ├── platinum.cpp │ ├── platinum.h │ ├── psx.cpp │ ├── psx.h │ └── spdram.h ├── serial │ ├── chario.cpp │ ├── chario.h │ ├── escc.cpp │ ├── escc.h │ └── z85c30.h ├── sound │ ├── awacs.cpp │ ├── awacs.h │ ├── burgundy.cpp │ ├── burgundy.h │ ├── soundserver.h │ └── soundserver_cubeb.cpp ├── storage │ ├── blockstoragedevice.cpp │ ├── blockstoragedevice.h │ ├── cdromdrive.cpp │ └── cdromdrive.h └── video │ ├── appleramdac.cpp │ ├── appleramdac.h │ ├── atimach64defs.h │ ├── atimach64gx.cpp │ ├── atimach64gx.h │ ├── atirage.cpp │ ├── atirage.h │ ├── control.cpp │ ├── control.h │ ├── display.h │ ├── display_sdl.cpp │ ├── displayid.cpp │ ├── displayid.h │ ├── pdmonboard.cpp │ ├── pdmonboard.h │ ├── rgb514defs.h │ ├── saa7187.cpp │ ├── saa7187.h │ ├── sixty6.cpp │ ├── sixty6.h │ ├── taos.cpp │ ├── taos.h │ ├── videoctrl.cpp │ └── videoctrl.h ├── dppcicon.ico ├── endianswap.h ├── icon.png ├── icon.rc ├── machines ├── CMakeLists.txt ├── machinebase.cpp ├── machinebase.h ├── machinebondi.cpp ├── machinecatalyst.cpp ├── machinefactory.cpp ├── machinefactory.h ├── machinegazelle.cpp ├── machinegossamer.cpp ├── machinepdm.cpp ├── machinepippin.cpp ├── machineproperties.cpp ├── machineproperties.h ├── machinetnt.cpp └── machineyosemite.cpp ├── main.cpp ├── main.h ├── main_sdl.cpp ├── main_sdl.m ├── memaccess.h ├── thirdparty ├── CLI11 │ └── CLI11.hpp └── loguru │ ├── CMakeLists.txt │ ├── loguru.cpp │ └── loguru.hpp ├── utils ├── CMakeLists.txt ├── imgfile.h ├── imgfile_sdl.cpp ├── profiler.cpp └── profiler.h ├── vcpkg.json └── zdocs ├── developers ├── aboutthis.md ├── adb.md ├── amic.md ├── atirage.md ├── awacs.md ├── bebox.md ├── bmac.md ├── cpu │ └── powerpc │ │ ├── mmu.md │ │ ├── mmuemu.md │ │ └── powerpc.md ├── dbdma.md ├── get-inherited-property notes.txt ├── grackle.md ├── heathrow.md ├── ibmpower.md ├── keylargo.md ├── machines │ └── pdmram.md ├── memorymaps.md ├── mesh.md ├── misc.md ├── motorolaatlas.md ├── openfirmware.md ├── swim3.md ├── valkyrie.md └── viacuda.md └── users └── manual.md /.clang-format: -------------------------------------------------------------------------------- 1 | Language: Cpp 2 | 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: AlwaysBreak 5 | AlignConsecutiveAssignments: true 6 | AlignConsecutiveDeclarations: false 7 | #AlignConsecutiveMacros: false 8 | AlignEscapedNewlines: Right 9 | AlignOperands: false 10 | AlignTrailingComments: true 11 | AllowAllArgumentsOnNextLine: true 12 | AllowAllConstructorInitializersOnNextLine: true 13 | AllowAllParametersOfDeclarationOnNextLine: true 14 | AllowShortBlocksOnASingleLine: false 15 | AllowShortCaseLabelsOnASingleLine: false 16 | AllowShortFunctionsOnASingleLine: Empty 17 | AllowShortIfStatementsOnASingleLine: Never 18 | #AllowShortLambdasOnASingleLine: All 19 | AllowShortLoopsOnASingleLine: false 20 | AlwaysBreakAfterDefinitionReturnType: None 21 | AlwaysBreakAfterReturnType: None 22 | AlwaysBreakBeforeMultilineStrings: true 23 | AlwaysBreakTemplateDeclarations: Yes 24 | BinPackArguments: false 25 | BinPackParameters: false 26 | BreakBeforeBinaryOperators: None 27 | BreakBeforeBraces: Attach 28 | BreakBeforeTernaryOperators: true 29 | BreakConstructorInitializers: BeforeComma 30 | #BreakInheritanceList: BeforeComma 31 | BreakStringLiterals: true 32 | ColumnLimit: 100 33 | CompactNamespaces: true 34 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 35 | ConstructorInitializerIndentWidth: 4 36 | ContinuationIndentWidth: 4 37 | Cpp11BracedListStyle: true 38 | DerivePointerAlignment: false 39 | FixNamespaceComments: true 40 | IncludeBlocks: Preserve 41 | IndentCaseLabels: false 42 | IndentPPDirectives: AfterHash 43 | IndentWidth: 4 44 | IndentWrappedFunctionNames: true 45 | KeepEmptyLinesAtTheStartOfBlocks: false 46 | MaxEmptyLinesToKeep: 2 47 | NamespaceIndentation: None 48 | PenaltyBreakAssignment: 50 49 | PenaltyBreakBeforeFirstCallParameter: 0 50 | PenaltyBreakComment: 100 51 | PenaltyBreakFirstLessLess: 200 52 | PenaltyBreakString: 100 53 | #PenaltyBreakTemplateDeclaration: 0 54 | PenaltyExcessCharacter: 10 55 | PenaltyReturnTypeOnItsOwnLine: 1000 56 | PointerAlignment: Left 57 | ReflowComments: true 58 | SortIncludes: true 59 | SpaceAfterCStyleCast: false 60 | #SpaceAfterLogicalNot: false 61 | SpaceAfterTemplateKeyword: true 62 | SpaceBeforeAssignmentOperators: true 63 | #SpaceBeforeCpp11BracedList: true 64 | #SpaceBeforeCtorInitializerColon: false 65 | #SpaceBeforeInheritanceColon: false 66 | SpaceBeforeParens: ControlStatements 67 | #SpaceBeforeRangeBasedForLoopColon: false 68 | #SpaceInEmptyBlock: false 69 | SpaceInEmptyParentheses: false 70 | SpacesBeforeTrailingComments: 4 71 | SpacesInAngles: false 72 | SpacesInCStyleCastParentheses: false 73 | SpacesInContainerLiterals: false 74 | SpacesInParentheses: false 75 | SpacesInSquareBrackets: false 76 | #Standard: c++17 77 | TabWidth: 4 78 | UseTab: Never 79 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | **Device Information (please complete the following information):** 26 | 27 | - Device Type: [e.g. Desktop, Smartphone] 28 | - Host OS: [e.g. Linux 4.4, Mac OS X 10.12, Windows 7] 29 | - Host Processor: [e.g. Intel Core 2 Duo, AMD Phenom II] 30 | - Host RAM: [e.g. 4 GB] 31 | - Guest OS: [e.g. Mac OS 8.6] 32 | - Guest Processor: [e.g. PowerPC G3 (750 v.1)] 33 | - Guest ROM: [e.g. Power Mac G3 Beige] 34 | - Guest RAM: [e.g. 64 MB] 35 | - Build Date [e.g. 22/7/2019 (dd/mm/yyyy format)] 36 | - Version [e.g. 22] 37 | 38 | **Additional context** 39 | Add any other context about the problem here. 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore binary files 2 | out/ 3 | vcpkg/ 4 | *.bin 5 | 6 | # Ignore compiled object files 7 | .vs/ 8 | .vscode/ 9 | *.o 10 | *.out 11 | *.obj 12 | *.d 13 | 14 | # Ignore CMake system files 15 | CMakeFiles 16 | cmake_install.cmake 17 | 18 | # Ignore Visual Studio configuration files 19 | CMakeSettings.json 20 | *.vcxproj 21 | *.vcxproj.filters 22 | 23 | # Ignore Visual Studio auto-save recovery folder 24 | enc_temp_folder/ 25 | 26 | # Ignore CodeLite configuration files 27 | *.workspace 28 | *.workspace.* 29 | compile_commands.json 30 | *.session 31 | *.tags 32 | 33 | # Ignore generated executables 34 | dingusppc 35 | dingusppc.exe 36 | 37 | # Ignore system files 38 | .DS_Store 39 | Thumb.db 40 | ehthumbs.db 41 | 42 | # IDE ignores 43 | build 44 | build-* 45 | *.dir 46 | *.user 47 | DerivedData 48 | *.xcodeproj/project.xcworkspace 49 | *.xcodeproj/xcuserdata 50 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "thirdparty/cubeb"] 2 | path = thirdparty/cubeb 3 | url = https://github.com/DingusDevOrg/cubeb.git 4 | [submodule "thirdparty/capstone"] 5 | path = thirdparty/capstone 6 | url = https://github.com/maximumspatium/capstone.git 7 | branch = next 8 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | General 2 | ======= 3 | 4 | * Test your contributions to assure they do not break existing functionality. 5 | * Commits to the repo should be done by portions; that is, by individual functionalities of the program. 6 | * Don't use any disrespectful language. 7 | 8 | Code 9 | ======= 10 | 11 | * Make sure the code can compile for all target systems - Windows, Linux, and macOS/Mac OS X. 12 | * All code must be compatible with at least C++11. 13 | * Minimize the amount of redundant code. 14 | * Avoid using absolute paths for the headers. 15 | * Code should maintain vertical alignment for better readability, for example: 16 | 17 | ```C 18 | one_hundred = 100; 19 | one_thousand = 1000; 20 | two_thousand = 2000; 21 | ``` 22 | 23 | * CamelCase for class names, lowercase for variables, UPPERCASE for enumerations 24 | * Avoid redundancy in namespaces (i.e. use ViaCuda::read() instead of ViaCuda::cuda_read()) 25 | 26 | Issues 27 | ======= 28 | 29 | * When creating an issue ticket, note which version you are using. 30 | * If possible, reference the git hashes for the relevant commits. 31 | * Once an issue is closed, do not re-open it. Instead, reference it in a new issue ticket. 32 | -------------------------------------------------------------------------------- /CREDITS.md: -------------------------------------------------------------------------------- 1 | # DingusPPC 2 | 3 | 4 | ## Developers 5 | 6 | - divingkatae 7 | - maximumspatium 8 | - joevt 9 | - mihaip 10 | - kkaisershot 11 | 12 | ## NT4/PPC fork 13 | 14 | - Wack0 15 | 16 | ## DevOps 17 | 18 | - Waqar144 19 | - webspacecreations 20 | - leap0x7b 21 | - sdkmap 22 | - dressupgeekout 23 | - kth5 24 | - dyharlan 25 | - roytam1 26 | - mrpapersonic 27 | - Randrianasulu 28 | - lefp 29 | - mathstuf 30 | 31 | ## Testing 32 | 33 | - LagLifeYT 34 | 35 | ## 3rd Party Libraries 36 | 37 | - [Capstone](https://github.com/capstone-engine/capstone) 38 | - [CLI11](https://github.com/CLIUtils/CLI11) 39 | - [Loguru](https://github.com/emilk/loguru) 40 | - [SDL 2](https://github.com/libsdl-org/SDL) 41 | 42 | ## Thanks 43 | 44 | - 68kmla 45 | - AppleFritter 46 | - Archive.org 47 | - Bitsavers 48 | - Blitter.net 49 | - Emaculation 50 | - GitHub 51 | - PenguinPPC 52 | - VirtuallyFun 53 | - The makers of Loguru, SDL2, Capstone, and CLI11 54 | - The developers of other PowerPC Mac emulators, past and present 55 | - All those preserving the software and source code of 68k and PowerPC Macs 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DingusPPC 2 | 3 | Written by divingkatae and maximumspatium 4 | 5 | Be warned the program is highly unfinished and could use a lot of testing. Any feedback is welcome. 6 | 7 | ## Philosophy of Use 8 | 9 | While many other PowerPC emus exist (PearPC, Sheepshaver), none of them currently attempt emulation of PowerPC Macs accurately (except for QEMU). 10 | 11 | This program aims to not only improve upon what Sheepshaver, PearPC, and other PowerPC Mac emulators have done, but also to provide a better debugging environment. This currently is designed to work best with PowerPC Old World ROMs, including those of the Power Mac 6100, 7200, and G3 Beige. 12 | 13 | ## Implemented Features 14 | 15 | This emulator has a debugging environment, complete with a disassembler. We also have implemented enough to allow Open Firmware to boot, going so far as to allow audio playback of the boot-up jingles. 16 | 17 | ## How to Use 18 | 19 | This program currently uses the command prompt to work. 20 | 21 | There are a few command line arguments one must enter when starting the program. 22 | 23 | ``` 24 | -r, --realtime 25 | ``` 26 | 27 | Run the emulator in runtime. 28 | 29 | ``` 30 | -d, --debugger 31 | ``` 32 | 33 | Enter the interactive debugger. 34 | 35 | ``` 36 | -b, --bootrom TEXT:FILE 37 | ``` 38 | 39 | Specifies the Boot ROM path (optional; looks for bootrom.bin by default) 40 | 41 | ``` 42 | -m, --machine TEXT 43 | ``` 44 | 45 | Specify machine ID (optional; will attempt to determine machine ID from the boot rom otherwise) 46 | 47 | As of now, the most complete machines are the Power Mac 6100 (SCSI emulation in progress) and the Power Mac G3 Beige (SCSI + ATA emulation in progress, No ATI Rage acceleration). 48 | 49 | ## How to Compile 50 | 51 | You need to install development tools first. 52 | 53 | At least, a C++20 compliant compiler and [CMake](https://cmake.org) are required. 54 | 55 | You will also have to recursive clone or run 56 | ``` 57 | git submodule update --init --recursive 58 | ``` 59 | 60 | This is because the CubeB, Capstone, and SDL2 modules are not included by default. 61 | 62 | For SDL2, Linux users may also have to run: 63 | 64 | ``` 65 | sudo apt install libsdl2-dev 66 | ``` 67 | 68 | CLI11 and loguru are already included in the thirdparty folder and compiled along with the rest of DingusPPC. 69 | 70 | For example, to build the project in a Unix-like environment, you will need to run 71 | the following commands in the OS terminal: 72 | ``` 73 | mkdir build 74 | cd build 75 | cmake -DCMAKE_BUILD_TYPE=Release .. 76 | make dingusppc 77 | ``` 78 | You may specify another build type using the variable CMAKE_BUILD_TYPE. 79 | 80 | For Raspbian, you may also need the following command: 81 | ``` 82 | sudo apt install doxygen graphviz 83 | ``` 84 | 85 | ## Testing 86 | 87 | DingusPPC includes a test suite for verifying the correctness of its PowerPC CPU 88 | emulation. To build the tests, use the following terminal commands: 89 | ``` 90 | mkdir build 91 | cd build 92 | cmake -DCMAKE_BUILD_TYPE=Release -DDPPC_BUILD_PPC_TESTS=True .. 93 | make testppc 94 | ``` 95 | 96 | ## Intended Minimum Requirements 97 | 98 | - Windows 7 or newer (64-bit), Linux 4.4 or newer, Mac OS X 10.9 or newer (64-bit) 99 | - Intel Core 2 Duo or better 100 | - 2 GB of RAM 101 | - 2 GB of Hard Disk Space 102 | - Graphics Card with a minimum resolution of 800*600 103 | 104 | ## Compiler Requirements 105 | 106 | - Any C++20 compatible compiler 107 | -------------------------------------------------------------------------------- /cmake/PlatformGlob.cmake: -------------------------------------------------------------------------------- 1 | # Detect platform suffix 2 | if (EMSCRIPTEN) 3 | set(PLATFORM_SUFFIX "_js$") 4 | else() 5 | set(PLATFORM_SUFFIX "_sdl|_cubeb$") 6 | endif() 7 | 8 | # Function to perform a platform-specific glob 9 | function(platform_glob RESULT_VAR) 10 | set(PLATFORM_SOURCES) 11 | foreach(GLOB_PATTERN ${ARGN}) 12 | file(GLOB GLOB_RESULT ${GLOB_PATTERN}) 13 | foreach(FILE_PATH ${GLOB_RESULT}) 14 | get_filename_component(BASE_NAME ${FILE_PATH} NAME_WE) 15 | if("${BASE_NAME}" MATCHES ${PLATFORM_SUFFIX} OR NOT "${BASE_NAME}" MATCHES "_js$|_sdl|_cubeb$") 16 | list(APPEND PLATFORM_SOURCES ${FILE_PATH}) 17 | endif() 18 | endforeach() 19 | endforeach() 20 | set(${RESULT_VAR} ${PLATFORM_SOURCES} PARENT_SCOPE) 21 | endfunction() 22 | -------------------------------------------------------------------------------- /core/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories("${PROJECT_SOURCE_DIR}" 2 | "${PROJECT_SOURCE_DIR}/thirdparty/loguru/" 3 | ) 4 | 5 | platform_glob(SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") 6 | 7 | add_library(core OBJECT ${SOURCES}) 8 | if (EMSCRIPTEN) 9 | target_link_libraries(core PRIVATE) 10 | else() 11 | target_link_libraries(core PRIVATE SDL2::SDL2) 12 | endif() 13 | -------------------------------------------------------------------------------- /core/bitops.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-25 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** Non-standard low-level bitwise operations. */ 23 | 24 | #ifndef BIT_OPS_H 25 | #define BIT_OPS_H 26 | 27 | #include 28 | 29 | #if defined(__GNUG__) && !defined(__clang__) && (defined(__x86_64__) || defined(__i386__)) // GCC, mybe ICC but not Clang 30 | 31 | # include 32 | 33 | # define ROTL_32(x, n) (_rotl((x), (n))) 34 | # define ROTR_32(x, n) (_rotr((x), (n))) 35 | 36 | #elif defined(_MSC_VER) // MSVC 37 | 38 | # include 39 | 40 | # define ROTL_32(x, n) (_rotl((x), (n))) 41 | # define ROTR_32(x, n) (_rotr((x), (n))) 42 | 43 | #else 44 | 45 | // cyclic rotation idioms that modern compilers will 46 | // recognize and generate very compact code for 47 | // involving specific machine instructions 48 | 49 | inline unsigned ROTL_32(unsigned x, unsigned n) { 50 | n &= 0x1F; 51 | if (n) 52 | return (x << n) | (x >> (32 - n)); 53 | return x; 54 | } 55 | 56 | inline unsigned ROTR_32(unsigned x, unsigned n) { 57 | n &= 0x1F; 58 | if (n) 59 | return (x >> n) | (x << (32 - n)); 60 | return x; 61 | } 62 | 63 | #endif 64 | 65 | template 66 | inline T extract_bits(T val, int pos, int len) { 67 | return (val >> pos) & ((len == sizeof(T) * 8) ? (T)-1 : ((T)1 << len) - 1); 68 | } 69 | 70 | template 71 | inline void insert_bits(T &old_val, T new_val, int pos, int len) { 72 | T mask = ((len == sizeof(T) * 8) ? (T)-1 : ((T)1 << len) - 1) << pos; 73 | old_val = (old_val & ~mask) | ((new_val << pos) & mask); 74 | } 75 | 76 | /* Return true if the specified bit is different in the given numbers. */ 77 | static inline bool bit_changed(uint64_t old_val, uint64_t new_val, int bit_num) { 78 | return (old_val ^ new_val) & (1ULL << bit_num); 79 | } 80 | 81 | static inline bool bit_set(const uint64_t val, const int bit_num) { 82 | return !!(val & (1ULL << bit_num)); 83 | } 84 | 85 | template 86 | inline void clear_bit(T &val, const int bit_num) { 87 | val &= ~((T)1 << bit_num); 88 | } 89 | 90 | template 91 | inline void set_bit(T &val, const int bit_num) { 92 | val |= ((T)1 << bit_num); 93 | } 94 | 95 | static inline uint32_t extract_with_wrap_around(uint32_t val, int pos, int size) { 96 | return (uint32_t)((((uint64_t)val << 32) | val) >> ((8 - (pos & 3) - size) << 3)) & 97 | ((1LL << (size << 3)) - 1); 98 | } 99 | 100 | #endif // BIT_OPS_H 101 | -------------------------------------------------------------------------------- /core/coresignal.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** Poor man's signals & slots mechanism implementation. */ 23 | 24 | // Inspired by http://schneegans.github.io/tutorials/2015/09/20/signal-slot 25 | 26 | #ifndef CORE_SIGNAL_H 27 | #define CORE_SIGNAL_H 28 | 29 | #include 30 | #include 31 | 32 | template 33 | class CoreSignal { 34 | public: 35 | CoreSignal() = default; 36 | ~CoreSignal() = default; 37 | 38 | // Connects a std::function type slot to the signal. 39 | // The return value can be used to disconnect the slot. 40 | int connect_func(std::function const& slot) const { 41 | _slots.insert(std::make_pair(++_current_id, slot)); 42 | return _current_id; 43 | } 44 | 45 | // Connects a class method type slot to the signal. 46 | // The return value can be used to disconnect the slot. 47 | template 48 | int connect_method(T *inst, void (T::*func)(Args...)) { 49 | return connect_func([=](Args... args) { 50 | (inst->*func)(args...); 51 | }); 52 | } 53 | 54 | // Calls all connected slots. 55 | void emit(Args... args) { 56 | if (!_is_enabled) { 57 | return; 58 | } 59 | for (auto const& it : _slots) { 60 | it.second(args...); 61 | } 62 | } 63 | 64 | void disconnect(int id) { 65 | _slots.erase(id); 66 | } 67 | 68 | void disconnect_all() { 69 | _slots.clear(); 70 | } 71 | 72 | void disable() { 73 | _is_enabled = false; 74 | } 75 | 76 | void enable() { 77 | _is_enabled = true; 78 | } 79 | 80 | bool is_enabled() { 81 | return _is_enabled; 82 | } 83 | 84 | private: 85 | mutable std::map> _slots; 86 | mutable unsigned int _current_id { 0 }; 87 | mutable bool _is_enabled { true }; 88 | }; 89 | 90 | #endif // CORE_SIGNAL_H 91 | -------------------------------------------------------------------------------- /core/mathutils.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-22 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | #include 23 | 24 | #ifndef MATH_UTILS_H 25 | #define MATH_UTILS_H 26 | 27 | inline void _u32xu64(uint32_t a, uint64_t b, uint32_t &hi, uint64_t &lo) 28 | { 29 | uint64_t p0 = (b & 0xffffffff) * a; 30 | uint64_t p1 = (b >> 32) * a; 31 | lo = p0 + (p1 << 32); 32 | hi = (p1 >> 32) + (lo < p0); 33 | } 34 | 35 | inline void _u32xu64(uint32_t a, uint64_t b, uint64_t &hi, uint32_t &lo) 36 | { 37 | uint64_t p0 = (b & 0xffffffff) * a; 38 | uint64_t p1 = (b >> 32) * a; 39 | lo = (uint32_t)p0; 40 | hi = (p0 >> 32) + p1; 41 | } 42 | 43 | inline void _u64xu64(uint64_t a, uint64_t b, uint64_t &hi, uint64_t &lo) 44 | { 45 | uint32_t p0h; uint64_t p0l; _u32xu64((uint32_t)b, a, p0h, p0l); 46 | uint64_t p1h; uint32_t p1l; _u32xu64(b >> 32, a, p1h, p1l); 47 | lo = p0l + ((uint64_t)p1l << 32); 48 | hi = p0h + p1h + (lo < p0l); 49 | } 50 | 51 | #endif // MATH_UTILS_H 52 | -------------------------------------------------------------------------------- /cpu/ppc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories("${PROJECT_SOURCE_DIR}" 2 | "${PROJECT_SOURCE_DIR}/thirdparty/loguru/") 3 | 4 | file(GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" 5 | "${CMAKE_CURRENT_SOURCE_DIR}/*.h" 6 | ) 7 | 8 | # The use of volatile is deprecated, but we still need it to avoid function 9 | # parameters being clobbered when using setjmp/longjmp. 10 | if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") 11 | add_compile_options(-Wno-deprecated-volatile) 12 | endif() 13 | 14 | add_library(cpu_ppc OBJECT ${SOURCES}) 15 | -------------------------------------------------------------------------------- /cpu/ppc/ppcdisasm.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-21 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | #ifndef PPCDISASM_H 23 | #define PPCDISASM_H 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | typedef struct PPCDisasmContext { 30 | uint32_t instr_addr; 31 | uint32_t instr_code; 32 | std::string instr_str; 33 | bool simplified; /* true if we should output simplified mnemonics */ 34 | std::vector regs_in; 35 | std::vector regs_out; 36 | } PPCDisasmContext; 37 | 38 | std::string disassemble_single(PPCDisasmContext* ctx); 39 | 40 | int test_ppc_disasm(void); 41 | 42 | /** sign-extend an integer. */ 43 | #define SIGNEXT(x, sb) ((x) | (((x) & (1 << (sb))) ? ~((1 << (sb)) - 1) : 0)) 44 | 45 | #endif /* PPCDISASM_H */ 46 | -------------------------------------------------------------------------------- /cpu/ppc/test/testdisasm.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-21 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | #include "../ppcdisasm.h" 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | using namespace std; 31 | 32 | /** testing vehicle */ 33 | static vector read_test_data() { 34 | string line, token; 35 | int i, lineno; 36 | PPCDisasmContext ctx; 37 | vector tstvec; 38 | 39 | ifstream tfstream("ppcdisasmtest.csv"); 40 | if (!tfstream.is_open()) { 41 | cout << "Could not open tests CSV file. Exiting..." << endl; 42 | return tstvec; 43 | } 44 | 45 | lineno = 0; 46 | 47 | while (getline(tfstream, line)) { 48 | lineno++; 49 | 50 | if (line.empty() || !line.rfind("#", 0)) 51 | continue; // skip empty/comment lines 52 | 53 | istringstream lnstream(line); 54 | 55 | vector tokens; 56 | 57 | while (getline(lnstream, token, ',')) { 58 | // cout << "Token: " << token << endl; 59 | tokens.push_back(token); 60 | } 61 | 62 | if (tokens.size() < 3) { 63 | cout << "Too few values in line " << lineno << ". Skipping..." << endl; 64 | continue; 65 | } 66 | 67 | ctx = {0}; 68 | ctx.instr_addr = (uint32_t)stoul(tokens[0], NULL, 16); 69 | ctx.instr_code = (uint32_t)stoul(tokens[1], NULL, 16); 70 | 71 | /* build disassembly string out of comma-separated parts */ 72 | ostringstream idisasm; 73 | 74 | /* put instruction mnemonic padded with trailing spaces */ 75 | idisasm << tokens[2]; 76 | idisasm << setw(streamsize(8) - (int)tokens[2].length()) << " "; 77 | 78 | /* now add comma-separated operands */ 79 | for (i = 3; i < tokens.size(); i++) { 80 | if (i > 3) 81 | idisasm << ", "; 82 | idisasm << tokens[i]; 83 | } 84 | 85 | ctx.instr_str = idisasm.str(); 86 | 87 | // cout << idisasm.str() << endl; 88 | 89 | tstvec.push_back(ctx); 90 | } 91 | 92 | return tstvec; 93 | } 94 | 95 | int test_ppc_disasm() { 96 | int i, nfailed; 97 | PPCDisasmContext ctx; 98 | 99 | vector testdata = read_test_data(); 100 | 101 | cout << "Imported " << testdata.size() << " test instructions." << endl; 102 | 103 | nfailed = 0; 104 | 105 | for (i = 0; i < testdata.size(); i++) { 106 | ctx = {0}; 107 | ctx.instr_addr = testdata[i].instr_addr; 108 | ctx.instr_code = testdata[i].instr_code; 109 | ctx.simplified = true; 110 | 111 | std::string disas = disassemble_single(&ctx); 112 | 113 | if (disas != testdata[i].instr_str) { 114 | cout << "Mismatch found, expected={" << testdata[i].instr_str << "}, got={" << disas 115 | << "}" << endl; 116 | nfailed++; 117 | } 118 | } 119 | 120 | cout << "Tested " << testdata.size() << " instructions. Failed: " << nfailed << "." << endl; 121 | 122 | return 0; 123 | } 124 | -------------------------------------------------------------------------------- /debugger/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories("${PROJECT_SOURCE_DIR}" 2 | "${PROJECT_SOURCE_DIR}/thirdparty/loguru/" 3 | "${PROJECT_SOURCE_DIR}/thirdparty/capstone/include") 4 | 5 | file(GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/*.h") 7 | 8 | add_library(debugger OBJECT ${SOURCES}) 9 | -------------------------------------------------------------------------------- /debugger/debugger.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-21 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | #ifndef DEBUGGER_H_ 23 | #define DEBUGGER_H_ 24 | 25 | #include 26 | 27 | class DppcDebugger { 28 | public: 29 | static DppcDebugger* get_instance() { 30 | if (!debugger_obj) { 31 | debugger_obj = std::unique_ptr(new DppcDebugger()); 32 | } 33 | return debugger_obj.get(); 34 | }; 35 | 36 | void enter_debugger(); 37 | 38 | private: 39 | inline static std::unique_ptr debugger_obj{nullptr}; 40 | explicit DppcDebugger(); // private constructor to implement a singleton 41 | }; 42 | 43 | #endif // DEBUGGER_H_ 44 | -------------------------------------------------------------------------------- /devices/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") 2 | include(PlatformGlob) 3 | 4 | include_directories("${PROJECT_SOURCE_DIR}" 5 | "${PROJECT_SOURCE_DIR}/thirdparty/loguru/" 6 | ) 7 | 8 | platform_glob(SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" 9 | "${CMAKE_CURRENT_SOURCE_DIR}/common/*.cpp" 10 | "${CMAKE_CURRENT_SOURCE_DIR}/common/adb/*.cpp" 11 | "${CMAKE_CURRENT_SOURCE_DIR}/common/ata/*.cpp" 12 | "${CMAKE_CURRENT_SOURCE_DIR}/common/clockgen/*.cpp" 13 | "${CMAKE_CURRENT_SOURCE_DIR}/common/firewire/*.cpp" 14 | "${CMAKE_CURRENT_SOURCE_DIR}/common/i2c/*.cpp" 15 | "${CMAKE_CURRENT_SOURCE_DIR}/common/nubus/*.cpp" 16 | "${CMAKE_CURRENT_SOURCE_DIR}/common/pci/*.cpp" 17 | "${CMAKE_CURRENT_SOURCE_DIR}/common/scsi/*.cpp" 18 | "${CMAKE_CURRENT_SOURCE_DIR}/common/usb/*.cpp" 19 | "${CMAKE_CURRENT_SOURCE_DIR}/ethernet/*.cpp" 20 | "${CMAKE_CURRENT_SOURCE_DIR}/floppy/*.cpp" 21 | "${CMAKE_CURRENT_SOURCE_DIR}/ioctrl/*.cpp" 22 | "${CMAKE_CURRENT_SOURCE_DIR}/memctrl/*.cpp" 23 | "${CMAKE_CURRENT_SOURCE_DIR}/serial/*.cpp" 24 | "${CMAKE_CURRENT_SOURCE_DIR}/sound/*.cpp" 25 | "${CMAKE_CURRENT_SOURCE_DIR}/storage/*.cpp" 26 | "${CMAKE_CURRENT_SOURCE_DIR}/video/*.cpp" 27 | "${CMAKE_CURRENT_SOURCE_DIR}/common/*.h" 28 | "${CMAKE_CURRENT_SOURCE_DIR}/common/adb/*.h" 29 | "${CMAKE_CURRENT_SOURCE_DIR}/common/ata/*.h" 30 | "${CMAKE_CURRENT_SOURCE_DIR}/common/i2c/*.h" 31 | "${CMAKE_CURRENT_SOURCE_DIR}/common/pci/*.h" 32 | "${CMAKE_CURRENT_SOURCE_DIR}/common/scsi/*.h" 33 | "${CMAKE_CURRENT_SOURCE_DIR}/ethernet/*.h" 34 | "${CMAKE_CURRENT_SOURCE_DIR}/floppy/*.h" 35 | "${CMAKE_CURRENT_SOURCE_DIR}/ioctrl/*.h" 36 | "${CMAKE_CURRENT_SOURCE_DIR}/memctrl/*.h" 37 | "${CMAKE_CURRENT_SOURCE_DIR}/serial/*.h" 38 | "${CMAKE_CURRENT_SOURCE_DIR}/sound/*.h" 39 | "${CMAKE_CURRENT_SOURCE_DIR}/storage/*.h" 40 | "${CMAKE_CURRENT_SOURCE_DIR}/video/*.h" 41 | ) 42 | 43 | add_library(devices OBJECT ${SOURCES}) 44 | if (EMSCRIPTEN) 45 | target_link_libraries(devices PRIVATE) 46 | else() 47 | target_link_libraries(devices PRIVATE cubeb SDL2::SDL2) 48 | endif() 49 | -------------------------------------------------------------------------------- /devices/common/adb/adbapplejack.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-24 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Apple Desktop Bus AppleJack controller emulation. */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | AdbAppleJack::AdbAppleJack(std::string name) : AdbMouse(name, AdbMouse::TRACKBALL, 2, 7, 300) { 31 | EventManager::get_instance()->add_gamepad_handler(this, &AdbAppleJack::event_handler); 32 | } 33 | 34 | void AdbAppleJack::event_handler(const GamepadEvent& event) { 35 | uint32_t button_bit = 1 << event.button; 36 | 37 | if (event.flags & GAMEPAD_EVENT_DOWN) 38 | this->buttons_state |= button_bit; 39 | else if (event.flags & GAMEPAD_EVENT_UP) 40 | this->buttons_state &= ~button_bit; 41 | 42 | if (button_bit & ((1 << GamepadButton::LeftTrigger) | (1 << GamepadButton::RightTrigger))) 43 | this->triggers_changed = true; 44 | else 45 | this->buttons_changed = true; 46 | } 47 | 48 | void AdbAppleJack::reset() { 49 | this->AdbMouse::reset(); 50 | this->buttons_state = 0; 51 | this->triggers_changed = false; 52 | this->buttons_changed = false; 53 | LOG_F(INFO, "%s: reset; in mouse emulation mode", this->name.c_str()); 54 | } 55 | 56 | bool AdbAppleJack::get_register_0() { 57 | bool changed = this->triggers_changed || this->buttons_changed; 58 | 59 | uint8_t mouse_buttons = this->AdbMouse::get_buttons_state(); 60 | // AppleJack triggers always affect the mouse button bits. 61 | mouse_buttons |= (this->buttons_state >> (GamepadButton::LeftTrigger - 0)) & 1; 62 | mouse_buttons |= (this->buttons_state >> (GamepadButton::RightTrigger - 1)) & 2; 63 | changed |= this->AdbMouse::get_register_0(mouse_buttons, changed); 64 | this->triggers_changed = false; 65 | 66 | if (this->dev_handler_id == APPLEJACK_HANDLER_ID && this->buttons_changed) { 67 | uint8_t* out_buf = this->host_obj->get_output_buf(); 68 | 69 | out_buf[2] = ~this->buttons_state >> 8; 70 | out_buf[3] = ~this->buttons_state & 0xFF; 71 | 72 | this->host_obj->set_output_count(4); 73 | this->buttons_changed = false; 74 | } 75 | 76 | return changed; 77 | } 78 | 79 | void AdbAppleJack::set_register_3() { 80 | if (this->host_obj->get_input_count() < 2) // ensure we got enough data 81 | return; 82 | 83 | const uint8_t* in_data = this->host_obj->get_input_buf(); 84 | 85 | switch (in_data[1]) { 86 | case APPLEJACK_HANDLER_ID: // switch over to AppleJack protocol 87 | this->dev_handler_id = in_data[1]; 88 | LOG_F(INFO, "%s: switched to AppleJack mode", this->name.c_str()); 89 | break; 90 | default: 91 | this->AdbMouse::set_register_3(); 92 | break; 93 | } 94 | } 95 | 96 | static const DeviceDescription AdbAppleJack_Descriptor = { 97 | AdbAppleJack::create, {}, {}, HWCompType::ADB_DEV 98 | }; 99 | 100 | REGISTER_DEVICE(AdbAppleJack, AdbAppleJack_Descriptor); 101 | -------------------------------------------------------------------------------- /devices/common/adb/adbapplejack.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-24 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Apple Desktop Bus AppleJack controller definitions. */ 23 | 24 | #ifndef ADB_APPLEJACK_H 25 | #define ADB_APPLEJACK_H 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | enum : uint8_t { 34 | APPLEJACK_HANDLER_ID = 0x46, 35 | }; 36 | 37 | class GamepadEvent; 38 | 39 | class AdbAppleJack : public AdbMouse { 40 | public: 41 | AdbAppleJack(std::string name); 42 | ~AdbAppleJack() = default; 43 | 44 | static std::unique_ptr create() { 45 | return std::unique_ptr(new AdbAppleJack("ADB-APPLEJACK")); 46 | } 47 | 48 | void reset() override; 49 | void event_handler(const GamepadEvent& event); 50 | 51 | bool get_register_0() override; 52 | void set_register_3() override; 53 | 54 | private: 55 | uint32_t buttons_state = 0; 56 | bool triggers_changed = false; 57 | bool buttons_changed = false; 58 | }; 59 | 60 | #endif // ADB_APPLEJACK_H 61 | -------------------------------------------------------------------------------- /devices/common/adb/adbbus.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Apple Desktop Bus definitions. */ 23 | 24 | #ifndef ADB_BUS_H 25 | #define ADB_BUS_H 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | constexpr auto ADB_MAX_DATA_SIZE = 8; 34 | 35 | /** ADB status. */ 36 | enum { 37 | ADB_STAT_OK = 0, 38 | ADB_STAT_SRQ_ACTIVE = 1 << 0, 39 | ADB_STAT_TIMEOUT = 1 << 1, 40 | ADB_STAT_AUTOPOLL = 1 << 6, 41 | }; 42 | 43 | class AdbDevice; // forward declaration to prevent compiler errors 44 | 45 | class AdbBus : public HWComponent { 46 | public: 47 | AdbBus(std::string name); 48 | ~AdbBus() = default; 49 | 50 | static std::unique_ptr create() { 51 | return std::unique_ptr(new AdbBus("ADB-BUS")); 52 | } 53 | 54 | int device_postinit() override; 55 | 56 | void register_device(AdbDevice* dev_obj); 57 | uint8_t process_command(const uint8_t* in_data, int data_size); 58 | uint8_t get_output_count() { return this->output_count; }; 59 | 60 | // Polls devices that have a service request flag set. Returns the talk 61 | // command corresponding to the first device that responded with data, or 62 | // 0 if no device responded. 63 | uint8_t poll(); 64 | 65 | // callbacks meant to be called by devices 66 | const uint8_t* get_input_buf() { return this->input_buf; }; 67 | uint8_t* get_output_buf() { return this->output_buf; }; 68 | uint8_t get_input_count() { return this->input_count; }; 69 | void set_output_count(uint8_t count) { this->output_count = count; }; 70 | bool already_answered() { return this->got_answer; }; 71 | 72 | private: 73 | std::vector devices; 74 | 75 | bool got_answer = false; 76 | const uint8_t* input_buf = nullptr; 77 | uint8_t output_buf[ADB_MAX_DATA_SIZE] = {}; 78 | uint8_t input_count = 0; 79 | uint8_t output_count = 0; 80 | }; 81 | 82 | #endif // ADB_BUS_H 83 | -------------------------------------------------------------------------------- /devices/common/adb/adbdevice.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Base class for Apple Desktop Bus devices. */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | AdbDevice::AdbDevice(std::string name) { 30 | this->set_name(name); 31 | this->supports_types(HWCompType::ADB_DEV); 32 | } 33 | 34 | int AdbDevice::device_postinit() { 35 | // register itself with the ADB host 36 | this->host_obj = dynamic_cast(gMachineObj->get_comp_by_type(HWCompType::ADB_HOST)); 37 | this->host_obj->register_device(this); 38 | 39 | return 0; 40 | }; 41 | 42 | uint8_t AdbDevice::poll() { 43 | if (!this->srq_flag) { 44 | return 0; 45 | } 46 | bool has_data = this->get_register_0(); 47 | if (!has_data) { 48 | return 0; 49 | } 50 | 51 | // Register 0 in bits 0-1 (both 0) 52 | // Talk command in bits 2-3 (both 1) 53 | // Device address in bits 4-7 54 | return 0xC | (this->my_addr << 4); 55 | } 56 | 57 | bool AdbDevice::talk(const uint8_t dev_addr, const uint8_t reg_num) { 58 | if (dev_addr == this->my_addr && !this->got_collision) { 59 | // see if another device already responded to this command 60 | if (this->host_obj->already_answered()) { 61 | this->got_collision = true; 62 | return false; 63 | } 64 | 65 | switch(reg_num & 3) { 66 | case 0: 67 | return this->get_register_0(); 68 | case 1: 69 | return this->get_register_1(); 70 | case 2: 71 | return this->get_register_2(); 72 | case 3: 73 | return this->get_register_3(); 74 | default: 75 | return false; 76 | } 77 | } else { 78 | return false; 79 | } 80 | } 81 | 82 | void AdbDevice::listen(const uint8_t dev_addr, const uint8_t reg_num) { 83 | if (dev_addr == this->my_addr) { 84 | switch(reg_num & 3) { 85 | case 0: 86 | this->set_register_0(); 87 | case 1: 88 | this->set_register_1(); 89 | case 2: 90 | this->set_register_2(); 91 | case 3: 92 | this->set_register_3(); 93 | } 94 | } 95 | } 96 | 97 | bool AdbDevice::get_register_3() { 98 | uint8_t* out_buf = this->host_obj->get_output_buf(); 99 | out_buf[0] = this->gen_random_address() | (this->exc_event_flag << 6) | 100 | (this->srq_flag << 5); 101 | out_buf[1] = this->dev_handler_id; 102 | this->host_obj->set_output_count(2); 103 | return true; 104 | } 105 | 106 | uint8_t AdbDevice::gen_random_address() { 107 | return (TimerManager::get_instance()->current_time_ns() + 8) & 0xF; 108 | } 109 | -------------------------------------------------------------------------------- /devices/common/adb/adbdevice.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Base class for Apple Desktop Bus devices. */ 23 | 24 | #ifndef ADB_DEVICE_H 25 | #define ADB_DEVICE_H 26 | 27 | #include 28 | 29 | #include 30 | 31 | /** Common ADB device addresses/types. */ 32 | enum { 33 | ADB_ADDR_KBD = 2, // keyboards 34 | ADB_ADDR_RELPOS = 3, // relative position devices (mouse) 35 | ADB_ADDR_ABSPOS = 4, // absolute position devices (graphic tablets) 36 | }; 37 | 38 | class AdbBus; // forward declaration to prevent compiler errors 39 | 40 | class AdbDevice : public HWComponent { 41 | public: 42 | AdbDevice(std::string name); 43 | ~AdbDevice() = default; 44 | 45 | int device_postinit() override; 46 | 47 | virtual void reset() = 0; 48 | virtual bool talk(const uint8_t dev_addr, const uint8_t reg_num); 49 | virtual void listen(const uint8_t dev_addr, const uint8_t reg_num); 50 | virtual uint8_t get_address() { return this->my_addr; }; 51 | 52 | // Attempts to poll the device. Returns the talk command corresponding to 53 | // the device if it has data, 0 otherwise. 54 | uint8_t poll(); 55 | 56 | protected: 57 | uint8_t gen_random_address(); 58 | 59 | virtual bool get_register_0() { return false; }; 60 | virtual bool get_register_1() { return false; }; 61 | virtual bool get_register_2() { return false; }; 62 | virtual bool get_register_3(); 63 | 64 | virtual void set_register_0() {}; 65 | virtual void set_register_1() {}; 66 | virtual void set_register_2() {}; 67 | virtual void set_register_3() {}; 68 | 69 | uint8_t exc_event_flag = 0; 70 | uint8_t srq_flag = 0; 71 | uint8_t my_addr = 0; 72 | uint8_t dev_handler_id = 0; 73 | bool got_collision = false; 74 | 75 | AdbBus* host_obj = nullptr; 76 | }; 77 | 78 | #endif // ADB_DEVICE_H 79 | -------------------------------------------------------------------------------- /devices/common/adb/adbmouse.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Apple Desktop Bus Mouse definitions. */ 23 | 24 | #ifndef ADB_MOUSE_H 25 | #define ADB_MOUSE_H 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | //#define ABSOLUTE 34 | 35 | class MouseEvent; 36 | 37 | class AdbMouse : public AdbDevice { 38 | public: 39 | enum DeviceClass { 40 | TABLET = 0, 41 | MOUSE = 1, 42 | TRACKBALL = 2, 43 | }; 44 | 45 | AdbMouse( 46 | std::string name, uint8_t device_class, int num_buttons, int num_bits, uint16_t resolution); 47 | ~AdbMouse() = default; 48 | 49 | static std::unique_ptr create() { 50 | #ifdef ABSOLUTE 51 | uint8_t device_class = TABLET; 52 | int num_buttons = 3; 53 | int num_bits = 16; 54 | uint16_t resolution = 72; 55 | #else 56 | uint8_t device_class = MOUSE; 57 | int num_buttons = 3; 58 | int num_bits = 10; 59 | uint16_t resolution = 300; 60 | #endif 61 | return std::unique_ptr( 62 | new AdbMouse("ADB-MOUSE", device_class, num_buttons, num_bits, resolution)); 63 | } 64 | 65 | void reset() override; 66 | void event_handler(const MouseEvent& event); 67 | 68 | bool get_register_0() override; 69 | bool get_register_1() override; 70 | void set_register_3() override; 71 | 72 | protected: 73 | bool get_register_0(uint8_t buttons_state, bool force); 74 | uint8_t get_buttons_state() const; 75 | 76 | private: 77 | int32_t x_rel = 0; 78 | int32_t y_rel = 0; 79 | int32_t x_abs = 0; 80 | int32_t y_abs = 0; 81 | uint8_t buttons_state = 0; 82 | bool changed = false; 83 | uint8_t device_class; 84 | int num_buttons; 85 | int num_bits; 86 | uint16_t resolution; 87 | }; 88 | 89 | #endif // ADB_MOUSE_H 90 | -------------------------------------------------------------------------------- /devices/common/ata/atabasedevice.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Base class for ATA devices. */ 23 | 24 | #ifndef ATA_BASE_DEVICE_H 25 | #define ATA_BASE_DEVICE_H 26 | 27 | #include 28 | #include 29 | #include "endianswap.h" 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | class IdeChannel; 36 | 37 | class AtaBaseDevice : public HWComponent, public AtaInterface 38 | { 39 | public: 40 | AtaBaseDevice(const std::string name, uint8_t type); 41 | ~AtaBaseDevice() = default; 42 | 43 | void set_host(IdeChannel* host, uint8_t dev_id) { 44 | this->host_obj = host; 45 | this->my_dev_id = dev_id; 46 | }; 47 | 48 | uint16_t read(const uint8_t reg_addr) override; 49 | void write(const uint8_t reg_addr, const uint16_t value) override; 50 | 51 | virtual int perform_command() = 0; 52 | 53 | int get_device_id() override { return this->my_dev_id; } 54 | 55 | void pdiag_callback() override { 56 | this->r_error &= 0x7F; 57 | }; 58 | 59 | virtual void device_reset(bool is_soft_reset); 60 | virtual void device_set_signature(); 61 | void device_control(const uint8_t new_ctrl); 62 | void update_intrq(uint8_t new_intrq_state); 63 | void signal_data_ready(); 64 | 65 | bool has_data() const { 66 | return data_ptr && xfer_cnt; 67 | } 68 | 69 | uint16_t get_data() { 70 | return BYTESWAP_16(*this->data_ptr++); 71 | } 72 | 73 | protected: 74 | bool is_selected() const { 75 | return ((this->r_dev_head >> 4) & 1) == this->my_dev_id; 76 | } 77 | 78 | void prepare_xfer(int xfer_size, int block_size); 79 | 80 | uint8_t my_dev_id = 0; // my IDE device ID configured by the host 81 | uint8_t device_type = ata_interface::DEVICE_TYPE_UNKNOWN; 82 | uint8_t intrq_state = 0; // INTRQ deasserted 83 | 84 | IdeChannel* host_obj = nullptr; 85 | 86 | // IDE aka task file registers 87 | uint8_t r_error = 0; 88 | uint8_t r_features; 89 | uint8_t r_sect_count; 90 | uint8_t r_sect_num; 91 | uint8_t r_cylinder_lo; 92 | uint8_t r_cylinder_hi; 93 | uint8_t r_dev_head; 94 | uint8_t r_command; 95 | uint8_t r_status; 96 | uint8_t r_status_save; 97 | uint8_t r_dev_ctrl = 0x08 | ata_interface::ATA_CTRL::IEN; // disable interrupts 98 | 99 | uint16_t *data_ptr = nullptr; 100 | uint16_t *cur_data_ptr = nullptr; 101 | alignas(uint16_t) 102 | uint8_t data_buf[512] = {}; 103 | int xfer_cnt = 0; 104 | int chunk_cnt = 0; 105 | int chunk_size = 0; 106 | 107 | std::function post_xfer_action = nullptr; 108 | }; 109 | 110 | #endif // ATA_BASE_DEVICE_H 111 | -------------------------------------------------------------------------------- /devices/common/ata/atahd.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-24 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file ATA hard disk definitions. */ 23 | 24 | #ifndef ATA_HARD_DISK_H 25 | #define ATA_HARD_DISK_H 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | constexpr auto ATA_HD_SEC_SIZE = 512; 33 | constexpr auto SECTORS_PER_INT = 16; 34 | 35 | // C:16383 x H:16 x S:63 = C:1032 x H:254 x S:63 = 8063.5078125 MiB = 8.46 GB 36 | constexpr auto ATA_BIOS_LIMIT = 16514064; 37 | // C:65535 x H:16 x S:255 = 127.498 GiB = 136.900 GB = largest identify 38 | constexpr auto REAL_CHS_LIMIT = 267382800; 39 | // C:65536 x H:16 x S:255 = 127.500 GiB = 136.902 GB = largest address 40 | constexpr auto CHS_LIMIT = 267386880; 41 | 42 | class AtaHardDisk : public AtaBaseDevice 43 | { 44 | public: 45 | AtaHardDisk(std::string name); 46 | ~AtaHardDisk() = default; 47 | 48 | static std::unique_ptr create() { 49 | return std::unique_ptr(new AtaHardDisk("ATA-HD")); 50 | } 51 | 52 | int device_postinit() override; 53 | 54 | void insert_image(std::string filename); 55 | int perform_command() override; 56 | 57 | protected: 58 | void prepare_identify_info(); 59 | uint64_t get_lba(); 60 | void calc_chs_params(); 61 | 62 | private: 63 | ImgFile hdd_img; 64 | uint64_t img_size = 0; 65 | uint32_t total_sectors = 0; 66 | uint64_t cur_fpos = 0; 67 | 68 | // fictive disk geometry for CHS-to-LBA translation 69 | uint16_t cylinders; 70 | uint8_t heads; 71 | uint8_t sectors; 72 | 73 | uint8_t sectors_per_int = 0; // sectors per interrupt for READ_MULTIPLE/WRITE_MULTIPLE 74 | 75 | char * buffer = new char[1 <<17]; 76 | }; 77 | 78 | #endif // ATA_HARD_DISK_H 79 | -------------------------------------------------------------------------------- /devices/common/ata/atapibasedevice.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Base class for ATAPI devices. */ 23 | 24 | #ifndef ATAPI_BASE_DEVICE_H 25 | #define ATAPI_BASE_DEVICE_H 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | class AtapiBaseDevice : public AtaBaseDevice 33 | { 34 | public: 35 | AtapiBaseDevice(const std::string name); 36 | ~AtapiBaseDevice() = default; 37 | 38 | void device_set_signature() override; 39 | 40 | uint16_t read(const uint8_t reg_addr) override; 41 | void write(const uint8_t reg_addr, const uint16_t value) override; 42 | 43 | // methods to be implemented in the particular device 44 | int perform_command() override; 45 | virtual void perform_packet_command() = 0; 46 | virtual int request_data() = 0; 47 | virtual bool data_available() = 0; 48 | 49 | // methods with default implementation 50 | virtual void data_out_phase(); 51 | virtual void present_status(); 52 | 53 | protected: 54 | uint8_t r_int_reason; 55 | uint16_t r_byte_count; 56 | bool status_expected = false; 57 | 58 | alignas(uint16_t) 59 | uint8_t cmd_pkt[12] = {}; 60 | }; 61 | 62 | #endif // ATAPI_BASE_DEVICE_H 63 | -------------------------------------------------------------------------------- /devices/common/ata/atapicdrom.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file ATAPI CDROM definitions. */ 23 | 24 | #ifndef ATAPI_CDROM_H 25 | #define ATAPI_CDROM_H 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | class AtapiCdrom : public CdromDrive, public AtapiBaseDevice { 33 | public: 34 | AtapiCdrom(std::string name); 35 | ~AtapiCdrom() = default; 36 | 37 | static std::unique_ptr create() { 38 | return std::unique_ptr(new AtapiCdrom("ATAPI-CDROM")); 39 | } 40 | 41 | int device_postinit() override; 42 | 43 | void perform_packet_command() override; 44 | 45 | int request_data() override; 46 | 47 | bool data_available() override { 48 | return this->data_left() != 0; 49 | } 50 | 51 | void status_good(); 52 | void status_error(uint8_t sense_key, uint8_t asc); 53 | 54 | uint16_t get_data(); 55 | private: 56 | uint8_t sense_key = 0; 57 | uint8_t asc = 0; 58 | uint8_t ascq = 0; 59 | 60 | bool doing_sector_areas = false; 61 | uint8_t sector_areas; 62 | uint32_t current_block; 63 | uint16_t current_block_byte; 64 | }; 65 | 66 | #endif // ATAPI_CDROM_H 67 | -------------------------------------------------------------------------------- /devices/common/ata/idechannel.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-24 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file IDE Channel (aka IDE port) definitions. */ 23 | 24 | #ifndef IDE_CHANNEL_H 25 | #define IDE_CHANNEL_H 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | class IdeChannel : public HWComponent 37 | { 38 | public: 39 | IdeChannel(const std::string name); 40 | ~IdeChannel() = default; 41 | 42 | void register_device(int id, AtaInterface* dev_obj); 43 | 44 | uint32_t read(const uint8_t reg_addr, const int size); 45 | void write(const uint8_t reg_addr, const uint32_t val, const int size); 46 | 47 | void assert_pdiag() { 48 | this->devices[0]->pdiag_callback(); 49 | } 50 | 51 | bool is_device1_present() { 52 | return this->devices[1]->get_device_id() != ata_interface::DEVICE_ID_INVALID; 53 | } 54 | 55 | void set_irq_callback(std::function cb) { 56 | this->irq_callback = cb; 57 | } 58 | 59 | void report_intrq(uint8_t intrq_state) { 60 | this->irq_callback(intrq_state); 61 | } 62 | 63 | protected: 64 | std::function irq_callback = nullptr; 65 | 66 | private: 67 | int cur_dev = 0; 68 | AtaInterface* devices[2]; 69 | 70 | std::unique_ptr device_stub; 71 | }; 72 | 73 | /** This class models an IDE channel specific to MacIO ASICs. */ 74 | class MacioIdeChannel : public IdeChannel 75 | { 76 | public: 77 | MacioIdeChannel(const std::string name) : IdeChannel(name) {}; 78 | ~MacioIdeChannel() = default; 79 | 80 | static std::unique_ptr create_first() { 81 | return std::unique_ptr(new MacioIdeChannel("IDE0")); 82 | } 83 | 84 | static std::unique_ptr create_second() { 85 | return std::unique_ptr(new MacioIdeChannel("IDE1")); 86 | } 87 | 88 | int device_postinit() override; 89 | 90 | uint32_t read(const uint8_t reg_addr, const int size); 91 | void write(const uint8_t reg_addr, const uint32_t val, const int size); 92 | 93 | private: 94 | uint32_t ch_config = 0; // timing configuration for this channel 95 | 96 | // interrupt stuff 97 | InterruptCtrl* int_ctrl = nullptr; 98 | uint64_t irq_id = 0; 99 | }; 100 | 101 | #endif // IDE_CHANNEL_H 102 | -------------------------------------------------------------------------------- /devices/common/clockgen/athens.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-24 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Athens clock generator definitions. */ 23 | 24 | #ifndef ATHENS_H 25 | #define ATHENS_H 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | constexpr auto ATHENS_NUM_REGS = 8; 33 | 34 | /** Default external crystal oscillator frequency. */ 35 | constexpr auto ATHENS_XTAL = 31334400.0f; 36 | 37 | namespace AthensRegs { 38 | 39 | enum AthensRegs: uint8_t { 40 | ID = 0, 41 | D2 = 1, 42 | N2 = 2, 43 | P2_MUX2 = 3, 44 | VN_CTRL = 4, // vendor specific control bits 45 | BD1 = 5, 46 | BN1 = 6, 47 | P1 = 7 48 | }; 49 | 50 | }; // namespace AthensRegs 51 | 52 | class AthensClocks : public I2CDevice, public HWComponent 53 | { 54 | public: 55 | AthensClocks(uint8_t dev_addr); 56 | AthensClocks(uint8_t dev_addr, const float crystal_freq); 57 | ~AthensClocks() = default; 58 | 59 | // I2CDevice methods 60 | void start_transaction(); 61 | bool send_subaddress(uint8_t sub_addr); 62 | bool send_byte(uint8_t data); 63 | bool receive_byte(uint8_t* p_data); 64 | 65 | // methods for querying virtual frequences 66 | int get_sys_freq(); 67 | int get_dot_freq(); 68 | 69 | private: 70 | uint8_t my_addr = 0; 71 | uint8_t reg_num = 0; 72 | int pos = 0; 73 | float xtal_freq = ATHENS_XTAL; 74 | 75 | uint8_t regs[ATHENS_NUM_REGS] = {}; 76 | }; 77 | 78 | #endif // ATHENS_H 79 | -------------------------------------------------------------------------------- /devices/common/hwcomponent.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | #ifndef HW_COMPONENT_H 23 | #define HW_COMPONENT_H 24 | 25 | #include 26 | #include 27 | 28 | /** types of different HW components */ 29 | enum HWCompType : uint64_t { 30 | UNKNOWN = 0ULL, // unknown component type 31 | MEM_CTRL = 1ULL << 0, // memory controller 32 | NVRAM = 1ULL << 1, // non-volatile random access memory 33 | ROM = 1ULL << 2, // read-only memory 34 | RAM = 1ULL << 3, // random access memory 35 | MMIO_DEV = 1ULL << 4, // memory mapped I/O device 36 | PCI_HOST = 1ULL << 5, // PCI host 37 | PCI_DEV = 1ULL << 6, // PCI device 38 | I2C_HOST = 1ULL << 8, // I2C host 39 | I2C_DEV = 1ULL << 9, // I2C device 40 | ADB_HOST = 1ULL << 12, // ADB host 41 | ADB_DEV = 1ULL << 13, // ADB device 42 | IOBUS_HOST = 1ULL << 14, // IOBus host 43 | IOBUS_DEV = 1ULL << 15, // IOBus device 44 | INT_CTRL = 1ULL << 16, // interrupt controller 45 | SCSI_BUS = 1ULL << 20, // SCSI bus 46 | SCSI_HOST = 1ULL << 21, // SCSI host adapter 47 | SCSI_DEV = 1ULL << 22, // SCSI device 48 | IDE_BUS = 1ULL << 23, // IDE bus 49 | IDE_HOST = 1ULL << 24, // IDE host controller 50 | IDE_DEV = 1ULL << 25, // IDE device 51 | SND_CODEC = 1ULL << 30, // sound codec 52 | SND_SERVER = 1ULL << 31, // host sound server 53 | FLOPPY_CTRL = 1ULL << 32, // floppy disk controller 54 | FLOPPY_DRV = 1ULL << 33, // floppy disk drive 55 | ETHER_MAC = 1ULL << 40, // Ethernet media access controller 56 | }; 57 | 58 | /** Base class for HW components. */ 59 | class HWComponent { 60 | public: 61 | HWComponent() = default; 62 | virtual ~HWComponent() = default; 63 | 64 | virtual std::string get_name(void) { 65 | return this->name; 66 | }; 67 | virtual void set_name(std::string name) { 68 | this->name = name; 69 | }; 70 | 71 | virtual bool supports_type(HWCompType type) { 72 | return !!(this->supported_types & type); 73 | }; 74 | 75 | virtual void supports_types(uint64_t types) { 76 | this->supported_types = types; 77 | }; 78 | 79 | virtual int device_postinit() { 80 | return 0; 81 | }; 82 | 83 | protected: 84 | std::string name; 85 | uint64_t supported_types = HWCompType::UNKNOWN; 86 | }; 87 | 88 | #endif // HW_COMPONENT_H 89 | -------------------------------------------------------------------------------- /devices/common/hwinterrupt.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-24 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | #ifndef HW_INTERRUPT_H 23 | #define HW_INTERRUPT_H 24 | 25 | #include 26 | 27 | //#define DEBUG_CPU_INT // uncomment this to enable hacks for debugging HW interrupts 28 | 29 | /** Enumerator for various interrupt sources. */ 30 | enum IntSrc : uint32_t { 31 | INT_UNKNOWN = 0, 32 | VIA_CUDA, 33 | VIA2, 34 | SCSI_MESH, 35 | SCSI_CURIO, 36 | SWIM3, 37 | ESCC, 38 | SCCA, 39 | SCCB, 40 | ETHERNET, 41 | NMI, 42 | EXT1, 43 | IDE0, 44 | IDE1, 45 | DAVBUS, 46 | PERCH1, 47 | PERCH2, 48 | PCI_A, 49 | PCI_B, 50 | PCI_C, 51 | PCI_D, 52 | PCI_E, 53 | PCI_F, 54 | PCI_GPU, 55 | PCI_PERCH, 56 | BANDIT1, 57 | BANDIT2, 58 | CONTROL, 59 | SIXTY6, 60 | PLANB, 61 | VCI, 62 | PLATINUM, 63 | DMA_ALL, 64 | DMA_SCSI_MESH, 65 | DMA_SCSI_CURIO, 66 | DMA_SWIM3, 67 | DMA_IDE0, 68 | DMA_IDE1, 69 | DMA_SCCA_Tx, 70 | DMA_SCCA_Rx, 71 | DMA_SCCB_Tx, 72 | DMA_SCCB_Rx, 73 | DMA_DAVBUS_Tx, 74 | DMA_DAVBUS_Rx, 75 | DMA_ETHERNET_Tx, 76 | DMA_ETHERNET_Rx, 77 | FIREWIRE, 78 | PCI_J12, 79 | PCI_J11, 80 | PCI_J10, 81 | PCI_J9, 82 | ATA, 83 | USB, 84 | PIPPIN_E, 85 | PIPPIN_F, 86 | ZIVA, 87 | PCI_CARDBUS, 88 | MEDIA_BAY, 89 | SLOT_ALL, 90 | SLOT_0, 91 | SLOT_1, 92 | SLOT_2, 93 | SLOT_PDS, 94 | SLOT_VDS, 95 | VBL, 96 | }; 97 | 98 | /** Base class for interrupt controllers. */ 99 | class InterruptCtrl { 100 | public: 101 | InterruptCtrl() = default; 102 | virtual ~InterruptCtrl() = default; 103 | 104 | // register interrupt sources for a device 105 | virtual uint64_t register_dev_int(IntSrc src_id) = 0; 106 | virtual uint64_t register_dma_int(IntSrc src_id) = 0; 107 | 108 | // acknowledge HW interrupt 109 | virtual void ack_int(uint64_t irq_id, uint8_t irq_line_state) = 0; 110 | virtual void ack_dma_int(uint64_t irq_id, uint8_t irq_line_state) = 0; 111 | }; 112 | 113 | typedef struct { 114 | InterruptCtrl *int_ctrl_obj; 115 | uint64_t irq_id; 116 | } IntDetails; 117 | 118 | #endif // HW_INTERRUPT_H 119 | -------------------------------------------------------------------------------- /devices/common/i2c/i2c.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-24 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file I2C bus emulation. 23 | 24 | Author: Max Poliakovski 25 | */ 26 | 27 | #ifndef I2C_H 28 | #define I2C_H 29 | 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | /** Base class for I2C devices */ 38 | class I2CDevice { 39 | public: 40 | virtual void start_transaction() = 0; 41 | virtual bool send_subaddress(uint8_t sub_addr) = 0; 42 | virtual bool send_byte(uint8_t data) = 0; 43 | virtual bool receive_byte(uint8_t* p_data) = 0; 44 | }; 45 | 46 | /** Base class for I2C hosts */ 47 | class I2CBus { 48 | public: 49 | I2CBus() { 50 | std::memset(this->dev_list, 0, sizeof(this->dev_list)); 51 | }; 52 | virtual ~I2CBus() = default; 53 | 54 | virtual void register_device(uint8_t dev_addr, I2CDevice* dev_obj) { 55 | if (this->dev_list[dev_addr]) { 56 | throw std::invalid_argument(std::string("I2C address already taken!")); 57 | } 58 | this->dev_list[dev_addr] = dev_obj; 59 | LOG_F(INFO, "New I2C device, address = 0x%X", dev_addr); 60 | }; 61 | 62 | virtual bool start_transaction(uint8_t dev_addr) { 63 | if (this->dev_list[dev_addr]) { 64 | this->dev_list[dev_addr]->start_transaction(); 65 | return true; 66 | } else { 67 | return false; 68 | } 69 | }; 70 | 71 | virtual bool send_subaddress(uint8_t dev_addr, uint8_t sub_addr) { 72 | if (!this->dev_list[dev_addr]) { 73 | return false; /* no device -> no acknowledge */ 74 | } 75 | return this->dev_list[dev_addr]->send_subaddress(sub_addr); 76 | }; 77 | 78 | virtual bool send_byte(uint8_t dev_addr, uint8_t data) { 79 | if (!this->dev_list[dev_addr]) { 80 | return false; /* no device -> no acknowledge */ 81 | } 82 | return this->dev_list[dev_addr]->send_byte(data); 83 | }; 84 | 85 | virtual bool receive_byte(uint8_t dev_addr, uint8_t* p_data) { 86 | if (!this->dev_list[dev_addr]) { 87 | return false; /* no device -> no acknowledge */ 88 | } 89 | return this->dev_list[dev_addr]->receive_byte(p_data); 90 | }; 91 | 92 | protected: 93 | I2CDevice* dev_list[128]; /* list of registered I2C devices */ 94 | }; 95 | 96 | #endif /* I2C_H */ 97 | -------------------------------------------------------------------------------- /devices/common/i2c/i2cprom.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-22 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Generic PROM device programmable over I2C. */ 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | I2CProm::I2CProm(uint8_t dev_addr, int size) 31 | { 32 | supports_types(HWCompType::I2C_DEV); 33 | 34 | this->my_addr = dev_addr; 35 | this->rom_size = size; 36 | 37 | // allocate storage for ROM data 38 | this->data = std::unique_ptr (new uint8_t[this->rom_size]); 39 | } 40 | 41 | void I2CProm::fill_memory(int start, int size, uint8_t c) 42 | { 43 | if ((start + size) <= this->rom_size) { 44 | std::memset(&this->data[start], c, size); 45 | } 46 | } 47 | 48 | void I2CProm::set_memory(int start, const uint8_t* in_data, int size) 49 | { 50 | if ((start + size) <= this->rom_size) { 51 | std::memcpy(&this->data[start], in_data, size); 52 | } 53 | } 54 | 55 | void I2CProm::start_transaction() { 56 | this->pos = 0; 57 | }; 58 | 59 | bool I2CProm::send_subaddress(uint8_t sub_addr) { 60 | this->pos = sub_addr; 61 | return true; 62 | }; 63 | 64 | bool I2CProm::send_byte(uint8_t data) { 65 | LOG_F(9, "I2CRom: 0x%X received", data); 66 | return true; 67 | }; 68 | 69 | bool I2CProm::receive_byte(uint8_t* p_data) { 70 | if (this->pos >= this->rom_size) { 71 | this->pos = 0; // attempt to read past last byte should wrap around 72 | } 73 | *p_data = this->data[this->pos++]; 74 | return true; 75 | }; 76 | -------------------------------------------------------------------------------- /devices/common/i2c/i2cprom.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-22 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Generic PROM device programmable over I2C. */ 23 | 24 | #ifndef I2C_PROM_H 25 | #define I2C_PROM_H 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | class I2CProm : public I2CDevice, public HWComponent 34 | { 35 | public: 36 | I2CProm(uint8_t dev_addr, int size); 37 | ~I2CProm() = default; 38 | 39 | // I2CDevice methods 40 | void start_transaction(); 41 | bool send_subaddress(uint8_t sub_addr); 42 | bool send_byte(uint8_t data); 43 | bool receive_byte(uint8_t* p_data); 44 | 45 | // data management methods 46 | void fill_memory(int start, int size, uint8_t c); 47 | void set_memory(int start, const uint8_t* in_data, int size); 48 | 49 | private: 50 | std::unique_ptr data; 51 | 52 | int rom_size = 0; 53 | int pos = 0; 54 | uint8_t my_addr = 0xA0; 55 | }; 56 | 57 | #endif // I2C_PROM_H 58 | -------------------------------------------------------------------------------- /devices/common/mmiodevice.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-21 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | #ifndef MMIO_DEVICE_H 23 | #define MMIO_DEVICE_H 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | /** Abstract class representing a simple, memory-mapped I/O device */ 31 | class MMIODevice : public HWComponent { 32 | public: 33 | MMIODevice() = default; 34 | virtual uint32_t read(uint32_t rgn_start, uint32_t offset, int size) = 0; 35 | virtual void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size) = 0; 36 | virtual ~MMIODevice() = default; 37 | }; 38 | 39 | #define SIZE_ARG(size) (size == 4 ? 'l' : size == 2 ? 'w' : \ 40 | size == 1 ? 'b' : '0' + size) 41 | 42 | #endif /* MMIO_DEVICE_H */ 43 | -------------------------------------------------------------------------------- /devices/common/nubus/nubusutils.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-24 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | #ifndef NUBUS_UTILS_H 23 | #define NUBUS_UTILS_H 24 | 25 | #include 26 | #include 27 | 28 | int load_declaration_rom(const std::string rom_path, int slot_num); 29 | 30 | #endif // NUBUS_UTILS_H 31 | -------------------------------------------------------------------------------- /devices/common/nvram.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | /** @file Non-volatile RAM implementation. 33 | */ 34 | 35 | using namespace std; 36 | 37 | /** the signature for NVRAM backing file identification. */ 38 | static char NVRAM_FILE_ID[] = "DINGUSPPCNVRAM"; 39 | 40 | NVram::NVram(std::string file_name, uint32_t ram_size) 41 | { 42 | this->name = "NVRAM"; 43 | 44 | supports_types(HWCompType::NVRAM); 45 | 46 | this->file_name = file_name; 47 | this->ram_size = ram_size; 48 | 49 | // allocate memory storage and fill it with zeroes 50 | this->storage = std::unique_ptr(new uint8_t[ram_size] ()); 51 | 52 | this->init(); 53 | } 54 | 55 | NVram::~NVram() { 56 | this->save(); 57 | } 58 | 59 | uint8_t NVram::read_byte(uint32_t offset) { 60 | return (this->storage[offset]); 61 | } 62 | 63 | void NVram::write_byte(uint32_t offset, uint8_t val) { 64 | this->storage[offset] = val; 65 | } 66 | 67 | void NVram::init() { 68 | char sig[sizeof(NVRAM_FILE_ID)]; 69 | uint16_t data_size; 70 | 71 | ifstream f(this->file_name, ios::in | ios::binary); 72 | 73 | if (f.fail() || !f.read(sig, sizeof(NVRAM_FILE_ID)) || 74 | !f.read((char*)&data_size, sizeof(data_size)) || 75 | memcmp(sig, NVRAM_FILE_ID, sizeof(NVRAM_FILE_ID)) || data_size != this->ram_size || 76 | !f.read((char*)this->storage.get(), this->ram_size)) { 77 | LOG_F(WARNING, "Could not restore NVRAM content from the given file \"%s\".", this->file_name.c_str()); 78 | memset(this->storage.get(), 0, this->ram_size); 79 | } 80 | 81 | f.close(); 82 | } 83 | 84 | void NVram::save() { 85 | if (is_deterministic) { 86 | LOG_F(INFO, "Skipping NVRAM write to \"%s\" in deterministic mode", this->file_name.c_str()); 87 | return; 88 | } 89 | ofstream f(this->file_name, ios::out | ios::binary); 90 | 91 | /* write file identification */ 92 | f.write(NVRAM_FILE_ID, sizeof(NVRAM_FILE_ID)); 93 | f.write((char*)&this->ram_size, sizeof(this->ram_size)); 94 | 95 | /* write NVRAM content */ 96 | f.write((char*)this->storage.get(), this->ram_size); 97 | 98 | f.close(); 99 | } 100 | 101 | static const DeviceDescription Nvram_Descriptor = { 102 | NVram::create, {}, {}, HWCompType::NVRAM 103 | }; 104 | 105 | REGISTER_DEVICE(NVRAM, Nvram_Descriptor); 106 | -------------------------------------------------------------------------------- /devices/common/nvram.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | #ifndef NVRAM_H 23 | #define NVRAM_H 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | /** @file Non-volatile RAM emulation. 32 | 33 | It implements a non-volatile random access storage whose content will be 34 | automatically saved to and restored from the dedicated file. 35 | */ 36 | 37 | class NVram : public HWComponent { 38 | public: 39 | NVram(std::string file_name = "nvram.bin", uint32_t ram_size = 8192); 40 | ~NVram(); 41 | 42 | static std::unique_ptr create() { 43 | return std::unique_ptr(new NVram()); 44 | } 45 | 46 | uint8_t read_byte(uint32_t offset); 47 | void write_byte(uint32_t offset, uint8_t value); 48 | 49 | private: 50 | std::string file_name; // file name for the backing file 51 | uint16_t ram_size; // NVRAM size 52 | std::unique_ptr storage; 53 | 54 | void init(); 55 | void save(); 56 | }; 57 | 58 | #endif /* NVRAM_H */ 59 | -------------------------------------------------------------------------------- /devices/common/pci/dec21154.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** DEC 21154 PCI-to-PCI bridge emulation. */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | DecPciBridge::DecPciBridge(std::string name) : PCIBridge(name) 32 | { 33 | supports_types(HWCompType::PCI_HOST | HWCompType::PCI_DEV); 34 | 35 | // initialize PCI config header 36 | this->vendor_id = PCI_VENDOR_DEC; 37 | this->device_id = 0x0026; 38 | this->class_rev = 0x06040002; 39 | this->cache_ln_sz = 0; 40 | this->command = 0; 41 | this->status = 0x2B0; 42 | } 43 | 44 | uint32_t DecPciBridge::pci_cfg_read(uint32_t reg_offs, AccessDetails &details) 45 | { 46 | if (reg_offs < 64) { 47 | return PCIBridge::pci_cfg_read(reg_offs, details); 48 | } 49 | 50 | switch (reg_offs) { 51 | case CHIP_CTRL: 52 | return (this->arb_ctrl << 16) | (this-> diag_ctrl << 8) | this->chip_ctrl; 53 | case PSERR_EVENT_DIS: 54 | return (this->gpio_out_en << 16) | this->pserr_event_dis; 55 | case SEC_CLK_CTRL: 56 | return this->sec_clock_ctrl; 57 | default: 58 | LOG_READ_UNIMPLEMENTED_CONFIG_REGISTER(); 59 | } 60 | 61 | return 0; 62 | } 63 | 64 | void DecPciBridge::pci_cfg_write(uint32_t reg_offs, uint32_t value, AccessDetails &details) 65 | { 66 | if (reg_offs < 64) { 67 | PCIBridge::pci_cfg_write(reg_offs, value, details); 68 | return; 69 | } 70 | 71 | switch (reg_offs) { 72 | case CHIP_CTRL: 73 | this->chip_ctrl = value & 0xFFU; 74 | this->diag_ctrl = (value >> 8) & 0xFFU; 75 | this->arb_ctrl = value >> 16; 76 | break; 77 | case PSERR_EVENT_DIS: 78 | this->pserr_event_dis = value & 0xFFU; 79 | this->gpio_out_en = (value >> 16) & 0xFFU; 80 | break; 81 | case SEC_CLK_CTRL: 82 | this->sec_clock_ctrl = value & 0xFFFFU; 83 | break; 84 | default: 85 | LOG_WRITE_UNIMPLEMENTED_CONFIG_REGISTER(); 86 | } 87 | } 88 | 89 | static const PropMap Dec21154Yosemite_Properties = { 90 | {"pci_FireWire", 91 | new StrProperty("")}, 92 | {"pci_UltraATA", 93 | new StrProperty("")}, 94 | {"pci_J11", 95 | new StrProperty("")}, 96 | {"pci_J10", 97 | new StrProperty("")}, 98 | {"pci_J9", 99 | new StrProperty("")}, 100 | {"pci_USB", 101 | new StrProperty("")}, 102 | }; 103 | 104 | static const DeviceDescription Dec21154_Descriptor = { 105 | DecPciBridge::create, {}, {}, HWCompType::PCI_HOST | HWCompType::PCI_DEV 106 | }; 107 | 108 | static const DeviceDescription Dec21154Yosemite_Descriptor = { 109 | DecPciBridge::create_yosemite, {}, Dec21154Yosemite_Properties, HWCompType::PCI_HOST | HWCompType::PCI_DEV 110 | }; 111 | 112 | REGISTER_DEVICE(Dec21154, Dec21154_Descriptor); 113 | REGISTER_DEVICE(Dec21154Yosemite, Dec21154Yosemite_Descriptor); 114 | -------------------------------------------------------------------------------- /devices/common/pci/dec21154.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** DEC 21154 PCI-to-PCI bridge definitions. */ 23 | 24 | #ifndef DEC_P2P_H 25 | #define DEC_P2P_H 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | enum { 33 | CHIP_CTRL = 0x40, 34 | PSERR_EVENT_DIS = 0x64, 35 | SEC_CLK_CTRL = 0x68, 36 | }; 37 | 38 | class DecPciBridge : public PCIBridge { 39 | public: 40 | DecPciBridge(std::string name); 41 | ~DecPciBridge() = default; 42 | 43 | static std::unique_ptr create() { 44 | return std::unique_ptr(new DecPciBridge("DEC21154")); 45 | } 46 | 47 | static std::unique_ptr create_yosemite() { 48 | return std::unique_ptr(new DecPciBridge("DEC21154Yosemite")); 49 | } 50 | 51 | // PCIDevice methods 52 | uint32_t pci_cfg_read(uint32_t reg_offs, AccessDetails &details); 53 | void pci_cfg_write(uint32_t reg_offs, uint32_t value, AccessDetails &details); 54 | 55 | private: 56 | uint8_t chip_ctrl = 0; 57 | uint8_t diag_ctrl = 0; 58 | uint16_t arb_ctrl = 0x0200; 59 | uint8_t pserr_event_dis = 0; 60 | uint8_t gpio_out_data = 0; 61 | uint8_t gpio_out_en = 0; 62 | uint8_t gpio_in_data = 0; 63 | uint16_t sec_clock_ctrl = 0; 64 | }; 65 | 66 | #endif // DEC_P2P_H 67 | -------------------------------------------------------------------------------- /devices/common/pci/pcibridgebase.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-25 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | #ifndef PCI_BRIDGE_BASE_H 23 | #define PCI_BRIDGE_BASE_H 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | /** PCI configuration space registers offsets (type 1 and 2) */ 35 | enum { 36 | PCI_CFG_PRIMARY_BUS = 0x18, // PRIMARY_BUS, SECONDARY_BUS, SUBORDINATE_BUS, SEC_LATENCY_TIMER 37 | }; 38 | 39 | class PCIBridgeBase : public PCIHost, public PCIBase { 40 | friend class PCIHost; 41 | public: 42 | PCIBridgeBase(std::string name, PCIHeaderType hdr_type, int num_bars); 43 | ~PCIBridgeBase() = default; 44 | 45 | // PCIHost methods 46 | virtual AddressMapEntry* pci_register_mmio_region(uint32_t start_addr, uint32_t size, PCIBase* obj) override; 47 | virtual bool pci_unregister_mmio_region(uint32_t start_addr, uint32_t size, PCIBase* obj) override; 48 | 49 | // PCIBase methods 50 | virtual uint32_t pci_cfg_read(uint32_t reg_offs, AccessDetails &details) override; 51 | virtual void pci_cfg_write(uint32_t reg_offs, uint32_t value, AccessDetails &details) override; 52 | 53 | bool supports_io_space() override { 54 | return true; 55 | }; 56 | 57 | // plugin interface for using in the derived classes 58 | std::function pci_rd_primary_bus; 59 | std::function pci_wr_primary_bus; 60 | std::function pci_rd_secondary_bus; 61 | std::function pci_wr_secondary_bus; 62 | std::function pci_rd_subordinate_bus; 63 | std::function pci_wr_subordinate_bus; 64 | std::function pci_rd_sec_latency_timer; 65 | std::function pci_wr_sec_latency_timer; 66 | std::function pci_rd_sec_status; 67 | std::function pci_wr_sec_status; 68 | std::function pci_rd_bridge_control; 69 | std::function pci_wr_bridge_control; 70 | 71 | // HWComponent methods 72 | virtual int device_postinit() override; 73 | 74 | protected: 75 | // PCI configuration space state 76 | uint8_t primary_bus = 0; 77 | uint8_t secondary_bus = 0; 78 | uint8_t subordinate_bus = 0; 79 | uint8_t sec_latency_timer = 0; // if supportss r/w then must reset to 0 80 | uint16_t sec_status = 0; 81 | uint16_t bridge_control = 0; 82 | 83 | // 0 = not writable, 0xf8 = limits the granularity to eight PCI clocks 84 | uint8_t sec_latency_timer_cfg = 0xff; 85 | }; 86 | 87 | #endif /* PCI_BRIDGE_BASE_H */ 88 | -------------------------------------------------------------------------------- /devices/common/pci/pcidevice.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | PCIDevice::PCIDevice(std::string name) : PCIBase(name, PCI_HEADER_TYPE_0, 6) 31 | { 32 | }; 33 | 34 | uint32_t PCIDevice::pci_cfg_read(uint32_t reg_offs, AccessDetails &details) 35 | { 36 | switch (reg_offs) { 37 | case PCI_CFG_BAR0: 38 | case PCI_CFG_BAR1: 39 | case PCI_CFG_BAR2: 40 | case PCI_CFG_BAR3: 41 | case PCI_CFG_BAR4: 42 | case PCI_CFG_BAR5: 43 | return this->bars[(reg_offs - 0x10) >> 2]; 44 | case PCI_CFG_SUBSYS_ID: 45 | return (this->subsys_id << 16) | (this->subsys_vndr); 46 | case PCI_CFG_ROM_BAR: 47 | return this->exp_rom_bar; 48 | case PCI_CFG_DWORD_13: 49 | return cap_ptr; 50 | case PCI_CFG_DWORD_15: 51 | return (max_lat << 24) | (min_gnt << 16) | (irq_pin << 8) | irq_line; 52 | default: 53 | return PCIBase::pci_cfg_read(reg_offs, details); 54 | } 55 | } 56 | 57 | void PCIDevice::pci_cfg_write(uint32_t reg_offs, uint32_t value, AccessDetails &details) 58 | { 59 | switch (reg_offs) { 60 | case PCI_CFG_BAR0: 61 | case PCI_CFG_BAR1: 62 | case PCI_CFG_BAR2: 63 | case PCI_CFG_BAR3: 64 | case PCI_CFG_BAR4: 65 | case PCI_CFG_BAR5: 66 | this->set_bar_value((reg_offs - 0x10) >> 2, value); 67 | break; 68 | case PCI_CFG_ROM_BAR: 69 | this->pci_wr_exp_rom_bar(value); 70 | break; 71 | case PCI_CFG_DWORD_15: 72 | this->irq_line = value >> 24; 73 | break; 74 | default: 75 | PCIBase::pci_cfg_write(reg_offs, value, details); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /devices/common/pci/pcidevice.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | #ifndef PCI_DEVICE_H 23 | #define PCI_DEVICE_H 24 | 25 | #include 26 | 27 | /** PCI configuration space registers offsets */ 28 | enum { 29 | PCI_CFG_BAR2 = 0x18, // base address register 2 30 | PCI_CFG_BAR3 = 0x1C, // base address register 3 31 | PCI_CFG_BAR4 = 0x20, // base address register 4 32 | PCI_CFG_BAR5 = 0x24, // base address register 5 33 | PCI_CFG_CIS_PTR = 0x28, // Cardbus CIS Pointer 34 | PCI_CFG_SUBSYS_ID = 0x2C, // Subsysten IDs 35 | PCI_CFG_ROM_BAR = 0x30, // expansion ROM base address 36 | }; 37 | 38 | class PCIDevice : public PCIBase { 39 | public: 40 | PCIDevice(std::string name); 41 | virtual ~PCIDevice() = default; 42 | 43 | // configuration space access methods 44 | virtual uint32_t pci_cfg_read(uint32_t reg_offs, AccessDetails &details); 45 | virtual void pci_cfg_write(uint32_t reg_offs, uint32_t value, AccessDetails &details); 46 | 47 | protected: 48 | // PCI configuration space state 49 | uint8_t max_lat = 0; 50 | uint8_t min_gnt = 0; 51 | uint16_t subsys_id = 0; 52 | uint16_t subsys_vndr = 0; 53 | }; 54 | 55 | #endif /* PCI_DEVICE_H */ 56 | -------------------------------------------------------------------------------- /devices/common/scsi/scsibusctrl.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-25 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file SCSI bus controller definitions. */ 23 | 24 | #ifndef SCSI_BUS_CTRL_H 25 | #define SCSI_BUS_CTRL_H 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | namespace Scsi_Bus_Controller { 35 | /** SCSI sequencer states. */ 36 | enum SeqState : uint32_t { 37 | IDLE = 0, 38 | BUS_FREE, 39 | ARB_BEGIN, 40 | ARB_END, 41 | SEL_BEGIN, 42 | SEL_END, 43 | SEND_MSG, 44 | SEND_CMD, 45 | CMD_COMPLETE, 46 | XFER_BEGIN, 47 | XFER_END, 48 | SEND_DATA, 49 | RCV_DATA, 50 | RCV_STATUS, 51 | RCV_MESSAGE, 52 | }; 53 | }; 54 | 55 | /** Sequencer error codes. */ 56 | enum : int { 57 | ARB_LOST = 1, 58 | SEL_TIMEOUT, 59 | }; 60 | 61 | constexpr auto DATA_FIFO_DEPTH = 16; 62 | 63 | class ScsiBusController : public ScsiDevice, public DmaDevice { 64 | public: 65 | ScsiBusController(std::string name, uint8_t my_bus_id=7) : ScsiDevice(name, my_bus_id) { 66 | supports_types(HWCompType::SCSI_HOST | HWCompType::SCSI_DEV); 67 | } 68 | ~ScsiBusController() = default; 69 | 70 | // implements SCSI FSM 71 | void sequencer(); 72 | 73 | virtual void step_completed() = 0; 74 | virtual void report_error(const int error) = 0; 75 | 76 | // ScsiDevice methods 77 | void notify(ScsiNotification notif_type, int param) override; 78 | bool prepare_data() override { return false; }; 79 | bool get_more_data() override { return false; }; 80 | bool has_data() override { return false; }; 81 | bool rcv_data(); 82 | int send_data(uint8_t* dst_ptr, int count) override; 83 | void process_command() override {}; 84 | 85 | // DmaDevice methods 86 | int xfer_from(uint8_t *buf, int len) override; 87 | 88 | protected: 89 | void seq_defer_state(uint64_t delay_ns); 90 | void update_irq(); 91 | void fifo_push(const uint8_t data); 92 | uint8_t fifo_pop(); 93 | 94 | ScsiBus* bus_obj = nullptr; 95 | uint8_t src_id; 96 | uint8_t dst_id; 97 | bool is_dma_cmd = false; 98 | bool is_initiator = true; 99 | bool assert_atn = false; 100 | 101 | // Data FIFO state 102 | int fifo_pos = 0; 103 | int to_xfer = 0; 104 | uint32_t xfer_count = 0; 105 | int bytes_out = 0; 106 | uint8_t data_fifo[DATA_FIFO_DEPTH] = {}; 107 | 108 | // Sequencer state 109 | uint32_t seq_timer_id = 0; 110 | uint32_t cur_state = Scsi_Bus_Controller::SeqState::IDLE; 111 | uint32_t next_state = Scsi_Bus_Controller::SeqState::IDLE; 112 | int cur_bus_phase = 0; 113 | 114 | // interrupt related stuff 115 | InterruptCtrl* int_ctrl = nullptr; 116 | uint64_t irq_id = 0; 117 | uint8_t irq = 0; 118 | uint8_t int_mask = 0; 119 | uint8_t int_stat = 0; 120 | }; 121 | 122 | #endif // SCSI_BUS_CTRL_H 123 | -------------------------------------------------------------------------------- /devices/common/scsi/scsicdrom.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-24 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file SCSI CD-ROM definitions. */ 23 | 24 | #ifndef SCSI_CDROM_H 25 | #define SCSI_CDROM_H 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | class ScsiCdrom : public CdromDrive, public ScsiDevice { 36 | public: 37 | ScsiCdrom(std::string name, int my_id); 38 | ~ScsiCdrom() = default; 39 | 40 | virtual void process_command() override; 41 | virtual bool prepare_data() override; 42 | virtual bool get_more_data() override; 43 | 44 | protected: 45 | int test_unit_ready(); 46 | void read(uint32_t lba, uint16_t nblocks, uint8_t cmd_len); 47 | uint32_t inquiry(uint8_t *cmd_ptr, uint8_t *data_ptr) override; 48 | void mode_select_6(uint8_t param_len); 49 | 50 | void mode_sense_6(); 51 | void read_capacity_10(); 52 | 53 | private: 54 | bool eject_allowed = true; 55 | int bytes_out = 0; 56 | uint8_t data_buf[2048] = {}; 57 | 58 | //inquiry info 59 | char vendor_info[9] = "SONY "; 60 | char prod_info[17] = "CD-ROM CDU-8003A"; 61 | char rev_info[5] = "1.9a"; 62 | }; 63 | 64 | #endif // SCSI_CDROM_H 65 | -------------------------------------------------------------------------------- /devices/common/scsi/scsihd.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-24 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file SCSI hard drive definitions. */ 23 | 24 | #ifndef SCSI_HD_H 25 | #define SCSI_HD_H 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | class ScsiHardDisk : public ScsiDevice { 35 | public: 36 | ScsiHardDisk(std::string name, int my_id); 37 | ~ScsiHardDisk() = default; 38 | 39 | void insert_image(std::string filename); 40 | void process_command(); 41 | bool prepare_data(); 42 | bool get_more_data() { return false; }; 43 | 44 | protected: 45 | int test_unit_ready(); 46 | int req_sense(uint16_t alloc_len); 47 | int send_diagnostic(); 48 | void mode_select_6(uint8_t param_len); 49 | 50 | void mode_sense_6(); 51 | void format(); 52 | void reassign(); 53 | uint32_t inquiry(uint8_t *cmd_ptr, uint8_t *data_ptr); 54 | void read_capacity_10(); 55 | void read(uint32_t lba, uint16_t transfer_len, uint8_t cmd_len); 56 | void write(uint32_t lba, uint16_t transfer_len, uint8_t cmd_len); 57 | void seek(uint32_t lba); 58 | void rewind(); 59 | void read_buffer(); 60 | 61 | private: 62 | ImgFile disk_img; 63 | uint64_t img_size; 64 | int total_blocks; 65 | uint64_t file_offset = 0; 66 | static const int sector_size = 512; 67 | bool eject_allowed = true; 68 | int bytes_out = 0; 69 | 70 | std::unique_ptr data_buf_obj = nullptr; 71 | uint8_t* data_buf = nullptr; 72 | uint32_t data_buf_size = 0; 73 | 74 | uint8_t error = ScsiError::NO_ERROR; 75 | uint8_t msg_code = 0; 76 | 77 | //inquiry info 78 | char vendor_info[8] = {'Q', 'U', 'A', 'N', 'T', 'U', 'M', '\0'}; 79 | char prod_info[16] = {'E', 'm', 'u', 'l', 'a', 't', 'e', 'd', ' ', 'D', 'i', 's', 'k', '\0'}; 80 | char rev_info[4] = {'d', 'i', '0', '1'}; 81 | }; 82 | 83 | #endif // SCSI_HD_H 84 | -------------------------------------------------------------------------------- /devices/deviceregistry.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-22 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Device registry implementation. */ 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | bool DeviceRegistry::add(const std::string name, DeviceDescription desc) 30 | { 31 | if (device_registered(name)) { 32 | return false; 33 | } 34 | 35 | get_registry()[name] = desc; 36 | return true; 37 | } 38 | 39 | bool DeviceRegistry::device_registered(const std::string dev_name) 40 | { 41 | if (get_registry().find(dev_name) != get_registry().end()) { 42 | return true; 43 | } 44 | 45 | return false; 46 | } 47 | 48 | std::unique_ptr DeviceRegistry::create(const std::string& name) 49 | { 50 | auto it = get_registry().find(name); 51 | if (it != get_registry().end()) { 52 | return it->second.m_create_func(); 53 | } 54 | 55 | return nullptr; 56 | } 57 | 58 | DeviceDescription& DeviceRegistry::get_descriptor(const std::string& name) 59 | { 60 | auto it = get_registry().find(name); 61 | if (it != get_registry().end()) { 62 | return it->second; 63 | } 64 | 65 | static DeviceDescription empty_descriptor = {}; 66 | 67 | return empty_descriptor; 68 | } 69 | -------------------------------------------------------------------------------- /devices/deviceregistry.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-25 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Device registry definitions. */ 23 | 24 | #ifndef DEVICE_REGISTRY_H 25 | #define DEVICE_REGISTRY_H 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | class HWComponent; 36 | 37 | typedef std::function ()> CreateFunc; 38 | 39 | struct DeviceDescription { 40 | CreateFunc m_create_func; 41 | std::vector subdev_list; 42 | PropMap properties; 43 | uint64_t supports_types; 44 | std::string description; 45 | }; 46 | 47 | class DeviceRegistry 48 | { 49 | public: 50 | DeviceRegistry() = delete; 51 | 52 | static bool add(const std::string name, DeviceDescription desc); 53 | 54 | static bool device_registered(const std::string dev_name); 55 | 56 | static std::unique_ptr create(const std::string& name); 57 | 58 | static DeviceDescription& get_descriptor(const std::string& name); 59 | 60 | private: 61 | static std::map & get_registry() { 62 | static std::map device_registry; 63 | return device_registry; 64 | } 65 | }; 66 | 67 | #define REGISTER_DEVICE(dev_name, dev_desc) \ 68 | static bool dev_name ## _registered = DeviceRegistry::add(#dev_name, (dev_desc)) 69 | 70 | #endif // DEVICE_REGISTRY_H 71 | -------------------------------------------------------------------------------- /devices/ethernet/mace.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-24 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Media Access Controller for Ethernet (MACE) definitions. */ 23 | 24 | #ifndef MACE_H 25 | #define MACE_H 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | /** Known MACE chip IDs. */ 34 | constexpr auto MACE_ID_REV_B0 = 0x0940; // Darwin-0.3 source 35 | constexpr auto MACE_ID_REV_A2 = 0x0941; // Darwin-0.3 source & Curio datasheet 36 | 37 | /** MACE registers offsets. */ 38 | // Refer to the Am79C940 datasheet for details 39 | namespace MaceEnet { 40 | enum MaceReg : uint8_t { 41 | Rcv_FIFO = 0, 42 | Xmit_FIFO = 1, 43 | Xmit_Frame_Ctrl = 2, 44 | Xmit_Frame_Stat = 3, 45 | Xmit_Retry_Cnt = 4, 46 | Rcv_Frame_Ctrl = 5, 47 | Rcv_Frame_Stat = 6, 48 | FIFO_Frame_Cnt = 7, 49 | Interrupt = 8, 50 | Interrupt_Mask = 9, 51 | Poll = 10, 52 | BIU_Config_Ctrl = 11, 53 | FIFO_Config = 12, 54 | MAC_Config_Ctrl = 13, 55 | PLS_Config_Ctrl = 14, 56 | PHY_Config_Ctrl = 15, 57 | Chip_ID_Lo = 16, 58 | Chip_ID_Hi = 17, 59 | Int_Addr_Config = 18, 60 | Log_Addr_Flt = 20, 61 | Phys_Addr = 21, 62 | Missed_Pkt_Cnt = 24, 63 | Runt_Pkt_Cnt = 26, // not used in Macintosh? 64 | Rcv_Collis_Cnt = 27, // not used in Macintosh? 65 | User_Test = 29, 66 | Rsrvd_Test_1 = 30, // not used in Macintosh? 67 | Rsrvd_Test_2 = 31, // not used in Macintosh? 68 | }; 69 | 70 | /** Bit definitions for BIU_Config_Ctrl register. */ 71 | enum { 72 | BIU_SWRST = 1 << 0, 73 | }; 74 | 75 | /** Bit definitions for the internal configuration register. */ 76 | enum { 77 | IAC_LOGADDR = 1 << 1, 78 | IAC_PHYADDR = 1 << 2, 79 | IAC_ADDRCHG = 1 << 7 80 | }; 81 | 82 | }; // namespace MaceEnet 83 | 84 | class MaceController : public DmaDevice, public HWComponent { 85 | public: 86 | MaceController(uint16_t id) { 87 | this->chip_id = id; 88 | this->set_name("MACE"); 89 | this->supports_types(HWCompType::MMIO_DEV | HWCompType::ETHER_MAC); 90 | }; 91 | ~MaceController() = default; 92 | 93 | static std::unique_ptr create() { 94 | return std::unique_ptr(new MaceController(MACE_ID_REV_A2)); 95 | } 96 | 97 | // MACE registers access 98 | uint8_t read(uint8_t reg_offset); 99 | void write(uint8_t reg_offset, uint8_t value); 100 | 101 | private: 102 | uint16_t chip_id; // per-instance MACE Chip ID 103 | uint8_t addr_cfg = 0; 104 | uint8_t addr_ptr = 0; 105 | uint8_t rcv_fc = 1; 106 | uint8_t biu_ctrl = 0; 107 | uint8_t mac_cfg = 0; 108 | uint64_t phys_addr = 0; 109 | uint64_t log_addr = 0; 110 | 111 | // interrupt stuff 112 | uint8_t int_stat = 0; 113 | uint8_t int_mask = 0; 114 | }; 115 | 116 | #endif // MACE_H 117 | -------------------------------------------------------------------------------- /devices/floppy/floppyimg.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-22 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Definitions for working with various floppy images. */ 23 | 24 | #ifndef FLOPPY_IMG_H 25 | #define FLOPPY_IMG_H 26 | 27 | #include 28 | #include 29 | 30 | constexpr auto BLOCK_SIZE = 512; // size in bytes of a logical block 31 | 32 | #define MFM_HD_SIZE (BLOCK_SIZE*2880) // maximal size of a high-density floppy 33 | 34 | /** Floppy image types. */ 35 | enum class FlopImgType { 36 | RAW, // raw image without metadata or low-level formatting 37 | DC42, // Disk Copy 4.2 image 38 | WOZ1, // WOZ v1 image with metadata and low-level data retained 39 | WOZ2, // WOZ v2 image with metadata and low-level data retained 40 | UNKNOWN, // invalid/unknown image format 41 | }; 42 | 43 | /** Interface for floppy image converters. */ 44 | class FloppyImgConverter { 45 | public: 46 | FloppyImgConverter() = default; 47 | virtual ~FloppyImgConverter() = default; 48 | 49 | virtual int calc_phys_params(void) = 0; 50 | virtual int get_raw_disk_data(char* buf) = 0; 51 | virtual int export_data(void) = 0; 52 | 53 | int get_data_size() const { 54 | return this->data_size; 55 | } 56 | 57 | int get_disk_rec_method() const { 58 | return this->rec_method; 59 | } 60 | 61 | int get_number_of_tracks() const { 62 | return this->num_tracks; 63 | } 64 | 65 | int get_number_of_sides() const { 66 | return this->num_sides; 67 | } 68 | 69 | int get_sectors_per_side() const { 70 | return this->num_sectors; 71 | } 72 | 73 | int get_rec_density() const { 74 | return this->density; 75 | } 76 | 77 | uint8_t get_format_byte() const { 78 | return this->format_byte; 79 | } 80 | 81 | protected: 82 | std::string img_path; 83 | int img_size; 84 | int data_size; // disk data size without image format specific stuff 85 | 86 | int rec_method; 87 | int num_tracks; 88 | int num_sides; 89 | int num_sectors; 90 | int density; 91 | uint8_t format_byte; // GCR format byte from sector header 92 | }; 93 | 94 | /** Converter for raw floppy images. */ 95 | class RawFloppyImg : public FloppyImgConverter { 96 | public: 97 | RawFloppyImg(std::string& file_path); 98 | ~RawFloppyImg() = default; 99 | 100 | int calc_phys_params(void); 101 | int get_raw_disk_data(char* buf); 102 | int export_data(void); 103 | }; 104 | 105 | /** Converter for Disk Copy 4.2 images. */ 106 | class DiskCopy42Img : public FloppyImgConverter { 107 | public: 108 | DiskCopy42Img(std::string& file_path); 109 | ~DiskCopy42Img() = default; 110 | 111 | int calc_phys_params(void); 112 | int get_raw_disk_data(char* buf); 113 | int export_data(void); 114 | }; 115 | 116 | extern FloppyImgConverter* open_floppy_image(std::string& img_path); 117 | 118 | #endif // FLOPPY_IMG_H 119 | -------------------------------------------------------------------------------- /devices/memctrl/aspen.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-24 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** Aspem Memory Controller definitions. 23 | 24 | Aspen is a custom memory controller and PCI bridge 25 | designed especially for Pippin. 26 | 27 | Kudos to Keith Kaisershot @ blitter.net for his precious technical help! 28 | */ 29 | 30 | #ifndef ASPEN_MEMCTRL_H 31 | #define ASPEN_MEMCTRL_H 32 | 33 | #include 34 | #include 35 | 36 | #include 37 | #include 38 | 39 | /** Aspen register definitions. */ 40 | enum { 41 | SYSTEM_ID = 4, // 0x10 42 | CHIP_REV = 5, // 0x14 43 | MEM_CONFIG = 6, // 0x18 44 | GPIO_IN = 12, // 0x30 45 | GPIO_ENABLE = 13, // 0x34 46 | GPIO_OUT = 14, // 0x38 47 | }; 48 | 49 | constexpr auto ASPEN_REV_1 = 0x01000000; 50 | 51 | /** Aspen RAM bank size bits. */ 52 | enum { 53 | BANK_SIZE_1MB = 0, // 256Kx16, 9 rows x 9 columns 54 | BANK_SIZE_4MB = 1, // 1Mx16, 10 rows x 10 columns 55 | BANK_SIZE_16MB = 2, // 4Mx16, 11 rows x 11 columns 56 | BANK_SIZE_8MB = 3, // 2Mx16, 11 rows x 10 columns 57 | }; 58 | 59 | class AspenCtrl : public MemCtrlBase, public MMIODevice { 60 | public: 61 | AspenCtrl(); 62 | ~AspenCtrl() = default; 63 | 64 | static std::unique_ptr create() { 65 | return std::unique_ptr(new AspenCtrl()); 66 | } 67 | 68 | int device_postinit() override; 69 | 70 | void insert_ram_dimm(int bank_num, uint32_t capacity); 71 | 72 | // MMIODevice methods 73 | uint32_t read(uint32_t rgn_start, uint32_t offset, int size) override; 74 | void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size) override; 75 | 76 | private: 77 | int map_phys_ram(); 78 | 79 | uint8_t gpio_enable = 0; 80 | 81 | uint32_t bank_sizes[4] = {}; 82 | uint8_t ram_config = (BANK_SIZE_16MB << 6) | (BANK_SIZE_16MB << 4) | 83 | (BANK_SIZE_16MB << 2) | (BANK_SIZE_16MB << 0); 84 | }; 85 | 86 | #endif // ASPEN_MEMCTRL_H 87 | -------------------------------------------------------------------------------- /devices/memctrl/hmc.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-25 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** Highspeed Memory Controller emulation. 23 | 24 | Author: Max Poliakovski 25 | 26 | Highspeed Memory Controller (HMC) is a custom memory 27 | and L2 cache controller designed especially for the 28 | first generation of the Power Macintosh computer. 29 | */ 30 | 31 | #ifndef HMC_H 32 | #define HMC_H 33 | 34 | #include 35 | #include 36 | 37 | #include 38 | #include 39 | 40 | /* Control register bit definitions. */ 41 | enum { 42 | HMC_CTRL_BITS = 35, // width of the HMC control register 43 | HMC_RAM_CFG_POS = 29, // DRAM configuration bits position 44 | HMC_VBASE_BIT = 33, // framebuffer base address: 0 - 0x00100000, 1 - 0x0 45 | }; 46 | 47 | /* Motherboard RAM size constans. */ 48 | enum { 49 | BANK_CFG_128MB = 0, // 12 x 12 address maxtrix (reset config) 50 | BANK_CFG_2MB = 1, // 9 x 9 address maxtrix 51 | BANK_CFG_8MB = 2, // 10 x 10 address maxtrix 52 | BANK_CFG_32MB = 3, // 11 x 11 address maxtrix 53 | BANK_SIZE_2MB = 0x200000, 54 | BANK_SIZE_4MB = 0x400000, 55 | BANK_SIZE_8MB = 0x800000, 56 | BANK_SIZE_32MB = 0x2000000, 57 | BANK_SIZE_120MB = 0x07800000, 58 | BANK_MB_START = 0x00000000, // starting address of the motherboard bank 59 | BANK_B_START = 0x08000000, 60 | BANK_A_ALIAS = 0x10000000, 61 | }; 62 | 63 | class HMC : public MemCtrlBase, public MMIODevice { 64 | public: 65 | HMC(); 66 | ~HMC() = default; 67 | 68 | static std::unique_ptr create() { 69 | return std::unique_ptr(new HMC()); 70 | } 71 | 72 | /* MMIODevice methods */ 73 | uint32_t read(uint32_t rgn_start, uint32_t offset, int size); 74 | void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size); 75 | 76 | int install_ram(uint32_t mb_bank_size, uint32_t bank_a_size, uint32_t bank_b_size); 77 | 78 | uint64_t get_control_reg(void) const { 79 | return this->ctrl_reg; 80 | } 81 | 82 | protected: 83 | void remap_ram_regions(); 84 | 85 | private: 86 | int bit_pos = 0; 87 | uint64_t ctrl_reg = 0; 88 | uint8_t bank_config = BANK_CFG_128MB; 89 | 90 | uint32_t mb_bank_start = -1; 91 | uint32_t bank_a_start = -1; 92 | uint32_t bank_b_start = -1; 93 | 94 | uint32_t mb_bank_size = 0; 95 | uint32_t bank_a_size = 0; 96 | uint32_t bank_b_size = 0; 97 | }; 98 | 99 | #endif // HMC_H 100 | -------------------------------------------------------------------------------- /devices/memctrl/psx.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-22 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** PSX Memory Controller definitions. */ 23 | 24 | #ifndef PSX_MEMCTRL_H 25 | #define PSX_MEMCTRL_H 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | namespace PsxReg { 35 | enum { 36 | Sys_Id = 0, 37 | Revision = 1, 38 | Sys_Config = 2, 39 | ROM_Config = 3, 40 | DRAM_Config = 4, 41 | DRAM_Refresh = 5, 42 | Flash_Config = 6, 43 | Page1_Mapping = 8, 44 | Page2_Mapping = 9, 45 | Page3_Mapping = 10, 46 | Page4_Mapping = 11, 47 | Page5_Mapping = 12, 48 | Bus_Timeout = 13 49 | }; 50 | }; // namespace PsxReg 51 | 52 | /** Bus (aka CPU) speed constants. */ 53 | enum { 54 | PSX_BUS_SPEED_38 = 0, // bus frequency 38 MHz 55 | PSX_BUS_SPEED_33 = 1, // bus frequency 33 MHz 56 | PSX_BUS_SPEED_40 = 2, // bus frequency 40 MHz 57 | PSX_BUS_SPEED_50 = 3, // bus frequency 50 MHz 58 | }; 59 | 60 | class PsxCtrl : public MemCtrlBase, public MMIODevice { 61 | public: 62 | PsxCtrl(int bridge_num, std::string name); 63 | ~PsxCtrl() = default; 64 | 65 | static std::unique_ptr create() { 66 | return std::unique_ptr(new PsxCtrl(1, "PSX-PCI1")); 67 | }; 68 | 69 | // MMIODevice methods 70 | uint32_t read(uint32_t rgn_start, uint32_t offset, int size); 71 | void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size); 72 | 73 | void insert_ram_dimm(int slot_num, uint32_t capacity); 74 | void map_phys_ram(); 75 | 76 | private: 77 | uint32_t sys_id; 78 | uint32_t chip_rev; 79 | uint32_t sys_config; 80 | uint32_t rom_cfg; 81 | uint32_t dram_cfg; 82 | uint32_t dram_refresh; 83 | uint32_t flash_cfg; 84 | uint32_t pages_cfg[5]; 85 | uint32_t bank_sizes[5] = {}; 86 | }; 87 | 88 | #endif // PSX_MEMCTRL_H 89 | -------------------------------------------------------------------------------- /devices/serial/chario.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-22 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** Character I/O definitions. */ 23 | 24 | #ifndef CHAR_IO_H 25 | #define CHAR_IO_H 26 | 27 | #include 28 | 29 | #ifdef _WIN32 30 | #else 31 | #include 32 | #include 33 | #endif 34 | 35 | enum { 36 | CHARIO_BE_NULL = 0, // NULL backend: swallows everything, receives nothing 37 | CHARIO_BE_STDIO = 1, // STDIO backend: uses STDIN for input and STDOUT for output 38 | CHARIO_BE_SOCKET = 2, // socket backend: uses a socket for input and output 39 | }; 40 | 41 | /** Interface for character I/O backends. */ 42 | class CharIoBackEnd { 43 | public: 44 | CharIoBackEnd() = default; 45 | virtual ~CharIoBackEnd() = default; 46 | 47 | virtual int rcv_enable() { return 0; }; 48 | virtual void rcv_disable() {}; 49 | virtual bool rcv_char_available() = 0; 50 | virtual bool rcv_char_available_now() = 0; 51 | virtual int xmit_char(uint8_t c) = 0; 52 | virtual int rcv_char(uint8_t *c) = 0; 53 | }; 54 | 55 | /** Null character I/O backend. */ 56 | class CharIoNull : public CharIoBackEnd { 57 | public: 58 | CharIoNull() = default; 59 | ~CharIoNull() = default; 60 | 61 | bool rcv_char_available(); 62 | bool rcv_char_available_now(); 63 | int xmit_char(uint8_t c); 64 | int rcv_char(uint8_t *c); 65 | }; 66 | 67 | /** Stdin character I/O backend. */ 68 | class CharIoStdin : public CharIoBackEnd { 69 | public: 70 | CharIoStdin() { this->stdio_inited = false; }; 71 | ~CharIoStdin() = default; 72 | 73 | int rcv_enable(); 74 | void rcv_disable(); 75 | bool rcv_char_available(); 76 | bool rcv_char_available_now(); 77 | int xmit_char(uint8_t c); 78 | int rcv_char(uint8_t *c); 79 | 80 | private: 81 | static void mysig_handler(int signum); 82 | bool stdio_inited; 83 | int consecutivechars = 0; 84 | }; 85 | 86 | /** Socket character I/O backend. */ 87 | class CharIoSocket : public CharIoBackEnd { 88 | public: 89 | CharIoSocket(); 90 | ~CharIoSocket(); 91 | 92 | int rcv_enable(); 93 | void rcv_disable(); 94 | bool rcv_char_available(); 95 | bool rcv_char_available_now(); 96 | int xmit_char(uint8_t c); 97 | int rcv_char(uint8_t *c); 98 | 99 | private: 100 | bool socket_inited = false; 101 | int sockfd = -1; 102 | int acceptfd = -1; 103 | const char* path = 0; 104 | int consecutivechars = 0; 105 | }; 106 | 107 | #endif // CHAR_IO_H 108 | -------------------------------------------------------------------------------- /devices/sound/burgundy.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** Burgundy sound codec emulation. */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | BurgundyCodec::BurgundyCodec(std::string name) : MacioSndCodec(name) 32 | { 33 | supports_types(HWCompType::SND_CODEC); 34 | 35 | static int burgundy_sample_rates[1] = { 44100 }; 36 | 37 | // Burgundy seems to supports only one sample rate 38 | this->sr_table = burgundy_sample_rates; 39 | this->max_sr_id = 1; 40 | 41 | this->set_sample_rate(0); // set default sample rate 42 | } 43 | 44 | uint32_t BurgundyCodec::snd_ctrl_read(uint32_t offset, int size) { 45 | uint32_t result = 0; 46 | 47 | switch (offset) { 48 | case AWAC_CODEC_CTRL_REG: 49 | result = this->last_ctrl_data; 50 | break; 51 | case AWAC_CODEC_STATUS_REG: 52 | result = (this->first_valid << 23) | BURGUNDY_READY | 53 | (this->byte_counter << 14) | (this->read_pos << 12) | 54 | (this->data_byte << 4); 55 | break; 56 | default: 57 | LOG_F(ERROR, "%s: read from unsupported register 0x%X", this->name.c_str(), 58 | offset); 59 | } 60 | 61 | return BYTESWAP_32(result); 62 | } 63 | 64 | void BurgundyCodec::snd_ctrl_write(uint32_t offset, uint32_t value, int size) { 65 | uint8_t reg_addr; 66 | uint8_t cur_byte; 67 | //uint8_t last_byte; 68 | 69 | value = BYTESWAP_32(value); 70 | 71 | switch (offset) { 72 | case AWAC_CODEC_CTRL_REG: 73 | this->last_ctrl_data = value; 74 | reg_addr = (value >> 12) & 0xFF; 75 | cur_byte = (value >> 8) & 3; 76 | //last_byte = (value >> 10) & 3; 77 | if (value & BURGUNDY_REG_WR) { 78 | uint32_t mask = 0xFFU << (cur_byte * 8); 79 | this->reg_array[reg_addr] = (this->reg_array[reg_addr] & ~mask) | 80 | ((value & 0xFFU) << (cur_byte * 8)); 81 | } else { 82 | this->reg_addr = reg_addr; 83 | this->read_pos = cur_byte; 84 | this->data_byte = (this->reg_array[reg_addr] >> (cur_byte * 8)) & 0xFFU; 85 | this->first_valid = 1; 86 | 87 | TimerManager::get_instance()->add_oneshot_timer( 88 | USECS_TO_NSECS(10), // not sure if this is the correct delay 89 | [this]() { 90 | this->first_valid = 0; 91 | this->byte_counter = (this->byte_counter + 1) & 3; 92 | }); 93 | } 94 | break; 95 | default: 96 | LOG_F(ERROR, "%s: write to unsupported register 0x%X", this->name.c_str(), 97 | offset); 98 | } 99 | } 100 | 101 | static const DeviceDescription Burgundy_Descriptor = { 102 | BurgundyCodec::create, {}, {}, HWCompType::SND_CODEC 103 | }; 104 | 105 | REGISTER_DEVICE(BurgundySnd, Burgundy_Descriptor); 106 | -------------------------------------------------------------------------------- /devices/sound/burgundy.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** Burgundy sound codec definitions. */ 23 | 24 | #ifndef BURGUNDY_H 25 | #define BURGUNDY_H 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | enum { 34 | BURGUNDY_REG_WR = 1 << 21, 35 | BURGUNDY_READY = 1 << 22, 36 | }; 37 | 38 | /** Number of internal registers implemented in Burgundy. */ 39 | constexpr auto BURGUNDY_NUM_REGS = 123; 40 | 41 | class BurgundyCodec : public MacioSndCodec { 42 | public: 43 | BurgundyCodec(std::string name); 44 | ~BurgundyCodec() = default; 45 | 46 | uint32_t snd_ctrl_read(uint32_t offset, int size); 47 | void snd_ctrl_write(uint32_t offset, uint32_t value, int size); 48 | 49 | static std::unique_ptr create() { 50 | return std::unique_ptr(new BurgundyCodec("Burgundy")); 51 | } 52 | 53 | private: 54 | uint32_t last_ctrl_data = 0; 55 | uint8_t byte_counter = 0; 56 | uint8_t reg_addr = 0; 57 | uint8_t first_valid = 0; 58 | uint8_t read_pos = 0; 59 | uint8_t data_byte = 0; 60 | 61 | uint32_t reg_array[BURGUNDY_NUM_REGS] = {}; 62 | }; 63 | 64 | #endif // BURGUNDY_H 65 | -------------------------------------------------------------------------------- /devices/sound/soundserver.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-21 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Sound server definitions. 23 | 24 | This class manages host audio HW. It's directly connected 25 | to a sound abstraction API (libsoundio in our case). 26 | 27 | Sound server provides a way to select between various 28 | host input and output devices independendly of emulated 29 | sound HW. 30 | 31 | Emulated sound HW only need to process sound streams. 32 | */ 33 | 34 | #ifndef SOUND_SERVER_H 35 | #define SOUND_SERVER_H 36 | 37 | #include 38 | 39 | #include 40 | 41 | class DmaOutChannel; 42 | 43 | class SoundServer : public HWComponent { 44 | public: 45 | SoundServer(); 46 | ~SoundServer(); 47 | 48 | int start(); 49 | void shutdown(); 50 | int open_out_stream(uint32_t sample_rate, DmaOutChannel *dma_ch); 51 | int start_out_stream(); 52 | void close_out_stream(); 53 | 54 | private: 55 | class Impl; // Holds private fields 56 | std::unique_ptr impl; 57 | }; 58 | 59 | #endif /* SOUND_SERVER_H */ 60 | -------------------------------------------------------------------------------- /devices/storage/blockstoragedevice.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-24 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Block storage device definitions. */ 23 | 24 | #ifndef BLOCK_STORAGE_DEVICE_H 25 | #define BLOCK_STORAGE_DEVICE_H 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | class BlockStorageDevice { 34 | public: 35 | BlockStorageDevice(const uint32_t cache_blocks, const uint32_t block_size=512, 36 | const uint64_t max_blocks=0xffffffffffffffff); 37 | ~BlockStorageDevice(); 38 | 39 | int set_host_file(std::string file_path); 40 | int set_block_size(const int blk_size); 41 | 42 | int set_fpos(const uint32_t lba); 43 | int read_begin(int nblocks, uint32_t max_len); 44 | int data_left() { return this->remain_size; }; 45 | int read_more(); 46 | int write_begin(char *buf, int nblocks); 47 | 48 | protected: 49 | void fill_cache(const int nblocks); 50 | 51 | ImgFile img_file; 52 | uint64_t size_bytes = 0; // image file size in bytes 53 | uint64_t size_blocks = 0; // image file size in blocks 54 | uint64_t max_blocks = 0; // maximum number of blocks supported 55 | uint64_t cur_fpos = 0; // current image file pointer position 56 | uint32_t block_size = 512; // physical block size 57 | uint32_t raw_blk_size = 512; // block size for raw images (CD-ROM) 58 | uint32_t data_offset = 0; // offset to block data for raw images 59 | uint32_t cache_blocks = 0; 60 | uint32_t cache_size = 0; // cache size 61 | uint32_t remain_size = 0; 62 | bool is_writeable = false; 63 | bool is_ready = false; // ready for operation 64 | 65 | std::unique_ptr data_cache; 66 | }; 67 | 68 | #endif // BLOCK_STORAGE_DEVICE_H 69 | -------------------------------------------------------------------------------- /devices/storage/cdromdrive.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-24 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Virtual CD-ROM drive definitions. */ 23 | 24 | #ifndef CD_ROM_DRIVE_H 25 | #define CD_ROM_DRIVE_H 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | /* Original CD-ROM addressing mode expressed 33 | in minutes, seconds and frames */ 34 | typedef struct { 35 | int min; 36 | int sec; 37 | int frm; 38 | } AddrMsf; 39 | 40 | /* Descriptor for CD-ROM tracks in TOC */ 41 | typedef struct { 42 | uint8_t trk_num; 43 | uint8_t adr_ctrl; 44 | uint32_t start_lba; 45 | } TrackDescriptor; 46 | 47 | constexpr auto CDROM_MAX_TRACKS = 100; 48 | constexpr auto LEAD_OUT_TRK_NUM = 0xAA; 49 | constexpr auto CDR_STD_DATA_SIZE = 2048; 50 | 51 | class CdromDrive : public BlockStorageDevice { 52 | public: 53 | CdromDrive(); 54 | virtual ~CdromDrive() = default; 55 | 56 | void set_error_callback(std::function&& err_cb) { 57 | this->set_error = std::move(err_cb); 58 | } 59 | 60 | bool medium_present() { return this->is_ready; } 61 | 62 | void insert_image(std::string filename); 63 | 64 | virtual uint32_t inquiry(uint8_t *cmd_ptr, uint8_t *data_ptr); 65 | virtual uint32_t mode_sense_ex(bool is_sense_6, uint8_t *cmd_ptr, uint8_t *data_ptr); 66 | virtual uint32_t request_sense(uint8_t *data_ptr, uint8_t sense_key, uint8_t asc, 67 | uint8_t ascq); 68 | virtual uint32_t report_capacity(uint8_t *data_ptr); 69 | virtual uint32_t read_toc(uint8_t *cmd_ptr, uint8_t *data_ptr); 70 | 71 | protected: 72 | std::function set_error; 73 | uint8_t hex_to_bcd(const uint8_t val); 74 | AddrMsf lba_to_msf(const int lba); 75 | bool detect_raw_image(); 76 | 77 | TrackDescriptor tracks[CDROM_MAX_TRACKS]; 78 | int num_tracks; 79 | }; 80 | 81 | #endif // CD_ROM_DRIVE_H 82 | -------------------------------------------------------------------------------- /devices/video/display.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-25 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Display/screen abstraction (implemented on each platform). */ 23 | 24 | #ifndef DISPLAY_H 25 | #define DISPLAY_H 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | class VideoCtrlBase; 33 | 34 | class Display { 35 | public: 36 | enum { 37 | not_full_screen, 38 | full_screen_small, 39 | full_screen_int, 40 | full_screen, 41 | full_screen_no_bars, 42 | }; 43 | 44 | Display(); 45 | ~Display(); 46 | 47 | void set_video_ctrl(VideoCtrlBase* video_ctrl) { 48 | this->video_ctrl = video_ctrl; 49 | } 50 | 51 | // Configures the display for the given width/height. 52 | // Returns true if this is the first time the screen has been configured. 53 | bool configure(int width, int height); 54 | 55 | void configure_dest(); 56 | void configure_texture(); 57 | void update_window_size(); 58 | 59 | // Clears the display 60 | void blank(); 61 | 62 | 63 | // Update the host framebuffer display. If the display adapter does its own 64 | // dirty tracking, fb_known_to_be_changed will be set to true, so that the 65 | // implementation can take that into account. 66 | void update(std::function convert_fb_cb, 67 | std::function cursor_ovl_cb, 68 | bool draw_hw_cursor, int cursor_x, int cursor_y, 69 | bool fb_known_to_be_changed); 70 | 71 | // Called in cases where the framebuffer contents have not changed, so a 72 | // normal update() call is not happening. Allows implementations that need 73 | // to do per-frame bookkeeping to still do that. 74 | void update_skipped(); 75 | 76 | void handle_events(const WindowEvent& wnd_event); 77 | void setup_hw_cursor(std::function draw_hw_cursor, 78 | int cursor_width, int cursor_height); 79 | void update_window_title(); 80 | void toggle_mouse_grab(); 81 | void update_mouse_grab(bool will_be_grabbed); 82 | private: 83 | class Impl; // Holds private fields 84 | std::unique_ptr impl; 85 | VideoCtrlBase* video_ctrl = nullptr; 86 | int full_screen_mode = not_full_screen; 87 | double scale_full_screen; 88 | double scale_window; 89 | }; 90 | 91 | #endif // DISPLAY_H 92 | -------------------------------------------------------------------------------- /devices/video/pdmonboard.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-25 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Definitions for the PDM on-board video. */ 23 | 24 | #ifndef PDM_ONBOARD_H 25 | #define PDM_ONBOARD_H 26 | 27 | #include 28 | 29 | #include 30 | 31 | class HMC; 32 | class InterruptCtrl; 33 | 34 | constexpr auto PDM_VMODE_OFF = 0x1F; 35 | 36 | /** Max. size of our framebuffer in bytes (RGB 13-inch, 16 bpp) */ 37 | constexpr auto PDM_FB_SIZE_MAX = (640 * 480 * 2); 38 | 39 | /** Fixed video modes supported by the PDM on-board video. */ 40 | enum PdmVideoMode : uint8_t { 41 | Portrait = 1, 42 | Rgb12in = 2, 43 | Rgb13in = 6, 44 | Rgb16in = 9, 45 | VGA = 0xB 46 | }; 47 | 48 | class PdmOnboardVideo : public VideoCtrlBase { 49 | public: 50 | PdmOnboardVideo(); 51 | ~PdmOnboardVideo() = default; 52 | 53 | uint8_t get_video_mode() const { 54 | return ((this->video_mode & 0x1F) | this->blanking); 55 | }; 56 | 57 | void set_video_mode(uint8_t new_mode); 58 | void set_pixel_depth(uint8_t depth); 59 | void set_vdac_config(uint8_t config); 60 | uint8_t get_vdac_config() const { 61 | return this->vdac_mode; 62 | }; 63 | void set_clut_index(uint8_t index); 64 | void set_clut_color(uint8_t color); 65 | 66 | void init_interrupts(InterruptCtrl *int_ctrl, uint32_t vbl_irq_id) { 67 | this->int_ctrl = int_ctrl; 68 | this->irq_id = vbl_irq_id; 69 | }; 70 | 71 | protected: 72 | void set_depth_internal(int width); 73 | void enable_video_internal(); 74 | void disable_video_internal(); 75 | void set_fb_base(); 76 | 77 | void pdm_convert_frame_1bpp_indexed(uint8_t *dst_buf, int dst_pitch); 78 | void pdm_convert_frame_2bpp_indexed(uint8_t *dst_buf, int dst_pitch); 79 | void pdm_convert_frame_4bpp_indexed(uint8_t *dst_buf, int dst_pitch); 80 | 81 | private: 82 | uint8_t video_mode; 83 | uint8_t blanking; 84 | uint8_t vdac_mode; 85 | uint8_t clut_index; 86 | uint8_t comp_index; 87 | uint8_t fb_loc = 0; 88 | uint8_t clut_color[3]; 89 | 90 | HMC* hmc_obj; 91 | }; 92 | 93 | #endif // PDM_ONBOARD_H 94 | -------------------------------------------------------------------------------- /devices/video/rgb514defs.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-22 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** IBM RGB514 RAMDAC definitions. */ 23 | 24 | #include 25 | 26 | #ifndef IBM_RGB514_DEFS_H 27 | #define IBM_RGB514_DEFS_H 28 | 29 | constexpr auto PLL_ENAB = 1; 30 | 31 | namespace Rgb514 { 32 | 33 | /** RGB514 direct register addresses. */ 34 | enum { 35 | // standard VGA registers 36 | CLUT_ADDR_WR = 0, 37 | CLUT_DATA = 1, 38 | CLUT_MASK = 2, 39 | CLUT_ADDR_RD = 3, 40 | 41 | // extended registers 42 | INDEX_LOW = 4, 43 | INDEX_HIGH = 5, 44 | INDEX_DATA = 6, 45 | INDEX_CNTL = 7 46 | }; 47 | 48 | /** RGB514 indirect registers. */ 49 | enum { 50 | MISC_CLK_CNTL = 0x0002, 51 | HOR_SYNC_POS = 0x0004, 52 | PWR_MNMGMT = 0x0005, 53 | PIX_FORMAT = 0x000A, 54 | PLL_CTL_1 = 0x0010, 55 | F0_M0 = 0x0020, 56 | F1_N0 = 0x0021, 57 | MISC_CNTL_1 = 0x0070, 58 | MISC_CNTL_2 = 0x0071, 59 | VRAM_MASK_LO = 0x0090, 60 | VRAM_MASK_HI = 0x0091, 61 | }; 62 | 63 | }; // namespace Rgb514 64 | 65 | #endif // IBM_RGB514_DEFS_H 66 | -------------------------------------------------------------------------------- /devices/video/saa7187.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file SAA7187 Digital video encoder emulation. */ 23 | 24 | #include 25 | #include 26 | 27 | Saa7187VideoEncoder::Saa7187VideoEncoder(uint8_t dev_addr) 28 | { 29 | supports_types(HWCompType::I2C_DEV); 30 | 31 | this->my_addr = dev_addr; 32 | } 33 | 34 | void Saa7187VideoEncoder::start_transaction() 35 | { 36 | LOG_F(INFO, "Saa7187: start_transaction"); 37 | this->pos = 0; // reset read/write position 38 | } 39 | 40 | bool Saa7187VideoEncoder::send_subaddress(uint8_t sub_addr) 41 | { 42 | LOG_F(ERROR, "Saa7187: send_subaddress 0x%02x", sub_addr); 43 | //this->pos = sub_addr; 44 | return true; 45 | } 46 | 47 | bool Saa7187VideoEncoder::send_byte(uint8_t data) 48 | { 49 | if (this->pos == 0) { 50 | this->reg_num = data; 51 | LOG_F(INFO, "Saa7187: write 0x%02x", data); 52 | } 53 | else { 54 | if (this->reg_num < Saa7187Regs::last_reg) { 55 | this->regs[this->reg_num] = data; 56 | LOG_F(INFO, "Saa7187: write 0x%02x = 0x%02x", this->reg_num, data); 57 | } 58 | else { 59 | LOG_F(ERROR, "Saa7187: write 0x%02x = 0x%02x", this->reg_num, data); 60 | } 61 | this->reg_num++; 62 | } 63 | this->pos++; 64 | return true; 65 | } 66 | 67 | bool Saa7187VideoEncoder::receive_byte(uint8_t* p_data) 68 | { 69 | LOG_F(ERROR, "Saa7187: receive_byte"); 70 | *p_data = 0x00; 71 | return true; 72 | } 73 | -------------------------------------------------------------------------------- /dppcicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dingusdev/dingusppc/253cffbaca0bef76d5ba1ca1caaaa5582a759e3b/dppcicon.ico -------------------------------------------------------------------------------- /endianswap.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-21 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Macros for performing byte swapping for quick endian conversion. 23 | 24 | It will try to use the fast built-in machine instructions first 25 | and fall back to the slow conversion if none were found. 26 | */ 27 | 28 | #ifndef ENDIAN_SWAP_H 29 | #define ENDIAN_SWAP_H 30 | 31 | #ifdef __GNUG__ /* GCC, ICC and Clang */ 32 | 33 | # define BYTESWAP_16(x) (__builtin_bswap16 (x)) 34 | # define BYTESWAP_32(x) (__builtin_bswap32 (x)) 35 | # define BYTESWAP_64(x) (__builtin_bswap64 (x)) 36 | 37 | #elif _MSC_VER /* MSVC */ 38 | 39 | # include 40 | 41 | # define BYTESWAP_16(x) (_byteswap_ushort (x)) 42 | # define BYTESWAP_32(x) (_byteswap_ulong (x)) 43 | # define BYTESWAP_64(x) (_byteswap_uint64 (x)) 44 | 45 | #elif __has_include() /* Many unixes */ 46 | 47 | # include 48 | 49 | # define BYTESWAP_16(x) (bswap_16(x)) 50 | # define BYTESWAP_32(x) (bswap_32(x)) 51 | # define BYTESWAP_64(x) (bswap_64(x)) 52 | 53 | // TODO: C++23 has std::byteswap 54 | 55 | #else 56 | 57 | // #warning is not standard until C++23: 58 | // 59 | // # warning "Unknown byte swapping built-ins (do it the slow way)!" 60 | 61 | # include 62 | 63 | // Most optimizing compilers will translate these functions directly 64 | // into their native instructions (e.g. bswap on x86). 65 | inline std::uint16_t byteswap_16_impl(std::uint16_t x) 66 | { 67 | return (x >> 8) | (x << 8); 68 | } 69 | 70 | inline std::uint32_t byteswap_32_impl(std::uint32_t x) 71 | { 72 | return ( 73 | ((x & UINT32_C(0x000000FF)) << 24) 74 | | ((x & UINT32_C(0x0000FF00)) << 8) 75 | | ((x & UINT32_C(0x00FF0000)) >> 8) 76 | | ((x & UINT32_C(0xFF000000)) >> 24) 77 | ); 78 | } 79 | 80 | inline std::uint64_t byteswap_64_impl(std::uint64_t x) 81 | { 82 | return ( 83 | ((x & UINT64_C(0x00000000000000FF)) << 56) 84 | | ((x & UINT64_C(0x000000000000FF00)) << 40) 85 | | ((x & UINT64_C(0x0000000000FF0000)) << 24) 86 | | ((x & UINT64_C(0x00000000FF000000)) << 8) 87 | | ((x & UINT64_C(0x000000FF00000000)) >> 8) 88 | | ((x & UINT64_C(0x0000FF0000000000)) >> 24) 89 | | ((x & UINT64_C(0x00FF000000000000)) >> 40) 90 | | ((x & UINT64_C(0xFF00000000000000)) >> 56) 91 | ); 92 | } 93 | 94 | # define BYTESWAP_16(x) (byteswap_16_impl(x)) 95 | # define BYTESWAP_32(x) (byteswap_32_impl(x)) 96 | # define BYTESWAP_64(x) (byteswap_64_impl(x)) 97 | 98 | #endif 99 | 100 | #define BYTESWAP_SIZED(val, size) \ 101 | ((size) == 2 ? BYTESWAP_16(val) : (size) == 4 ? BYTESWAP_32(val) : (val)) 102 | 103 | #endif /* ENDIAN_SWAP_H */ 104 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dingusdev/dingusppc/253cffbaca0bef76d5ba1ca1caaaa5582a759e3b/icon.png -------------------------------------------------------------------------------- /icon.rc: -------------------------------------------------------------------------------- 1 | MAINICON ICON "dppcicon.ico" 2 | -------------------------------------------------------------------------------- /machines/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CMAKE_CXX_STANDARD 20) 2 | 3 | include_directories("${PROJECT_SOURCE_DIR}" 4 | "${PROJECT_SOURCE_DIR}/devices" 5 | "${PROJECT_SOURCE_DIR}/thirdparty/loguru/") 6 | 7 | file(GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" 8 | "${CMAKE_CURRENT_SOURCE_DIR}/*.h" 9 | ) 10 | 11 | add_library(machines OBJECT ${SOURCES}) 12 | target_link_libraries(machines PRIVATE) 13 | -------------------------------------------------------------------------------- /machines/machinebase.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-22 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | std::unique_ptr gMachineObj = 0; 31 | 32 | MachineBase::MachineBase(std::string name) { 33 | this->name = name; 34 | 35 | /* initialize internal maps */ 36 | this->device_map.clear(); 37 | } 38 | 39 | MachineBase::~MachineBase() { 40 | this->device_map.clear(); 41 | } 42 | 43 | void MachineBase::add_device(std::string name, std::unique_ptr dev_obj) { 44 | if (this->device_map.count(name)) { 45 | LOG_F(ERROR, "Device %s already exists!", name.c_str()); 46 | return; 47 | } 48 | 49 | this->device_map[name] = std::move(dev_obj); 50 | } 51 | 52 | void MachineBase::remove_device(HWComponent* dev_obj) { 53 | for (auto it = this->device_map.begin(); it != this->device_map.end(); ++it) 54 | if (it->second.get() == dev_obj) { 55 | this->device_map.erase(it->first); 56 | break; 57 | } 58 | } 59 | 60 | HWComponent* MachineBase::get_comp_by_name(std::string name) { 61 | if (this->device_map.count(name)) { 62 | return this->device_map[name].get(); 63 | } else { 64 | LOG_F(WARNING, "Component name %s not found!", name.c_str()); 65 | return nullptr; 66 | } 67 | } 68 | 69 | HWComponent* MachineBase::get_comp_by_name_optional(std::string name) { 70 | if (this->device_map.count(name)) { 71 | return this->device_map[name].get(); 72 | } else { 73 | return nullptr; 74 | } 75 | } 76 | 77 | HWComponent* MachineBase::get_comp_by_type(HWCompType type) { 78 | std::string comp_name; 79 | bool found = false; 80 | 81 | for (auto it = this->device_map.begin(); it != this->device_map.end(); it++) { 82 | if (it->second->supports_type(type)) { 83 | comp_name = it->first; 84 | found = true; 85 | break; 86 | } 87 | } 88 | 89 | if (found) { 90 | return this->get_comp_by_name(comp_name); 91 | } else { 92 | LOG_F(WARNING, "No component of type %llu was found!", type); 93 | return nullptr; 94 | } 95 | } 96 | 97 | int MachineBase::postinit_devices() 98 | { 99 | // Allow additional devices to be registered by device_postinit, in which 100 | // case we'll initialize them too. 101 | std::set initialized_devices; 102 | while (initialized_devices.size() < this->device_map.size()) { 103 | for (auto it = this->device_map.begin(); it != this->device_map.end(); it++) { 104 | if (initialized_devices.find(it->first) == initialized_devices.end()) { 105 | if (it->second->device_postinit()) { 106 | LOG_F(ERROR, "Could not initialize device %s", it->first.c_str()); 107 | return -1; 108 | } 109 | initialized_devices.insert(it->first); 110 | } 111 | } 112 | } 113 | 114 | return 0; 115 | } 116 | -------------------------------------------------------------------------------- /machines/machinebase.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-22 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Base class for managing different HW components of a machine. 23 | 24 | Author: Max Poliakovski 25 | */ 26 | 27 | #ifndef MACHINE_BASE_H 28 | #define MACHINE_BASE_H 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | class HWComponent; 35 | enum HWCompType : uint64_t; 36 | 37 | class MachineBase { 38 | public: 39 | MachineBase(std::string name); 40 | ~MachineBase(); 41 | 42 | void add_device(std::string name, std::unique_ptr dev_obj); 43 | void remove_device(HWComponent* dev_obj); 44 | HWComponent* get_comp_by_name(std::string name); 45 | HWComponent* get_comp_by_name_optional(std::string name); 46 | HWComponent* get_comp_by_type(HWCompType type); 47 | int postinit_devices(); 48 | 49 | private: 50 | std::string name; 51 | std::map> device_map; 52 | }; 53 | 54 | extern std::unique_ptr gMachineObj; 55 | 56 | #endif /* MACHINE_BASE_H */ 57 | -------------------------------------------------------------------------------- /machines/machinefactory.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-22 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Factory for creating different machines. 23 | 24 | Author: Max Poliakovski 25 | */ 26 | 27 | #ifndef MACHINE_FACTORY_H 28 | #define MACHINE_FACTORY_H 29 | 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | struct DeviceDescription; 39 | 40 | struct MachineDescription { 41 | std::string name; 42 | std::string description; 43 | std::vector devices; 44 | PropMap settings; 45 | std::function init_func; 46 | }; 47 | 48 | typedef std::function(const std::string&)> GetSettingValueFunc; 49 | 50 | class MachineFactory 51 | { 52 | public: 53 | MachineFactory() = delete; 54 | 55 | static bool add(const std::string& machine_id, MachineDescription desc); 56 | 57 | static size_t read_boot_rom(std::string& rom_filepath, char *rom_data); 58 | static std::string machine_name_from_rom(char *rom_data, size_t rom_size); 59 | 60 | static int create(std::string& mach_id); 61 | static int create_machine_for_id(std::string& id, char *rom_data, size_t rom_size); 62 | 63 | static void register_device_settings(const std::string &name); 64 | static int register_machine_settings(const std::string& id); 65 | 66 | static void list_machines(); 67 | static void list_properties(); 68 | 69 | static GetSettingValueFunc get_setting_value; 70 | 71 | private: 72 | static void create_device(std::string& dev_name, DeviceDescription& dev); 73 | static void print_settings(const PropMap& p); 74 | static void list_device_settings(DeviceDescription& dev); 75 | static int load_boot_rom(char *rom_data, size_t rom_size); 76 | static void register_settings(const PropMap& p); 77 | 78 | static std::map & get_registry() { 79 | static std::map machine_registry; 80 | return machine_registry; 81 | } 82 | }; 83 | 84 | #define REGISTER_MACHINE(mach_name, mach_desc) \ 85 | static bool mach_name ## _registered = MachineFactory::add(#mach_name, (mach_desc)) 86 | 87 | #endif /* MACHINE_FACTORY_H */ 88 | -------------------------------------------------------------------------------- /machines/machinepippin.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-24 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Bandai/Atmark Pippin emulation. */ 23 | 24 | /** 25 | Kudos to Keith Kaisershot @ blitter.net for his precious technical help! 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | static std::vector aspen_irq_map = { 37 | // {nullptr , DEV_FUN(0x0B,0), IntSrc::BANDIT1 }, 38 | // {"pci_A1", DEV_FUN(0x0D,0), IntSrc::PCI_A }, 39 | {"pci_B1", DEV_FUN(0x0E,0), IntSrc::PIPPIN_E}, 40 | {"pci_C1", DEV_FUN(0x0F,0), IntSrc::PIPPIN_F}, 41 | {nullptr , DEV_FUN(0x10,0), }, // GrandCentral 42 | }; 43 | 44 | int initialize_pippin(std::string& id) { 45 | LOG_F(INFO, "Building machine Pippin..."); 46 | 47 | PCIHost *pci_host = dynamic_cast(gMachineObj->get_comp_by_name("AspenPci1")); 48 | pci_host->set_irq_map(aspen_irq_map); 49 | 50 | // connect GrandCentral I/O controller to the PCI1 bus 51 | pci_host->pci_register_device(DEV_FUN(0x10,0), 52 | dynamic_cast(gMachineObj->get_comp_by_name("GrandCentralTnt"))); 53 | 54 | // get (raw) pointer to the memory controller 55 | AspenCtrl* aspen_obj = dynamic_cast(gMachineObj->get_comp_by_name("Aspen")); 56 | 57 | // allocate ROM region 58 | if (!aspen_obj->add_rom_region(0xFFC00000, 0x400000)) { 59 | LOG_F(ERROR, "Could not allocate ROM region!"); 60 | return -1; 61 | } 62 | 63 | // configure RAM 64 | aspen_obj->insert_ram_dimm(0, GET_INT_PROP("rambank1_size")); // soldered onboard RAM 65 | aspen_obj->insert_ram_dimm(1, GET_INT_PROP("rambank2_size")); // soldered onboard RAM 66 | aspen_obj->insert_ram_dimm(2, GET_INT_PROP("rambank3_size")); // RAM expansion slot 67 | aspen_obj->insert_ram_dimm(3, GET_INT_PROP("rambank4_size")); // RAM expansion slot 68 | 69 | // init virtual CPU 70 | ppc_cpu_init(aspen_obj, PPC_VER::MPC603, false, 16500000ULL); 71 | 72 | return 0; 73 | } 74 | 75 | static const PropMap Pippin_Settings = { 76 | {"rambank1_size", 77 | new IntProperty(4, std::vector({4}))}, // fixed size 78 | {"rambank2_size", 79 | new IntProperty(1, std::vector({1}))}, // fixed size 80 | {"rambank3_size", 81 | new IntProperty(0, std::vector({0, 1, 4, 8, 16}))}, 82 | {"rambank4_size", 83 | new IntProperty(0, std::vector({0, 1, 4, 8, 16}))}, 84 | {"emmo", 85 | new BinProperty(0)}, 86 | {"adb_devices", 87 | new StrProperty("AppleJack,Keyboard")}, 88 | }; 89 | 90 | static std::vector Pippin_devices = { 91 | "Aspen", "AspenPci1", "GrandCentralTnt", "TaosVideo" 92 | }; 93 | 94 | static const MachineDescription Pippin_Descriptor = { 95 | .name = "pippin", 96 | .description = "Bandai Pippin", 97 | .devices = Pippin_devices, 98 | .settings = Pippin_Settings, 99 | .init_func = &initialize_pippin 100 | }; 101 | 102 | REGISTER_MACHINE(pippin, Pippin_Descriptor); 103 | -------------------------------------------------------------------------------- /main.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Platform-specific main functions. */ 23 | 24 | bool init(); 25 | void cleanup(); 26 | -------------------------------------------------------------------------------- /main_sdl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file SDL-specific main functions. */ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #ifdef __APPLE__ 29 | extern "C" void remap_appkit_menu_shortcuts(); 30 | #endif 31 | 32 | bool init() { 33 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER)) { 34 | LOG_F(ERROR, "SDL_Init error: %s", SDL_GetError()); 35 | return false; 36 | } 37 | 38 | int num_joysticks = SDL_NumJoysticks(); 39 | for (int i = 0; i < num_joysticks; ++i) { 40 | if (SDL_IsGameController(i)) { 41 | SDL_GameControllerOpen(i); /* only support one controller for now */ 42 | break; 43 | } 44 | } 45 | 46 | #ifdef __APPLE__ 47 | remap_appkit_menu_shortcuts(); 48 | #endif 49 | 50 | return true; 51 | } 52 | 53 | void cleanup() { 54 | SDL_Quit(); 55 | } 56 | -------------------------------------------------------------------------------- /main_sdl.m: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | #include 23 | 24 | /** @file SDL-specific main function additions for macOS hosts. */ 25 | 26 | // Replace Command shortcuts with Control shortcuts in the menu bar, so that 27 | // they're not going to conflict with ones in the guest OS (but we still allow 28 | // some of them to be used in the host OS, e.g. Control+Q to quit). 29 | void remap_appkit_menu_shortcuts(void) { 30 | for (NSMenuItem *menuItem in [NSApp mainMenu].itemArray) { 31 | if (menuItem.hasSubmenu) { 32 | for (NSMenuItem *item in menuItem.submenu.itemArray) { 33 | if (item.keyEquivalentModifierMask & NSEventModifierFlagCommand) { 34 | item.keyEquivalentModifierMask &= ~NSEventModifierFlagCommand; 35 | item.keyEquivalentModifierMask |= NSEventModifierFlagControl; 36 | } 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /thirdparty/loguru/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CMAKE_CXX_STANDARD 11) 2 | 3 | include_directories("${PROJECT_SOURCE_DIR}") 4 | 5 | file(GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/loguru.cpp" 6 | "${CMAKE_CURRENT_SOURCE_DIR}/loguru.hpp") 7 | 8 | add_library(loguru OBJECT ${SOURCES}) 9 | -------------------------------------------------------------------------------- /utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") 2 | include(PlatformGlob) 3 | 4 | include_directories("${PROJECT_SOURCE_DIR}" 5 | "${PROJECT_SOURCE_DIR}/thirdparty/loguru/" 6 | ) 7 | 8 | platform_glob(SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") 9 | 10 | add_library(utils OBJECT ${SOURCES}) 11 | target_link_libraries(utils PRIVATE) 12 | -------------------------------------------------------------------------------- /utils/imgfile.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** @file Image file abstraction for floppy, hard drive and CD-ROM images 23 | * (implemented on each platform). */ 24 | 25 | #ifndef IMGFILE_H 26 | #define IMGFILE_H 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | class ImgFile { 33 | public: 34 | ImgFile(); 35 | ~ImgFile(); 36 | 37 | bool open(const std::string& img_path); 38 | void close(); 39 | 40 | uint64_t size() const; 41 | 42 | uint64_t read(void* buf, uint64_t offset, uint64_t length) const; 43 | uint64_t write(const void* buf, uint64_t offset, uint64_t length); 44 | private: 45 | class Impl; // Holds private fields 46 | std::unique_ptr impl; 47 | }; 48 | 49 | #endif // IMGFILE_H 50 | -------------------------------------------------------------------------------- /utils/imgfile_sdl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-23 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | extern bool is_deterministic; 30 | 31 | class ImgFile::Impl { 32 | public: 33 | std::unique_ptr stream; 34 | }; 35 | 36 | ImgFile::ImgFile(): impl(std::make_unique()) 37 | { 38 | 39 | } 40 | 41 | ImgFile::~ImgFile() = default; 42 | 43 | bool ImgFile::open(const std::string &img_path) 44 | { 45 | if (is_deterministic) { 46 | // Avoid writes to the underlying file by reading it all in memory and 47 | // only operating on that. 48 | auto mem_stream = std::make_unique(); 49 | std::ifstream temp(img_path, std::ios::in | std::ios::binary); 50 | if (!temp) return false; 51 | *mem_stream << temp.rdbuf(); 52 | impl->stream = std::move(mem_stream); 53 | } else { 54 | auto file_stream = std::make_unique(img_path, std::ios::in | std::ios::out | std::ios::binary); 55 | if (!file_stream->is_open()) return false; 56 | impl->stream = std::move(file_stream); 57 | } 58 | return impl->stream && impl->stream->good(); 59 | } 60 | 61 | void ImgFile::close() 62 | { 63 | if (!impl->stream) { 64 | LOG_F(WARNING, "ImgFile::close before disk was opened, ignoring."); 65 | return; 66 | } 67 | impl->stream.reset(); 68 | } 69 | 70 | uint64_t ImgFile::size() const 71 | { 72 | if (!impl->stream) { 73 | LOG_F(WARNING, "ImgFile::size before disk was opened, ignoring."); 74 | return 0; 75 | } 76 | impl->stream->seekg(0, impl->stream->end); 77 | return impl->stream->tellg(); 78 | } 79 | 80 | uint64_t ImgFile::read(void* buf, uint64_t offset, uint64_t length) const 81 | { 82 | if (!impl->stream) { 83 | LOG_F(WARNING, "ImgFile::read before disk was opened, ignoring."); 84 | return 0; 85 | } 86 | impl->stream->seekg(offset, std::ios::beg); 87 | impl->stream->read((char *)buf, length); 88 | return impl->stream->gcount(); 89 | } 90 | 91 | uint64_t ImgFile::write(const void* buf, uint64_t offset, uint64_t length) 92 | { 93 | if (!impl->stream) { 94 | LOG_F(WARNING, "ImgFile::write before disk was opened, ignoring."); 95 | return 0; 96 | } 97 | impl->stream->seekp(offset, std::ios::beg); 98 | impl->stream->write((const char *)buf, length); 99 | #if defined(WIN32) || defined(__APPLE__) || defined(__linux) 100 | impl->stream->flush(); 101 | #endif 102 | return uint64_t(impl->stream->tellp()) - offset; 103 | } 104 | -------------------------------------------------------------------------------- /utils/profiler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-25 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | #include "profiler.h" 23 | #include 24 | #include 25 | #include 26 | 27 | /** global profiler object */ 28 | std::unique_ptr gProfilerObj = 0; 29 | 30 | Profiler::Profiler() 31 | { 32 | this->profiles_map.clear(); 33 | } 34 | 35 | bool Profiler::register_profile(std::string name, 36 | std::unique_ptr profile_obj) 37 | { 38 | // bail out if a profile corresponding to 'name' already exists 39 | if (this->profiles_map.find(name) != this->profiles_map.end()) { 40 | return false; 41 | } 42 | 43 | this->profiles_map[name] = std::move(profile_obj); 44 | return true; 45 | } 46 | 47 | void Profiler::print_profile(std::string name) 48 | { 49 | if (this->profiles_map.find(name) == this->profiles_map.end()) { 50 | std::cout << "Profile " << name << " not found." << std::endl; 51 | return; 52 | } 53 | 54 | // Set a locale so we get thousands separators when outputting numbers. 55 | // Would be nice if we could use the default locale, but that does not 56 | // appear to work. 57 | std::cout.imbue(std::locale("en_US.UTF-8")); 58 | 59 | std::cout << std::endl; 60 | std::cout << "Summary of the profile '" << name << "':" << std::endl; 61 | std::cout << "------------------------------------------" << std::endl; 62 | 63 | auto prof_it = this->profiles_map.find(name); 64 | 65 | std::vector vars; 66 | 67 | // ask the corresponding profile class to fill its variables for us 68 | prof_it->second->populate_variables(vars); 69 | 70 | int name_width = 10; 71 | for (auto& var : vars) { 72 | name_width = std::max(name_width, int(var.name.length())); 73 | } 74 | 75 | for (auto& var : vars) { 76 | std::cout << std::left << std::setw(name_width) << var.name << " : "; 77 | switch(var.format) { 78 | case ProfileVarFmt::DEC: 79 | std::cout << var.value << std::endl; 80 | break; 81 | case ProfileVarFmt::HEX: 82 | std::cout << std::hex << var.value << std::endl; 83 | break; 84 | case ProfileVarFmt::COUNT: 85 | std::cout << var.value << std::fixed << std::setprecision(2) << " (" 86 | << (double(var.value) / double(var.count_total) * 100) 87 | << "%)" << std::endl; 88 | break; 89 | default: 90 | std::cout << "Unknown value in variable " << var.name << std::endl; 91 | } 92 | } 93 | 94 | std::cout << std::right << std::endl; 95 | } 96 | 97 | void Profiler::reset_profile(std::string name) 98 | { 99 | if (this->profiles_map.find(name) == this->profiles_map.end()) { 100 | std::cout << "Profile " << name << " not found." << std::endl; 101 | return; 102 | } 103 | 104 | this->profiles_map.find(name)->second->reset(); 105 | } 106 | -------------------------------------------------------------------------------- /utils/profiler.h: -------------------------------------------------------------------------------- 1 | /* 2 | DingusPPC - The Experimental PowerPC Macintosh emulator 3 | Copyright (C) 2018-21 divingkatae and maximum 4 | (theweirdo) spatium 5 | 6 | (Contact divingkatae#1017 or powermax#2286 on Discord for more info) 7 | 8 | This program is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program. If not, see . 20 | */ 21 | 22 | /** Interface definition for the Profiler. 23 | */ 24 | 25 | #ifndef PROFILER_H 26 | #define PROFILER_H 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | enum class ProfileVarFmt { DEC, HEX, COUNT }; 35 | 36 | /** Define a special data type for profile variables. */ 37 | typedef struct ProfileVar { 38 | std::string name; 39 | ProfileVarFmt format; 40 | uint64_t value; 41 | uint64_t count_total; 42 | } ProfileVar; 43 | 44 | /** Base class for user-defined profiles. */ 45 | class BaseProfile { 46 | public: 47 | BaseProfile(std::string name) { this->name = name; }; 48 | 49 | virtual ~BaseProfile() = default; 50 | 51 | virtual void populate_variables(std::vector& vars) = 0; 52 | 53 | virtual void reset(void) = 0; // reset profile counters 54 | 55 | private: 56 | std::string name; 57 | }; 58 | 59 | /** Profiler class for managing of user-defined profiles. */ 60 | class Profiler { 61 | public: 62 | Profiler(); 63 | 64 | virtual ~Profiler() = default; 65 | 66 | bool register_profile(std::string name, std::unique_ptr profile_obj); 67 | 68 | void print_profile(std::string name); 69 | 70 | void reset_profile(std::string name); 71 | 72 | private: 73 | std::map> profiles_map; 74 | }; 75 | 76 | extern std::unique_ptr gProfilerObj; 77 | 78 | #endif /* PROFILER_H */ 79 | -------------------------------------------------------------------------------- /vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dingusppc", 3 | "version-string": "0.01-pre", 4 | "homepage": "https://github.com/dingusdev/dingusppc", 5 | "description": "Experimental Power Macintosh emulator", 6 | "license": "GPL-3.0-or-later", 7 | "dependencies": [ 8 | "sdl2" 9 | ] 10 | } -------------------------------------------------------------------------------- /zdocs/developers/aboutthis.md: -------------------------------------------------------------------------------- 1 | This folder contains hardware and software documentation, much of which the developers 2 | used during the development of DingusPPC. 3 | -------------------------------------------------------------------------------- /zdocs/developers/adb.md: -------------------------------------------------------------------------------- 1 | The Apple Desktop Bus is a bit-serial peripheral bus, Apple themselves cited a 2-MHz Motorola 68HC11 microcontroller as an example platform to implement the ADB standard with. Its transfer speed is usually around 10.0 kilobits per second, roughly comparable to a PS/2 port at 12.0 kilobits per second. 2 | 3 | The device commands are in the form of single byte strings. The first four bits are to signal which of the 16 devices are to be used. The next two bits are for which action to execute (talk, listen, flush, or reset). These are followed by two bits which determine the register to reference (register 0 is usually a communications register, while register 3 is used for device info). 4 | 5 | Heathrow and Paddington-based Macintoshes have a Master Cell, which is a fully-featured ADB implementation for hardware, but isn't used by Mac OS itself. 6 | 7 | # Commands 8 | 9 | | Command Name | Number | 10 | |:---------------------------:|:-------:| 11 | | DEVCMD_CHANGE_ID_AND_ENABLE | 0x00 | 12 | | DEVCMD_CHANGE_ID | 0xFD | 13 | | DEVCMD_CHANGE_ID_AND_ACT | 0xFE | 14 | | DEVCMD_SELF_TEST | 0xFF | 15 | 16 | # Devices 17 | 18 | | Device Type | Example | Default Address | 19 | |:-----------------:|:-------------:|:---------------:| 20 | | Protection | | 0x1 | 21 | | Encoded | Keyboard | 0x2 | 22 | | Relative-position | Mouse | 0x3 | 23 | | Absolute-position | Tablet | 0x4 | 24 | | Data transfer | Modem | 0x5 | 25 | | Other | | 0x6 | 26 | | Other | | 0x7 | -------------------------------------------------------------------------------- /zdocs/developers/amic.md: -------------------------------------------------------------------------------- 1 | The AMIC is the I/O controller used in the Power Mac 6100. Physically, it's located at 0x50F00000. 2 | 3 | It also: 4 | 5 | * Controls the video timing signals 6 | 7 | ## Subdevices 8 | 9 | | Subdevice | Range | 10 | |:--------------:|:--------------------:| 11 | | VIA 1 | 0x0 - 0x1FFF | 12 | | SCC | 0x4000 - 0x5FFF | 13 | | MACE | 0xA000 - 0xBFFF | 14 | | SCSI | 0x10000 - 0x11FFF | 15 | | AWACS | 0x14000 - 0x15FFF | 16 | | SWIM III | 0x16000 - 0x17FFF | 17 | | VIA 2 | 0x26000 - 0x27FFF | 18 | | Video | 0x28000 - 0x29FFF | 19 | | DMA | 0x31000 - 0x32FFF | 20 | | Mem Control | 0x40000 - 0x41FFF | -------------------------------------------------------------------------------- /zdocs/developers/atirage.md: -------------------------------------------------------------------------------- 1 | The ATI Rage is a video card that comes bundled with early Power Mac G3s and New World Macs (like the first revisions of the iMac G3). Its predecessor was the ATI Mach 64 GX, used in earlier Old World Macs. 2 | 3 | # Memory Map 4 | 5 | The ATI Rage can usually be located at IOBase (ex.: 0xF3000000 for Power Mac G3 Beige) + 0x9000. However, the video memory appears to be at 0x81000000 and is capped at 8 MB. 6 | 7 | # Register Map 8 | 9 | | Register Name | Offset | 10 | |:-------------------:|:------:| 11 | | BUS_CNTL | 0xA0 | 12 | | EXT_MEM_CNTL | 0xAC | 13 | | MEM_CNTL | 0xB0 | 14 | | MEM_VGA_WP_SEL | 0xB4 | 15 | | MEM_VGA_RP_SEL | 0xB8 | 16 | | GEN_TEST_CNTL | 0xD0 | 17 | | CONFIG_CNTL | 0xDC | 18 | | CONFIG_CHIP_ID | 0xE0 | 19 | | CONFIG_STAT0 | 0xE4 | 20 | | DST_CNTL | 0x130 | 21 | | SRC_OFF_PITCH | 0x180 | 22 | | SRC_X | 0x184 | 23 | | SRC_Y | 0x188 | 24 | | SRC_Y_X | 0x18C | 25 | | SRC_WIDTH1 | 0x190 | 26 | | SRC_HEIGHT1 | 0x194 | 27 | | SRC_HEIGHT1_WIDTH1 | 0x198 | 28 | | SRC_CNTL | 0x1B4 | 29 | | SCALE_3D_CNTL | 0x1FC | 30 | | HOST_DATA0 | 0x200 | 31 | | HOST_CNTL | 0x240 | 32 | | DP_PIX_WIDTH | 0x2D0 | 33 | | DP_SRC | 0x2D8 | -------------------------------------------------------------------------------- /zdocs/developers/awacs.md: -------------------------------------------------------------------------------- 1 | AWACS is an audio controller present on several Old World Macs and can usually be located at IOBase (ex.: 0xF3000000 for Power Mac G3 Beige) + 0x14000. 2 | 3 | New World Macs have a Screamer chip, which is backwards compatible with the AWACS chip, but with some additional capabilities. 4 | 5 | # Register Maps 6 | 7 | ## NuBus Macs 8 | | Register | Offset | Length 9 | |:-----------------:|:------:|:------:| 10 | | Codec Control | 0x0 | 3 | 11 | | Codec Status | 0x4 | 3 | 12 | | Buffer Size | 0x8 | 2 | 13 | | Phaser | 0xA | 4 | 14 | | Sound Control | 0xE | 2 | 15 | | DMA In | 0x12 | 1 | 16 | | DMA Out | 0x16 | 1 | 17 | 18 | ## PCI Macs 19 | 20 | All registers are 32-bit here. 21 | 22 | | Register | Offset | 23 | |:-----------------:|:------:| 24 | | Sound Control | 0x0 | 25 | | Codec Control | 0x10 | 26 | | Codec Status | 0x20 | 27 | | Clipping Count | 0x30 | 28 | | Byte Swapping | 0x40 | 29 | | Frame Count | 0x50 | 30 | 31 | ## Sound Control Register bits 32 | 33 | | Register | Bit Mask | 34 | |:-------------------------:|:--------:| 35 | | Input Subframe Select | 0x000F | 36 | | Output Subframe Select | 0x00F0 | 37 | | Sound Rate | 0x0700 | 38 | | Error | 0x0800 | 39 | 40 | 41 | Separate volume controls exist for the CD drive and the microphone. 42 | 43 | The DMA buffer size is set to be 0x40000 bytes, while the DMA hardware buffer size is set to be 0x2000 bytes. 44 | -------------------------------------------------------------------------------- /zdocs/developers/bebox.md: -------------------------------------------------------------------------------- 1 | The following document is intended primarily as a documentation on how the BeBox operates. It is currently not implemented in DingusPPC. 2 | 3 | ## BeBox 4 | 5 | The BeBox is a dual PowerPC 603(e) CPU setup. As it was designed with the intent of using standard PC parts, it has both three PCI slots and five ISA slots. As it was made with media production as its primary audience, it contains both input and output RCA jacks, a microphone input, and MIDI ports. 6 | 7 | It also has a unique 37-pin connector dubbed the Geekport to allow hobbyists to create unique devices. 8 | 9 | ### Known components 10 | 11 | * MPC105 PCI Bridge (Codename: Eagle) - Predecessor to the MPC106 (Grackle); Used for bridging between the motherboard and PCI slots 12 | * Intel 82378ZB - Used for bridging between the motherboard and ISA slots 13 | * SYM53C810A - SCSI I/O Processor 14 | * bq3285 - Used for the Real-Time Clock 15 | 16 | ### Motherboard registers 17 | 18 | | Register name | Address | Default value | 19 | |:---------------------------:|:--------------:|:--------------:| 20 | | CPU 0 Interrupt Mask | 0x7FFFF0F0 | | 21 | | CPU 1 Interrupt Mask | 0x7FFFF1F0 | | 22 | | Interrupt sources | 0x7FFFF2F0 | | 23 | | Cross-proccessor interrupts | 0x7FFFF3F0 | | 24 | | Proc. resets, other stuff | 0x7FFFF4F0 | | 25 | 26 | 27 | ### Memory Map 28 | 29 | | Region | Starting Address | Ending Address | 30 | |:---------------------------:|:----------------:|:----------------:| 31 | | Main Memory | 0x00000000 | 0x3FFFFFFF | 32 | | Other Memory | 0x40000000 | 0x7FFFFFFF | 33 | | ISA I/O | 0x80000000 | 0x807FFFFF | 34 | | PCI I/O | 0x81000000 | 0xBEFFFFFF | 35 | | PCI/ISA Interrupt Ack | 0xBFFFFFF0 | 0xBFFFFFFF | 36 | | PCI Memory | 0xC0000000 | 0xFEFFFFFF | 37 | | ROM/Flash | 0xFF000000 | 0xFFFFFFFF | 38 | 39 | ### Sources 40 | 41 | * https://www.haiku-os.org/legacy-docs/benewsletter/Issue1-27.html 42 | * https://www.cebix.net/downloads/bebox/82378zb.pdf 43 | -------------------------------------------------------------------------------- /zdocs/developers/cpu/powerpc/mmu.md: -------------------------------------------------------------------------------- 1 | ## Disabling BAT translation 2 | 3 | BAT translation can be disabled by invalidating BAT registers. This is somewhat CPU specific. 4 | MPC601 implements its own format for BAT registers that differs from the PowerPC specification. 5 | 6 | MPC601-specific lower BAT registers has the "V" bit. If it's cleared, the corresponding BAT pair 7 | is invalid and won't be used for address translation. To invalidate BATs on MPC601, it's enough 8 | to write NULL to lower BAT registers. That's exactly what Power Mac 6100 ROM does: 9 | ``` 10 | li r0, 0 11 | mtspr ibat0l, r0 12 | mtspr ibat1l, r0 13 | mtspr ibat2l, r0 14 | ``` 15 | 16 | PowerPC CPUs starting with 603 uses the BAT register format described in the PowerPC specification. 17 | The upper BAT registers contain two bits: Vs (supervisor state valid bit) and Vp (problem/user state valid bit). 18 | PowerPC Architecture First Edition from 1993 gives the following code: 19 | 20 | ```BAT_entry_valid = (Vs & ~MSR_PR) | (Vp & MSR_PR)``` 21 | 22 | If neither Vs nor Vp is set, the corresponding BAT pair isn't valid and doesn't participate in address translation. 23 | To invalidate BATs on non-601, it's sufficient to set the upper BAT register to 0x00000000. 24 | -------------------------------------------------------------------------------- /zdocs/developers/dbdma.md: -------------------------------------------------------------------------------- 1 | The Description-Based Direct Memory Access (DBDMA) relies on memory-based descriptions, minimizing CPU interrupts. 2 | 3 | | Channel | Number | 4 | |:-----------------:|:------:| 5 | | SCSI0 | 0x0 | 6 | | FLOPPY | 0x1 | 7 | | ETHERNET TRANSMIT | 0x2 | 8 | | ETHERNET RECIEVE | 0x3 | 9 | | SCC TRANSMIT A | 0x4 | 10 | | SCC RECIEVE A | 0x5 | 11 | | SCC TRANSMIT B | 0x6 | 12 | | SCC RECIEVE B | 0x7 | 13 | | AUDIO OUT | 0x8 | 14 | | AUDIO IN | 0x9 | 15 | | SCSI1 | 0xA | 16 | 17 | What's notable about the registers is that they are in little-endian format, thus Mac OS uses the stwbrx and lwbrx instructions to store values. 18 | 19 | | Register | Offset | 20 | |:-----------------:|:------:| 21 | | ChannelControl | 0x00 | 22 | | ChannelStatus | 0x04 | 23 | | CommandPtrHi | 0x08 | 24 | | CommandPtrLo | 0x0C | 25 | | InterruptSelect | 0x10 | 26 | | BranchSelect | 0x14 | 27 | | WaitSelect | 0x18 | 28 | | TransferMode | 0x1C | 29 | | Data2PtrHi | 0x20 | 30 | | Data2PtrLo | 0x24 | 31 | | BranchPtrHi | 0x2C | 32 | | BranchPtrLo | 0x30 | 33 | 34 | | Command | Value | 35 | |:-----------------:|:------:| 36 | | OUTPUT_MORE | 0x0 | 37 | | OUTPUT_LAST | 0x1 | 38 | | INPUT_MORE | 0x2 | 39 | | INPUT_LAST | 0x3 | 40 | | STORE_QUAD | 0x4 | 41 | | LOAD_QUAD | 0x5 | 42 | | NOP | 0x6 | 43 | | STOP | 0x7 | 44 | 45 | | Key Name | Value | 46 | |:-----------------:|:------:| 47 | | KEY_STREAM0 | 0x0 | 48 | | KEY_STREAM1 | 0x1 | 49 | | KEY_STREAM2 | 0x2 | 50 | | KEY_STREAM3 | 0x3 | 51 | | KEY_REGS | 0x5 | 52 | | KEY_SYSTEM | 0x6 | 53 | | KEY_DEVICE | 0x7 | 54 | 55 | ## Control Register 56 | 57 | | Value | Offset | 58 | |:-----------:|:------:| 59 | | Branch | 0x100 | 60 | | Active | 0x400 | 61 | | Dead | 0x800 | 62 | | Wake | 0x1000 | 63 | | Flush | 0x2000 | 64 | | Pause | 0x4000 | 65 | | Run | 0x8000 | 66 | 67 | 68 | ## References 69 | 70 | * https://stuff.mit.edu/afs/sipb/contrib/doc/specs/protocol/chrp/chrp_io.pdf 71 | * https://stuff.mit.edu/afs/sipb/contrib/doc/specs/protocol/chrp/chrp_hrpa.pdf -------------------------------------------------------------------------------- /zdocs/developers/grackle.md: -------------------------------------------------------------------------------- 1 | The MPC106, codenamed "Grackle", is a PCI bridge/memory controller. Its predecessor was the MPC105, codenamed "Eagle". It replaced an Apple-made host bridge codenamed "Bandit", part number 343S1125. 2 | 3 | Unlike the CPU, which generally runs in big-endian mode, the Grackle runs in little-endian mode in compliance with the PCI standard. This usually means that to get the result in the correct endian, the PowerPC must load and store byte-reversed inputs and results. 4 | 5 | By default, Grackle operates on Address Map B. 6 | 7 | CONFIG_ADDR can be found at any address in the range 0xFEC00000–0xFEDFFFFF, while CONFIG_DAT can be found at any address in the range 0xFEE00000–0xFEEFFFFF. The device trees also establish 0xFEF00000 as the 8259 interrupt acknowledgement register. 8 | 9 | PCI Config addresses work as follows: 10 | 11 | bus << 16 | device << 11 | function << 8 | offset 12 | 13 | # Revisions 14 | 15 | Revisions under 4.0 could allow up to 75 MHz, whereas 4.0 and newer can allow up to 83 MHz. 16 | 17 | # General Data 18 | 19 | Vendor ID: 0x1057 (Motorola) 20 | Device ID: 0x0002 (MPC106) 21 | 22 | Within the Mac's own device tree, this is usually device 0. 23 | 24 | It also spans for 0x7F000000 bytes starting from 0x80000000. 25 | 26 | # Adding PCI devices to dingusppc 27 | 28 | The dingusppc CLI can add known PCI devices to a PCI slot (A1, B1, C1). 29 | 30 | Only the following device numbers connected to grackle are probed by Open Firmware: 31 | 32 | - @0 used by pci [grackle] 33 | - @c slot PERCH interrupt 0x1c 34 | - @d slot A1 interrupt 0x17 35 | - @e slot B1 interrupt 0x18 36 | - @f slot C1 interrupt 0x19 37 | - @10 used by mac-io [heathrow] which includes many devices with different interrupts 38 | - @12 slot F1 interrupt 0x16 used by AtiRageGT or AtiRagePro 39 | 40 | With minor additions to source code, dingusppc can add a known PCI device to any device number between @1 and @1f except for @10 and @12. A nvramrc patch can make Open Firmware probe the other device numbers. An OS might be able to probe these other device numbers even if they are not probed by Open Firmware. 41 | 42 | A better approach may be to attach a PCI bridge to one of the supported slots. Then additional devices can be attached to the PCI bridge. For a PCI bridge, Open Firmware will probe device numbers between @0 and @f. Some nvramrc patches could maybe make Open Firmware probe the PCI bridge devices up to device number @1f. PCI bridges can be nested. In any case, each device number can have up to 8 functions numbered from 0 to 7. 43 | 44 | The dingusppc CLI doesn't yet support adding devices to PCI bridges or adding function numbers 1 to 7. 45 | -------------------------------------------------------------------------------- /zdocs/developers/ibmpower.md: -------------------------------------------------------------------------------- 1 | The following document is intended primarily as a documentation on how the IBM Personal Power series (and similar computers) operates. It is currently not implemented in DingusPPC. 2 | 3 | ## Sources 4 | 5 | * http://ps-2.kev009.com/rs6000/redbook-cd/sg245120.pdf 6 | * http://ps-2.kev009.com/rs6000/rs6000_ps_pdf/Graphics/RS6000_Graphics_Handbook.pdf -------------------------------------------------------------------------------- /zdocs/developers/keylargo.md: -------------------------------------------------------------------------------- 1 | The KeyLargo ASIC is an intergrated I/O controller designed for use in New World Power 2 | Macintosh G3 and iMac computers. 3 | 4 | It would later be succeeded by the K2 ASIC 5 | 6 | ## PCI configuration space registers 7 | 8 | | Register name | Default value | 9 | |:-------------:|:--------------:| 10 | | VendorID | 0x106B (Apple) | 11 | | DeviceID | 0x0019 | 12 | | RevisionID | 0x01 | 13 | | Class code | 0xFF0000 | 14 | 15 | ## Additions 16 | 17 | * USB support 18 | * MPIC support 19 | -------------------------------------------------------------------------------- /zdocs/developers/memorymaps.md: -------------------------------------------------------------------------------- 1 | # VIRTUAL MEMORY MAP 2 | 3 | | Address | Area | 4 | |:-------------:|:--------------------------------------:| 5 | | 0x5FFFE000 | InfoRecord | 6 | | 0x5FFFEFF0 | NKSystemInfo | 7 | | 0x68000000 | Motorola 68K Emulator (0x100000 bytes) | 8 | | 0x68060000 | Emulator Code | 9 | | 0x68080000 | Opcode Dispatch Table | 10 | | 0x68FFE000 | KernelData | 11 | | 0x68FFF000 | EmulatorData | 12 | | 0xFF800000 | Open Firmware | 13 | | 0xFFF0C000 | HardwarePriv | 14 | 15 | # PHYSICAL MEMORY MAP 16 | 17 | ## NuBus Power Macs 18 | 19 | (Sourced Heavily from: http://mess.redump.net/mess/driver_info/mac_technical_notes) 20 | 21 | |Starting Address|Ending Address| Area | 22 | |:--------------:|:------------:|:----------------------------:| 23 | | 0x00000000 | 0x3FFFFFFF | Main Memory | 24 | | 0x40000000 | 0x4FFFFFFF | ROM Mirrors | 25 | | 0x50000000 | 0x5FFFFFFF | IO Devices | 26 | | 0x5FFFFFFC | | "cpuid", really a Machine ID | 27 | | 0x60000000 | 0xEFFFFFFF | NuBus "super slot" space | 28 | | 0xF1000000 | 0xFFBFFFFF | NuBus "standard slot" space | 29 | | 0xFFC00000 | 0xFFFFFFFF | ROM | 30 | 31 | ### IO Bus 32 | 33 | | Address | Area | 34 | |:-------------:|:------------------:| 35 | | 0x50F00000 | IO Base Address | 36 | | 0x50F04000 | SCC | 37 | | 0x50F14000 | Sound Chip (AWACS) | 38 | | 0x50F24000 | CLUT Control | 39 | | 0x50F28000 | Video Control | 40 | | 0x50F2A000 | Interrupt Control | 41 | 42 | 43 | ## PCI Power Macs 44 | 45 | ### Main Memory 46 | * 0x00000000 - 0x7FFFFFFF 47 | Mac OS 48 | 49 | * 0x00400000 - Open Firmware 50 | 51 | ### PCI/Device Memory Area 0x80000000 - 0xFF000000 52 | 53 | * 0x81000000 - Video Display Device (normally) 54 | 55 | * 0xF3000000 - 56 | Mac OS I/O Device area 57 | 58 | * 0xF3008000 - 0xF3008FFF - DMA Channels 59 | 60 | * 0xF3008000 - SCSI DMA 61 | * 0xF3008100 - Floppy DMA 62 | * 0xF3008200 - Ethernet transmit DMA 63 | * 0xF3008300 - Ethernet receive DMA 64 | * 0xF3008400 - SCC channel A transmit DMA 65 | * 0xF3008500 - SCC channel A receive DMA 66 | * 0xF3008600 - SCC channel B transmit DMA 67 | * 0xF3008700 - SCC channel B receive DMA 68 | * 0xF3008800 - Audio out DMA 69 | * 0xF3008900 - Audio in DMA 70 | 71 | * 0xF3009000 - ATI Mach 64 video card 72 | 73 | * 0xF3010000 - SCSI device registers (0x100 bytes) 74 | * 0xF3011000 - MACE (serial) device registers (0x100 bytes) 75 | * 0xF3012000 - SCC compatibility port (?) (0x100 bytes) 76 | * 0xF3013000 - SCC MacRISC port (Serial for 0x20, then Modem for 0x20, with remaining 0xC0 unknown) 77 | * 0xF3014000 - AWAC (Audio) chip device registers 78 | * 0xF3015000 - SWIM3 (floppy controller) device registers 79 | * 0xF3016000 - pseudo VIA1 device registers 80 | * 0xF3017000 - pseudo VIA2 device registers 81 | 82 | * 0xF3020000 - Heathrow ATA 83 | 84 | * 0xF8000000 - Hammerhead memory controller registers (0x1000000 bytes) 85 | 86 | * 0xFE010000 - 53C875 Hard Drive Controller 87 | 88 | * 0xFE000000 - Grackle Low/Base 89 | * 0xFEC00000 - Grackle CONFIG_ADDR (0x4 bytes, all redirected to 0xXXXXXCF8) 90 | * 0xFEE00000 - Grackle CONFIG_DATA (0x4 bytes, all redirected to 0xXXXXXCFF) 91 | 92 | ### ROM / Misc Area (0xFF000000 - 0xFFFFFFFF) 93 | * 0xFF000000 - ? 94 | 95 | * 0xFF000004 - "cpuid", really a machine ID 96 | 97 | * 0xFFC00000 - 0xFFFFFFFF 98 | Mac OS ROM Area 99 | 100 | * 0xFFC00000 - 0xFFEFFFFF - 68k Code Area 101 | 102 | (below addresses apply to Old World ROMs) 103 | 104 | * 0xFFF00100 - Reset Area (where the ROM begins executing) 105 | * 0xFFF10000 - Nanokernel Code 106 | * 0xFFF20000 - HW Init -------------------------------------------------------------------------------- /zdocs/developers/mesh.md: -------------------------------------------------------------------------------- 1 | The MESH is a SCSI controller used in Power Mac machines. 2 | 3 | # Registers 4 | 5 | | Register Name | Number | 6 | |:----------------:|:------:| 7 | | R_COUNT0 | 0x0 | 8 | | R_COUNT1 | 0x1 | 9 | | R_FIFO | 0x2 | 10 | | R_CMD | 0x3 | 11 | | R_BUS0STATUS | 0x4 | 12 | | R_BUS1STATUS | 0x5 | 13 | | FIFO_CNT | 0x6 | 14 | | EXCPT | 0x7 | 15 | | ERROR | 0x8 | 16 | | INTMASK | 0x9 | 17 | | INTERRUPT | 0xA | 18 | | SOURCEID | 0xB | 19 | | DESTID | 0xC | 20 | | SYNC | 0xD | 21 | | MESHID | 0xE | 22 | | SEL_TIMEOUT | 0xF | 23 | 24 | # Commands 25 | 26 | | Command Name | Number | 27 | |:----------------:|:------:| 28 | | NOP | 0x0 | 29 | | ARBITRATE | 0x1 | 30 | | SELECT | 0x2 | 31 | | COMMAND | 0x3 | 32 | | STATUS | 0x4 | 33 | | DATAOUT | 0x5 | 34 | | DATAIN | 0x6 | 35 | | MSGOUT | 0x7 | 36 | | MSGIN | 0x8 | 37 | | BUSFREE | 0x9 | 38 | | ENABLE_PARITY | 0xA | 39 | | DISABLE_PARITY | 0xB | 40 | | ENABLE_RESELECT | 0xC | 41 | | DISABLE_RESELECT | 0xD | 42 | | RESET_MESH | 0xE | 43 | | FLUSH_FIFO | 0xF | 44 | | SEQ_DMA | 0x20 | 45 | | SEQ_TARGET | 0x40 | 46 | | SEQ_ATN | 0x80 | -------------------------------------------------------------------------------- /zdocs/developers/motorolaatlas.md: -------------------------------------------------------------------------------- 1 | The following document is intended primarily as a documentation on how the Motorola Atlas operates. It is currently not implemented in DingusPPC. 2 | 3 | ## General 4 | 5 | The computer generally follows the PReP standard, but there is some x86 emulation for using the VGA BIOS. 6 | 7 | ## Sources 8 | 9 | * https://cdn.preterhuman.net/texts/computing/chrp_prep/ambih.pdf -------------------------------------------------------------------------------- /zdocs/developers/swim3.md: -------------------------------------------------------------------------------- 1 | The SWIM 3 (Sanders-Wozniak integrated machine 3) is the floppy drive disk controller. As can be inferred by the name, the SWIM III chip is the improvement of a combination of floppy disk driver designs by Steve Wozniak (who worked on his own floppy drive controller for early Apple computers) and Wendell B. Sander (who worked on an MFM-compatible IBM floppy drive controller). 2 | 3 | The original SWIM chip supported Group Coded Recording (GCR)-formatted floppy disks in 400 kb and 800 kb formats, while the newer SWIM2 and SWIM3 chips include support for 1.44 MB floppies in MFM format. 4 | 5 | The SWIM chip is resided on the logic board physically and is located at IOBase + 0x15000 in the device tree. It sits between the I/O controller and the floppy disk connector. Its function is to translate the I/O commands to specialized signals to drive the floppy disk drive, i.e. disk spinning speed, head position, phase sync, etc. 6 | 7 | Unlike its predecessors, it allowed some DMA capability to transfer read or write data. 8 | 9 | The floppy drives themselves were provided by Sony. 10 | 11 | Some New World Macs such as Rev. A iMac G3s do have a SWIM 3 driver present, but this normally goes unused due to no floppy drive being connected. 12 | 13 | # Registers 14 | 15 | | Offset | Functionality | 16 | |:------:|:-------------------------------:| 17 | | 0x0 | Data | 18 | | 0x1 | Timer | 19 | | 0x2 | Error | 20 | | 0x3 | Parameter Data | 21 | | 0x4 | Phase | 22 | | 0x5 | Setup | 23 | | 0x6 | Read Mode (Read), Mode (Write) | 24 | | 0x7 | Handshake (Read), Mode (Write) | 25 | | 0x8 | Interrupt | 26 | | 0x9 | Step | 27 | | 0xA | Current Track | 28 | | 0xB | Current Sector | 29 | | 0xC | Gap/Format | 30 | | 0xD | First Sector | 31 | | 0xE | Sectors to Transfer | 32 | | 0xF | Interrupt Mask | -------------------------------------------------------------------------------- /zdocs/developers/valkyrie.md: -------------------------------------------------------------------------------- 1 | The Valkyrie video chip is included in some Quadras and Performas. The Marathon games (2 and Infinity, at least) use this chip to blit 16-bit video. 2 | 3 | | Register Name | Offset | 4 | |:-------------------------:|:------:| 5 | | CLUT Address | 0x4000 | 6 | | CLUT Graphic | 0x4004 | 7 | | CLUT Video Data | 0x4008 | 8 | | CLUT Color Key | 0x400C | 9 | | Subsystem Config | 0xA00C | 10 | | Video In Control | 0xA020 | 11 | | Window X Start | 0xA060 | 12 | | Window Y Start | 0xA064 | 13 | | Window Width | 0xA070 | 14 | | Window Height | 0xA074 | 15 | | Video Field X Start | 0xA080 | 16 | | Video Field Y Start | 0xA084 | 17 | --------------------------------------------------------------------------------