[
  {
    "path": ".clang-format",
    "content": "---\nLanguage:        Cpp\n# BasedOnStyle:  LLVM\nAccessModifierOffset: -2\nAlignAfterOpenBracket: Align\nAlignConsecutiveMacros: false\nAlignConsecutiveAssignments: false\nAlignConsecutiveDeclarations: false\nAlignEscapedNewlines: Right\nAlignOperands:   true\nAlignTrailingComments: true\nAllowAllArgumentsOnNextLine: true\nAllowAllConstructorInitializersOnNextLine: true\nAllowAllParametersOfDeclarationOnNextLine: true\nAllowShortBlocksOnASingleLine: false\nAllowShortCaseLabelsOnASingleLine: false\nAllowShortFunctionsOnASingleLine: All\nAllowShortLambdasOnASingleLine: All\nAllowShortIfStatementsOnASingleLine: Never\nAllowShortLoopsOnASingleLine: false\nAlwaysBreakAfterDefinitionReturnType: None\nAlwaysBreakAfterReturnType: None\nAlwaysBreakBeforeMultilineStrings: false\nAlwaysBreakTemplateDeclarations: MultiLine\nBinPackArguments: true\nBinPackParameters: true\nBraceWrapping:\n  AfterCaseLabel:  false\n  AfterClass:      false\n  AfterControlStatement: false\n  AfterEnum:       false\n  AfterFunction:   false\n  AfterNamespace:  false\n  AfterObjCDeclaration: false\n  AfterStruct:     false\n  AfterUnion:      false\n  AfterExternBlock: false\n  BeforeCatch:     false\n  BeforeElse:      false\n  IndentBraces:    false\n  SplitEmptyFunction: true\n  SplitEmptyRecord: true\n  SplitEmptyNamespace: true\nBreakBeforeBinaryOperators: None\nBreakBeforeBraces: Attach\nBreakBeforeInheritanceComma: false\nBreakInheritanceList: BeforeColon\nBreakBeforeTernaryOperators: true\nBreakConstructorInitializersBeforeComma: false\nBreakConstructorInitializers: BeforeColon\nBreakAfterJavaFieldAnnotations: false\nBreakStringLiterals: true\nColumnLimit:     80\nCommentPragmas:  '^ IWYU pragma:'\nCompactNamespaces: false\nConstructorInitializerAllOnOneLineOrOnePerLine: false\nConstructorInitializerIndentWidth: 4\nContinuationIndentWidth: 4\nCpp11BracedListStyle: true\nDerivePointerAlignment: false\nDisableFormat:   false\nExperimentalAutoDetectBinPacking: false\nFixNamespaceComments: true\nForEachMacros:\n  - foreach\n  - Q_FOREACH\n  - BOOST_FOREACH\nIncludeBlocks:   Preserve\nIncludeCategories:\n  - Regex:           '^\"(llvm|llvm-c|clang|clang-c)/'\n    Priority:        2\n  - Regex:           '^(<|\"(gtest|gmock|isl|json)/)'\n    Priority:        3\n  - Regex:           '.*'\n    Priority:        1\nIncludeIsMainRegex: '(Test)?$'\nIndentCaseLabels: false\nIndentPPDirectives: None\nIndentWidth:     2\nIndentWrappedFunctionNames: false\nJavaScriptQuotes: Leave\nJavaScriptWrapImports: true\nKeepEmptyLinesAtTheStartOfBlocks: true\nMacroBlockBegin: ''\nMacroBlockEnd:   ''\nMaxEmptyLinesToKeep: 1\nNamespaceIndentation: None\nObjCBinPackProtocolList: Auto\nObjCBlockIndentWidth: 2\nObjCSpaceAfterProperty: false\nObjCSpaceBeforeProtocolList: true\nPenaltyBreakAssignment: 2\nPenaltyBreakBeforeFirstCallParameter: 19\nPenaltyBreakComment: 300\nPenaltyBreakFirstLessLess: 120\nPenaltyBreakString: 1000\nPenaltyBreakTemplateDeclaration: 10\nPenaltyExcessCharacter: 1000000\nPenaltyReturnTypeOnItsOwnLine: 60\nPointerAlignment: Right\nReflowComments:  true\nSortIncludes:    true\nSortUsingDeclarations: true\nSpaceAfterCStyleCast: false\nSpaceAfterLogicalNot: false\nSpaceAfterTemplateKeyword: true\nSpaceBeforeAssignmentOperators: true\nSpaceBeforeCpp11BracedList: false\nSpaceBeforeCtorInitializerColon: true\nSpaceBeforeInheritanceColon: true\nSpaceBeforeParens: ControlStatements\nSpaceBeforeRangeBasedForLoopColon: true\nSpaceInEmptyParentheses: false\nSpacesBeforeTrailingComments: 1\nSpacesInAngles:  false\nSpacesInContainerLiterals: true\nSpacesInCStyleCastParentheses: false\nSpacesInParentheses: false\nSpacesInSquareBrackets: false\nStandard:        Cpp11\nStatementMacros:\n  - Q_UNUSED\n  - QT_REQUIRE_VERSION\nTabWidth:        8\nUseTab:          Never\n...\n\n"
  },
  {
    "path": ".github/workflows/build-test-and-artifact.yml",
    "content": "name: Build, run test and upload binaries \n\non: [push, pull_request]\n\njobs:\n\n  linux-x86-clang:\n    runs-on: \"ubuntu-24.04\"\n\n    steps:\n    - uses: actions/checkout@v4\n\n    - name: Get current date\n      id: date\n      run: echo \"name=date::$(date +'%Y-%m-%dT%H%M')\" >> $GITHUB_OUTPUT\n\n    - name: Install build dependencies\n      run: sudo apt -y update && sudo apt -y install libpcap-dev libsdl-dev netcat-openbsd\n\n    - name: Create build environment\n      run: cmake -E make_directory ${{runner.workspace}}/build\n\n    - name: Configure CMake\n      shell: bash\n      working-directory: ${{runner.workspace}}/build\n      run: cmake $GITHUB_WORKSPACE -DCMAKE_C_COMPILER=\"clang\" -DCMAKE_CXX_COMPILER=\"clang++\" -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=\"-Wall\"\n\n    - name: Build\n      working-directory: ${{runner.workspace}}/build\n      shell: bash\n      run: cmake --build . --config Release\n      env:\n        MAKEFLAGS: \"-j2\"\n\n    - name: Run test scripts\n      working-directory: ${{runner.workspace}}/axpbox\n      shell: bash\n      run: ${{runner.workspace}}/axpbox/test/run\n\n    - name: Upload AXPbox binary\n      uses: actions/upload-artifact@v4\n      with:\n        name: AXPbox-linux-x86-clang-${{ env.BUILD_DATE }}\n        path: ${{runner.workspace}}/build/axpbox \n      env:\n        BUILD_DATE: ${{ steps.date.outputs.date }}\n\n  linux-x86-gcc:\n    runs-on: \"ubuntu-24.04\"\n\n    steps:\n    - uses: actions/checkout@v4\n\n    - name: Get current date\n      id: date\n      run: echo \"name=date::$(date +'%Y-%m-%dT%H%M')\" >> $GITHUB_OUTPUT\n      \n    - name: Install gcovr\n      run: pip install gcovr\n\n    - name: Install build dependencies\n      run: sudo apt -y update && sudo apt -y install libpcap-dev libsdl1.2-dev netcat-openbsd\n\n    - name: Create build environment\n      run: cmake -E make_directory ${{runner.workspace}}/build\n\n    - name: Configure CMake\n      shell: bash\n      working-directory: ${{runner.workspace}}/build\n      run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=\"-Wall\" -DCMAKE_EXPORT_COMPILE_COMMANDS=1\n\n    - name: Build\n      working-directory: ${{runner.workspace}}/build\n      shell: bash\n      run: cmake --build . --config Release\n      env:\n        MAKEFLAGS: \"-j2\"\n\n    - name: Run test scripts\n      working-directory: ${{runner.workspace}}/axpbox\n      shell: bash\n      run: ${{runner.workspace}}/axpbox/test/run\n\n    - name: Upload AXPbox binary\n      uses: actions/upload-artifact@v4\n      with:\n        name: AXPbox-linux-x86-gcc-${{ env.BUILD_DATE }}\n        path: ${{runner.workspace}}/build/axpbox\n      env:\n        BUILD_DATE: ${{ steps.date.outputs.date }} \n\n  linux-arm-gcc-crosscompile:\n    runs-on: \"ubuntu-24.04\"\n    continue-on-error: true\n\n    steps:\n    - uses: actions/checkout@v4\n\n    - name: Get current date\n      id: date\n      run: echo \"::set-output name=date::$(date +'%Y-%m-%dT%H%M')\"\n\n    - name: Install build dependencies\n      run: sudo apt -y update && sudo apt -y install netcat-openbsd qemu-user qemu-user-binfmt gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf libc6-dev-armhf-cross\n\n    - name: Create build environment\n      run: cmake -E make_directory ${{runner.workspace}}/build\n\n    - name: Configure CMake\n      shell: bash\n      working-directory: ${{runner.workspace}}/build\n      run: cmake $GITHUB_WORKSPACE -DSTATIC_COMPILE=yes -DDISABLE_PCAP=yes -DDISABLE_SDL=yes -DDISABLE_X11=yes -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=\"-Wall\" -DCMAKE_C_COMPILER=arm-linux-gnueabihf-gcc -DCMAKE_CXX_COMPILER=arm-linux-gnueabihf-g++ -DCMAKE_CXX_FLAGS=\"-O3 -mcpu=cortex-a7 -mfpu=neon -mfloat-abi=hard -mno-unaligned-access\"\n\n    - name: Build\n      working-directory: ${{runner.workspace}}/build\n      shell: bash\n      run: cmake --build . --config Release\n      env:\n        MAKEFLAGS: \"-j2\"\n\n    - name: Run binary\n      working-directory: ${{runner.workspace}}/axpbox\n      shell: bash\n      run: ${{runner.workspace}}/build/axpbox\n\n    - name: Binary info\n      working-directory: ${{runner.workspace}}/axpbox\n      shell: bash\n      run: file ${{runner.workspace}}/build/axpbox\n\n    - name: Upload AXPbox binary\n      uses: actions/upload-artifact@v4\n      with:\n        name: AXPbox-linux-ARM-gcc-${{ env.BUILD_DATE }}\n        path: ${{runner.workspace}}/build/axpbox\n      env:\n        BUILD_DATE: ${{ steps.date.outputs.date }}        \n\n  windows-x86-msvc:\n    runs-on: windows-2025\n    steps:\n    - uses: actions/checkout@v4\n\n    - name: Create npcap sdk folder\n      working-directory: ${{runner.workspace}}\\\n      run: mkdir pcap\n\n    - name: Download npcap sdk\n      working-directory: ${{runner.workspace}}\\pcap\n      run: curl -o ./npcap-sdk-1.13.zip https://npcap.com/dist/npcap-sdk-1.13.zip\n\n    - name: unzip npcap sdk\n      working-directory: ${{runner.workspace}}\\pcap\n      run: unzip npcap-sdk-1.13.zip\n\n    - name: Get current date\n      id: date\n      run: echo \"name=date::$(date +'%Y-%m-%dT%H%M')\" >> $GITHUB_OUTPUT\n\n    - name: Create build environment\n      run: cmake -E make_directory ${{runner.workspace}}\\build\n\n    - name: Configure CMake\n      shell: bash\n      working-directory: ${{runner.workspace}}/build\n      run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=Release  -DPCAP_INCLUDE_DIR=\"${{runner.workspace}}/pcap/Include/\"  -DPCAP_LIBRARY=\"${{runner.workspace}}/pcap/Lib/x64/wpcap.lib\"\n\n    - name: Build\n      working-directory: ${{runner.workspace}}\\build\n      shell: bash\n      run: cmake --build . --config Release\n      env:\n        MAKEFLAGS: \"-j2\"\n\n    - name: Test run\n      working-directory: ${{runner.workspace}}\\build\n      run: ${{runner.workspace}}\\build\\Release\\axpbox.exe\n\n    - name: Upload AXPbox Binary\n      uses: actions/upload-artifact@v4\n      with:\n        name: AXPbox-windows-x86-msvc-${{ env.BUILD_DATE }}.exe\n        path: ${{runner.workspace}}\\build\\Release\\axpbox.exe\n      env:\n        BUILD_DATE: ${{ steps.date.outputs.date }}\n\n  osx-x86-appleclang:\n    runs-on: macos-15\"  \n    steps:\n    - uses: actions/checkout@v4\n\n    - name: Get current date\n      id: date\n      run: echo \"::set-output name=date::$(date +'%Y-%m-%dT%H%M')\"\n\n    - name: Create build environment\n      run: cmake -E make_directory ${{runner.workspace}}/build\n\n    - name: Install dependencies\n      run: brew install libpcap netcat gnu-sed # sdl2 libx11 / sdl doesnt work see #44\n\n    - name: Configure CMake\n      shell: bash\n      working-directory: ${{runner.workspace}}/build\n      run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=\"-Wall -std=c++11 -stdlib=libc++ -I/usr/local/opt/libpcap/include\"\n\n    - name: Build\n      working-directory: ${{runner.workspace}}/build\n      shell: bash\n      run: cmake --build . --config Release\n      env:\n        MAKEFLAGS: \"-j2\"\n\n    - name: Upload AXPbox Binary\n      uses: actions/upload-artifact@v4\n      with:\n        name: AXPbox-osx-x86-12-appleclang-${{ env.BUILD_DATE }}\n        path: ${{runner.workspace}}/build/axpbox \n      env:\n        BUILD_DATE: ${{ steps.date.outputs.date }} \n\n"
  },
  {
    "path": ".gitignore",
    "content": "cmake-build-debug/\ncmake-build-release/\nbuild**/\n.idea/\n.vs/\nCMakeSettings.json\nrun/\nimg/\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: cpp\ndist: focal\ncompiler: clang\n\nbefore_install: sudo apt-get install cmake libpcap-dev libsdl-dev netcat-openbsd\ninstall:\n  - mkdir build\n  - cd build\n  - cmake .. -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=\"-Wall -Werror\"\n  - make\n  - cd ..\nscript:\n  - test/run\n\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.10)\nset(CMAKE_CXX_STANDARD 11)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nproject(AXPBox VERSION 1.1.3)\n\n# Source files\nfile(GLOB srcs src/*.cpp src/base/*.cpp src/gui/*.cpp)\nfile(GLOB include_sources src/base/*WIN32.cpp src/base/*POSIX.cpp)\nlist(REMOVE_ITEM srcs ${include_sources})\n\nadd_executable(axpbox ${srcs} src/Main.cpp)\ntarget_include_directories(axpbox PRIVATE src src/base src/gui ${CMAKE_BINARY_DIR}/src)\n\n# Path to additional CMake modules\nset(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)\n\nif (CMAKE_GENERATOR MATCHES \"Visual Studio\")\n  add_definitions(-DNOMINMAX -D_WIN32_WINNT=0x0A00 -DLANG_CXX11 -DCOMPILER_MSVC -D__VERSION__=\\\"MSVC\\\")\n  add_definitions(-DWIN32 -DOS_WIN -D_MBCS -DWIN64 -DWIN32_LEAN_AND_MEAN -DNOGDI -DPLATFORM_WINDOWS)\n  add_definitions(/bigobj /nologo /EHsc /GF /FC /MP /Gm-)\n  # Suppress warnings to reduce build log size.\n  add_definitions(/wd4267 /wd4244 /wd4800 /wd4503 /wd4554 /wd4996 /wd4348 /wd4018)\n  add_definitions(/wd4099 /wd4146 /wd4267 /wd4305 /wd4307)\n  add_definitions(/wd4715 /wd4722 /wd4723 /wd4838 /wd4309 /wd4334)\n  set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /MP\")\nendif()\n\nfind_package(Threads REQUIRED)\ntarget_link_libraries(axpbox Threads::Threads)\n\n# Configuration options\ninclude(CheckSymbolExists)\ninclude(CheckIncludeFile)\ninclude(CheckLibraryExists)\ninclude(CheckTypeSize)\ninclude(CheckIncludeFiles)\ninclude(TestBigEndian)\ninclude(CheckLargeFiles)\n\nTEST_BIG_ENDIAN(IS_BIG_ENDIAN)\nif(IS_BIG_ENDIAN)\n    set(ES40_BIG_ENDIAN 1)\nelse()\n    set(ES40_LITTLE_ENDIAN 1)\nendif()\n\ncheck_symbol_exists(alarm \"unistd.h\" HAVE_ALARM)\ncheck_include_file(\"arpa/inet.h\" HAVE_ARPA_INET_H)\ncheck_include_file(\"arpa/telnet.h\" HAVE_ARPA_TELNET_H)\ncheck_symbol_exists(atexit \"stdlib.h\" HAVE_ATEXIT)\ncheck_include_file(\"ctype.h\" HAVE_CTYPE_H)\ncheck_include_file(\"errno.h\" HAVE_ERRNO_H)\ncheck_include_file(\"fcntl.h\" HAVE_FCNTL_H)\ncheck_symbol_exists(fopen \"stdio.h\" HAVE_FOPEN)\ncheck_symbol_exists(fopen64 \"stdio.h\" HAVE_FOPEN64)\ncheck_symbol_exists(fork \"unistd.h\" HAVE_FORK)\ncheck_symbol_exists(fseek \"stdio.h\" HAVE_FSEEK)\ncheck_symbol_exists(fseeko \"stdio.h\" HAVE_FSEEKO)\ncheck_symbol_exists(fseeko64 \"stdio.h\" HAVE_FSEEKO64)\ncheck_symbol_exists(ftell \"stdio.h\" HAVE_FTELL)\ncheck_symbol_exists(ftello \"stdio.h\" HAVE_FTELLO)\ncheck_symbol_exists(ftello64 \"stdio.h\" HAVE_FTELLO64)\ncheck_symbol_exists(gmtime_s \"time.h\" HAVE_GMTIME_S)\ncheck_symbol_exists(inet_aton \"arpa/inet.h\" HAVE_INET_ATON)\ncheck_include_file(\"inet.h\" HAVE_INET_H)\ncheck_include_file(\"inttypes.h\" HAVE_INTTYPES_H)\ncheck_include_file(\"in.h\" HAVE_IN_H)\ncheck_symbol_exists(isblank \"ctype.h\" HAVE_ISBLANK)\ncheck_symbol_exists(localtime_s \"time.h\" HAVE_LOCALTIME_S)\ncheck_symbol_exists(malloc \"stdlib.h\" HAVE_MALLOC)\ncheck_include_file(\"malloc.h\" HAVE_MALLOC_H)\ncheck_include_file(\"memory.h\" HAVE_MEMORY_H)\ncheck_symbol_exists(memset \"string.h\" HAVE_MEMSET)\ncheck_include_file(\"netinet/in.h\" HAVE_NETINET_IN_H)\ncheck_symbol_exists(pow \"math.h\" HAVE_POW)\ncheck_include_file(\"process.h\" HAVE_PROCESS_H)\ncheck_library_exists(pthread pthread_self \"\" HAVE_PTHREAD)\ncheck_include_file(\"pthread.h\" HAVE_PTHREAD_H)\ncheck_symbol_exists(realloc \"stdlib.h\" HAVE_REALLOC)\ncheck_symbol_exists(select \"sys/select.h\" HAVE_SELECT)\ncheck_include_file(\"signal.h\" HAVE_SIGNAL_H)\ncheck_symbol_exists(socket \"sys/socket.h\" HAVE_SOCKET)\ncheck_include_file(\"socket.h\" HAVE_SOCKET_H)\ncheck_symbol_exists(sqrt \"math.h\" HAVE_SQRT)\ncheck_include_file(\"stdbool.h\" HAVE_STDBOOL_H)\ncheck_include_file(\"stdint.h\" HAVE_STDINT_H)\ncheck_include_file(\"stdlib.h\" HAVE_STDLIB_H)\ncheck_symbol_exists(strcasecmp \"string.h\" HAVE_STRCASECMP)\ncheck_symbol_exists(strchr \"string.h\" HAVE_STRCHR)\ncheck_symbol_exists(strdup \"string.h\" HAVE_STRDUP)\ncheck_include_file(\"stddef.h\" HAVE_STDDEF_H)\ncheck_include_file(\"strings.h\" HAVE_STRINGS_H)\ncheck_include_file(\"string.h\" HAVE_STRING_H)\ncheck_symbol_exists(strncasecmp \"string.h\" HAVE_STRNCASECMP)\ncheck_symbol_exists(strspn \"string.h\" HAVE_STRSPN)\ncheck_include_file(\"sys/param.h\" HAVE_SYS_PARAM_H)\ncheck_include_file(\"sys/select.h\" HAVE_SYS_SELECT_H)\ncheck_include_file(\"sys/socket.h\" HAVE_SYS_SOCKET_H)\ncheck_include_file(\"sys/stat.h\" HAVE_SYS_STAT_H)\ncheck_include_file(\"sys/time.h\" HAVE_SYS_TIME_H)\ncheck_include_file(\"sys/types.h\" HAVE_SYS_TYPES_H)\ncheck_include_file(\"sys/wait.h\" HAVE_SYS_WAIT_H)\ncheck_include_file(\"unistd.h\" HAVE_UNISTD_H)\ncheck_symbol_exists(vfork \"unistd.h\" HAVE_VFORK)\ncheck_include_file(\"vfork.h\" HAVE_VFORK_H)\ncheck_include_file(\"windows.h\" HAVE_WINDOWS_H)\ncheck_include_file(\"winsock2.h\" HAVE_WINSOCK2_H)\nset(HAVE_WORKING_FORK ${HAVE_FORK})\nset(HAVE_WORKING_VFORK ${HAVE_VFORK})\ncheck_include_file(\"ws2tcpip.h\" HAVE_WS2TCPIP_H)\ncheck_type_size(_Bool _BOOL)\ncheck_symbol_exists(_fseeki64 \"stdio.h\" HAVE__FSEEKI64)\ncheck_symbol_exists(_ftelli64 \"stdio.h\" HAVE__FTELLI64)\ncheck_symbol_exists(_strdup \"string.h\" HAVE__STRDUP)\ncheck_symbol_exists(_stricasecmp \"string.h\" HAVE__STRICASECMP)\ncheck_symbol_exists(_stricmp \"string.h\" HAVE__STRICMP)\n\n# Features\ncheck_include_file(\"SDL/SDL.h\" HAVE_SDL)\ncheck_include_file(\"X11/X.h\" HAVE_X11)\n# Large file support (fopen64 / disk files > 2 GB)\nAXPBOX_TEST_LARGE_FILES(HAVE_LARGE_FILES)\n\nif (DISABLE_PCAP STREQUAL \"yes\")\n    set(WANT_PCAP 0)\nelse()\n    set(WANT_PCAP 1)\nendif()\n\nif(WANT_PCAP)\n    find_package(PCAP)\n    if(PCAP_FOUND)\n        message(STATUS \"pcap found. Networking support enabled\")\n        set(HAVE_PCAP 1)\n        include_directories(${PCAP_INCLUDE_DIR})\n        target_link_libraries(axpbox ${PCAP_LIBRARY})\n    else()\n        message(STATUS \"pcap not found. Networking support disabled\")\n    endif()\nelse()\n    message(STATUS \"pcap disabled. Networking support disabled\")\nendif()\n\nif (DISABLE_SDL STREQUAL \"yes\")\n    set(HAVE_SDL 0)\nendif()\nif (DISABLE_X11 STREQUAL \"yes\")\n    set(HAVE_X11 0)\nendif()\n\nif(HAVE_SDL)\n    target_link_libraries(axpbox SDL)\n    message(STATUS \"sdl found. SDL graphics support enabled\")\nelse()\n    message(WARNING \"sdl not found. Building without SDL graphics support\")\nendif()\nif(HAVE_X11)\n    target_link_libraries(axpbox X11)\n    message(STATUS \"x11 found. x11 graphics support enabled\")\nelse()\n    message(WARNING \"x11 not found. Building without x11 graphics support\")\nendif()\n\nif (STATIC_COMPILE STREQUAL \"yes\")\n    message(STATUS \"Static compilation\")\n    set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -static -lpthread -lrt -Wl,--whole-archive -lpthread -Wl,--no-whole-archive\")\n    set(CMAKE_EXE_LINKER_FLAGS \"-static\")\n    set(CMAKE_FIND_LIBRARY_SUFFIXES \".a\")\n    set(BUILD_SHARED_LIBS OFF)\nendif()\n\nif (NOT CMAKE_GENERATOR MATCHES \"Visual Studio\")\n    if (CMAKE_BUILD_TYPE STREQUAL \"Debug\")\n        set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -Og -ggdb\")\n        set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -Og -ggdb\")\n    elseif (CMAKE_BUILD_TYPE STREQUAL \"Release\")\n        set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -O3\")\n        set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -O3 -DNDEBUG\")\n    endif()\nendif()\n\nif(HAVE_LARGE_FILES)\n    message(STATUS \"Large file support enabled\")\nelse()\n    message(WARNING \"Building without large file graphics support\")\nendif()\n\nfind_package(Git)\nif (GIT_FOUND)\n    execute_process(COMMAND\n        \"${GIT_EXECUTABLE}\" describe --match=NeVeRmAtCh --always --abbrev=40 --dirty\n        WORKING_DIRECTORY \"${CMAKE_SOURCE_DIR}\"\n        OUTPUT_VARIABLE GIT_SHA\n        ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)\n\n    set(PACKAGE_GITSHA \"\\\"${GIT_SHA}\\\"\")\nendif()\n\nset(PACKAGE ${PROJECT_NAME})\nset(PACKAGE_BUGREPORT \"tglozar@gmail.com\")\nset(PACKAGE_NAME string(TOLOWER ${PROJECT_NAME}))\nset(PACKAGE_VERSION ${PROJECT_VERSION})\nset(PACKAGE_STRING ${PACKAGE_NAME}-${PACKAGE_VERSION})\nset(PACKAGE_TARNAME ${PACKAGE_STRING}.tar.gz)\nset(PACKAGE_URL \"http://github.com/lenticularis39/axpbox\")\n\nset(PTHREAD_CREATE_JOINABLE \"PTHREAD_CREATE_JOINABLE\")\nset(SELECT_TYPE_ARG1 \"int\")\nset(SELECT_TYPE_ARG234 \"fd_set *\")\nset(SELECT_TYPE_ARG5 \"struct timeval *\")\nset(RETSIGTYPE \"void\")\nset(STDC_HEADERS 1)\ncheck_include_files(\"time.h;sys/time.h\" TIME_WITH_SYS_TIME)\n\nconfigure_file(src/config.hpp.in src/config.hpp)\n\ninstall(TARGETS axpbox DESTINATION bin)\n\nmessage(STATUS \"C++ compiler flags  : ${CMAKE_CXX_FLAGS}\")\nmessage(STATUS \"C compiler flags    : ${CMAKE_C_FLAGS}\")\nmessage(STATUS \"Linker flags        : ${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS} ${CMAKE_STATIC_LINKER_FLAGS}\")\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.,\n 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Lesser General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n                            NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.\n"
  },
  {
    "path": "README.md",
    "content": "# AXPbox Alpha emulator\n\nAXPbox is a fork of the discontinued es40 emulator. It could theoretically used for running any operating system that runs on the OpenVMS or Tru64 PALcode (e.g. OpenVMS, Tru64 UNIX, Linux, NetBSD), however as of now only OpenVMS and some versions of NetBSD can be installed (for more details see [Guest support](https://github.com/lenticularis39/axpbox/wiki/Guest-support)).\n\nThe emulator supports SCSI, IDE, serial ports, Ethernet (using PCAP) and [VGA graphics](https://github.com/lenticularis39/axpbox/wiki/VGA) (using SDL).\n\n![OpenVMS 8.4 desktop](https://i.ibb.co/zQh35hm/Sn-mek-z-2021-01-24-14-18-41.png)\n\nOpenVMS 8.4 desktop in AXPbox. [Here is a wiki page showing you how to get this CDE desktop running](https://github.com/lenticularis39/axpbox/wiki/GUI-Desktop-Environment-(CDE))\n\n## Getting AXPbox\n\nPre-built binaries for generic Linux amd64, Windows 10 amd64 and macOS amd64 are available for each release, and also as artifacts produced for each commit in CI. T2 SDE has an [official package](http://t2sde.org/packages/axpbox) for AXPbox, and openSUSE's Emulators project has an [AXPbox package](https://build.opensuse.org/package/show/Emulators/axpbox), too. The former gets updated the same day when a release happens, while requests are submitted now the latter that undergo approval of Emulators maintainers.\n\nYou can also build from source using CMake; you need a C++ 11 compiler, optional dependencies are PCAP for networking and SDL or X11 for graphics support.\n\n## Usage\n\nFirst invoke the interactive configuration file generator:\n```\naxpbox configure\n```\nThis creates a file named es40.cfg, which you can now modify (the generator UI doesn't allow to set all options). After the configuration file and the required ROM image are ready, you can start the emulation:\n```\naxpbox run\n```\n\nPlease read the [Installation Guide](https://github.com/lenticularis39/axpbox/wiki/OpenVMS-installation-guide) for information to get OpenVMS installed in the emulator. A guide for NetBSD is [also available on the Wiki](https://github.com/lenticularis39/axpbox/wiki/NetBSD-9.2-install-guide)\n\n## Changes in comparison with es40\n\n- Renamed from es40 to AXPbox to avoid confusion with the physical machine (AlphaServer ES40)\n- CMake is used for compilation instead of autotools\n- OpenVMS host support was dropped\n- es40 and es40_cfg were merged into one executable (axpbox)\n- The code was cleaned to compile without warnings on most compilers\n- Code modernizing, replacing POCO framework parts by native C++11 counterparts not available in 2008 (std::threads, etc)\n- Incorporate various patches from other es40 forks, for example, added MC146818 periodic interrupt to allow netbsd to boot and install, skip_memtest for faster booting.\n- Bug fixes, less segfaults, overall less crashes. \n- [More](https://github.com/lenticularis39/axpbox/wiki/) documentation and usage information on the various features and operating systems\n\n## What doesn't work (also see issues)\n\n- Some guest operating systems (see [Guest support](https://github.com/lenticularis39/axpbox/wiki/Guest-support))\n- ARC\n- VGA in OpenVMS\n- SDL keyboard (partly works, but easily breaks)\n- Multiple CPU system emulation\n- Running on big endian platforms\n- Some SCSI and IDE commands\n- Copying large files between IDE CD-ROM to IDE hard drive (this usually doesn't affect OpenVMS installation)\n"
  },
  {
    "path": "cmake/CheckLargeFiles.cmake",
    "content": "# Via: https://github.com/uclouvain/openjpeg/blob/master/cmake/TestLargeFiles.cmake\n# - Define macro to check large file support\n#\n#  AXPBOX_TEST_LARGE_FILES(VARIABLE)\n#\n#  VARIABLE will be set to true if off_t is 64 bits, and fseeko/ftello present.\n#  This macro will also defines the necessary variable enable large file support, for instance\n#  _LARGE_FILES\n#  _LARGEFILE_SOURCE\n#  _FILE_OFFSET_BITS 64\n#  AXPBOX_HAVE_FSEEKO\n#\n#  Adapted from Gromacs project (http://www.gromacs.org/)\n#  by Julien Malik\n#\n\nmacro(AXPBOX_TEST_LARGE_FILES VARIABLE)\n    if(NOT DEFINED ${VARIABLE})\n\n        # On most platforms it is probably overkill to first test the flags for 64-bit off_t,\n        # and then separately fseeko. However, in the future we might have 128-bit filesystems\n        # (ZFS), so it might be dangerous to indiscriminately set e.g. _FILE_OFFSET_BITS=64.\n\n        message(STATUS \"Checking for 64-bit off_t\")\n\n        # First check without any special flags\n        try_compile(FILE64_OK \"${PROJECT_BINARY_DIR}\"\n                \"${PROJECT_SOURCE_DIR}/cmake/TestFileOffsetBits.c\")\n        if(FILE64_OK)\n            message(STATUS \"Checking for 64-bit off_t - present\")\n        endif()\n\n        if(NOT FILE64_OK)\n            # Test with _FILE_OFFSET_BITS=64\n            try_compile(FILE64_OK \"${PROJECT_BINARY_DIR}\"\n                    \"${PROJECT_SOURCE_DIR}/cmake/TestFileOffsetBits.c\"\n                    COMPILE_DEFINITIONS \"-D_FILE_OFFSET_BITS=64\" )\n            if(FILE64_OK)\n                message(STATUS \"Checking for 64-bit off_t - present with _FILE_OFFSET_BITS=64\")\n                set(_FILE_OFFSET_BITS 64)\n            endif()\n        endif()\n\n        if(NOT FILE64_OK)\n            # Test with _LARGE_FILES\n            try_compile(FILE64_OK \"${PROJECT_BINARY_DIR}\"\n                    \"${PROJECT_SOURCE_DIR}/cmake/TestFileOffsetBits.c\"\n                    COMPILE_DEFINITIONS \"-D_LARGE_FILES\" )\n            if(FILE64_OK)\n                message(STATUS \"Checking for 64-bit off_t - present with _LARGE_FILES\")\n                set(_LARGE_FILES 1)\n            endif()\n        endif()\n\n        if(NOT FILE64_OK)\n            # Test with _LARGEFILE_SOURCE\n            try_compile(FILE64_OK \"${PROJECT_BINARY_DIR}\"\n                    \"${PROJECT_SOURCE_DIR}/cmake/TestFileOffsetBits.c\"\n                    COMPILE_DEFINITIONS \"-D_LARGEFILE_SOURCE\" )\n            if(FILE64_OK)\n                message(STATUS \"Checking for 64-bit off_t - present with _LARGEFILE_SOURCE\")\n                set(_LARGEFILE_SOURCE 1)\n            endif()\n        endif()\n\n\n        #if(NOT FILE64_OK)\n        #    # now check for Windows stuff\n        #    try_compile(FILE64_OK \"${PROJECT_BINARY_DIR}\"\n        #                \"${PROJECT_SOURCE_DIR}/cmake/TestWindowsFSeek.c\")\n        #    if(FILE64_OK)\n        #        message(STATUS \"Checking for 64-bit off_t - present with _fseeki64\")\n        #        set(HAVE__FSEEKI64 1)\n        #    endif()\n        #endif()\n\n        if(NOT FILE64_OK)\n            message(STATUS \"Checking for 64-bit off_t - not present\")\n        endif()\n\n        set(_FILE_OFFSET_BITS ${_FILE_OFFSET_BITS} CACHE INTERNAL \"Result of test for needed _FILE_OFFSET_BITS=64\")\n        set(_LARGE_FILES      ${_LARGE_FILES}      CACHE INTERNAL \"Result of test for needed _LARGE_FILES\")\n        set(_LARGEFILE_SOURCE ${_LARGEFILE_SOURCE} CACHE INTERNAL \"Result of test for needed _LARGEFILE_SOURCE\")\n\n        # Set the flags we might have determined to be required above\n        configure_file(\"${PROJECT_SOURCE_DIR}/cmake/TestLargeFiles.c.cmake.in\"\n                \"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/TestLargeFiles.c\")\n\n        message(STATUS \"Checking for fseeko/ftello\")\n\n        # Test if ftello/fseeko are\tavailable\n        try_compile(FSEEKO_COMPILE_OK\n                \"${PROJECT_BINARY_DIR}\"\n                \"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/TestLargeFiles.c\")\n\n        if(FSEEKO_COMPILE_OK)\n            message(STATUS \"Checking for fseeko/ftello - present\")\n        endif()\n\n        if(NOT FSEEKO_COMPILE_OK)\n            # glibc 2.2 needs _LARGEFILE_SOURCE for fseeko (but not for 64-bit off_t...)\n            try_compile(FSEEKO_COMPILE_OK\n                    \"${PROJECT_BINARY_DIR}\"\n                    \"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/TestLargeFiles.c\"\n                    COMPILE_DEFINITIONS \"-D_LARGEFILE_SOURCE\" )\n\n            if(FSEEKO_COMPILE_OK)\n                message(STATUS \"Checking for fseeko/ftello - present with _LARGEFILE_SOURCE\")\n                set(_LARGEFILE_SOURCE ${_LARGEFILE_SOURCE} CACHE INTERNAL \"Result of test for needed _LARGEFILE_SOURCE\")\n            endif()\n        endif()\n\n        if(FSEEKO_COMPILE_OK)\n            set(AXPBOX_HAVE_FSEEKO ON CACHE INTERNAL \"Result of test for fseeko/ftello\")\n        else()\n            message(STATUS \"Checking for fseeko/ftello - not found\")\n            set(AXPBOX_HAVE_FSEEKO OFF CACHE INTERNAL \"Result of test for fseeko/ftello\")\n        endif()\n\n        if(FILE64_OK AND FSEEKO_COMPILE_OK)\n            message(STATUS \"Large File support - found\")\n            set(${VARIABLE} ON CACHE INTERNAL \"Result of test for large file support\")\n        else()\n            message(STATUS \"Large File support - not found\")\n            set(${VARIABLE} OFF CACHE INTERNAL \"Result of test for large file support\")\n        endif()\n\n    endif()\nendmacro()\n\n\n\n"
  },
  {
    "path": "cmake/FindPCAP.cmake",
    "content": "# ~~~\n# - Try to find libpcap include dirs and libraries\n#\n# Usage of this module as follows:\n#\n#     find_package(PCAP)\n#\n# Variables used by this module, they can change the default behaviour and need\n# to be set before calling find_package:\n#\n# Imported Targets:\n#  PCAP::PCAP                The libpcap library, if found\n#\n# Variables defined by this module:\n#\n#  PCAP_FOUND                System has libpcap, include and library dirs found\n#  PCAP_INCLUDE_DIR          The libpcap include directories.\n#  PCAP_LIBRARY              The libpcap library (possibly includes a thread\n#                            library e.g. required by pf_ring's libpcap)\n#  HAVE_PCAP_IMMEDIATE_MODE  If the version of libpcap found supports immediate mode\n#  HAVE_PCAP_DIRECTION       If the version of libpcap found support for setting direction\n#\n# Hints and Backward Compatibility\n# ================================\n#\n# To tell this module where to look, a user may set the environment variable\n# PCAP_ROOT to point cmake to the *root* of a directory with include and lib\n# subdirectories for packet.dll (e.g WpdPack or npcap-sdk). Alternatively,\n# PCAP_ROOT may also be set from cmake command line or GUI (e.g cmake\n# -DPCAP_ROOT=C:\\path\\to\\packet [...])\n# ~~~\n\nfind_path(\n        PCAP_INCLUDE_DIR\n        NAMES pcap/pcap.h pcap.h\n        PATH_SUFFIXES include Include)\n\n# The 64-bit Wpcap.lib is located under /x64\nif(WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 8)\n    #\n    # For the WinPcap and Npcap SDKs, the Lib subdirectory of the top-level directory contains 32-bit libraries. The\n    # 64-bit libraries are in the Lib/x64 directory.\n    #\n    # The only way to *FORCE* CMake to look in the Lib/x64 directory without searching in the Lib directory first appears\n    # to be to set CMAKE_LIBRARY_ARCHITECTURE to \"x64\".\n    #\n    set(CMAKE_LIBRARY_ARCHITECTURE \"x64\")\nendif()\n\nfind_library(PCAP_LIBRARY NAMES pcap wpcap)\n\n# If Pcap is not found as this level no need to continue\nif(NOT PCAP_LIBRARY OR NOT PCAP_INCLUDE_DIR)\n    return()\nendif()\n\ninclude(CheckCXXSourceCompiles)\nset(CMAKE_REQUIRED_LIBRARIES ${PCAP_LIBRARY})\ncheck_cxx_source_compiles(\"int main() { return 0; }\" PCAP_LINKS_SOLO)\nset(CMAKE_REQUIRED_LIBRARIES)\n\n# check if linking against libpcap also needs to link against a thread library\nif(NOT PCAP_LINKS_SOLO)\n    find_package(Threads)\n    if(THREADS_FOUND)\n        set(CMAKE_REQUIRED_LIBRARIES ${PCAP_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})\n        check_cxx_source_compiles(\"int main() { return 0; }\" PCAP_NEEDS_THREADS)\n        set(CMAKE_REQUIRED_LIBRARIES)\n    endif(THREADS_FOUND)\n    if(THREADS_FOUND AND PCAP_NEEDS_THREADS)\n        set(_tmp ${PCAP_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})\n        list(REMOVE_DUPLICATES _tmp)\n        set(PCAP_LIBRARY\n                ${_tmp}\n                CACHE STRING \"Libraries needed to link against libpcap\" FORCE)\n    else(THREADS_FOUND AND PCAP_NEEDS_THREADS)\n        message(FATAL_ERROR \"Couldn't determine how to link against libpcap\")\n    endif(THREADS_FOUND AND PCAP_NEEDS_THREADS)\nendif(NOT PCAP_LINKS_SOLO)\n\ninclude(CheckFunctionExists)\nset(CMAKE_REQUIRED_LIBRARIES ${PCAP_LIBRARY})\ncheck_function_exists(pcap_set_immediate_mode HAVE_PCAP_IMMEDIATE_MODE)\ncheck_function_exists(pcap_setdirection HAVE_PCAP_DIRECTION)\ncheck_function_exists(pcap_lib_version HAVE_PCAP_LIB_VERSION)\nset(CMAKE_REQUIRED_LIBRARIES)\n\n# Check libPCAP version\nif(HAVE_PCAP_LIB_VERSION AND NOT CMAKE_CROSSCOMPILING)\n    # Simple C code to extract the libpcap version\n    set(PCAP_VERSION_CODE\n            \"\n  #include <stdio.h>\n  #include <string.h>\n  #include <pcap/pcap.h>\n\n  int main() {\n    const char* version = pcap_lib_version();\n    const char* prefix = \\\"libpcap version \\\";\n    if (strncmp(version, prefix, strlen(prefix)) == 0) {\n        version += strlen(prefix);\n    }\n    printf(\\\"%s\\\", version);\n    return 0;\n  }\n  \")\n\n    # Write the code to a temporary file\n    set(detect_pcap_version_file \"${PROJECT_BINARY_DIR}/detect_pcap_version.c\")\n    file(WRITE \"${detect_pcap_version_file}\" \"${PCAP_VERSION_CODE}\")\n\n    # Try to compile and run the program\n    try_run(\n            RUN_RESULT_VAR\n            COMPILE_RESULT_VAR\n            \"${CMAKE_BINARY_DIR}\"\n            \"${detect_pcap_version_file}\"\n            CMAKE_FLAGS \"-DINCLUDE_DIRECTORIES=${PCAP_INCLUDE_DIR}\" LINK_LIBRARIES ${PCAP_LIBRARY}\n            RUN_OUTPUT_VARIABLE PCAP_VERSION_OUTPUT)\n\n    # If successful, parse the output to get the version string\n    if(COMPILE_RESULT_VAR AND RUN_RESULT_VAR EQUAL 0)\n        set(PCAP_VERSION ${PCAP_VERSION_OUTPUT})\n    endif()\nendif()\n\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(\n        PCAP\n        REQUIRED_VARS PCAP_LIBRARY PCAP_INCLUDE_DIR\n        VERSION_VAR PCAP_VERSION)\n\n# create IMPORTED target for libpcap dependency\nif(NOT TARGET PCAP::PCAP)\n    add_library(PCAP::PCAP IMPORTED SHARED)\n    set_target_properties(\n            PCAP::PCAP\n            PROPERTIES IMPORTED_LOCATION ${PCAP_LIBRARY}\n            IMPORTED_IMPLIB ${PCAP_LIBRARY}\n            INTERFACE_INCLUDE_DIRECTORIES ${PCAP_INCLUDE_DIR})\nendif()\n\nmark_as_advanced(PCAP_INCLUDE_DIR PCAP_LIBRARY)\n"
  },
  {
    "path": "cmake/TestFileOffsetBits.c",
    "content": "#include <sys/types.h>\n\n/* Cause a compile-time error if off_t is smaller than 64 bits */\n#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))\nint off_t_is_large[ (LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1 ];\n\nint main(int argc, char **argv)\n{\n  return 0;\n}\n\n"
  },
  {
    "path": "cmake/TestLargeFiles.c.cmake.in",
    "content": "#cmakedefine _LARGEFILE_SOURCE\n#cmakedefine _LARGE_FILES\n#cmakedefine _FILE_OFFSET_BITS @_FILE_OFFSET_BITS@\n\n#include <sys/types.h>\n#include <stdio.h>\n#include <stdlib.h>\n\nint main(int argc, char **argv)\n{\n  /* Cause a compile-time error if off_t is smaller than 64 bits,\n   * and make sure we have ftello / fseeko.\n   */\n#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))\n  int off_t_is_large[ (LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1 ];\n  FILE *fp = fopen(argv[0],\"r\");\n  off_t offset = ftello( fp );\n\n  fseeko( fp, offset, SEEK_CUR );\n  fclose(fp);\n  return 0;\n}\n\n"
  },
  {
    "path": "cmake/TestWindowsFSeek.c",
    "content": "#include <stdio.h>\n\nint main()\n{\n  __int64 off=0;\n\n  _fseeki64(NULL, off, SEEK_SET);\n\n  return 0;\n}"
  },
  {
    "path": "es40.cfg",
    "content": "/**\n * AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n\n * \\file\n * Sample configuration file.\n *\n * $Id: es40.cfg,v 1.22 2008/03/05 14:41:46 iamcamiel Exp $\n *\n * X-1.22           Camiel Vanderhoeven                             05-MAR-2008\n *      Multi-threading version.\n *\n * X-1.21           Camiel Vanderhoeven                             02-MAR-2008\n *      Natural way to specify large numeric values (\"10M\").\n *\n * X-1.20           Camiel Vanderhoeven                             16-FEB-2008\n *      Added Symbios 53C810 controller.\n *\n * X-1.19         \tCamiel Vanderhoeven 13-FEB-2008 Put SCSI controller on a\n *different PCI ID, and clarified PCI configuration rules. Thanks to Eduardo\n *Marcelo Serrat.\n *\n * X-1.18         \tCamiel Vanderhoeven 25-JAN-2008 Added autocreate_size\n *option for disk-images.\n *\n * X-1.17         \tCamiel Vanderhoeven 25-JAN-2008 Added option to disable\n *the icache.\n *\n * X-1.16         \tCamiel Vanderhoeven 23-JAN-2008 Added comments for win32\n *and X11 gui's.\n *\n * X-1.15         \tCamiel Vanderhoeven 05-JAN-2008 Added device as a disk.\n *\n * X-1.14         \tDavid Hittner 04-JAN-2008 Replaced decnet variable with\n *mac variable.\n *\n * X-1.13         \tCamiel Vanderhoeven 12-DEC-2007 Changed the way disks\n *work.\n *\n * X-1.12         \tCamiel Vanderhoeven 10-DEC-2007 Added vga_console\n *parameter.\n *\n * X-1.11         \tCamiel Vanderhoeven 10-DEC-2007 New structure for\n *configuration file.\n *\n * X-1.10         \tCamiel Vanderhoeven 10-DEC-2007 Unintended version #\n *increase.\n *\n * X-1.9         \tBrian Wheeler 22-NOV-2007 Added nic0.disabled\n *configuration option.\n *\n * X-1.8\t\tCamiel Vanderhoeven 17-NOV-2007 Clarified nic0.adapter\n *syntax.\n *\n * X-1.7\t\tCamiel Vanderhoeven 17-NOV-2007 Added configuration\n *lines for the network interface.\n *\n * X-1.6\t\tCamiel Vanderhoeven 16-APR-2007 Added configuration\n *lines to start PuTTy for each serial port.\n *\n * X-1.5\t\tCamiel Vanderhoeven 10-APR-2007 a)\tAdded\n *rom.decompressed variable. b)\tFixed some of the documentation mistakes.\n *\n * X-1.4\t\tCamiel Vanderhoeven 1-APR-2007 Documented, and added old\n *changelog comments.\n *\n * X-1.3\t\tBrian wheeler 7-FEB-2007 Added memory.bits variable.\n *\n * X-1.2\t\tBrian Wheeler 3-FEB-2007 Added serial.base variable.\n *\n * X-1.1\t\tBrian Wheeler 3-FEB-2007 Created this file.\n **/\n\n// Specifying values\n//\n// Numeric values can be specified as a number (\"500\"), as a number with a\n// suffix (\"100K\" = 102400), or as a fancy combination (\"2G512M\" = 2.5 G).\n//\n// Boolean values can be specified as \"true\"/\"false\", \"yes\"/\"no\", or \"1\"/\"0\".\n//\n// String-constants are best specified in double quotes (\"string\"). If the\n// string needs to contain double quotes, double the double quotes.\n// (\"One \"\"word\"\" in this string is quoted\")\n\n// GUI\n//\n// If you want to use an emulated graphics card, the emulator needs to interface\n// with the OS'es user interface. There are three ways to do this:\n//\n// On systems that have the SDL (simple directmedia layer) run-time libraries\n// installed, you can use SDL. (gui=sdl) The emulator needs to be compiled with\n// -DHAVE_SDL.\n//\n// On MS Windows-systems, you can use Win32 API calls. (gui=win32)\n//\n// On many Linux, BSD and UNIX systems, you can use X11. (gui=X11)\n\ngui = sdl {\n  keyboard.use_mapping = false;\n  keyboard.map = \"keys.map\";\n}\n\nsys0 = tsunami {\n\n  // VARIABLE: rom.srm\n  //\n  // Specify the filename of the original (compressed) ROM image. This file is\n  // essential to the functioning of the emulator. This file an be obtained from\n  // HP (it's on the firmware-update CD-ROM for Alpha ES40 systems).\n  //\n  rom.srm = \"rom\\cl67srmrom.exe\";\n\n  // VARIABLE: rom.decompressed\n  //\n  // Specify the filename of the decompressed ROM image. If possible, it will be\n  // created the first time the emulator is run. When it exists, it allows the\n  // emulator to start quicker by skipping the ROM decompression.\n  //\n  rom.decompressed = \"rom\\decompressed.rom\";\n\n  // VARIABLES: rom.flash and rom.dpr\n  //\n  // Specify the filenames of Flash and DPR ROM images. These files are not\n  // required, but will be created he first time the emulator runs. Contents of\n  // Flash and DPR ROM will be put in these files after successful termination\n  // of the emulator. This allows setting SRM variables such as auto_action and\n  // boot_osflags.\n  //\n  rom.flash = \"rom\\flash.rom\";\n  rom.dpr = \"rom\\dpr.rom\";\n\n  // VARIABLE: memory.bits\n  //\n  // Only amounts of memory that are a power of 2 are supported. This number\n  // determines the amount of memory, by setting the number of bits in the\n  // address (and thus which power of 2).\n  //\n  // 26 = 64 MB\n  // 27 = 128MB\n  // 28 = 256 MB\n  // 29 = 512 MB\n  // 30 = 1GB\n  // 31 = 2GB\n  //\n  memory.bits = 30;\n\n  // VARIABLE: time\n  //\n  // Override the guest clock with a fixed date/time.\n  // Format: \"YYYY-MM-DD\" or \"YYYY-MM-DD HH:MM:SS\"\n  //\n  //time = \"2017-05-01\";              // fake date (YYYY-MM-DD)\n  //time = \"2017-05-01 12:00:00\";     // fake date+time (YYYY-MM-DD HH:MM:SS)\n\n  cpu0 = ev68cb {\n    // VARIABLE: icache\n    //\n    // enables or disables the onchip-cache. The emulator runs faster\n    // when this is disabled, but that might lead to problems with some\n    // OS'es, so here is the option to enable it.\n    icache = false;\n    speed = 800M;\n  }\n\n  cpu1 = ev68cb {\n    icache = false;\n    speed = 800M;\n  }\n\n  // System Internal PCI Devices: ali, ali_ide, ali_usb\n  //\n  // The following PCI-devices are built into the system, and should\n  // always be at the PCI-id's they are on in this sample configuration\n  // file for compatibility.\n\n  pci0 .7 = ali {\n    mouse.enabled = true;\n    lpt.outfile = \"lpt.out\";\n    vga_console = true;\n    timezone = \"utc\"; // Sets timezone to UTC\n    timezone = \"local\"; // Sets timezone to host timezone (default)\n    timezone = \"utc+1h\"; // Sets timezone to UTC plus 1 hour\n    timezone = \"local-20M\"; // Sets timezone to localtime minus 20 months\n    timezone = \"utc+2y\"; // Sets timezone to UTC + two years\n  }\n\n  pci0 .15 = ali_ide {\n    // sub-components: disk<x>.<y>\n    //\n    // Here, up to 4 IDE disks can be defined (0.0, 0.1, 1.0 and 1.1).\n    //\n    // file: create a disk using a file on the host filesystem as a disk image\n\n    disk0 .0 = file {\n      file = \"img\\disk0.img\";\n      serial_number = \"VMS\";\n      rev_number = \"8.3\";\n      model_number = \"OpenVMS8.3\";\n      read_only = false;\n      cdrom = false;\n\n      // if the file does not exist, it will be created if autocreate_size is\n      // set to the desired size of the disk.\n      autocreate_size = 600M;\n    }\n    disk1 .0 = file {\n      file = \"img\\vms83.iso\";\n      read_only = true;\n      cdrom = true;\n    }\n\n    // device: create a disk using a physical device\n    //\n    // WARNING: making a physical disk device writeable here may\n    // seriously jeopardize the contents of that disk.\n    //\n    // Windows syntax for device: \\\\.\\CDRom0, \\\\.\\PhysicalDrive0\n    //\n    // UNIX-like syntax for device: /dev/sda\n\n    disk1 .0 = device {\n      device = \"\\\\.\\CDRom0\";\n      read_only = true;\n      cdrom = true;\n    }\n\n    // ramdisk: create a disk using a portion of host RAM\n    disk1 .1 = ramdisk { size = 10M; }\n  }\n\n  pci0 .19 = ali_usb {}\n\n  // \"Free\" PCI Devices\n  //\n  // These can occupy pci0.1 .. pci0.4 and pci1.1 .. pci1.6\n  //\n  // AFAIK, VGA should always be on pci0.x.\n\n  pci0 .2 = cirrus { rom = \"rom\\vgabios-0.6a.debug.bin\"; }\n\n  // pci0.2 = s3\n  //{\n  //  rom = \"rom\\vgabios-0.6a.debug.bin\";\n  //}\n\n  // Symbios SCSI controller\n  //\n  // There are two flavors of SCSI controllers on the emulator; 53c810\n  // and 53c895. The 53c810 supports 7 disks (0.0..0.6), the 53c895\n  // supports 15 disks (0.0..0.6 and 0.8..0.15).\n  //\n  // Right now, the 53c810 is the only controller that works with OpenVMS.\n  pci0 .3 = sym53c810 {\n    disk0 .0 = file {\n      file = \"img\\dka0.img\";\n      read_only = false;\n      cdrom = false;\n    }\n    disk0 .4 = file {\n      file = \"img\\scsi_cd.iso\";\n      read_only = true;\n      cdrom = true;\n    }\n    disk0 .5 = ramdisk { size = 10M; }\n  }\n\n  pci0 .4 = dec21143 {\n\n    // VARIABLE: adapter\n    //\n    // Defines the host computer's adapter to use for the emulated NIC. If\n    // you're unsure of this, start the emulator without this variable set, and\n    // you will be presented with a list of adapters to choose from. You can\n    // enter the name indicated on this line.\n    //\n    // Windows syntax:\n    // adapter = \"\\Device\\NPF_{F266CDC2-6BA2-43D8-8B00-1C468F737ED7}\";\n    //\n    // Linux syntax:\n    // adapter = \"eth0\";\n\n    // adapter = \"\\Device\\NPF_{F266CDC2-6BA2-43D8-8B00-1C468F737ED7}\";\n\n    // VARIABLE: mac\n    //\n    // Defines the ethernet MAC address to be used by the virtual nic.\n    // The variable format is: xx-xx-xx-xx-xx-xx, where all values are in hex.\n    // This value should be unique on your network, or Bad Things Will Happen.\n    //\n    // The default value is: 08-00-2B-E5-40-<nic#>\n\n    // mac = \"08-00-2B-E5-40-00\";\n  }\n\n  serial0 = serial {\n\n    // VARIABLE: port\n    //\n    // Determines which Telnet port is opened to receive connections for the\n    // emulated serial port. The default is 8000 + the port number.\n\n    port = 21264;\n\n    // VARIABLE: action\n    //\n    // Defines the action to take for each serial port (= a telnet client). If\n    // you want to connect manually, leave this out.\n\n    action = \"\"\n             \"c:\\Program Files\\PuTTY\\putty.exe\"\n             \" telnet://localhost:21264\";\n  }\n\n  serial1 = serial {\n    port = 21265;\n    action = \"\"\n             \"c:\\Program Files\\PuTTY\\putty.exe\"\n             \" telnet://localhost:21265\";\n  }\n}\n"
  },
  {
    "path": "sonar-project.properties",
    "content": "sonar.projectKey=rve_axpbox\r\nsonar.organization=rve\r\n\r\n# This is the name and version displayed in the SonarCloud UI.\r\nsonar.projectName=AXPBox\r\nsonar.projectVersion=1.1.3\r\n\r\n\r\n# Path is relative to the sonar-project.properties file. Replace \"\\\" by \"/\" on Windows.\r\nsonar.sources=src/\r\n\r\n# use complation database\r\nsonar.cfamily.compile-commands=../build/compile_commands.json\r\n\r\n# Encoding of the source code. Default is default system encoding\r\n#sonar.sourceEncoding=UTF-8"
  },
  {
    "path": "src/AliM1543C.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Copyright (C) 2020 Martin Vorländer\n * Copyright (C) 2012 Dmitry Kalinkin\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"AliM1543C.hpp\"\n#include \"StdAfx.hpp\"\n#include \"System.hpp\"\n#include \"VGA.hpp\"\n\n#ifdef DEBUG_PIC\nbool pic_messages = false;\n#endif\n\n/* Timer Calibration: Instructions per Microsecond (assuming 1 clock = 1\n * instruction) */\n#define IPus 847\n\nu32 ali_cfg_data[64] = {\n    /*00*/ 0x153310b9, // CFID: vendor + device\n    /*04*/ 0x0200000f, // CFCS: command + status\n    /*08*/ 0x060100c3, // CFRV: class + revision\n    /*0c*/ 0x00000000, // CFLT: latency timer + cache line size\n    /*10*/ 0x00000000, // BAR0:\n    /*14*/ 0x00000000, // BAR1:\n    /*18*/ 0x00000000, // BAR2:\n    /*1c*/ 0x00000000, // BAR3:\n    /*20*/ 0x00000000, // BAR4:\n    /*24*/ 0x00000000, // BAR5:\n    /*28*/ 0x00000000, // CCIC: CardBus\n    /*2c*/ 0x00000000, // CSID: subsystem + vendor\n    /*30*/ 0x00000000, // BAR6: expansion rom base\n    /*34*/ 0x00000000, // CCAP: capabilities pointer\n    /*38*/ 0x00000000,\n    /*3c*/ 0x00000000, // CFIT: interrupt configuration\n    0,\n    0,\n    0,\n    0,\n    0,\n    /*54*/ 0x00000200, //\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0};\n\nu32 ali_cfg_mask[64] = {\n    /*00*/ 0x00000000, // CFID: vendor + device\n    /*04*/ 0x00000000, // CFCS: command + status\n    /*08*/ 0x00000000, // CFRV: class + revision\n    /*0c*/ 0x00000000, // CFLT: latency timer + cache line size\n    /*10*/ 0x00000000, // BAR0\n    /*14*/ 0x00000000, // BAR1: CBMA\n    /*18*/ 0x00000000, // BAR2:\n    /*1c*/ 0x00000000, // BAR3:\n    /*20*/ 0x00000000, // BAR4:\n    /*24*/ 0x00000000, // BAR5:\n    /*28*/ 0x00000000, // CCIC: CardBus\n    /*2c*/ 0x00000000, // CSID: subsystem + vendor\n    /*30*/ 0x00000000, // BAR6: expansion rom base\n    /*34*/ 0x00000000, // CCAP: capabilities pointer\n    /*38*/ 0x00000000,\n    /*3c*/ 0x00000000, // CFIT: interrupt configuration\n    /*40*/ 0xffcfff7f,\n    /*44*/ 0xff00cbdf,\n    /*48*/ 0xffffffff,\n    /*4c*/ 0x000000ff,\n    /*50*/ 0xffff8fff,\n    /*54*/ 0xf0ffff00,\n    /*58*/ 0x030f0d7f,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0};\n\n/**\n * Constructor.\n **/\nCAliM1543C::CAliM1543C(CConfigurator *cfg, CSystem *c, int pcibus, int pcidev)\n    : CPCIDevice(cfg, c, pcibus, pcidev) {\n  if (theAli != 0)\n    FAILURE(Configuration, \"More than one Ali\");\n  theAli = this;\n}\n\n/**\n * Initialize the Ali device.\n **/\nvoid CAliM1543C::init() {\n  add_function(0, ali_cfg_data, ali_cfg_mask);\n\n  int i;\n  char *filename;\n\n  add_legacy_io(1, 0x61, 1);\n\n  state.reg_61 = 0;\n\n  add_legacy_io(2, 0x70, 4);\n  cSystem->RegisterMemory(this, 2, U64(0x00000801fc000070), 4);\n  for (i = 0; i < 4; i++)\n    state.toy_access_ports[i] = 0;\n  for (i = 0; i < 256; i++)\n    state.toy_stored_data[i] = 0;\n\n  state.toy_stored_data[0x17] = myCfg->get_bool_value(\"vga_console\") ? 1 : 0;\n\n  if (state.toy_stored_data[0x17] && !theVGA) {\n    printf(\"! CONFIGURATION WARNING ! vga_console set to true, but no VGA card \"\n           \"installed.\\n\");\n    state.toy_stored_data[0x17] = 0;\n  }\n\n  state.toy_pi_last_fire = 0;\n\n  ResetPCI();\n\n  // PIT Setup\n  add_legacy_io(6, 0x40, 4);\n  for (i = 0; i < 3; i++)\n    state.pit_status[i] = 0x40; // invalid/null counter\n  for (i = 0; i < 9; i++)\n    state.pit_counter[i] = 0;\n\n  add_legacy_io(7, 0x20, 2);\n  add_legacy_io(8, 0xa0, 2);\n  add_legacy_io(30, 0x4d0, 2);\n\n  // odd one, byte read in PCI IACK (interrupt acknowledge) cycle. Interrupt\n  // vector.\n  cSystem->RegisterMemory(this, 20, U64(0x00000801f8000000), 1);\n\n  for (i = 0; i < 2; i++) {\n    state.pic_mode[i] = 0;\n    state.pic_intvec[i] = 0;\n    state.pic_mask[i] = 0;\n    state.pic_asserted[i] = 0;\n  }\n\n  // Initialize parallel port\n  add_legacy_io(27, 0x3bc, 4);\n  filename = myCfg->get_text_value(\"lpt.outfile\");\n  if (filename) {\n    lpt = fopen(filename, \"ab\");\n  } else {\n    lpt = NULL;\n  }\n\n  lpt_reset();\n\n  myRegLock = new CMutex(\"ali-reg\");\n\n  printf(\"%s: $Id: AliM1543C.cpp,v 1.66 2008/05/31 15:47:07 iamcamiel Exp $\\n\",\n         devid_string);\n}\n\nvoid CAliM1543C::start_threads() {\n  if (!myThread) {\n    printf(\" ali\");\n    StopThread = false;\n    myThread = std::make_unique<std::thread>([this]() { this->run(); });\n  }\n}\n\nvoid CAliM1543C::stop_threads() {\n  StopThread = true;\n  if (myThread) {\n    printf(\" ali\");\n    myThread->join();\n    myThread = nullptr;\n  }\n}\n\n/**\n * Destructor.\n **/\nCAliM1543C::~CAliM1543C() {\n  stop_threads();\n\n  if (lpt)\n    fclose(lpt);\n}\n\n/**\n * Calculates VM time based on the configuration specified in the configuration\n * file.\n * @return The time.\n */\nstruct tm CAliM1543C::get_time() {\n  struct tm time_out;\n  time_t time_raw;\n\n  // Timezone setting from configuration file\n  std::string timezone{myCfg->get_text_value(\"timezone\", \"local\")};\n\n  // Time base (local or utc)\n  std::string timebase;\n\n  // Time offset\n  bool offset_present = false;\n  long offset;\n\n  // Check for absolute time override: \"YYYY-MM-DD\" or \"YYYY-MM-DD HH:MM:SS\"\n  // Read from system-level config (sys0 block)\n  char *faketime = myCfg->get_myParent()->get_text_value(\"time\");\n  if (faketime) {\n    struct tm ft;\n    memset(&ft, 0, sizeof(ft));\n    ft.tm_isdst = -1; // let mktime figure it out\n    int n = sscanf(faketime, \"%d-%d-%d %d:%d:%d\", &ft.tm_year, &ft.tm_mon,\n                   &ft.tm_mday, &ft.tm_hour, &ft.tm_min, &ft.tm_sec);\n    if (n >= 3) {\n      ft.tm_year -= 1900;\n      ft.tm_mon -= 1;\n      time_raw = mktime(&ft);\n      if (time_raw == (time_t)-1) {\n        FAILURE_1(Configuration, \"Invalid time value: %s\", faketime);\n      }\n      // Apply timezone conversion and return\n      if (timezone.rfind(\"utc\") == 0) {\n        gmtime_s(&time_out, &time_raw);\n      } else {\n#ifdef _WIN32\n        localtime_s(&time_out, &time_raw);\n#else\n        localtime_s(&time_raw, &time_out);\n#endif\n      }\n      return time_out;\n    } else {\n      FAILURE_1(Configuration,\n                \"Invalid time format: %s (use YYYY-MM-DD or \"\n                \"YYYY-MM-DD HH:MM:SS)\",\n                faketime);\n    }\n  }\n\n  // Get raw time\n  time(&time_raw);\n\n  // Set time base\n  if (timezone.rfind(\"local\") == 0) {\n    timebase = \"local\";\n  } else if (timezone.rfind(\"utc\") == 0) {\n    timebase = \"utc\";\n  } else {\n    FAILURE_1(Configuration, \"Invalid timezone %s\", timezone.c_str());\n  }\n\n  // Characters remaining after time base\n  int remaining_chars = timezone.length() - timebase.length();\n\n  if (remaining_chars > 0 &&\n      timezone.at(timezone.length() - remaining_chars) == '+') {\n    // An offset is included in the timezone\n    offset_present = true;\n    sscanf(timezone.c_str() + timezone.length() - remaining_chars + 1, \"%ld\",\n           &offset);\n    remaining_chars -= std::to_string(offset).length() + 1;\n\n    if (remaining_chars != 1) {\n      // Offset type always has one character\n      FAILURE_1(Configuration, \"Invalid timezone %s\", timezone.c_str());\n    }\n  } else if (remaining_chars > 0) {\n    FAILURE_1(Configuration, \"Invalid timezone %s\", timezone.c_str());\n  }\n\n  if (offset_present) {\n    // Apply POSIX time offset (seconds, minutes, hours, days)\n    switch (timezone.at(timezone.length() - 1)) {\n    case 's':\n      time_raw += offset;\n      break;\n    case 'm':\n      time_raw += offset * 60;\n      break;\n    case 'h':\n      time_raw += offset * 3600;\n      break;\n    case 'd':\n      time_raw += offset * 86400;\n      break;\n    case 'M':\n    case 'y':\n      break;\n    default:\n      FAILURE_1(Configuration, \"Invalid timezone offset type %c\",\n                timezone.at(timezone.length() - 1));\n    }\n  }\n\n  // Convert POSIX time to date\n  if (timebase == \"local\") {\n#ifdef _WIN32\n    localtime_s(&time_out, &time_raw);\n#else\n    localtime_s(&time_raw, &time_out);\n#endif\n  } else if (timebase == \"utc\") {\n    gmtime_s(&time_out, &time_raw);\n  } else {\n    // This shouldn't happen\n    FAILURE_1(Configuration, \"Invalid timezone %s\", timezone.c_str());\n  }\n\n  if (offset_present) {\n    // Apply date offset (months, years)\n    switch (timezone.at(timezone.length() - 1)) {\n    case 'M':\n      time_out.tm_year += offset / 12;\n      time_out.tm_mon += offset % 12;\n      break;\n    case 'y':\n      time_out.tm_year += offset;\n      break;\n    }\n\n    // Fix day of week\n    mktime(&time_out);\n  }\n\n  return time_out;\n}\n\n/**\n * Read (byte,word,longword) from one of the legacy ranges. Only byte-accesses\n *are supported.\n *\n * Ranges are:\n *  - 1. I/O port 61h\n *  - 2. I/O ports 70h-73h (time-of-year clock)\n *  - 6. I/O ports 40h-43h (programmable interrupt timer)\n *  - 7. I/O ports 20h-21h (primary programmable interrupt controller)\n *  - 8. I/O ports a0h-a1h (secondary (cascaded) programmable interrupt\n *controller)\n *  - 20. PCI IACK address (interrupt vector)\n *  - 27. I/O ports 3bch-3bfh (parallel port)\n *  - 30. I/O ports 4d0h-4d1h (edge/level register of programmable interrupt\n *controller)\n *  .\n **/\nu32 CAliM1543C::ReadMem_Legacy(int index, u32 address, int dsize) {\n  if (dsize != 8 &&\n      index != 20) // when interrupt vector is read, dsize doesn't matter.\n  {\n    FAILURE_4(\n        InvalidArgument,\n        \"%s: DSize %d reading from legacy memory range # %d at address %02x\\n\",\n        devid_string, dsize, index, address);\n  }\n\n  int channel = 0;\n  switch (index) {\n  case 1:\n    return reg_61_read();\n  case 2:\n    return toy_read(address);\n  case 6:\n    return pit_read(address);\n  case 8:\n    channel = 1;\n  case 7:\n    return pic_read(channel, address);\n  case 20:\n    return pic_read_vector();\n  case 30:\n    return pic_read_edge_level(address);\n  case 27:\n    return lpt_read(address);\n  }\n\n  return 0;\n}\n\n/**\n * Write (byte,word,longword) to one of the legacy ranges. Only byte-accesses\n *are supported.\n *\n * Ranges are:\n *  - 1. I/O port 61h\n *  - 2. I/O ports 70h-73h (time-of-year clock)\n *  - 6. I/O ports 40h-43h (programmable interrupt timer)\n *  - 7. I/O ports 20h-21h (primary programmable interrupt controller)\n *  - 8. I/O ports a0h-a1h (secondary (cascaded) programmable interrupt\n *controller)\n *  - 12. I/O ports 00h-0fh (primary DMA controller)\n *  - 13. I/O ports c0h-dfh (secondary DMA controller)\n *  - 20. PCI IACK address (interrupt vector)\n *  - 27. I/O ports 3bch-3bfh (parallel port)\n *  - 30. I/O ports 4d0h-4d1h (edge/level register of programmable interrupt\n *controller)\n *  - 33. I/O ports 80h-8fh (DMA controller memory base low page register)\n *  - 34. I/O ports 480h-48fh (DMA controller memory base high page register)\n *  .\n **/\nvoid CAliM1543C::WriteMem_Legacy(int index, u32 address, int dsize, u32 data) {\n  if (dsize != 8) {\n    FAILURE_4(\n        InvalidArgument,\n        \"%s: DSize %d writing to legacy memory range # %d at address %02x\\n\",\n        devid_string, dsize, index, address);\n  }\n\n  int channel = 0;\n  switch (index) {\n  case 1:\n    reg_61_write((u8)data);\n    return;\n  case 2:\n    toy_write(address, (u8)data);\n    return;\n  case 6:\n    pit_write(address, (u8)data);\n    return;\n  case 8:\n    channel = 1;\n  case 7:\n    pic_write(channel, address, (u8)data);\n    return;\n  case 30:\n    pic_write_edge_level(address, (u8)data);\n    return;\n  case 27:\n    lpt_write(address, (u8)data);\n    return;\n  }\n}\n\n/**\n * Read port 61h (speaker/ miscellaneous).\n *\n * BDW:\n * This may need some expansion to help with timer delays.  It looks like\n * the 8254 flips bits on occasion, and the linux kernel (at least) uses\n *   do {\n *     count++;\n *   } while ((inb(0x61) & 0x20) == 0 && count < TIMEOUT_COUNT);\n * to calibrate the cpu clock.\n *\n * Every 1500 reads the bit gets flipped so maybe the timing will\n * seem reasonable to the OS.\n */\nu8 CAliM1543C::reg_61_read() {\n#if 0\n  static long read_count = 0;\n  if(!(state.reg_61 & 0x20))\n  {\n    if(read_count % 1500 == 0)\n      state.reg_61 |= 0x20;\n  }\n  else\n  {\n    state.reg_61 &= ~0x20;\n  }\n\n  read_count++;\n#else\n  state.reg_61 &= ~0x20;\n  state.reg_61 |= (state.pit_status[2] & 0x80) >> 2;\n#endif\n  return state.reg_61;\n}\n\n/**\n * Write port 61h (speaker/ miscellaneous).\n **/\nvoid CAliM1543C::reg_61_write(u8 data) {\n  state.reg_61 = (state.reg_61 & 0xf0) | (((u8)data) & 0x0f);\n}\n\n/**\n * Read time-of-year clock ports (70h-73h).\n **/\nu8 CAliM1543C::toy_read(u32 address) {\n  // printf(\"%%ALI-I-READTOY: read port %02x: 0x%02x\\n\", (u32)(0x70 + address),\n  // state.toy_access_ports[address]);\n  return (u8)state.toy_access_ports[address];\n}\n\n/**\n * Write time-of-year clock ports (70h-73h). On a write to port 0, recalculate\n * clock values.\n **/\nvoid CAliM1543C::toy_write(u32 address, u8 data) {\n  struct tm stime;\n  static long read_count = 0;\n  static long hold_count = 0;\n\n  // printf(\"%%ALI-I-WRITETOY: write port %02x: 0x%02x\\n\", (u32)(0x70 +\n  // address), data);\n  state.toy_access_ports[address] = (u8)data;\n\n  switch (address) {\n  case 0:\n    if ((data & 0x7f) < 14) {\n      // Assign VRT (valid RAM and time) bit\n      state.toy_stored_data[RTC_REG_D] = RTC_VRT;\n      // Update time\n      stime = get_time();\n\n      if (state.toy_stored_data[RTC_REG_B] & RTC_DM) {\n        // binary\n        state.toy_stored_data[0] = (u8)(stime.tm_sec);\n        state.toy_stored_data[2] = (u8)(stime.tm_min);\n        if (state.toy_stored_data[RTC_REG_B] & RTC_2412) // 24-hour\n          state.toy_stored_data[4] = (u8)(stime.tm_hour);\n        else\n          // 12-hour\n          state.toy_stored_data[4] =\n              (u8)(((stime.tm_hour / 12) ? 0x80 : 0) | (stime.tm_hour % 12));\n        state.toy_stored_data[6] = (u8)(stime.tm_wday + 1);\n        state.toy_stored_data[7] = (u8)(stime.tm_mday);\n        state.toy_stored_data[8] = (u8)(stime.tm_mon + 1);\n        state.toy_stored_data[9] = (u8)(stime.tm_year % 100);\n      } else {\n        // BCD\n        state.toy_stored_data[0] =\n            (u8)(((stime.tm_sec / 10) << 4) | (stime.tm_sec % 10));\n        state.toy_stored_data[2] =\n            (u8)(((stime.tm_min / 10) << 4) | (stime.tm_min % 10));\n        if (state.toy_stored_data[0x0b] & 2) // 24-hour\n          state.toy_stored_data[4] =\n              (u8)(((stime.tm_hour / 10) << 4) | (stime.tm_hour % 10));\n        else { // 12-hour\n          state.toy_stored_data[4] = (u8)(((stime.tm_hour / 12) ? 0x80 : 0) |\n                                          (((stime.tm_hour % 12) / 10) << 4) |\n                                          ((stime.tm_hour % 12) % 10));\n        }\n\n        state.toy_stored_data[6] = (u8)(stime.tm_wday + 1);\n        state.toy_stored_data[7] =\n            (u8)(((stime.tm_mday / 10) << 4) | (stime.tm_mday % 10));\n        state.toy_stored_data[8] =\n            (u8)((((stime.tm_mon + 1) / 10) << 4) | ((stime.tm_mon + 1) % 10));\n        state.toy_stored_data[9] = (u8)((((stime.tm_year % 100) / 10) << 4) |\n                                        ((stime.tm_year % 100) % 10));\n      }\n\n      // SRM initializes the value of A register to 0x26. This means:\n      //  xtal speed is set to MC_BASE_32_KHz 32.768KHz (standard)\n      //  periodic interrupt rate divisor of 32 = interrupt every 976.562 ms\n      //  (1024Hz clock)\n      if (state.toy_stored_data[RTC_REG_A] & RTC_UIP) {\n        // Once the UIP line goes high, we have to stay high for 2228us.\n        hold_count--;\n        if (hold_count == 0 || (state.toy_stored_data[RTC_REG_B] & RTC_SET)) {\n          // Set UIP low and trigger the related interrupt.\n          state.toy_stored_data[RTC_REG_A] &= ~RTC_UIP;\n          state.toy_stored_data[RTC_REG_C] |= RTC_UF;\n          toy_update_irqf();\n          read_count = 0;\n        }\n      } else {\n        // UIP isn't high, so if we're looping and waiting for it to go, it\n        // will take 1,000,000/(IPus*3) reads for a 3 instruction loop.\n        // If it happens to be a one time read, it'll only throw our\n        // calculations off a tiny bit, and they'll be re-synced on the next\n        // read-loop.\n        read_count++;\n        if (read_count > 1000000 / (IPus * 3)) // 3541 @ 847IPus\n        {\n          state.toy_stored_data[RTC_REG_A] |= RTC_UIP;\n          hold_count =\n              (2228 / (IPus * 3)) + 1; // .876 @ 847IPus, so we add one.\n        }\n      }\n    }\n\n    toy_handle_periodic_interrupt(data);\n    toy_update_irqf();\n\n    // Assign specified data to port so it can be read by the program\n    state.toy_access_ports[1] = state.toy_stored_data[data & 0x7f];\n\n    // Register C is cleared after a read, and we don't care if it's a write\n    if (data == RTC_REG_C)\n      state.toy_stored_data[data & 0x7f] = 0;\n\n    break;\n  case 1:\n    if (state.toy_access_ports[0] == RTC_REG_B &&\n        data & 0x040) // If we're writing to register B, we make register C look\n                      // like it fired.\n                      // TODO: Do actual interrupt implementation instead of\n                      //       a workaround.\n      state.toy_stored_data[RTC_REG_C] = 0xf0;\n    state.toy_stored_data[state.toy_access_ports[0] & 0x7f] = (u8)data;\n    break;\n\n  case 2:\n    state.toy_access_ports[3] = state.toy_stored_data[0x80 + (data & 0x7f)];\n    break;\n\n  case 3:\n    state.toy_stored_data[0x80 + (state.toy_access_ports[2] & 0x7f)] = (u8)data;\n    break;\n  }\n}\n\n/**\n * Handle RTC periodic interrupt.\n **/\nvoid CAliM1543C::toy_handle_periodic_interrupt(u8 data) {\n  /*\n   See sys/dev/ic/mc146818reg.h and sys/arch/alpha/alpha/mcclock.c in NetBSD and\n   the RTC datasheet: https://www.nxp.com/docs/en/data-sheet/MC146818.pdf.\n  */\n  clock_t now = clock();\n  double timedelta = (now - state.toy_pi_last_fire) / (double)CLOCKS_PER_SEC;\n\n  // For the meaning of the period calculation see the table on page 14 of the\n  // aforementioned datasheet\n  int rate_pow = state.toy_stored_data[RTC_REG_A] & 0x0f;\n  double period = (1 << rate_pow) / 65536.0;\n\n  if (state.toy_stored_data[RTC_REG_A] & MC_BASE_32_KHz) {\n    if (rate_pow == 0x1) {\n      period = 1 / 256.0;\n    } else if (rate_pow == 0x2) {\n      period = 1 / 128.0;\n    }\n  }\n\n  if (rate_pow && (timedelta >= period)) {\n    // Elapsed time since last check is equal or greater than the specified\n    // period - fire the interrupt by setting the PF flag in register C\n    // (see page 16 in the datasheet).\n    state.toy_stored_data[RTC_REG_C] |= RTC_PF;\n    state.toy_pi_last_fire = now;\n  }\n}\n\n/**\n * Update RTC interrupt request flag\n **/\nvoid CAliM1543C::toy_update_irqf() {\n  if ((state.toy_stored_data[RTC_REG_B] & RTC_PIE &&\n       state.toy_stored_data[RTC_REG_C] & RTC_PF) ||\n      (state.toy_stored_data[RTC_REG_B] & RTC_UIE &&\n       state.toy_stored_data[RTC_REG_C] & RTC_UF) ||\n      (state.toy_stored_data[RTC_REG_B] & RTC_AIE &&\n       state.toy_stored_data[RTC_REG_C] & RTC_AF))\n    state.toy_stored_data[RTC_REG_C] |= RTC_IRQF;\n  else\n    state.toy_stored_data[RTC_REG_C] &= ~RTC_IRQF;\n}\n\n/**\n * Read from the programmable interrupt timer ports (40h-43h)\n *\n * BDW:\n * Here's the PIT Traffic during SRM and Linux Startup:\n *\n * SRM\n * PIT Write:  3, 36  = counter 0, load lsb + msb, mode 3\n * PIT Write:  0, 00\n * PIT Write:  0, 00  = 65536 = 18.2 Hz = timer interrupt.\n * PIT Write:  3, 54  = counter 1, msb only, mode 2\n * PIT Write:  1, 12  = 0x1200 = memory refresh?\n * PIT Write:  3, b6  = counter 2, load lsb + msb, mode 3\n * PIT Write:  3, 00\n * PIT Write:  0, 00\n * PIT Write:  0, 00\n *\n * Linux Startup\n * PIT Write:  3, b0  = counter 2, load lsb+msb, mode 0\n * PIT Write:  2, a4\n * PIT Write:  2, ec  = eca4\n * PIT Write:  3, 36  = counter 0, load lsb+msb, mode 3\n * PIT Write:  0, 00\n * PIT Write:  0, 00  = 65536\n * PIT Write:  3, b6  = counter 2, load lsb+msb, mode 3\n * PIT Write:  2, 31\n * PIT Write:  2, 13  = 1331\n **/\nu8 CAliM1543C::pit_read(u32 address) {\n\n  // printf(\"PIT Read: %02\" PRIx64 \" \\n\",address);\n  u8 data;\n  data = 0;\n  return data;\n}\n\n/**\n * Write to the programmable interrupt timer ports (40h-43h)\n **/\nvoid CAliM1543C::pit_write(u32 address, u8 data) {\n\n  // printf(\"PIT Write: %02\" PRIx64 \", %02x \\n\",address,data);\n  if (address == 3) { // control\n    if (data != 0) {\n      state.pit_status[address] = data; // last command seen.\n      if ((data & 0xc0) >> 6 != 3) {\n        state.pit_status[(data & 0xc0) >> 6] = data & 0x3f;\n        state.pit_mode[(data & 0xc0) >> 6] = (data & 0x30) >> 4;\n      } else {                            // readback command 8254 only\n        state.pit_status[address] = 0xc0; // bogus :)\n      }\n    }\n  } else { // a counter\n    switch (state.pit_mode[address]) {\n    case 0:\n      break;\n\n    case 1:\n    case 3:\n      state.pit_counter[address] =\n          (state.pit_counter[address] & 0xff) | data << 8;\n      state.pit_counter[address + PIT_OFFSET_MAX] = state.pit_counter[address];\n      if (state.pit_mode[address] == 3) {\n        state.pit_mode[address] = 2;\n      } else\n        state.pit_status[address] &= ~0xc0; // no longer high, counter valid.\n      break;\n\n    case 2:\n      state.pit_counter[address] = (state.pit_counter[address] & 0xff00) | data;\n\n      // two bytes were written with 0x00, so its really 0x10000\n      if ((state.pit_status[address] & 0x30) >> 4 == 3 &&\n          state.pit_counter[address] == 0) {\n        state.pit_counter[address] = 65536;\n      }\n\n      state.pit_counter[address + PIT_OFFSET_MAX] = state.pit_counter[address];\n      state.pit_status[address] &= ~0xc0; // no longer high, counter valid.\n      break;\n    }\n  }\n}\n\n#define PIT_FACTOR 5000\n#define PIT_DEC(p) p = (p < PIT_FACTOR ? 0 : p - PIT_FACTOR);\n\n/**\n * Handle the PIT interrupt.\n *\n *  - counter 0 is the 18.2Hz time counter.\n *  - counter 1 is the ram refresh, we don't care.\n *  - counter 2 is the speaker and/or generic timer\n *  .\n **/\nvoid CAliM1543C::pit_clock() {\n  int i;\n  for (i = 0; i < 3; i++) {\n    // decrement the counter.\n    if (state.pit_status[i] & 0x40)\n      continue;\n    PIT_DEC(state.pit_counter[i]);\n    switch ((state.pit_status[i] & 0x0e) >> 1) {\n    case 0: // interrupt at terminal\n      if (!state.pit_counter[i]) {\n        state.pit_status[i] |= 0xc0; // out pin high, no count set.\n      }\n      break;\n\n    case 3: // square wave generator\n      if (!state.pit_counter[i]) {\n        if (state.pit_status[i] & 0x80) {\n          state.pit_status[i] &= ~0x80; // lower output;\n        } else {\n          state.pit_status[i] |= 0x80; // raise output\n          if (i == 0) {\n            pic_interrupt(0, 0); // counter 0 is tied to irq 0.\n            // printf(\"Generating timer interrupt.\\n\");\n          }\n        }\n\n        state.pit_counter[i] = state.pit_counter[i + PIT_OFFSET_MAX];\n      }\n\n      // decrement again, since we want a half-wide square wave.\n      PIT_DEC(state.pit_counter[i]);\n      break;\n\n    default:\n      break; // we don't care to handle it.\n    }\n  }\n}\n\n/**\n * Thread entry point.\n **/\nvoid CAliM1543C::run() {\n  try {\n    for (;;) {\n      std::this_thread::sleep_for(std::chrono::milliseconds(1));\n      if (StopThread)\n        return;\n      do_pit_clock();\n    }\n  }\n\n  catch (CException &e) {\n    printf(\"Exception in Ali thread: %s.\\n\", e.displayText().c_str());\n    myThreadDead.store(true);\n    // Let the thread die...\n  }\n}\n\n#define PIT_RATIO 1\n\n/**\n * Handle all events that need to be handled on a clock-driven basis.\n *\n * This is a slow-clocked device, which means this DoClock isn't called as often\n *as the CPU's DoClock. Do the following:\n *  - Handle PIT clock.\n *  .\n **/\nvoid CAliM1543C::do_pit_clock() {\n  static int pit_counter = 0;\n  if (pit_counter++ >= PIT_RATIO) {\n    pit_counter = 0;\n    pit_clock();\n  }\n}\n\n#define PIC_STD 0\n#define PIC_INIT_0 1\n#define PIC_INIT_1 2\n#define PIC_INIT_2 3\n\n/**\n * Read a byte from one of the programmable interrupt controller's registers.\n **/\nu8 CAliM1543C::pic_read(int index, u32 address) {\n  u8 data;\n\n  data = 0;\n\n  if (address == 1)\n    data = state.pic_mask[index];\n\n#ifdef DEBUG_PIC\n  if (pic_messages)\n    printf(\"%%PIC-I-READ: read %02x from port %\" PRId64 \" on PIC %d\\n\", data,\n           address, index);\n#endif\n  return data;\n}\n\n/**\n * Read a byte from the edge/level register of one of the programmable interrupt\n *controllers.\n **/\nu8 CAliM1543C::pic_read_edge_level(int index) {\n  return state.pic_edge_level[index];\n}\n\n/**\n * Read the interrupt vector during a PCI IACK cycle.\n **/\nu8 CAliM1543C::pic_read_vector() {\n  if (state.pic_asserted[0] & 1)\n    return state.pic_intvec[0];\n  if (state.pic_asserted[0] & 2)\n    return state.pic_intvec[0] + 1;\n  if (state.pic_asserted[0] & 4) {\n    if (state.pic_asserted[1] & 1)\n      return state.pic_intvec[1];\n    if (state.pic_asserted[1] & 2)\n      return state.pic_intvec[1] + 1;\n    if (state.pic_asserted[1] & 4)\n      return state.pic_intvec[1] + 2;\n    if (state.pic_asserted[1] & 8)\n      return state.pic_intvec[1] + 3;\n    if (state.pic_asserted[1] & 16)\n      return state.pic_intvec[1] + 4;\n    if (state.pic_asserted[1] & 32)\n      return state.pic_intvec[1] + 5;\n    if (state.pic_asserted[1] & 64)\n      return state.pic_intvec[1] + 6;\n    if (state.pic_asserted[1] & 128)\n      return state.pic_intvec[1] + 7;\n  }\n\n  if (state.pic_asserted[0] & 8)\n    return state.pic_intvec[0] + 3;\n  if (state.pic_asserted[0] & 16)\n    return state.pic_intvec[0] + 4;\n  if (state.pic_asserted[0] & 32)\n    return state.pic_intvec[0] + 5;\n  if (state.pic_asserted[0] & 64)\n    return state.pic_intvec[0] + 6;\n  if (state.pic_asserted[0] & 128)\n    return state.pic_intvec[0] + 7;\n  return 0;\n}\n\n/**\n * Write a byte to one of the programmable interrupt controller's registers.\n **/\nvoid CAliM1543C::pic_write(int index, u32 address, u8 data) {\n  int level;\n  int op;\n#ifdef DEBUG_PIC\n  if (pic_messages)\n    printf(\"%%PIC-I-WRITE: write %02x to port %\" PRId64 \" on PIC %d\\n\", data,\n           address, index);\n#endif\n  switch (address) {\n  case 0:\n    if (data & 0x10)\n      state.pic_mode[index] = PIC_INIT_0;\n    else\n      state.pic_mode[index] = PIC_STD;\n    if (data & 0x08) {\n\n      // OCW3\n    } else {\n\n      // OCW2\n      op = (data >> 5) & 7;\n      level = data & 7;\n      switch (op) {\n      case 1:\n\n        // non-specific EOI\n        state.pic_asserted[index] = 0;\n\n        //\n        if (index == 1)\n          state.pic_asserted[0] &= ~(1 << 2);\n\n        //\n        if (!state.pic_asserted[0])\n          cSystem->interrupt(55, false);\n#ifdef DEBUG_PIC\n        pic_messages = false;\n#endif\n        break;\n\n      case 3:\n\n        // specific EOI\n        state.pic_asserted[index] &= ~(1 << level);\n\n        //\n        if ((index == 1) && (!state.pic_asserted[1]))\n          state.pic_asserted[0] &= ~(1 << 2);\n\n        //\n        if (!state.pic_asserted[0])\n          cSystem->interrupt(55, false);\n#ifdef DEBUG_PIC\n        pic_messages = false;\n#endif\n        break;\n      }\n    }\n\n    return;\n\n  case 1:\n    switch (state.pic_mode[index]) {\n    case PIC_INIT_0:\n      state.pic_intvec[index] = (u8)data & 0xf8;\n      state.pic_mode[index] = PIC_INIT_1;\n      return;\n\n    case PIC_INIT_1:\n      state.pic_mode[index] = PIC_INIT_2;\n      return;\n\n    case PIC_INIT_2:\n      state.pic_mode[index] = PIC_STD;\n      return;\n\n    case PIC_STD:\n      state.pic_mask[index] = data;\n      state.pic_asserted[index] &= ~data;\n      return;\n    }\n  }\n}\n\n/**\n * Write a byte to the edge/level register of one of the programmable interrupt\n *controllers.\n **/\nvoid CAliM1543C::pic_write_edge_level(int index, u8 data) {\n  state.pic_edge_level[index] = data;\n}\n\n#define DEBUG_EXPR (index != 0 || (intno != 0 && intno > 4))\n\n/**\n * Assert an interrupt on one of the programmable interrupt controllers.\n **/\nvoid CAliM1543C::pic_interrupt(int index, int intno) {\n#ifdef DEBUG_PIC\n  if (DEBUG_EXPR) {\n    printf(\"%%PIC-I-INCOMING: Interrupt %d incomming on PIC %d\", intno, index);\n    pic_messages = true;\n  }\n#endif\n\n  // do we have this interrupt enabled?\n  if (state.pic_mask[index] & (1 << intno)) {\n#ifdef DEBUG_PIC\n    if (DEBUG_EXPR)\n      printf(\" (masked)\\n\");\n    pic_messages = false;\n#endif\n    return;\n  }\n\n  if (state.pic_asserted[index] & (1 << intno)) {\n#ifdef DEBUG_PIC\n    if (DEBUG_EXPR)\n      printf(\" (already asserted)\\n\");\n#endif\n    return;\n  }\n\n#ifdef DEBUG_PIC\n  if (DEBUG_EXPR)\n    printf(\"\\n\");\n#endif\n  state.pic_asserted[index] |= (1 << intno);\n\n  if (index == 1)\n    pic_interrupt(0, 2); // cascade\n  if (index == 0)\n    cSystem->interrupt(55, true);\n}\n\n/**\n * De-assert an interrupt on one of the programmable interrupt controllers.\n **/\nvoid CAliM1543C::pic_deassert(int index, int intno) {\n  if (!(state.pic_asserted[index] & (1 << intno)))\n    return;\n\n  //  printf(\"De-asserting %d,%d\\n\",index,intno);\n  state.pic_asserted[index] &= ~(1 << intno);\n  if (index == 1 && state.pic_asserted[1] == 0)\n    pic_deassert(0, 2); // cascade\n  if (index == 0 && state.pic_asserted[0] == 0)\n    cSystem->interrupt(55, false);\n}\n\nstatic u32 ali_magic1 = 0xA111543C;\nstatic u32 ali_magic2 = 0xC345111A;\n\n/**\n * Save state to a Virtual Machine State file.\n **/\nint CAliM1543C::SaveState(FILE *f) {\n  long ss = sizeof(state);\n  int res;\n\n  if ((res = CPCIDevice::SaveState(f)))\n    return res;\n\n  fwrite(&ali_magic1, sizeof(u32), 1, f);\n  fwrite(&ss, sizeof(long), 1, f);\n  fwrite(&state, sizeof(state), 1, f);\n  fwrite(&ali_magic2, sizeof(u32), 1, f);\n  printf(\"%s: %d bytes saved.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\n/**\n * Restore state from a Virtual Machine State file.\n **/\nint CAliM1543C::RestoreState(FILE *f) {\n  long ss;\n  u32 m1;\n  u32 m2;\n  int res;\n  size_t r;\n\n  if ((res = CPCIDevice::RestoreState(f)))\n    return res;\n\n  r = fread(&m1, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m1 != ali_magic1) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&ss, sizeof(long), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (ss != sizeof(state)) {\n    printf(\"%s: STRUCT SIZE does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&state, sizeof(state), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&m2, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m2 != ali_magic2) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  printf(\"%s: %d bytes restored.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\n/**\n * Parallel Port information:\n * address 0 (R/W):  data pins.  On read, the last byte written is returned.\n *\n *\n * address 1 (R): status register\n * \\code\n *   1 0 0 0 0 0 00 <-- default\n *   ^ ^ ^ ^ ^ ^ ^\n *   | | | | | | +- Undefined\n *   | | | | | +--- IRQ (undefined?)\n *   | | | | +----- printer has error condition\n *   | | | +------- printer is not selected.\n *   | | +--------- printer has paper (online)\n *   | +----------- printer is asserting 'ack'\n *   +------------- printer busy (active low).\n * \\endcode\n *\n * address 2 (R/W): control register.\n * \\code\n *   00 0 0 1 0 1 1  <-- default\n *   ^  ^ ^ ^ ^ ^ ^\n *   |  | | | | | +-- Strobe (active low)\n *   |  | | | | +---- Auto feed (active low)\n *   |  | | | +------ Initialize\n *   |  | | +-------- Select (active low)\n *   |  | +---------- Interrupt Control\n *   |  +------------ Bidirectional control (unimplemented)\n *   +--------------- Unused\n * \\endcode\n **/\nvoid CAliM1543C::lpt_reset() {\n  state.lpt_data = ~0;\n  state.lpt_status = 0xd8;  // busy, ack, online, error\n  state.lpt_control = 0x0c; // select, init\n  state.lpt_init = false;\n}\n\n/**\n * Read a byte from one of the parallel port controller's registers.\n **/\nu8 CAliM1543C::lpt_read(u32 address) {\n  u8 data = 0;\n  switch (address) {\n  case 0:\n    data = state.lpt_data;\n    break;\n\n  case 1:\n    data = state.lpt_status;\n    if ((state.lpt_status & 0x80) == 0 && (state.lpt_control & 0x01) == 0) {\n      if (state.lpt_status & 0x40) { // test ack\n        state.lpt_status &= ~0x40;   // turn off ack\n      } else {\n        state.lpt_status |= 0x40; // set ack.\n        state.lpt_status |= 0x80; // set (not) busy.\n      }\n    }\n    break;\n\n  case 2:\n    data = state.lpt_control;\n  }\n\n#ifdef DEBUG_LPT\n  printf(\"%%LPT-I-READ: port %d = %x\\n\", address, data);\n#endif\n  return data;\n}\n\n/**\n * Write a byte to one of the parallel port controller's registers.\n **/\nvoid CAliM1543C::lpt_write(u32 address, u8 data) {\n#ifdef DEBUG_LPT\n  printf(\"%%LPT-I-WRITE: port %d = %x\\n\", address, data);\n#endif\n  switch (address) {\n  case 0:\n    state.lpt_data = data;\n    break;\n\n  case 1:\n    break;\n\n  case 2:\n    if ((data & 0x04) == 0) {\n      state.lpt_init = true;\n      state.lpt_status = 0xd8;\n    } else {\n      if (data & 0x08) {             // select bit\n        if (data & 0x01) {           // strobe?\n          state.lpt_status &= ~0x80; // we're busy\n\n          // do the write!\n          if (lpt && state.lpt_init)\n            fputc(state.lpt_data, lpt);\n          if (state.lpt_control & 0x10) {\n            pic_interrupt(0, 7);\n          }\n        } else {\n\n          // ?\n        }\n      }\n    }\n\n    state.lpt_control = data;\n  }\n}\n\n/**\n * Check if threads are still running.\n **/\nvoid CAliM1543C::check_state() {\n  if (myThreadDead.load())\n    FAILURE(Thread, \"ALi thread has died\");\n}\n\nCAliM1543C *theAli = 0;\n"
  },
  {
    "path": "src/AliM1543C.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_ALIM1543C_H_)\n#define INCLUDED_ALIM1543C_H_\n\n#include \"PCIDevice.hpp\"\n\n#define PIT_OFFSET_MAX 6\n\n// RTC register A (MC_BASE_32_KHz is a divider bits configuration)\n#define RTC_REG_A 0x0a\n#define RTC_UIP 0x80\n#define MC_BASE_32_KHz 0x20\n\n// RTC register B (here most options reside; 0x08 is the unused square wave\n// enable pin)\n#define RTC_REG_B 0x0b\n#define RTC_SET 0x80\n#define RTC_PIE 0x40\n#define RTC_AIE 0x20\n#define RTC_UIE 0x10\n#define RTC_DM 0x04\n#define RTC_2412 0x02\n#define RTC_DSE 0x01\n\n// RTC register C (rest of register is always zero)\n#define RTC_REG_C 0x0c\n#define RTC_IRQF 0x80\n#define RTC_PF 0x40\n#define RTC_AF 0x20\n#define RTC_UF 0x10\n\n// RTC register D (rest of register is always zero)\n#define RTC_REG_D 0x0d\n#define RTC_VRT 0x80\n\n/**\n * \\brief Emulated ISA part of the ALi M1543C chipset.\n *\n * The ALi M1543C device provides i/o and glue logic support to the system:\n * ISA, DMA, Interrupt, Timer, TOY Clock.\n *\n * Documentation consulted:\n *  - Ali M1543C B1 South Bridge Version 1.20\n *(http://mds.gotdns.com/sensors/docs/ali/1543dScb1-120.pdf)\n *  - MC146818 RTC\n *(https://www.nxp.com/docs/en/data-sheet/MC146818.pdf)\n *  - Keyboard Scancodes, by Andries Brouwer\n *(http://www.win.tue.nl/~aeb/linux/kbd/scancodes.html)\n *  .\n **/\nclass CAliM1543C : public CPCIDevice {\npublic:\n  virtual int SaveState(FILE *f);\n  virtual int RestoreState(FILE *f);\n\n  virtual void check_state();\n  virtual void WriteMem_Legacy(int index, u32 address, int dsize, u32 data);\n  virtual u32 ReadMem_Legacy(int index, u32 address, int dsize);\n\n  void do_pit_clock();\n\n  CAliM1543C(CConfigurator *cfg, class CSystem *c, int pcibus, int pcidev);\n  virtual ~CAliM1543C();\n  void pic_interrupt(int index, int intno);\n  void pic_deassert(int index, int intno);\n\n  void init();\n  void start_threads();\n  void stop_threads();\n  void run();\n\nprivate:\n  std::unique_ptr<std::thread> myThread;\n  std::atomic_bool myThreadDead{false};\n  CMutex *myRegLock;\n  bool StopThread;\n\n  struct tm get_time();\n\n  // REGISTER 61 (NMI)\n  u8 reg_61_read();\n  void reg_61_write(u8 data);\n\n  // REGISTERS 70 - 73: TOY\n  u8 toy_read(u32 address);\n  void toy_write(u32 address, u8 data);\n  void toy_handle_periodic_interrupt(u8 data);\n  void toy_update_irqf();\n\n  // Timer/Counter\n  u8 pit_read(u32 address);\n  void pit_write(u32 address, u8 data);\n  void pit_clock();\n\n  // interrupt controller\n  u8 pic_read(int index, u32 address);\n  void pic_write(int index, u32 address, u8 data);\n  u8 pic_read_vector();\n  u8 pic_read_edge_level(int index);\n  void pic_write_edge_level(int index, u8 data);\n\n  // LPT controller\n  u8 lpt_read(u32 address);\n  void lpt_write(u32 address, u8 data);\n  void lpt_reset();\n\n  /// The state structure contains all elements that need to be saved to the\n  /// statefile.\n  struct SAli_state {\n    // REGISTER 61 (NMI)\n    u8 reg_61;\n\n    // REGISTERS 70 - 73: TOY\n    u8 toy_stored_data[256];\n    u8 toy_access_ports[4];\n\n    // TOY periodic interrupt last fire\n    clock_t toy_pi_last_fire;\n\n    // Timer/Counter\n    u32 pit_counter[9];\n    u8 pit_status[4];\n    u8 pit_mode[4];\n\n    // interrupt controller\n    int pic_mode[2];\n    u8 pic_intvec[2];\n    u8 pic_mask[2];\n    u8 pic_asserted[2];\n    u8 pic_edge_level[2];\n\n    u8 lpt_data;\n    u8 lpt_control;\n    u8 lpt_status;\n    bool lpt_init;\n  } state;\n\n  FILE *lpt;\n};\n\nextern CAliM1543C *theAli;\n#endif // !defined(INCLUDED_ALIM1543C_H_)\n"
  },
  {
    "path": "src/AliM1543C_ide.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\n * 02110-1301, USA.\n *\n * Although this is not required, the author would appreciate being\n * notified of, and receiving any modifications you may make to the\n * source code that might serve the general public.\n */\n\n#ifdef DEBUG_IDE_LOCKS\n#define DEBUG_LOCKS\n#endif\n#include \"AliM1543C_ide.hpp\"\n#include \"StdAfx.hpp\"\n#include \"System.hpp\"\n\n#include <cmath>\n\n#include \"gui/keymap.hpp\"\n#include \"gui/scancodes.hpp\"\n\n#include \"AliM1543C.hpp\"\n#include \"Disk.hpp\"\n\n#define PAUSE(msg)                                                             \\\n  do {                                                                         \\\n    printf(\"Debug Pause: \");                                                   \\\n    printf(msg);                                                               \\\n    getc(stdin);                                                               \\\n  } while (0);\n\nu32 AliM1543C_ide_cfg_data[64] = {\n    /*00*/ 0x522910b9, // CFID: vendor + device\n    /*04*/ 0x02800000, // CFCS: command + status\n    /*08*/ 0x0101fac1, // CFRV: class + revision\n    /*0c*/ 0x00000000, // CFLT: latency timer + cache line size\n    /*10*/ 0x000001f1, // BAR0:\n    /*14*/ 0x000003f5, // BAR1:\n    /*18*/ 0x00000171, // BAR2:\n    /*1c*/ 0x00000375, // BAR3:\n    /*20*/ 0x0000f001, // BAR4:\n    /*24*/ 0x00000000, // BAR5:\n    /*28*/ 0x00000000, // CCIC: CardBus\n    /*2c*/ 0x00000000, // CSID: subsystem + vendor\n    /*30*/ 0x00000000, // BAR6: expansion rom base\n    /*34*/ 0x00000000, // CCAP: capabilities pointer\n    /*38*/ 0x00000000,\n    /*3c*/ 0x040201ff, // CFIT: interrupt configuration\n    0,\n    0,\n    /*48*/ 0x4a000000, // UDMA test\n    /*4c*/ 0x1aba0000, // reserved\n    0,\n    /*54*/ 0x44445555, // udma setting + fifo treshold\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    /*78*/ 0x00000021, // ide clock\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0};\n\nu32 AliM1543C_ide_cfg_mask[64] = {\n    /*00*/ 0x00000000, // CFID: vendor + device\n    /*04*/ 0x00000105, // CFCS: command + status\n    /*08*/ 0x00000000, // CFRV: class + revision\n    /*0c*/ 0x0000ffff, // CFLT: latency timer + cache line size\n    /*10*/ 0xfffffff8, // BAR0\n    /*14*/ 0xfffffffc, // BAR1: CBMA\n    /*18*/ 0xfffffff8, // BAR2:\n    /*1c*/ 0xfffffffc, // BAR3:\n    /*20*/ 0xfffffff0, // BAR4:\n    /*24*/ 0x00000000, // BAR5:\n    /*28*/ 0x00000000, // CCIC: CardBus\n    /*2c*/ 0x00000000, // CSID: subsystem + vendor\n    /*30*/ 0x00000000, // BAR6: expansion rom base\n    /*34*/ 0x00000000, // CCAP: capabilities pointer\n    /*38*/ 0x00000000,\n    /*3c*/ 0x000000ff, // CFIT: interrupt configuration\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0};\n\n/**\n * Constructor.\n **/\nCAliM1543C_ide::CAliM1543C_ide(CConfigurator *cfg, CSystem *c, int pcibus,\n                               int pcidev)\n    : CPCIDevice(cfg, c, pcibus, pcidev), CDiskController(2, 2) {\n  if (theIDE != 0)\n    FAILURE(Configuration, \"More than one IDE controller\");\n  theIDE = this;\n\n  // create scsi busses\n  CSCSIBus *a = new CSCSIBus(cfg, c);\n  CSCSIBus *b = new CSCSIBus(cfg, c);\n  scsi_register(0, a, 7); // scsi id 7 by default\n  scsi_register(1, b, 7); // scsi id 7 by default\n}\n\n/**\n * Initialize the IDE device.\n **/\nvoid CAliM1543C_ide::init() {\n  add_function(0, AliM1543C_ide_cfg_data, AliM1543C_ide_cfg_mask);\n\n  add_legacy_io(PRI_COMMAND, 0x1f0, 8);\n  add_legacy_io(PRI_CONTROL, 0x3f6, 2);\n  add_legacy_io(SEC_COMMAND, 0x170, 8);\n  add_legacy_io(SEC_CONTROL, 0x376, 2);\n  add_legacy_io(PRI_BUSMASTER, 0xf000, 8);\n  add_legacy_io(SEC_BUSMASTER, 0xf008, 8);\n\n  usedma = myCfg->get_bool_value(\"dma\", true);\n  if (!usedma) {\n    printf(\"IDE: DMA Transfers turned off.\\n\");\n  }\n\n  ResetPCI();\n\n  // start controller threads\n  StopThread = false;\n  mtRegisters[0] = new CRWLock(\"ide0-registers\");\n  mtRegisters[1] = new CRWLock(\"ide1-registers\");\n  mtBusMaster[0] = new CRWLock(\"ide0-busmaster\");\n  mtBusMaster[1] = new CRWLock(\"ide1-busmaster\");\n\n  for (int i = 0; i < 2; i++) {\n    semController[i] = new CSemaphore(0, 1);      // disk controller\n    semControllerReady[i] = new CSemaphore(0, 1); // disk controller ready\n    semBusMaster[i] = new CSemaphore(0, 1);       // bus master\n    semBusMasterReady[i] = new CSemaphore(0, 1);  // bus master ready\n    semControllerReady[i]->set();\n    semBusMasterReady[i]->set();\n    thrController[i] = 0;\n  }\n\n  printf(\"%%IDE-I-INIT: New IDE emulator initialized.\\n\");\n}\n\nvoid CAliM1543C_ide::start_threads() {\n  char buffer[5];\n  for (int i = 0; i < 2; i++) {\n    if (!thrController[i]) {\n      sprintf(buffer, \"ide%d\", i);\n      thrController[i] =\n          std::make_unique<std::thread>([this, i]() { this->run(i); });\n      printf(\" %s\", buffer);\n      StopThread = false;\n    }\n  }\n}\n\nvoid CAliM1543C_ide::stop_threads() {\n  char buffer[5];\n  StopThread = true;\n  for (int i = 0; i < 2; i++) {\n    if (thrController[i]) {\n      sprintf(buffer, \"ide%d\", i);\n      printf(\" %s\", buffer);\n      semController[i]->set();\n      thrController[i]->join();\n      thrController[i] = nullptr;\n    }\n  }\n}\n\nCAliM1543C_ide::~CAliM1543C_ide() { stop_threads(); }\n\nvoid CAliM1543C_ide::ResetPCI() {\n  int i;\n\n  int j;\n  CPCIDevice::ResetPCI();\n\n  for (i = 0; i < 2; i++) {\n    CONTROLLER(i).bm_status = 0;\n    CONTROLLER(i).selected = 0;\n    for (j = 0; j < 2; j++) {\n      REGISTERS(i, j).error = 0;\n      COMMAND(i, j).command_in_progress = 0;\n      COMMAND(i, j).command_cycle = 0;\n      STATUS(i, j).busy = false;\n      STATUS(i, j).drive_ready = false;\n      STATUS(i, j).drq = false;\n      STATUS(i, j).err = false;\n      STATUS(i, j).index_pulse = false;\n      STATUS(i, j).index_pulse_count = 0;\n      STATUS(i, j).seek_complete = false;\n      PER_DRIVE(i, j).multiple_size = 1;\n      set_signature(i, j);\n    }\n  }\n}\n\nvoid CAliM1543C_ide::register_disk(class CDisk *dsk, int bus, int dev) {\n  CDiskController::register_disk(dsk, bus, dev);\n  if (dsk->cdrom()) {\n    dsk->scsi_register(0, scsi_bus[bus], dev);\n    dsk->set_atapi_mode();\n  }\n}\n\nstatic u32 ide_magic1 = 0xB222654D;\nstatic u32 ide_magic2 = 0xD456222C;\n\n/**\n * Save state to a Virtual Machine State file.\n **/\nint CAliM1543C_ide::SaveState(FILE *f) {\n  long ss = sizeof(state);\n  int res;\n\n  if ((res = CPCIDevice::SaveState(f)))\n    return res;\n\n  fwrite(&ide_magic1, sizeof(u32), 1, f);\n  fwrite(&ss, sizeof(long), 1, f);\n  fwrite(&state, sizeof(state), 1, f);\n  fwrite(&ide_magic2, sizeof(u32), 1, f);\n  printf(\"%s: %d bytes saved.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\n/**\n * Restore state from a Virtual Machine State file.\n **/\nint CAliM1543C_ide::RestoreState(FILE *f) {\n  long ss;\n  u32 m1;\n  u32 m2;\n  int res;\n  size_t r;\n\n  if ((res = CPCIDevice::RestoreState(f)))\n    return res;\n\n  r = fread(&m1, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m1 != ide_magic1) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&ss, sizeof(long), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (ss != sizeof(state)) {\n    printf(\"%s: STRUCT SIZE does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&state, sizeof(state), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&m2, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m2 != ide_magic2) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  printf(\"%s: %d bytes restored.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\n/*\n * Region read/write redirection\n */\nu32 CAliM1543C_ide::ReadMem_Legacy(int index, u32 address, int dsize) {\n  int channel = 0;\n  switch (index) {\n  case SEC_COMMAND:\n    channel = 1;\n\n  case PRI_COMMAND:\n    return ide_command_read(channel, address, dsize);\n\n  case SEC_CONTROL:\n    channel = 1;\n\n  case PRI_CONTROL:\n    return ide_control_read(channel, address);\n\n  case SEC_BUSMASTER:\n    channel = 1;\n\n  case PRI_BUSMASTER:\n    return ide_busmaster_read(channel, address, dsize);\n  }\n\n  return 0;\n}\n\nvoid CAliM1543C_ide::WriteMem_Legacy(int index, u32 address, int dsize,\n                                     u32 data) {\n  int channel = 0;\n  switch (index) {\n  case SEC_COMMAND:\n    channel = 1;\n\n  case PRI_COMMAND:\n    ide_command_write(channel, address, dsize, data);\n    break;\n\n  case SEC_CONTROL:\n    channel = 1;\n\n  case PRI_CONTROL:\n    ide_control_write(channel, address, data);\n    break;\n\n  case SEC_BUSMASTER:\n    channel = 1;\n\n  case PRI_BUSMASTER:\n    ide_busmaster_write(channel, address, dsize, data);\n    break;\n  }\n}\n\nu32 CAliM1543C_ide::ReadMem_Bar(int func, int bar, u32 address, int dsize) {\n  int channel = 0;\n  switch (bar) {\n  case BAR_SEC_COMMAND:\n    channel = 1;\n\n  case BAR_PRI_COMMAND:\n    return ide_command_read(channel, address, dsize);\n\n  case BAR_SEC_CONTROL:\n    channel = 1;\n\n  case BAR_PRI_CONTROL:\n\n    // we have to offset by two because the BAR starts at 3f4 vs 3f6\n    return ide_control_read(channel, address - 2);\n\n  case BAR_BUSMASTER:\n    if (address < 8)\n      return ide_busmaster_read(0, address, dsize);\n    else\n      return ide_busmaster_read(1, address - 8, dsize);\n  }\n\n  return 0;\n}\n\nvoid CAliM1543C_ide::WriteMem_Bar(int func, int bar, u32 address, int dsize,\n                                  u32 data) {\n  int channel = 0;\n  switch (bar) {\n  case BAR_SEC_COMMAND:\n    channel = 1;\n\n  case BAR_PRI_COMMAND:\n    ide_command_write(channel, address, dsize, data);\n    return;\n\n  case BAR_SEC_CONTROL:\n    channel = 1;\n\n  case BAR_PRI_CONTROL:\n    // we have to offset by two because the BAR starts at 3f4 vs 3f6\n    ide_control_write(channel, address - 2, data);\n    return;\n\n  case BAR_BUSMASTER:\n    if (address < 8)\n      return ide_busmaster_write(0, address, data, dsize);\n    else\n      return ide_busmaster_write(1, address - 8, data, dsize);\n  }\n}\n\n/*\n * Register read/write handlers\n */\nu32 CAliM1543C_ide::ide_command_read(int index, u32 address, int dsize) {\n  u32 data = 0;\n  if (!get_disk(index, 0) && !get_disk(index, 1)) {\n\n    // no disks are present, so the data lines actually float to\n    // a high state, which is logical 1.\n    return 0xffffffff;\n  }\n\n  switch (address) {\n  case REG_COMMAND_DATA:\n    if (!SEL_STATUS(index).drq) {\n#ifdef DEBUG_IDE_REG_COMMAND\n      printf(\"Reading from data buffer when data is not ready.\\n\");\n      ide_status(index);\n      PAUSE(\"WTF\");\n#endif\n      break;\n    }\n\n    data = 0;\n\n    switch (dsize) {\n    case 32:\n      data = CONTROLLER(index).data[CONTROLLER(index).data_ptr++];\n      data |= CONTROLLER(index).data[CONTROLLER(index).data_ptr++] << 16;\n      break;\n\n    case 16:\n      data = CONTROLLER(index).data[CONTROLLER(index).data_ptr++];\n    }\n\n    if (CONTROLLER(index).data_ptr >= CONTROLLER(index).data_size) {\n\n      // there's no more to take.\n      SEL_STATUS(index).drq = false;\n      if (SEL_COMMAND(index).command_in_progress) {\n        SEL_STATUS(index).busy = true;\n        SEL_STATUS(index).drive_ready = false;\n        UPDATE_ALT_STATUS(index);\n        semControllerReady[index]->wait();\n        semController[index]->set(); // wake up the controller.\n#if defined(DEBUG_IDE_MULTIPLE) || defined(DEBUG_IDE_PACKET)\n        printf(\"Command still in progress, waking up controller.\\n\");\n        printf(\"-- Packet Phase: %d\\n\", SEL_COMMAND(index).packet_phase);\n        ide_status(index);\n#endif\n      }\n    }\n\n    if (CONTROLLER(index).data_ptr > IDE_BUFFER_SIZE) {\n      printf(\"%%IDE-W-OVERFLOW: data pointer past end of buffer,  setting to \"\n             \"0.\\n\");\n      CONTROLLER(index).data_ptr = 0;\n      SEL_STATUS(index).drq = false;\n      UPDATE_ALT_STATUS(index);\n    }\n    break;\n\n  case REG_COMMAND_ERROR:\n    data = SEL_REGISTERS(index).error;\n    break;\n\n  case REG_COMMAND_SECTOR_COUNT:\n    data = SEL_REGISTERS(index).sector_count;\n    break;\n\n  case REG_COMMAND_SECTOR_NO:\n    data = SEL_REGISTERS(index).sector_no;\n    break;\n\n  case REG_COMMAND_CYL_LOW:\n    data = SEL_REGISTERS(index).cylinder_no & 0xff;\n    break;\n\n  case REG_COMMAND_CYL_HI:\n    data = (SEL_REGISTERS(index).cylinder_no >> 8) & 0xff;\n    break;\n\n  case REG_COMMAND_DRIVE:\n    data = 0x80 | (SEL_REGISTERS(index).lba_mode ? 0x40 : 0x00) |\n           0x20 // 512 byte sector size\n           | (CONTROLLER(index).selected ? 0x10 : 0x00) |\n           (SEL_REGISTERS(index).head_no & 0x0f);\n    break;\n\n  case REG_COMMAND_STATUS:\n\n    // get the status and clear the interrupt.\n    data = get_status(index);\n    theAli->pic_deassert(1, 6 + index);\n#ifdef DEBUG_IDE_INTERRUPT\n    printf(\"%%IDE-I-INTERRUPT: Interrupt Acknowledged on %d.\\n\", index);\n#endif\n    break;\n  }\n\n#ifdef DEBUG_IDE_REG_COMMAND\n  if (address != 0) {\n    printf(\"%%IDE-I-REGCMD: Read from command register %d (%s) on controller \"\n           \"%d, value: %x\\n\",\n           address, register_names[address], index, data);\n  }\n#endif\n  return data;\n}\n\nvoid CAliM1543C_ide::ide_command_write(int index, u32 address, int dsize,\n                                       u32 data) {\n#ifdef DEBUG_IDE_REG_COMMAND\n  if (address != 0) {\n    printf(\"%%IDE-I-REGCMD: Write to command register %d (%s) on controller \"\n           \"%d, value: %x\\n\",\n           address, register_names[address], index, data);\n  }\n\n  SEL_STATUS(index).debug_status_update = true;\n#endif\n  switch (address) {\n  case REG_COMMAND_DATA:\n    if (!SEL_STATUS(index).drq) {\n#ifdef DEBUG_IDE_REG_COMMAND\n      printf(\"%%IDE-I-DATA: Unrequested data written to data port: %x\\n\", data);\n      ide_status(index);\n#endif\n      break;\n    }\n\n    switch (dsize) {\n    case 32:\n      CONTROLLER(index).data[CONTROLLER(index).data_ptr++] = data & 0xffff;\n      CONTROLLER(index).data[CONTROLLER(index).data_ptr++] =\n          (data >> 16) & 0xffff;\n      break;\n\n    case 16:\n      CONTROLLER(index).data[CONTROLLER(index).data_ptr++] = data & 0xffff;\n    }\n\n    if (CONTROLLER(index).data_ptr >= CONTROLLER(index).data_size) {\n\n      // we don't want any more.\n      SEL_STATUS(index).drq = false;\n      SEL_STATUS(index).busy = true;\n      UPDATE_ALT_STATUS(index);\n      semControllerReady[index]->wait();\n      semController[index]->set(); // wake the controller up.\n    }\n\n    if (CONTROLLER(index).data_ptr > IDE_BUFFER_SIZE) {\n      printf(\"%%IDE-W-OVERFLOW: data pointer overflow,  setting to 0.\\n\");\n      CONTROLLER(index).data_ptr = 0;\n      SEL_STATUS(index).drq = false;\n      UPDATE_ALT_STATUS(index);\n    }\n    break;\n\n  case REG_COMMAND_FEATURES:\n    REGISTERS(index, 0).features = data;\n    REGISTERS(index, 1).features = data;\n    break;\n\n  case REG_COMMAND_SECTOR_COUNT:\n    REGISTERS(index, 0).sector_count = REGISTERS(index, 1).sector_count =\n        data & 0xff;\n    break;\n\n  case REG_COMMAND_SECTOR_NO:\n    REGISTERS(index, 0).sector_no = REGISTERS(index, 1).sector_no = data & 0xff;\n    break;\n\n  case REG_COMMAND_CYL_LOW:\n    REGISTERS(index, 0).cylinder_no = REGISTERS(index, 1).cylinder_no =\n        (REGISTERS(index, 1).cylinder_no & 0xff00) | (data & 0xff);\n    break;\n\n  case REG_COMMAND_CYL_HI:\n    REGISTERS(index, 0).cylinder_no = REGISTERS(index, 1).cylinder_no =\n        (REGISTERS(index, 1).cylinder_no & 0xff) | ((data << 8) & 0xff00);\n    break;\n\n  case REG_COMMAND_DRIVE:\n    if (((data >> 4) & 1) != CONTROLLER(index).selected)\n#ifdef DEBUG_IDE\n      printf(\"Setting selected device on %d to: %d.  val=%02x\\n\", index,\n             (data >> 4) & 1, data);\n#endif\n    CONTROLLER(index).selected = (data >> 4) & 1;\n    REGISTERS(index, 0).head_no = REGISTERS(index, 1).head_no = data & 0x0f;\n    REGISTERS(index, 0).lba_mode = REGISTERS(index, 1).lba_mode =\n        (data >> 6) & 1;\n\n    break;\n\n  case REG_COMMAND_COMMAND:\n    theAli->pic_deassert(1, 6 + index); // interrupt is cleared on write.\n    if (!SEL_DISK(index)) {\n#ifdef DEBUG_IDE\n      printf(\"%%IDE-I-NODEV: Command to non-existing device %d.%d. cmd=%x\\n\",\n             index, CONTROLLER(index).selected, data);\n#endif\n    }\n\n    if (SEL_COMMAND(index).command_in_progress == true) {\n\n      // we're already working, why is another command being issued?\n#ifdef DEBUG_IDE\n      printf(\"%%IDE-W-CIP: Command is already in progress.\\n\");\n      PAUSE(\"dang it!\");\n#endif\n    }\n\n    if ((data & 0xf0) == 0x10)\n      data = 0x10;\n\n    SEL_COMMAND(index).command_in_progress = false;\n    SEL_COMMAND(index).current_command = data;\n#ifdef DEBUG_IDE_CMD\n    printf(\"%%IDE-I-CMD: Command %02x issued on controller %d, disk %d.\\n\",\n           data, index, CONTROLLER(index).selected);\n#endif\n    SEL_COMMAND(index).command_cycle = 0;\n    SEL_STATUS(index).drq = false;\n    UPDATE_ALT_STATUS(index);\n    CONTROLLER(index).data_ptr = 0;\n\n    if (data != 0x00) {\n      SEL_STATUS(index).busy = true;\n      UPDATE_ALT_STATUS(index);\n      SEL_COMMAND(index).command_in_progress = true;\n      SEL_COMMAND(index).packet_phase = PACKET_NONE;\n      semControllerReady[index]->wait();\n      semController[index]->set(); // wake up the controller.\n    } else {\n\n      // this is a nop, so we cancel everything that's pending and\n      // pretend that this operation got done super fast!\n      if (SEL_DISK(index))\n        command_aborted(index, data);\n    }\n    break;\n  }\n}\n\nu32 CAliM1543C_ide::ide_control_read(int index, u32 address) {\n  u32 data = 0;\n  switch (address) {\n  case 0:\n    // Compute status live from current state rather than using cached\n    // alt_status, to avoid stale values when the controller thread has\n    // updated status fields but not yet called UPDATE_ALT_STATUS.\n    // Unlike get_status(), this does not affect index_pulse or clear interrupts.\n    if (SEL_DISK(index)) {\n      data = (SEL_STATUS(index).busy ? 0x80 : 0x00) |\n             (SEL_STATUS(index).drive_ready ? 0x40 : 0x00) |\n             (SEL_STATUS(index).fault ? 0x20 : 0x00) |\n             (SEL_STATUS(index).seek_complete ? 0x10 : 0x00) |\n             (SEL_STATUS(index).drq ? 0x08 : 0x00) |\n             (SEL_STATUS(index).index_pulse ? 0x02 : 0x00) |\n             (SEL_STATUS(index).err ? 0x01 : 0x00);\n    }\n#ifdef DEBUG_IDE_REG_CONTROL\n    static u32 last_data = 0;\n    if (last_data != data) {\n      printf(\"%%IDE-I-READCTRL: alternate status on IDE control %d: 0x%02x\\n\",\n             index, data);\n    }\n\n    last_data = data;\n#endif\n    break;\n\n  case 1:\n\n    // 3x7h drive address register. (floppy?)\n    data |= (CONTROLLER(index).selected == 0) ? 1 : 2;\n    data |= (SEL_REGISTERS(index).head_no) << 2;\n    data = (~data) & 0xff; // negate everything\n#ifdef DEBUG_IDE_REG_CONTROL\n    printf(\"%%IDE-I-READCTRL: drive address port on IDE control %d: 0x%02x\\n\",\n           index, data);\n#endif\n    break;\n  }\n\n  return data;\n}\n\n/**\n * Write to the IDE controller control interface.\n **/\nvoid CAliM1543C_ide::ide_control_write(int index, u32 address, u32 data) {\n  bool prev_reset;\n#ifdef DEBUG_IDE_REG_CONTROL\n  printf(\"%%IDE-I-WRITCTRL: write port %d on IDE control %d: 0x%02x\\n\",\n         (u32)(address), index, data);\n#endif\n  switch (address) {\n  case 0:\n    prev_reset = CONTROLLER(index).reset;\n    CONTROLLER(index).reset = (data >> 2) & 1;\n    CONTROLLER(index).disable_irq = (data >> 1) & 1;\n\n    if (!prev_reset && CONTROLLER(index).reset) {\n#ifdef DEBUG_IDE_REG_CONTROL\n      printf(\"IDE reset on index %d started.\\n\", index);\n#endif\n      STATUS(index, 0).busy = true;\n      STATUS(index, 0).drive_ready = false;\n      STATUS(index, 0).seek_complete = true;\n      STATUS(index, 0).drq = false;\n      STATUS(index, 0).err = false;\n      COMMAND(index, 0).current_command = 0;\n      COMMAND(index, 0).command_in_progress = false;\n      STATUS(index, 1).busy = true;\n      STATUS(index, 1).drive_ready = false;\n      STATUS(index, 1).seek_complete = true;\n      STATUS(index, 1).drq = false;\n      STATUS(index, 1).err = false;\n      COMMAND(index, 1).current_command = 0;\n      COMMAND(index, 1).command_in_progress = false;\n\n      CONTROLLER(index).reset_in_progress = true;\n      SEL_REGISTERS(index).error = 0x01; // no error\n      COMMAND(index, 0).current_command = 0;\n      CONTROLLER(index).disable_irq = false;\n    } else if (prev_reset && !CONTROLLER(index).reset) {\n#ifdef DEBUG_IDE_REG_CONTROL\n      printf(\"IDE reset on index %d ended.\\n\", index);\n#endif\n      STATUS(index, 0).busy = false;\n      STATUS(index, 0).drive_ready = true;\n      STATUS(index, 1).busy = false;\n      STATUS(index, 1).drive_ready = true;\n      CONTROLLER(index).reset_in_progress = false;\n\n      set_signature(index, 0);\n      set_signature(index, 1);\n    }\n    break;\n\n  case 1:\n\n    // floppy?\n    break;\n  }\n}\n\n/**\n * Read from the IDE controller busmaster interface.\n **/\nu32 CAliM1543C_ide::ide_busmaster_read(int index, u32 address, int dsize) {\n  u32 data = 0;\n  switch (dsize) {\n  case 8:\n    data = CONTROLLER(index).busmaster[address];\n    break;\n\n  case 32:\n    data = *(u32 *)(&CONTROLLER(index).busmaster[address]);\n    break;\n\n  default:\n    FAILURE(InvalidArgument, \"16-bit read from busmaster\");\n    break;\n  }\n\n#ifdef DEBUG_IDE_BUSMASTER\n  printf(\n      \"%%IDE-I-READBUSM: read port %d on IDE bus master %d: 0x%02x, %d bytes\\n\",\n      (u32)(address), index, data, dsize / 8);\n#endif\n  return data;\n}\n\n/**\n * Write to the IDE controller busmaster interface.\n **/\nvoid CAliM1543C_ide::ide_busmaster_write(int index, u32 address, u32 data,\n                                         int dsize) {\n#ifdef DEBUG_IDE_BUSMASTER\n  if (!(dsize == 8 && (address >= 4 && address <= 7))) {\n    printf(\"%%IDE-I-WRITBUSM: write port %d on IDE bus master %d: 0x%02x, %d \"\n           \"bytes\\n\",\n           (u32)(address), index, data, dsize / 8);\n  }\n#endif\n\n  u32 prd_address;\n\n  //  u32 base, control;\n  switch (dsize) {\n  case 32:\n    ide_busmaster_write(index, address, data & 0xff, 8);\n    ide_busmaster_write(index, address + 1, (data >> 8) & 0xff, 8);\n    ide_busmaster_write(index, address + 2, (data >> 16) & 0xff, 8);\n    ide_busmaster_write(index, address + 3, (data >> 24) & 0xff, 8);\n    return;\n\n  case 16:\n    ide_busmaster_write(index, address, data & 0xff, 8);\n    ide_busmaster_write(index, address + 1, (data >> 8) & 0xff, 8);\n    return;\n  }\n\n  switch (address) {\n  case 0: // command register\n#ifdef DEBUG_IDE_BUSMASTER\n    printf(\"%%IDE-I-BUSM: Bus master command got data: %x (%s,%s)\\n\", data,\n           (data & 0x08 ? \"write\" : \"read\"), (data & 0x01 ? \"start\" : \"stop\"));\n#endif\n\n    // bits 7:4 & 2:1 are reserved and must return zero on read.\n    CONTROLLER(index).busmaster[0] = data & 0x09;\n    if (data & 0x01) {\n\n      // set the status register\n      CONTROLLER(index).busmaster[2] |= 0x01;\n      semBusMasterReady[index]->wait();\n      semBusMaster[index]->set(); // wake up the controller for busmastering\n    } else {\n\n      // clear the status register\n      CONTROLLER(index).busmaster[2] &= 0xfe;\n    }\n    break;\n\n  case 2: // status\n    // bit 7 = simplex only (0=both channels are independent)\n    // bit 6 = drive 1 dma capable.\n    // bit 5 = drive 0 dma capable.\n    // bit 4,3 = reserved\n    // bit 2 = interrupt (write 1 to reset)\n    // bit 1 = error (write 1 to reset)\n    // bit 0 = busmaster active.\n    CONTROLLER(index).busmaster[2] = data & 0x67;\n    if (data & 0x04) // interrupt\n      CONTROLLER(index).busmaster[2] &= ~0x04;\n    if (data & 0x02) // error\n      CONTROLLER(index).busmaster[2] &= ~0x02;\n    if (data & 0x01) // busy\n      CONTROLLER(index).busmaster[2] &= ~0x01;\n    break;\n\n  case 4: // descriptor table pointer register(s)\n  case 5:\n  case 6:\n    CONTROLLER(index).busmaster[address] = data;\n    break;\n\n  case 7:\n    CONTROLLER(index).busmaster[address] = data;\n    prd_address = endian_32(*(u32 *)(&CONTROLLER(index).busmaster[4]));\n#ifdef DEBUG_IDE_BUSMASTER\n    printf(\"%%IDE-I-PRD: Virtual address: %\" PRIx64 \"  \\n\",\n           endian_32(*(u32 *)(&CONTROLLER(index).busmaster[4])));\n    printf(\"-IDE-I-PRD: Physical address: %\" PRIx64 \"  \\n\", prd_address);\n    u32 base, control;\n    do {\n      do_pci_read(prd_address, &base, 4, 1);\n      do_pci_read(prd_address + 4, &control, 4, 1);\n      printf(\"-IDE-I-PRD: base: %x, control: %x  \\n\", base, control);\n      prd_address += 8;\n    } while (base & 0x80 == 0);\n#endif\n    break;\n\n  default:\n    break;\n  }\n}\n\nvoid CAliM1543C_ide::set_signature(int index, int id) {\n\n  // Device signature\n  REGISTERS(index, id).head_no = 0;\n  REGISTERS(index, id).sector_count = 1;\n  REGISTERS(index, id).sector_no = 1;\n  if (get_disk(index, id)) {\n    if (!get_disk(index, id)->cdrom()) {\n      REGISTERS(index, id).cylinder_no = 0;\n      CONTROLLER(index).selected = 0; // XXX: This may not be correct.\n    } else {\n      REGISTERS(index, id).cylinder_no = 0xeb14;\n    }\n  } else {\n    REGISTERS(index, id).cylinder_no = 0xffff;\n  }\n}\n\nvoid CAliM1543C_ide::raise_interrupt(int index) {\n  if (!CONTROLLER(index).disable_irq) {\n#ifdef DEBUG_IDE_INTERRUPT\n    printf(\"%%IDE-I-INTERRUPT: Interrupt raised on controller %d.\\n\", index);\n#endif\n\n#if !defined(IDE_YIELD_INTERRUPTS)\n    {\n      SCOPED_WRITE_LOCK(mtBusMaster[index]);\n      CONTROLLER(index).busmaster[2] |= 0x04;\n    }\n    UPDATE_ALT_STATUS(index);\n    theAli->pic_interrupt(1, 6 + index);\n#else\n    CONTROLLER(index).interrupt_pending = true;\n#endif\n  }\n}\n\nu8 CAliM1543C_ide::get_status(int index) {\n  u8 data;\n  if (!SEL_DISK(index)) {\n#ifdef DEBUG_IDE_REG_COMMAND\n    printf(\"%%IDE-I-STATUS: Read status for nonexiting device %d.%d\\n\", index,\n           CONTROLLER(index).selected);\n#endif\n    return 0;\n  }\n\n  data = (SEL_STATUS(index).busy ? 0x80 : 0x00) |\n         (SEL_STATUS(index).drive_ready ? 0x40 : 0x00) |\n         (SEL_STATUS(index).fault ? 0x20 : 0x00) |\n         (SEL_STATUS(index).seek_complete ? 0x10 : 0x00) |\n         (SEL_STATUS(index).drq ? 0x08 : 0x00) |\n         (SEL_STATUS(index).index_pulse ? 0x02 : 0x00) |\n         (SEL_STATUS(index).err ? 0x01 : 0x00);\n  SEL_STATUS(index).index_pulse_count++;\n  SEL_STATUS(index).index_pulse = false;\n  if (SEL_STATUS(index).index_pulse_count >= 10) {\n    SEL_STATUS(index).index_pulse_count = 0;\n    SEL_STATUS(index).index_pulse = true;\n  }\n\n#ifdef DEBUG_IDE_REG_COMMAND\n  if ((SEL_STATUS(index).debug_last_status & 0xfd) != (data & 0xfd) ||\n      SEL_STATUS(index).debug_status_update) {\n    printf(\"%%IDE-I-STATUS: Controller %d status: %x = %s %s %s %s %s %s %s\\n\",\n           index, data, SEL_STATUS(index).busy ? \"busy\" : \"\",\n           SEL_STATUS(index).drive_ready ? \"drdy\" : \"\",\n           SEL_STATUS(index).fault ? \"fault\" : \"\",\n           SEL_STATUS(index).seek_complete ? \"seek_complete\" : \"\",\n           SEL_STATUS(index).drq ? \"drq\" : \"\",\n           SEL_STATUS(index).index_pulse ? \"pulse\" : \"\",\n           SEL_STATUS(index).err ? \"error\" : \"\");\n    SEL_STATUS(index).debug_status_update = false;\n  }\n\n  SEL_STATUS(index).debug_last_status = data;\n#endif\n  return data;\n}\n\nvoid CAliM1543C_ide::identify_drive(int index, bool packet) {\n  char serial_number[21];\n  char model_number[41];\n  char rev_number[9];\n  size_t i;\n\n  // clear the block.\n  for (i = 0; i < 256; i++)\n    CONTROLLER(index).data[i] = 0;\n\n  CONTROLLER(index).data_ptr = 0;\n  CONTROLLER(index).data_size = 256;\n\n  // The data here was taken from T13/1153D revision 18\n  if (!packet) {\n\n    // flags:  0x0080 = removable, 0x0040 = fixed.\n    CONTROLLER(index).data[0] = SEL_DISK(index)->cdrom() ? 0x0080 : 0x0040;\n  } else {\n\n    // flags: 15-14: 10=atapi, 11=reserved; 12-8: packet set; 7:\n    // removable 6-5: timing info, 4-2: command, 1-0: 00= 12 byte packet\n    CONTROLLER(index).data[0] = 0x8580;\n  }\n\n  // logical cylinders\n  if (SEL_DISK(index)->get_cylinders() > 16383)\n    CONTROLLER(index).data[1] = 16383;\n  else\n    CONTROLLER(index).data[1] = (u16)(SEL_DISK(index)->get_cylinders());\n\n  // logical heads\n  CONTROLLER(index).data[3] = (u16)(SEL_DISK(index)->get_heads());\n\n  // logical sectors per logical track\n  CONTROLLER(index).data[6] = (u16)(SEL_DISK(index)->get_sectors());\n\n  // serial number\n  strcpy(serial_number, \"                    \");\n  i = strlen(SEL_DISK(index)->get_serial());\n  i = (i > 20) ? 20 : i;\n  memcpy(model_number, SEL_DISK(index)->get_serial(), i);\n  for (i = 0; i < 10; i++)\n    CONTROLLER(index).data[10 + i] =\n        (serial_number[i * 2] << 8) | serial_number[i * 2 + 1];\n\n  // firmware revision\n  strcpy(rev_number, \"        \");\n  i = strlen(SEL_DISK(index)->get_rev());\n  i = (i > 8) ? 8 : i;\n  memcpy(model_number, SEL_DISK(index)->get_rev(), i);\n  for (i = 0; i < 4; i++)\n    CONTROLLER(index).data[23 + i] =\n        (rev_number[i * 2] << 8) | rev_number[i * 2 + 1];\n\n  // model number\n  strcpy(model_number, \"                                        \");\n  i = strlen(SEL_DISK(index)->get_model());\n  i = (i > 40) ? 40 : i;\n  memcpy(model_number, SEL_DISK(index)->get_model(), i);\n  for (i = 0; i < 20; i++)\n    CONTROLLER(index).data[i + 27] =\n        (model_number[i * 2] << 8) | model_number[i * 2 + 1];\n\n  // read/write multiple (15-8 = 0x80, 7-0 = # sectors)\n  CONTROLLER(index).data[47] = 0x8000 | MAX_MULTIPLE_SECTORS;\n\n  // capabilities\n  if (!packet) {\n    CONTROLLER(index).data[49] = 0x0300;\n  } else {\n    CONTROLLER(index).data[49] = 0x0b00; // dma, iordy\n  }\n\n  // capabilities (2)\n  CONTROLLER(index).data[50] = 0x4000;\n\n  // pio data transfer number (bits 15-8)\n  CONTROLLER(index).data[51] = 0x0300;\n\n  // validity:  bit 2 = #88 valid, 1 = 64-70 valid, 0 = 54-58 valid\n  CONTROLLER(index).data[53] = 7;\n\n  // geometry\n  CONTROLLER(index).data[54] = (u16)(SEL_DISK(index)->get_cylinders());\n  CONTROLLER(index).data[55] = (u16)(SEL_DISK(index)->get_heads());\n  CONTROLLER(index).data[56] = (u16)(SEL_DISK(index)->get_sectors());\n  CONTROLLER(index).data[57] =\n      (u16)(SEL_DISK(index)->get_chs_size() >> 0) & 0xFFFF;\n  CONTROLLER(index).data[58] =\n      (u16)(SEL_DISK(index)->get_chs_size() >> 16) & 0xFFFF;\n\n  // multiple sector setting (valid, 1 sector per interrupt)\n  if (SEL_PER_DRIVE(index).multiple_size != 0) {\n    CONTROLLER(index).data[59] = 0x0100 | SEL_PER_DRIVE(index).multiple_size;\n  } else {\n    CONTROLLER(index).data[59] = 0x0000;\n  }\n\n  // lba capacity\n  CONTROLLER(index).data[60] =\n      (u16)(SEL_DISK(index)->get_lba_size() >> 0) & 0xFFFF;\n  CONTROLLER(index).data[61] =\n      (u16)(SEL_DISK(index)->get_lba_size() >> 16) & 0xFFFF;\n\n  // multiword dma capability (10-8: modes selected, 2-0, modes\n  // supported)\n  if (usedma)\n    CONTROLLER(index).data[63] =\n        CONTROLLER(index).dma_mode << 8 | 0x01; // dma 0 supported\n  else\n    CONTROLLER(index).data[63] =\n        CONTROLLER(index).dma_mode << 8 | 0x00; // dma not supported\n\n  // pio modes supported (bit 0 = mode 3, bit 1 = mode 4)\n  CONTROLLER(index).data[64] = 0x0002;\n\n  // minimum cycle times\n  CONTROLLER(index).data[65] = 480; // mode 0\n  CONTROLLER(index).data[66] = 480; // mode 0\n  CONTROLLER(index).data[67] = 120; // pio4\n  CONTROLLER(index).data[68] = 120; // pio4\n  if (packet) {\n\n    // packet to bus release time\n    CONTROLLER(index).data[71] = 120;\n\n    // service to bus release time\n    CONTROLLER(index).data[72] = 120;\n  }\n\n  // queue depth (we don't do queing)\n  CONTROLLER(index).data[75] = 0;\n\n  // ata version supported (bits/version: 1,2,3,4)\n  CONTROLLER(index).data[80] = 0x001e;\n\n  // atapi revision supported (ata/atapi-4 T13 1153D revision 17)\n  CONTROLLER(index).data[81] = 0x0017;\n\n  // command set supported (cdrom = nop,packet,removable; disk=nop)\n  CONTROLLER(index).data[82] = SEL_DISK(index)->cdrom() ? 0x4014 : 0x4000;\n\n  // command sets supported(no additional command sets)\n  CONTROLLER(index).data[83] = 0x4000;\n  CONTROLLER(index).data[84] = 0x4000;\n\n  // command sets enabled.\n  CONTROLLER(index).data[85] = SEL_DISK(index)->cdrom() ? 0x4014 : 0x4000;\n  CONTROLLER(index).data[86] = 0x4000;\n  CONTROLLER(index).data[87] = 0x4000;\n\n  // ultra dma modes supported (10-8: modes selected, 2-0, modes\n  // supported)\n  CONTROLLER(index).data[88] = 0x0000;\n}\n\nvoid CAliM1543C_ide::command_aborted(int index, u8 command) {\n  printf(\"ide%d.%d aborting on command 0x%02x \\n\", index,\n         CONTROLLER(index).selected, command);\n  SEL_STATUS(index).busy = false;\n  SEL_STATUS(index).drive_ready = true;\n  SEL_STATUS(index).err = true;\n  SEL_STATUS(index).drq = false;\n  SEL_REGISTERS(index).error |= 0x04; // command ABORTED\n  CONTROLLER(index).data_ptr = 0;\n  SEL_COMMAND(index).command_in_progress = false;\n  UPDATE_ALT_STATUS(index);\n  raise_interrupt(index);\n}\n\nCAliM1543C_ide *theIDE = 0;\n\nvoid CAliM1543C_ide::ide_status(int index) {\n  printf(\"IDE %d.%d: [busy: %d, drdy: %d, flt: %d, drq: %d, err: %d]\\n\"\n         \"         [c: %d, h: %d, s: %d, #: %d, f: %x, lba: %d]\\n\"\n         \"         [ptr: %d, size: %d, error: %d, cmd: %x, in progress: %d]\\n\"\n         \"         [cycle: %d, pkt phase: %d, pkt cmd: %x, dma: %d]\\n\"\n         \"         [bm-cmd: %x  bm-stat: %x]\\n\",\n         index, CONTROLLER(index).selected, SEL_STATUS(index).busy,\n         SEL_STATUS(index).drive_ready, SEL_STATUS(index).fault,\n         SEL_STATUS(index).drq, SEL_STATUS(index).err,\n         SEL_REGISTERS(index).cylinder_no, SEL_REGISTERS(index).head_no,\n         SEL_REGISTERS(index).sector_no, SEL_REGISTERS(index).sector_count,\n         SEL_REGISTERS(index).features,\n         (SEL_REGISTERS(index).head_no << 24) |\n             (SEL_REGISTERS(index).cylinder_no << 8) |\n             SEL_REGISTERS(index).sector_no,\n         CONTROLLER(index).data_ptr, CONTROLLER(index).data_size,\n         SEL_REGISTERS(index).error, SEL_COMMAND(index).current_command & 0xff,\n         SEL_COMMAND(index).command_in_progress,\n         SEL_COMMAND(index).command_cycle, SEL_COMMAND(index).packet_phase,\n         SEL_COMMAND(index).packet_command[0], SEL_COMMAND(index).packet_dma,\n         CONTROLLER(index).busmaster[0], CONTROLLER(index).busmaster[2]);\n}\n\n/**\n * Check if threads are still running.\n **/\nvoid CAliM1543C_ide::check_state() {\n  if (thrController[0] && thrControllerDead[0].load())\n    FAILURE(Thread, \"IDE 0 thread has died\");\n\n  if (thrController[1] && thrControllerDead[1].load())\n    FAILURE(Thread, \"IDE 1 thread has died\");\n}\n\nvoid CAliM1543C_ide::execute(int index) {\n  if (SEL_DISK(index) == NULL && SEL_COMMAND(index).current_command != 0x90) {\n\n    // this device doesn't exist (and its not execute device\n    // diagnostic)\n    // so we'll just timeout\n    SEL_COMMAND(index).command_in_progress = false;\n  } else {\n#ifdef DEBUG_IDE_COMMAND\n    printf(\"%%IDE-I-COMMAND: Processing command on controller %d.\\n\", index);\n    ide_status(index);\n#endif\n    switch (SEL_COMMAND(index).current_command) {\n    case 0x00: // nop\n      SEL_REGISTERS(index).error = 0x04;\n      SEL_STATUS(index).busy = false;\n      SEL_STATUS(index).drive_ready = true;\n      SEL_STATUS(index).fault = true;\n      SEL_STATUS(index).drq = false;\n      SEL_STATUS(index).err = true;\n      SEL_COMMAND(index).command_in_progress = false;\n      raise_interrupt(index);\n      printf(\"got nop on %d.%d\\n\", index, CONTROLLER(index).selected);\n\n      // FAILURE(\"This isn't possible, but you're seeing it.\");\n      break;\n\n    case 0x08: // device reset\n      if (SEL_DISK(index)->cdrom() || 1) {\n\n        // the spec says that non-packet devices must not respond\n        // to device reset.  However, by allowing it, Tru64\n        // recognizes the device properly.\n        SEL_COMMAND(index).command_in_progress = false;\n        if (CONTROLLER(index).selected == 0) {\n          REGISTERS(index, 0).error = 0x01; // device passed.\n          REGISTERS(index, 1).error = 0x01; // slave not present or passed\n        } else {\n          REGISTERS(index, 1).error = 0x01; // slave passed\n        }\n\n        set_signature(index, CONTROLLER(index).selected);\n\n        // step \"k\", page 216 (232)\n        SEL_STATUS(index).drq = false;   // bit 3\n        SEL_STATUS(index).bit_2 = false; // bit 2\n        SEL_STATUS(index).err = false;   // bit 0\n        if (SEL_DISK(index)->cdrom()) {\n          SEL_STATUS(index).fault = false;       // bit 5\n          SEL_STATUS(index).drive_ready = false; // per step \"m2\"\n        } else {\n          SEL_STATUS(index).drive_ready = true; // step \"m1\"\n        }\n\n        SEL_STATUS(index).busy = false;\n\n        // some sources say there's no reset on device reset.\n        // raise_interrupt(index);\n      } else {\n        command_aborted(index, SEL_COMMAND(index).current_command);\n      }\n      break;\n\n    case 0x10: // calibrate drive\n      SEL_STATUS(index).busy = false;\n      SEL_STATUS(index).drive_ready = true;\n      SEL_STATUS(index).seek_complete = true;\n      SEL_STATUS(index).fault = false;\n      SEL_STATUS(index).drq = false;\n      SEL_STATUS(index).err = false;\n      SEL_REGISTERS(index).cylinder_no = 0;\n      SEL_COMMAND(index).command_in_progress = false;\n      raise_interrupt(index);\n      break;\n\n    case 0x20: // read with retries\n    case 0x21: // read without retries\n      if (SEL_COMMAND(index).command_cycle == 0) {\n\n        // fixup the 0=256 case.\n        if (SEL_REGISTERS(index).sector_count == 0)\n          SEL_REGISTERS(index).sector_count = 256;\n      }\n\n      if (!SEL_STATUS(index).drq) {\n\n        // buffer is empty, so lets fill it.\n        if (!SEL_REGISTERS(index).lba_mode) {\n          FAILURE(NotImplemented, \"Non-LBA disk read\");\n        } else {\n          u32 lba = (SEL_REGISTERS(index).head_no << 24) |\n                    (SEL_REGISTERS(index).cylinder_no << 8) |\n                    SEL_REGISTERS(index).sector_no;\n\n          SEL_DISK(index)->seek_block(lba);\n          SEL_DISK(index)->read_blocks(&(CONTROLLER(index).data[0]), 1);\n#if defined(ES40_BIG_ENDIAN)\n          for (int i = 0; i < SEL_DISK(index)->get_block_size() / sizeof(u16);\n               i++)\n            CONTROLLER(index).data[i] = endian_16(CONTROLLER(index).data[i]);\n#endif\n          SEL_STATUS(index).busy = false;\n          SEL_STATUS(index).drive_ready = true;\n          SEL_STATUS(index).fault = false;\n          SEL_STATUS(index).drq = true;\n          SEL_STATUS(index).err = false;\n          CONTROLLER(index).data_ptr = 0;\n          CONTROLLER(index).data_size = 256;\n\n          // prepare for next sector\n          SEL_REGISTERS(index).sector_count--;\n          if (SEL_REGISTERS(index).sector_count == 0) {\n            SEL_COMMAND(index).command_in_progress = false;\n            if (SEL_DISK(index)->cdrom())\n              set_signature(index, CONTROLLER(index).selected); // per 9.1\n          } else {\n\n            // set the next block to read.\n            // increment the lba.\n            SEL_REGISTERS(index).sector_no++;\n            if (SEL_REGISTERS(index).sector_no > 255) {\n              SEL_REGISTERS(index).sector_no = 0;\n              SEL_REGISTERS(index).cylinder_no++;\n              if (SEL_REGISTERS(index).cylinder_no > 65535) {\n                SEL_REGISTERS(index).cylinder_no = 0;\n                SEL_REGISTERS(index).head_no++;\n              }\n            }\n          }\n        }\n        \n        UPDATE_ALT_STATUS(index);\n        raise_interrupt(index);\n      }\n      break;\n\n    case 0x30: // write with retries\n    case 0x31: // write without retries\n      if (SEL_COMMAND(index).command_cycle == 0) {\n\n        // this is our first time through\n        if (SEL_DISK(index)->cdrom() || SEL_DISK(index)->ro()) {\n          printf(\"%%IDE-W-RO: Write attempt to read-only disk %d.%d.\\n\", index,\n                 CONTROLLER(index).selected);\n          command_aborted(index, SEL_COMMAND(index).current_command);\n        } else {\n          SEL_STATUS(index).drq = true;\n          SEL_STATUS(index).busy = false;\n          CONTROLLER(index).data_size = 256;\n          if (SEL_REGISTERS(index).sector_count == 0)\n            SEL_REGISTERS(index).sector_count = 256;\n        }\n      } else {\n\n        // now we should be getting data.\n        if (!SEL_STATUS(index).drq) {\n\n          // the buffer is full.  Do something with the data.\n          if (!SEL_REGISTERS(index).lba_mode) {\n            FAILURE(NotImplemented, \"Non-LBA disk write\");\n          } else {\n            u32 lba = (SEL_REGISTERS(index).head_no << 24) |\n                      (SEL_REGISTERS(index).cylinder_no << 8) |\n                      SEL_REGISTERS(index).sector_no;\n\n#if defined(ES40_BIG_ENDIAN)\n            {\n              u16 data[IDE_BUFFER_SIZE];\n\n              SEL_DISK(index)->seek_block(lba);\n              for (int i = 0;\n                   i < SEL_DISK(index)->get_block_size() / sizeof(u16); i++)\n                data[i] = endian_16(CONTROLLER(index).data[i]);\n              SEL_DISK(index)->write_blocks(&(data[0]), 1);\n            }\n\n#else\n            SEL_DISK(index)->seek_block(lba);\n            SEL_DISK(index)->write_blocks(&(CONTROLLER(index).data[0]), 1);\n#endif\n            SEL_STATUS(index).busy = false;\n            SEL_STATUS(index).drive_ready = true;\n            SEL_STATUS(index).fault = false;\n            SEL_STATUS(index).drq = true;\n            SEL_STATUS(index).err = false;\n            CONTROLLER(index).data_ptr = 0;\n\n            // prepare for next sector\n            SEL_REGISTERS(index).sector_count--;\n            if (SEL_REGISTERS(index).sector_count == 0) {\n\n              // we're done\n              SEL_STATUS(index).drq = false;\n              SEL_COMMAND(index).command_in_progress = false;\n            } else {\n\n              // set the next block to read.\n              // increment the lba.\n              SEL_REGISTERS(index).sector_no++;\n              if (SEL_REGISTERS(index).sector_no > 255) {\n                SEL_REGISTERS(index).sector_no = 0;\n                SEL_REGISTERS(index).cylinder_no++;\n                if (SEL_REGISTERS(index).cylinder_no > 65535) {\n                  SEL_REGISTERS(index).cylinder_no = 0;\n                  SEL_REGISTERS(index).head_no++;\n                }\n              }\n            }\n          }\n\n          raise_interrupt(index);\n        }\n      }\n      break;\n\n    /*\n     * case 0x40, 0x41: read verify sector(s) is mandatory for\n     * non-packet (no w/packet\n     */\n    case 0x70: // seek\n      if (SEL_DISK(index)->cdrom()) {\n        command_aborted(index, SEL_COMMAND(index).current_command);\n      } else {\n        SEL_STATUS(index).busy = false;\n        SEL_STATUS(index).drive_ready = true;\n        SEL_STATUS(index).seek_complete = true;\n        SEL_STATUS(index).fault = false;\n        SEL_STATUS(index).drq = false;\n        SEL_STATUS(index).err = false;\n        SEL_COMMAND(index).command_in_progress = false;\n        raise_interrupt(index);\n      }\n      break;\n\n    /*\n     * 0x90: execute device diagnostic: mandatory\n     */\n    case 0x91: // initialize device parameters\n      SEL_COMMAND(index).command_in_progress = false;\n      if (SEL_DISK(index)->cdrom()) {\n        command_aborted(index, SEL_COMMAND(index).current_command);\n      } else {\n#ifdef DEBUG_IDE\n        printf(\"Original c: %d, h: %d, s: %d\\n\",\n               SEL_DISK(index)->get_cylinders(), SEL_DISK(index)->get_heads(),\n               SEL_DISK(index)->get_sectors());\n        printf(\"Requested c: %d, h: %d, s: %d\\n\",\n               SEL_REGISTERS(index).cylinder_no,\n               SEL_REGISTERS(index).head_no + 1,\n               SEL_REGISTERS(index).sector_count);\n#endif\n        if (SEL_DISK(index)->get_heads() ==\n                (SEL_REGISTERS(index).head_no + 1) &&\n            SEL_DISK(index)->get_sectors() ==\n                SEL_REGISTERS(index).sector_count) {\n\n          // use the default translation -- ok!\n          SEL_STATUS(index).busy = false;\n          SEL_STATUS(index).drive_ready = true;\n          SEL_STATUS(index).fault = false;\n          SEL_STATUS(index).drq = false;\n          SEL_STATUS(index).err = false;\n          raise_interrupt(index);\n        } else {\n#ifdef DEBUG_IDE\n          PAUSE(\"INIT DEV PARAMS -- geometry not supported!\");\n#endif\n          SEL_STATUS(index).busy = false;\n          SEL_STATUS(index).drive_ready = true;\n          SEL_STATUS(index).fault = false;\n          SEL_STATUS(index).drq = false;\n          SEL_STATUS(index).err = true;\n          SEL_REGISTERS(index).error = 0x04; // ABORT.\n          raise_interrupt(index);\n        }\n      }\n      break;\n\n    case 0xa0: // packet send\n      /*\n       * The state machine and protocol used here was actually\n       * derived from ATA/ATAPI-5 (D1321R3) instead of the -4\n       * documenation.  State names were taken from that document.\n       */\n      if (!SEL_DISK(index)->cdrom()) {\n        command_aborted(index, SEL_COMMAND(index).current_command);\n      } else {\n        if (SEL_REGISTERS(index).features & 0x02) {\n\n          // overlap not supported\n          PAUSE(\"overlapping not supported\");\n          command_aborted(index, SEL_COMMAND(index).current_command);\n        } else {\n          if (SEL_COMMAND(index).packet_phase == PACKET_NONE) {\n\n            // this must be the first time through.\n            if (!scsi_arbitrate(index))\n              FAILURE(IllegalState, \"ATAPI SCSI bus busy\");\n            if (!scsi_select(index, CONTROLLER(index).selected))\n              FAILURE(IllegalState, \"ATAPI device not responding to selection\");\n            SEL_REGISTERS(index).REASON = IR_CD;\n            SEL_STATUS(index).busy = false;\n            SEL_STATUS(index).drq = true;\n            SEL_STATUS(index).DMRD = false;\n            SEL_STATUS(index).SERV = false;\n            CONTROLLER(index).data_ptr = 0;\n            CONTROLLER(index).data_size = 6;\n            SEL_COMMAND(index).packet_dma =\n                (SEL_REGISTERS(index).features & 0x01) ? true : false;\n            SEL_COMMAND(index).packet_phase = PACKET_DP1;\n\n            // we drop out of the thread and shut down the\n            // controller. we will be awakened when the drq flag\n            // is false, and the process will start in the state machine.\n            break;\n          }\n\n          /*\n           * This is the Packet I/O state machine. The gist of\n           * it is this: we loop until yield==true, so we can\n           * move from state to state in the same DoClock().\n           * By the time we get here, we're in DP1 (Receive\n           * Packet) and we're waiting for an actual packet to\n           * arrive.\n           */\n#ifdef DEBUG_IDE_PACKET\n          printf(\"Entering Packet state machine %d\\n\", index);\n          ide_status(index);\n#endif\n\n          bool yield = false;\n          do {\n#ifdef DEBUG_IDE_PACKET\n            printf(\"PACKET STATE: %s (%d)\\n\",\n                   packet_states[SEL_COMMAND(index).packet_phase],\n                   SEL_COMMAND(index).packet_phase);\n#endif\n            switch (SEL_COMMAND(index).packet_phase) {\n            case PACKET_DP1: // receive packet\n              // we now have a full command packet.\n              if (scsi_get_phase(index) != SCSI_PHASE_COMMAND)\n                FAILURE(IllegalState, \"SCSI command phase expected\");\n\n              memcpy(scsi_xfer_ptr(index, 12), CONTROLLER(index).data, 12);\n              memcpy(SEL_COMMAND(index).packet_command, CONTROLLER(index).data,\n                     12);\n              scsi_xfer_done(index);\n\n              SEL_COMMAND(index).packet_phase = PACKET_DP2;\n              SEL_COMMAND(index).packet_buffersize =\n                  SEL_REGISTERS(index).cylinder_no;\n              SEL_STATUS(index).busy = true;\n              break;\n\n            case PACKET_DP2: // prepare b\n              SEL_STATUS(index).busy = true;\n              SEL_STATUS(index).drq = false;\n\n              if (SEL_COMMAND(index).command_in_progress) {\n                switch (scsi_get_phase(index)) {\n                case SCSI_PHASE_DATA_IN: {\n                  size_t num_bytes = scsi_expected_xfer(index);\n                  void *data_ptr = scsi_xfer_ptr(index, num_bytes);\n                  memcpy(CONTROLLER(index).data, data_ptr, num_bytes);\n                  scsi_xfer_done(index);\n                  SEL_COMMAND(index).packet_phase = PACKET_DP34;\n                  SEL_REGISTERS(index).BYTE_COUNT = (int)num_bytes;\n                  CONTROLLER(index).data_size =\n                      (int)num_bytes / 2; // word count.\n                  CONTROLLER(index).data_ptr = 0;\n                } break;\n\n                case SCSI_PHASE_DATA_OUT:\n                  FAILURE(NotImplemented,\n                          \"ATAPI for now does not support write operations\");\n                  break;\n\n                case SCSI_PHASE_STATUS:\n                  scsi_xfer_ptr(index, scsi_expected_xfer(index));\n                  scsi_xfer_done(index);\n                  if (scsi_get_phase(index) != SCSI_PHASE_FREE)\n                    FAILURE(IllegalState, \"SCSI bus free phase expected\");\n                  SEL_COMMAND(index).packet_phase = PACKET_DI;\n                  break;\n\n                default:\n                  FAILURE(IllegalState, \"Unexpected SCSI phase\");\n                }\n              } else {\n\n                // transition to an idle state\n#if defined(DEBUG_IDE_PACKET)\n                printf(\"Transition into idle state from DP2.\\n\");\n#endif\n                SEL_COMMAND(index).packet_phase = PACKET_DI;\n              }\n              break;\n\n            case PACKET_DP34:\n              if (SEL_COMMAND(index).packet_dma) {\n\n                // send back via dma\n#ifdef DEBUG_IDE_PACKET\n                printf(\"Sending ATAPI data back via DMA.\\n\");\n#endif\n\n                do_dma_transfer(index, (u8 *)(&CONTROLLER(index).data[0]),\n                                SEL_REGISTERS(index).BYTE_COUNT, false);\n                if (scsi_get_phase(index) != SCSI_PHASE_STATUS)\n                  FAILURE(IllegalState, \"SCSI status phase expected\");\n                scsi_xfer_ptr(index, scsi_expected_xfer(index));\n                scsi_xfer_done(index);\n                if (scsi_get_phase(index) != SCSI_PHASE_FREE)\n                  FAILURE(IllegalState, \"SCSI bus free phase expected\");\n                SEL_STATUS(index).drq = true;\n                SEL_STATUS(index).busy = false;\n                SEL_COMMAND(index).packet_phase = PACKET_DI;\n              } else {\n\n                // send back via pio\n#ifdef DEBUG_IDE_PACKET\n                printf(\"Sending ATAPI data back via PIO.\\n\");\n#endif\n#if 0\n                if((!SEL_STATUS(index).drq) && (CONTROLLER(index).data_ptr == 0))\n                {\n\n                  // first time through: no data\n                  // transferred, and drq=0\n                  SEL_STATUS(index).drq = true;\n                  SEL_STATUS(index).busy = false;\n                  SEL_REGISTERS(index).REASON = IR_IO;\n                  raise_interrupt(index);\n                  yield = true;\n                }\n                else\n                {\n                  if(!SEL_STATUS(index).drq)\n                  {\n                    // all of the data has been read\n                    // from the buffer.\n                    // for now I assume that it is\n                    // everything.\n                    if(scsi_get_phase(index) != SCSI_PHASE_STATUS)\n                      FAILURE(IllegalState, \"SCSI status phase expected\");\n                    scsi_xfer_ptr(index, scsi_expected_xfer(index));\n                    scsi_xfer_done(index);\n                    if(scsi_get_phase(index) != SCSI_PHASE_FREE)\n                      FAILURE(IllegalState, \"SCSI bus free phase expected\");\n#ifdef DEBUG_IDE_PACKET\n                    printf(\"Finished transferring!\\n\");\n#endif\n                    SEL_COMMAND(index).packet_phase = PACKET_DI;\n                    yield = false;\n                  }\n                }\n\n#else\n\n                // do the transfer\n                SEL_STATUS(index).drq = true;\n                SEL_STATUS(index).busy = false;\n                SEL_REGISTERS(index).REASON = IR_IO;\n                if (scsi_get_phase(index) != SCSI_PHASE_STATUS)\n                  FAILURE(IllegalState, \"SCSI status phase expected\");\n                scsi_xfer_ptr(index, scsi_expected_xfer(index));\n                scsi_xfer_done(index);\n                if (scsi_get_phase(index) != SCSI_PHASE_FREE)\n                  FAILURE(IllegalState, \"SCSI Bus free phase expected\");\n#ifdef DEBUG_IDE_PACKET\n                printf(\"Finished Transferring\\n\");\n#endif\n                raise_interrupt(index);\n                SEL_COMMAND(index).packet_phase = PACKET_DI;\n                yield = true;\n#endif\n              }\n              break;\n\n            case PACKET_DI:\n\n              // this is either DI0 or DI1\n              SEL_REGISTERS(index).REASON = IR_CD | IR_IO;\n              SEL_STATUS(index).busy = false;\n              SEL_STATUS(index).drive_ready = true;\n              SEL_STATUS(index).SERV = false;\n              SEL_STATUS(index).CHK = false;\n              SEL_STATUS(index).drq = false;\n              raise_interrupt(index);\n              SEL_COMMAND(index).command_in_progress = false;\n              yield = true;\n              break;\n\n            default:\n              FAILURE(InvalidArgument, \"Unknown packet phase\");\n            }\n          } while (!yield);\n#ifdef DEBUG_IDE_PACKET\n          printf(\"Drop out of packet state machine %d\\n\", index);\n          ide_status(index);\n#endif\n        }\n      }\n      break;\n\n    case 0xa1: // identify packet device\n      if (SEL_DISK(index)->cdrom()) {\n        identify_drive(index, true);\n        SEL_STATUS(index).busy = false;\n        SEL_STATUS(index).drive_ready = true;\n        SEL_STATUS(index).seek_complete = true;\n        SEL_STATUS(index).fault = false;\n        SEL_STATUS(index).drq = true;\n        SEL_STATUS(index).err = false;\n        SEL_COMMAND(index).command_in_progress = false;\n        raise_interrupt(index);\n      } else {\n        command_aborted(index, SEL_COMMAND(index).current_command);\n      }\n      break;\n\n    case 0xc4: // read multiple\n      if (SEL_DISK(index)->cdrom()) {\n        command_aborted(index, SEL_COMMAND(index).current_command);\n      } else {\n        if (SEL_COMMAND(index).command_cycle == 0) {\n\n          // fixup the 0=256 case.\n          if (SEL_REGISTERS(index).sector_count == 0)\n            SEL_REGISTERS(index).sector_count = 256;\n          SEL_STATUS(index).drq = false;\n        }\n\n        if (!SEL_STATUS(index).drq) {\n\n          // buffer is empty, so lets fill it.\n          if (!SEL_REGISTERS(index).lba_mode) {\n            FAILURE(NotImplemented, \"Non-LBA disk read\");\n          } else {\n            u32 lba = (SEL_REGISTERS(index).head_no << 24) |\n                      (SEL_REGISTERS(index).cylinder_no << 8) |\n                      SEL_REGISTERS(index).sector_no;\n\n            if (SEL_REGISTERS(index).sector_count >=\n                SEL_PER_DRIVE(index).multiple_size) {\n\n              // easy, its a full block\n              CONTROLLER(index).data_size =\n                  256 * SEL_PER_DRIVE(index).multiple_size;\n              SEL_REGISTERS(index).sector_count -=\n                  SEL_PER_DRIVE(index).multiple_size;\n            } else {\n\n              // partial block.\n              CONTROLLER(index).data_size =\n                  256 * SEL_REGISTERS(index).sector_count;\n              SEL_REGISTERS(index).sector_count = 0;\n            }\n\n#ifdef DEBUG_IDE_MULTIPLE\n            printf(\"IDE %d.%d: Reading %d sectors, %d sectors left.\\n\", index,\n                   CONTROLLER(index).selected,\n                   CONTROLLER(index).data_size / 256,\n                   SEL_REGISTERS(index).sector_count);\n#endif\n            SEL_DISK(index)->seek_block(lba);\n            SEL_DISK(index)->read_blocks(\n                &(CONTROLLER(index).data[0]),\n                CONTROLLER(index).data_size /\n                    256); // actual number of blocks we want.\n#if defined(ES40_BIG_ENDIAN)\n            for (int i = 0; i < 256; i++)\n              CONTROLLER(index).data[i] = endian_16(CONTROLLER(index).data[i]);\n#endif\n            SEL_STATUS(index).busy = false;\n            SEL_STATUS(index).drive_ready = true;\n            SEL_STATUS(index).fault = false;\n            SEL_STATUS(index).drq = true;\n            SEL_STATUS(index).err = false;\n            CONTROLLER(index).data_ptr = 0;\n\n            // prepare for next sector\n            if (SEL_REGISTERS(index).sector_count == 0) {\n              SEL_COMMAND(index).command_in_progress = false;\n              if (SEL_DISK(index)->cdrom())\n                set_signature(index, CONTROLLER(index).selected); // per 9.1\n            } else {\n\n              // set the next block to read.\n              // increment the lba.\n              SEL_REGISTERS(index).sector_no +=\n                  CONTROLLER(index).data_size / 256; // # sectors read.\n              if (SEL_REGISTERS(index).sector_no > 255) {\n                SEL_REGISTERS(index).sector_no = 0;\n                SEL_REGISTERS(index).cylinder_no++;\n                if (SEL_REGISTERS(index).cylinder_no > 65535) {\n                  SEL_REGISTERS(index).cylinder_no = 0;\n                  SEL_REGISTERS(index).head_no++;\n                }\n              }\n            }\n          }\n\n          raise_interrupt(index);\n        }\n      }\n      break;\n\n    case 0xc5: // write multiple\n      if (SEL_DISK(index)->cdrom()) {\n        command_aborted(index, SEL_COMMAND(index).current_command);\n      } else {\n        if (SEL_COMMAND(index).command_cycle == 0) {\n\n          // this is our first time through\n          if (SEL_DISK(index)->ro()) {\n            printf(\"%%IDE-W-RO: Write attempt to read-only disk %d.%d.\\n\",\n                   index, CONTROLLER(index).selected);\n            command_aborted(index, SEL_COMMAND(index).current_command);\n          } else {\n            SEL_STATUS(index).drq = true;\n            SEL_STATUS(index).busy = false;\n            if (SEL_REGISTERS(index).sector_count == 0)\n              SEL_REGISTERS(index).sector_count = 256;\n            if (SEL_REGISTERS(index).sector_count >=\n                SEL_PER_DRIVE(index).multiple_size) {\n              CONTROLLER(index).data_size =\n                  256 * SEL_PER_DRIVE(index).multiple_size;\n              SEL_REGISTERS(index).sector_count -=\n                  SEL_PER_DRIVE(index).multiple_size;\n            } else {\n              CONTROLLER(index).data_size =\n                  256 * SEL_REGISTERS(index).sector_count;\n              SEL_REGISTERS(index).sector_count = 0;\n            }\n          }\n        } else {\n\n          // now we should be getting data.\n          if (!SEL_STATUS(index).drq) {\n\n            // the buffer is full.  Do something with the data.\n            if (!SEL_REGISTERS(index).lba_mode) {\n              FAILURE(NotImplemented, \"Non-LBA disk write\");\n            } else {\n              u32 lba = (SEL_REGISTERS(index).head_no << 24) |\n                        (SEL_REGISTERS(index).cylinder_no << 8) |\n                        SEL_REGISTERS(index).sector_no;\n\n#if defined(ES40_BIG_ENDIAN)\n              {\n                u16 data[IDE_BUFFER_SIZE];\n\n                SEL_DISK(index)->seek_block(lba);\n                for (int i = 0; i < CONTROLLER(index).data_size; i++)\n                  data[i] = endian_16(CONTROLLER(index).data[i]);\n                SEL_DISK(index)->write_blocks(\n                    &(data[0]), CONTROLLER(index).data_size / 256);\n              }\n\n#else\n              SEL_DISK(index)->seek_block(lba);\n              SEL_DISK(index)->write_blocks(&(CONTROLLER(index).data[0]),\n                                            CONTROLLER(index).data_size / 256);\n#endif\n              SEL_STATUS(index).busy = false;\n              SEL_STATUS(index).drive_ready = true;\n              SEL_STATUS(index).fault = false;\n              SEL_STATUS(index).drq = true;\n              SEL_STATUS(index).err = false;\n              CONTROLLER(index).data_ptr = 0;\n\n              if (SEL_REGISTERS(index).sector_count == 0) {\n\n                // we're done\n                SEL_STATUS(index).drq = false;\n                SEL_COMMAND(index).command_in_progress = false;\n              } else {\n\n                // prepare for next block\n                if (SEL_REGISTERS(index).sector_count >=\n                    SEL_PER_DRIVE(index).multiple_size) {\n                  CONTROLLER(index).data_size =\n                      256 * SEL_PER_DRIVE(index).multiple_size;\n                  SEL_REGISTERS(index).sector_count -=\n                      SEL_PER_DRIVE(index).multiple_size;\n                } else {\n                  CONTROLLER(index).data_size =\n                      256 * SEL_REGISTERS(index).sector_count;\n                  SEL_REGISTERS(index).sector_count = 0;\n                }\n\n                // set the next block to read.\n                // increment the lba.\n                SEL_REGISTERS(index).sector_no++;\n                if (SEL_REGISTERS(index).sector_no > 255) {\n                  SEL_REGISTERS(index).sector_no = 0;\n                  SEL_REGISTERS(index).cylinder_no++;\n                  if (SEL_REGISTERS(index).cylinder_no > 65535) {\n                    SEL_REGISTERS(index).cylinder_no = 0;\n                    SEL_REGISTERS(index).head_no++;\n                  }\n                }\n              }\n            }\n\n            raise_interrupt(index);\n          }\n        }\n      }\n      break;\n\n    case 0xc6: // set multiple mode\n      if (SEL_DISK(index)->cdrom()) {\n        command_aborted(index, SEL_COMMAND(index).current_command);\n      } else {\n        SEL_PER_DRIVE(index).multiple_size = SEL_REGISTERS(index).sector_count;\n#ifdef DEBUG_IDE_MULTIPLE\n        printf(\"Set multiple mode: sector_count = %d\\n\",\n               SEL_REGISTERS(index).sector_count);\n#endif\n        SEL_STATUS(index).busy = false;\n        SEL_STATUS(index).drive_ready = true;\n        SEL_STATUS(index).fault = false;\n        SEL_STATUS(index).drq = false;\n        SEL_STATUS(index).err = false;\n        SEL_COMMAND(index).command_in_progress = false;\n        raise_interrupt(index);\n      }\n      break;\n\n    case 0xc8: // read dma\n    case 0xc9: // read dma (old)\n      if (SEL_DISK(index)->cdrom()) {\n        command_aborted(index, SEL_COMMAND(index).current_command);\n        SEL_COMMAND(index).command_in_progress = false;\n      } else {\n        if (SEL_REGISTERS(index).sector_count == 0)\n          SEL_REGISTERS(index).sector_count = 256;\n\n#ifdef DEBUG_IDE_DMA\n        printf(\"%%IDE-I-DMA: Read %d sectors = %d bytes.\\n\",\n               SEL_REGISTERS(index).sector_count,\n               SEL_REGISTERS(index).sector_count * 512);\n#endif\n\n        u32 lba = (SEL_REGISTERS(index).head_no << 24) |\n                  (SEL_REGISTERS(index).cylinder_no << 8) |\n                  SEL_REGISTERS(index).sector_no;\n\n        SEL_DISK(index)->seek_block(lba);\n\n        SEL_DISK(index)->read_blocks(&(CONTROLLER(index).data[0]),\n                                     SEL_REGISTERS(index).sector_count);\n\n        u8 *ptr = (u8 *)(&CONTROLLER(index).data[0]);\n        do_dma_transfer(index, ptr, SEL_REGISTERS(index).sector_count * 512,\n                        false);\n        SEL_COMMAND(index).command_in_progress = false;\n        SEL_STATUS(index).drive_ready = true;\n        SEL_STATUS(index).seek_complete = true;\n        SEL_STATUS(index).fault = false;\n        SEL_STATUS(index).drq = false;\n        SEL_STATUS(index).err = false;\n        SEL_STATUS(index).busy = false;\n      }\n      break;\n\n    case 0xca: // write dma\n    case 0xcb: // write dma (old)\n      if (SEL_DISK(index)->cdrom() || SEL_DISK(index)->ro()) {\n        command_aborted(index, SEL_COMMAND(index).current_command);\n        SEL_COMMAND(index).command_in_progress = false;\n      } else {\n        if (SEL_DISK(index)->ro()) {\n          printf(\"%%IDE-W-RO: DMA Write attempt to read-only disk %d.%d.\\n\",\n                 index, CONTROLLER(index).selected);\n          command_aborted(index, SEL_COMMAND(index).current_command);\n        } else {\n          if (SEL_REGISTERS(index).sector_count == 0)\n            SEL_REGISTERS(index).sector_count = 256;\n\n#ifdef DEBUG_IDE_DMA\n          printf(\"%%IDE-I-DMA: Write %d sectors = %d bytes.\\n\",\n                 SEL_REGISTERS(index).sector_count,\n                 SEL_REGISTERS(index).sector_count * 512);\n#endif\n\n          u8 *ptr = (u8 *)(&CONTROLLER(index).data[0]);\n          do_dma_transfer(index, ptr, SEL_REGISTERS(index).sector_count * 512,\n                          true);\n          u32 lba = (SEL_REGISTERS(index).head_no << 24) |\n                    (SEL_REGISTERS(index).cylinder_no << 8) |\n                    SEL_REGISTERS(index).sector_no;\n\n          SEL_DISK(index)->seek_block(lba);\n          SEL_DISK(index)->write_blocks(&(CONTROLLER(index).data[0]),\n                                        SEL_REGISTERS(index).sector_count);\n          SEL_COMMAND(index).command_in_progress = false;\n          SEL_STATUS(index).drive_ready = true;\n          SEL_STATUS(index).seek_complete = true;\n          SEL_STATUS(index).fault = false;\n          SEL_STATUS(index).drq = false;\n          SEL_STATUS(index).err = false;\n          SEL_STATUS(index).busy = false;\n        }\n      }\n      break;\n\n#if 0\n\n    case 0xe5:  // check power mode\n      ide_status(index);\n      command_aborted(index, SEL_COMMAND(index).current_command);\n      SEL_COMMAND(index).command_in_progress = false;\n\n      // raise_interrupt(index);\n      break;\n#endif\n\n    case 0xec: // identify\n      if (!SEL_DISK(index)->cdrom()) {\n        identify_drive(index, false);\n        SEL_STATUS(index).busy = false;\n        SEL_STATUS(index).drive_ready = true;\n        SEL_STATUS(index).seek_complete = true;\n        SEL_STATUS(index).fault = false;\n        SEL_STATUS(index).drq = true;\n        SEL_STATUS(index).err = false;\n        SEL_COMMAND(index).command_in_progress = false;\n        raise_interrupt(index);\n      } else {\n        set_signature(index, CONTROLLER(index).selected); // per\n\n        //\n        // 9.1\n        command_aborted(index, 0xec);\n      }\n      break;\n\n    case 0xef: // set features\n      SEL_COMMAND(index).command_in_progress = false;\n      switch (SEL_REGISTERS(index).features) {\n      case 0x03: // set transfer mode\n        if (SEL_REGISTERS(index).sector_count < 16) {\n\n          // allow all PIO modes.\n          SEL_STATUS(index).busy = false;\n          SEL_STATUS(index).drive_ready = true;\n          SEL_STATUS(index).seek_complete = true;\n          SEL_STATUS(index).fault = false;\n          SEL_STATUS(index).drq = false;\n          SEL_STATUS(index).err = false;\n          raise_interrupt(index);\n          break;\n        } else {\n\n          // a DMA mode.\n          switch (SEL_REGISTERS(index).sector_count) {\n          case 0x20:\n          case 0x21:\n          case 0x22:\n\n            // multiword dma\n            CONTROLLER(index).dma_mode =\n                SEL_REGISTERS(index).sector_count & 0x03;\n            SEL_STATUS(index).busy = false;\n            SEL_STATUS(index).drive_ready = true;\n            SEL_STATUS(index).seek_complete = true;\n            SEL_STATUS(index).fault = false;\n            SEL_STATUS(index).drq = false;\n            SEL_STATUS(index).err = false;\n            raise_interrupt(index);\n            break;\n\n          case 0x40:\n          case 0x41:\n          case 0x42:\n\n            // ultra dma\n            command_aborted(index, SEL_COMMAND(index).current_command);\n            break;\n          }\n          break;\n        }\n\n      default:\n        printf(\"%%IDE-I-FEAT: Unhandled set feature subcommand %x\\n\",\n               SEL_REGISTERS(index).features);\n        command_aborted(index, SEL_COMMAND(index).current_command);\n        break;\n      }\n      break;\n\n    /***\n     * Special cases:  commands we don't support, but return success.\n     ***/\n    case 0xe0: // standby now\n    case 0xe1: // idle immediate\n    case 0xe2: // standby\n    case 0xe3: // idle\n    case 0xe6: // sleep\n    case 0xe7: // flush cache\n    case 0xea: // flush cache ext\n      SEL_STATUS(index).busy = false;\n      SEL_STATUS(index).drive_ready = true;\n      SEL_STATUS(index).drq = false;\n      SEL_STATUS(index).err = false;\n      SEL_COMMAND(index).command_in_progress = false;\n      raise_interrupt(index);\n      break;\n\n    default: // unknown/unhandled ATA command\n      ide_status(index);\n      FAILURE_1(NotImplemented, \"Unknown IDE command %x\",\n                SEL_COMMAND(index).current_command);\n      break;\n    }\n\n#ifdef DEBUG_IDE_COMMAND\n    if (SEL_COMMAND(index).command_in_progress == false) {\n      printf(\"%%IDE-I-COMMAND: Command has completed on controller %d.\\n\",\n             index);\n      ide_status(index);\n      printf(\"==================================================\\n\");\n    } else {\n      printf(\"%%IDE-I-COMMAND: controller %d is yielding to host.\\n\", index);\n      ide_status(index);\n      printf(\"--------------------------------------------------\\n\");\n    }\n#endif\n  }\n\n  SEL_COMMAND(index).command_cycle++;\n}\n\nint CAliM1543C_ide::do_dma_transfer(int index, u8 *buffer, u32 buffersize,\n                                    bool direction) {\n  u8 xfer;\n  size_t xfersize = 0;\n  u8 status = 0;\n  u8 count = 0;\n  u32 prd;\n  semBusMaster[index]->wait(); // wait until the start bit is set.\n  {\n    SCOPED_READ_LOCK(mtBusMaster[index]);\n    prd = endian_32(*(u32 *)(&CONTROLLER(index).busmaster[4]));\n  }\n  do {\n    u32 base;\n    do_pci_read(prd, &base, 4, 1);\n\n    u16 size_16;\n    do_pci_read(prd + 4, &size_16, 2, 1);\n\n    size_t size = size_16 ? size_16 : 65536;\n    do_pci_read(prd + 7, &xfer, 1, 1);\n\n#ifdef DEBUG_IDE_DMA\n    printf(\"-IDE-I-DMA: Transfer %d bytes to/from %lx (%x)\\n\", size, base,\n           xfer);\n#endif\n    if (xfersize + size > buffersize) {\n      // only copy as much data as we have from the disk.\n      size = buffersize - xfersize;\n      status = 2;\n#ifdef DEBUG_IDE_DMA\n      printf(\"-IDE-I-DMA: Actual transfer size: %d bytes\\n\", size);\n#endif\n    }\n\n    // copy it to/from ram.\n    if (!direction) {\n      do_pci_write(base, buffer, 1, size);\n      buffer += size;\n    } else {\n      do_pci_read(base, buffer, 1, size);\n      buffer += size;\n    }\n\n    xfersize += size;\n    prd += 8; // go to next entry.\n    if (xfer == 0x80 && xfersize < buffersize) {\n\n      // we still have disk data left over!\n      status = 1;\n    }\n\n    if (count++ > 32) {\n      FAILURE(InvalidArgument, \"Too many PRD nodes?\");\n    }\n\n    if (buffersize == xfersize && xfer != 0x80) {\n      // we're done, but there's more prd nodes.\n      status = 2;\n    }\n  } while (xfer != 0x80 && status == 0);\n\n  switch (status) {\n  case 0: // normal completion.\n  {\n    SCOPED_WRITE_LOCK(mtBusMaster[index]);\n    CONTROLLER(index).busmaster[2] &= 0xfe; // clear active.\n  }\n\n    raise_interrupt(index);\n    break;\n\n  case 1: // PRD is smaller than the data we have.\n  {\n    SCOPED_WRITE_LOCK(mtBusMaster[index]);\n    CONTROLLER(index).busmaster[2] &= 0xfe; // clear active.\n  }\n\n  // do not raise an interrupt\n  break;\n\n  case 2: // PRD is larger than the data we have.\n    // leave active set.\n    raise_interrupt(index);\n    break;\n  }\n\n  semBusMasterReady[index]->set();\n  return status;\n}\n\n/**\n * Thread entry point.\n **/\nvoid CAliM1543C_ide::run(int index) {\n  try {\n    for (;;) {\n      semController[index]->wait();\n      if (StopThread)\n        return;\n      {\n#ifdef DEBUG_IDE_THREADS\n        printf(\"Thread %d: \\n\", index);\n        ide_status(index);\n#endif\n        if (SEL_COMMAND(index).command_in_progress)\n          execute(index);\n        UPDATE_ALT_STATUS(index);\n\n#ifdef IDE_YIELD_INTERRUPTS\n        if (CONTROLLER(index).interrupt_pending) {\n          {\n            SCOPED_WRITE_LOCK(mtBusMaster[index]);\n            CONTROLLER(index).busmaster[2] |= 0x04;\n          }\n          theAli->pic_interrupt(1, 6 + index);\n        }\n#endif\n      }\n      semControllerReady[index]->set();\n    }\n  }\n\n  catch (CException &e) {\n    printf(\"Exception in IDE thread: %s.\\n\", e.displayText().c_str());\n    thrControllerDead[index].store(true);\n    // Let the thread die...\n  }\n}\n"
  },
  {
    "path": "src/AliM1543C_ide.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_ALIM1543C_IDE_H_)\n#define INCLUDED_ALIM1543C_IDE_H_\n\n// If DEBUG_IDE is defined, define all IDE debugging flags.\n#ifdef DEBUG_IDE\n#define DEBUG_IDE_BUSMASTER\n#define DEBUG_IDE_COMMAND\n#define DEBUG_IDE_DMA\n#define DEBUG_IDE_INTERRUPT\n#define DEBUG_IDE_REG_COMMAND\n#define DEBUG_IDE_REG_CONTROL\n#define DEBUG_IDE_PACKET\n#define DEBUG_IDE_MULTIPLE\n#endif\n\n#include \"Configurator.hpp\"\n#include \"DiskController.hpp\"\n#include \"PCIDevice.hpp\"\n#include \"SCSIBus.hpp\"\n#include \"SCSIDevice.hpp\"\n\n#define MAX_MULTIPLE_SECTORS 128\n\n/**\n * \\brief Emulated IDE part of ALi M1543C multi-function device.\n *\n * Documentation consulted:\n *  - Ali M1543C B1 South Bridge Version 1.20\n *(http://mds.gotdns.com/sensors/docs/ali/1543dScb1-120.pdf)\n *  - AT Attachment with Packet Interface - 5 (ATA/ATAPI-5)\n *(http://www.t13.org/Documents/UploadedDocuments/project/d1321r3-ATA-ATAPI-5.pdf)\n *  - Programming Interface for Bus Master IDE COntroller\n *(http://suif.stanford.edu/%7Ecsapuntz/specs/idems100.ps)\n *  - T13-1153Dr18  ATA/ATAPI-4\n *  - Mt. Fuji Commands for Multimedia Devices Version 7 INF-8090i v7\n *  .\n **/\nclass CAliM1543C_ide : public CPCIDevice,\n                       public CDiskController,\n                       public CSCSIDevice {\npublic:\n  CAliM1543C_ide(CConfigurator *cfg, class CSystem *c, int pcibus, int pcidev);\n  virtual ~CAliM1543C_ide();\n  virtual void register_disk(class CDisk *dsk, int bus, int dev);\n\n  virtual void WriteMem_Legacy(int index, u32 address, int dsize, u32 data);\n  virtual u32 ReadMem_Legacy(int index, u32 address, int dsize);\n\n  virtual void WriteMem_Bar(int func, int bar, u32 address, int dsize,\n                            u32 data);\n  virtual u32 ReadMem_Bar(int func, int bar, u32 address, int dsize);\n\n  virtual int SaveState(FILE *f);\n  virtual int RestoreState(FILE *f);\n\n  virtual void check_state();\n  virtual void ResetPCI();\n\n  void run(int index);\n  virtual void init();\n  virtual void start_threads();\n  virtual void stop_threads();\n\nprivate:\n  // IDE controller\n  u32 ide_command_read(int channel, u32 address, int dsize);\n  void ide_command_write(int channel, u32 address, int dsize, u32 data);\n  u32 ide_control_read(int channel, u32 address);\n  void ide_control_write(int channel, u32 address, u32 data);\n  u32 ide_busmaster_read(int channel, u32 address, int dsize);\n  void ide_busmaster_write(int channel, u32 address, u32 data, int dsize);\n  int do_dma_transfer(int index, u8 *buffer, u32 size, bool direction);\n\n  void raise_interrupt(int channel);\n  void set_signature(int channel, int id);\n  u8 get_status(int index);\n  void command_aborted(int index, u8 command);\n  void identify_drive(int index, bool packet);\n  void ide_status(int index);\n\n  void execute(int index);\n\n  std::unique_ptr<std::thread> thrController[2];\n  std::atomic_bool thrControllerDead[2] = {{false}, {false}};\n  CSemaphore *semController[2];      // controller start/stop\n  CSemaphore *semControllerReady[2]; // controller ready\n  CSemaphore *semBusMaster[2];       // bus master start/stop\n  CSemaphore *semBusMasterReady[2];  // bus master ready\n  CRWLock *mtRegisters[2];           // main registers\n  CRWLock *mtBusMaster[2];           // busmaster registers\n  bool StopThread;\n\n  bool usedma;\n\n  // The state structure contains all elements that need to be saved to the\n  // statefile.\n  struct SAliM1543C_ideState {\n    struct SDriveState {\n      struct {\n        bool busy;\n        bool drive_ready;\n        bool fault;\n        bool seek_complete;\n        bool drq;\n        bool bit_2;\n        bool index_pulse;\n        bool err;\n        int index_pulse_count;\n\n        // debugging\n        u8 debug_last_status;\n        bool debug_status_update;\n\n        u8 alt_status; // this is the latched status.\n      } status;\n\n      struct {\n        bool lba_mode;\n        int features;\n        int error;\n        int sector_count;\n        int sector_no;\n        int cylinder_no;\n        int head_no;\n        int command;\n      } registers;\n\n      struct {\n        bool command_in_progress;\n        int current_command;\n        int command_cycle;\n        bool packet_dma;\n        int packet_phase;\n        u8 packet_command[12];\n        int packet_buffersize;\n        u8 packet_sense;\n        u8 packet_asc;\n        u8 packet_ascq;\n      } command;\n\n      u8 multiple_size;\n    };\n\n    struct SControllerState {\n\n      // the attached devices\n      struct SDriveState drive[2];\n\n      // control data.\n      bool disable_irq;\n      bool reset;\n\n      // internal state\n      bool reset_in_progress;\n      int selected;\n\n      // dma stuff\n      u8 busmaster[8];\n      u8 dma_mode;\n      u8 bm_status;\n\n      // pio stuff\n#define IDE_BUFFER_SIZE 65536 // 64K words = 128K = 256 sectors @ 512 bytes\n      u16 data[IDE_BUFFER_SIZE];\n      int data_ptr;\n      int data_size;\n\n      bool interrupt_pending;\n    } controller[2];\n  } state;\n};\n\n/// Status for selected drive on controller a\n#define SEL_STATUS(a)                                                          \\\n  state.controller[a].drive[state.controller[a].selected].status\n\n/// Command for selected drive on controller a\n#define SEL_COMMAND(a)                                                         \\\n  state.controller[a].drive[state.controller[a].selected].command\n\n/// Registers for selected drive on controller a\n#define SEL_REGISTERS(a)                                                       \\\n  state.controller[a].drive[state.controller[a].selected].registers\n\n/// Selected drive on controller a\n#define SEL_DISK(a) get_disk(a, state.controller[a].selected)\n\n/// Per-drive data for selected drive on controller a\n#define SEL_PER_DRIVE(a) state.controller[a].drive[state.controller[a].selected]\n\n// Status for drive b on controller a\n#define STATUS(a, b) state.controller[a].drive[b].status\n\n// Command for drive b on controller a\n#define COMMAND(a, b) state.controller[a].drive[b].command\n\n// Registers for drive b on controller a\n#define REGISTERS(a, b) state.controller[a].drive[b].registers\n\n// Per-drive data for drive b on controller a\n#define PER_DRIVE(a, b) state.controller[a].drive[b]\n\n// Data for controller a\n#define CONTROLLER(a) state.controller[a]\n\n// Update alt-status for controller a with locking\n#define UPDATE_ALT_STATUS(a)                                                   \\\n  {                                                                            \\\n    SCOPED_WRITE_LOCK(mtRegisters[a]);                                         \\\n    SEL_STATUS(a).alt_status = get_status(a);                                  \\\n  }\n\n/* memory region ids */\n#define PRI_COMMAND 1\n#define PRI_CONTROL 2\n#define SEC_COMMAND 3\n#define SEC_CONTROL 4\n#define PRI_BUSMASTER 5\n#define SEC_BUSMASTER 6\n\n/* bar IDs */\n#define BAR_PRI_COMMAND 0\n#define BAR_PRI_CONTROL 1\n#define BAR_SEC_COMMAND 2\n#define BAR_SEC_CONTROL 3\n#define BAR_BUSMASTER 4\n\n/* device registers */\n#define REG_COMMAND_DATA 0\n#define REG_COMMAND_ERROR 1\n#define REG_COMMAND_FEATURES 1\n#define REG_COMMAND_SECTOR_COUNT 2\n#define REG_COMMAND_SECTOR_NO 3\n#define REG_COMMAND_CYL_LOW 4\n#define REG_COMMAND_CYL_HI 5\n#define REG_COMMAND_DRIVE 6\n#define REG_COMMAND_STATUS 7\n#define REG_COMMAND_COMMAND 7\n\nstatic const char *register_names[] = {\n    \"DATA\",      \"ERROR/FEATURES\",       \"SECTOR_COUNT/PKT REASON\",\n    \"SECTOR_NO\", \"CYL_LOW/PKT BYTE LOW\", \"CYL_HI/PKT BYTE HI\",\n    \"DRIVE\",     \"STATUS/COMMAND\",\n};\n\n/* misc constants */\n\n/* Packet Protocol Aliases */\n#define DMRD fault\n#define SERV seek_complete\n#define CHK err\n#define BYTE_COUNT cylinder_no\n#define REASON sector_count\n#define IR_CD 0x01\n#define IR_IO 0x02\n#define IR_REL 0x04\n\n/* Packet protocol states */\nstatic const char *packet_states[] = {\n    \"DP0: Prepare A\",         \"DP1: Receive Packet\",\n    \"DP2: Prepare B\",         \"DP3/4: Ready INITRQ/Transfer Data\",\n    \"DIx: Device Interrupt \",\n};\n\n#define PACKET_NONE 0\n#define PACKET_DP0 0\n#define PACKET_DP1 1\n#define PACKET_DP2 2\n#define PACKET_DP34 3\n#define PACKET_DI 4\n\n/* SCSI SENSE Constants */\n#define SENSE_NONE 0x00\n#define SENSE_RECOVERED_ERROR 0x01\n#define SENSE_NOT_READY 0x02\n#define SENSE_MEDIUM_ERROR 0x03\n#define SENSE_HARDWARE_ERROR 0x04\n#define SENSE_ILLEGAL_REQUEST 0x05\n#define SENSE_UNIT_ATTENTION 0x06\n#define SENSE_DATA_PROTECT 0x07\n#define SENSE_BLANK_CHECK 0x08\n#define SENSE_ABORT_COMMAND 0x0b\n#define SENSE_MISCOMPARE 0x0e\n\nextern CAliM1543C_ide *theIDE;\n\n#endif\n"
  },
  {
    "path": "src/AliM1543C_usb.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"AliM1543C_usb.hpp\"\n#include \"StdAfx.hpp\"\n#include \"System.hpp\"\n\nu32 usb_cfg_data[64] = {\n    /*00*/ 0x523710b9, // CFID: vendor + device\n    /*04*/ 0x02800000, // CFCS: command + status\n    /*08*/ 0x0c031003, // CFRV: class + revision\n    /*0c*/ 0x00000000, // CFLT: latency timer + cache line size\n    /*10*/ 0x00000000, // BAR0:\n    /*14*/ 0x00000000, // BAR1:\n    /*18*/ 0x00000000, // BAR2:\n    /*1c*/ 0x00000000, // BAR3:\n    /*20*/ 0x00000000, // BAR4:\n    /*24*/ 0x00000000, // BAR5:\n    /*28*/ 0x00000000, // CCIC: CardBus\n    /*2c*/ 0x00000000, // CSID: subsystem + vendor\n    /*30*/ 0x00000000, // BAR6: expansion rom base\n    /*34*/ 0x00000000, // CCAP: capabilities pointer\n    /*38*/ 0x00000000,\n    /*3c*/ 0x500001ff, // CFIT: interrupt configuration\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0};\n\nu32 usb_cfg_mask[64] = {\n    /*00*/ 0x00000000, // CFID: vendor + device\n    /*04*/ 0x00000157, // CFCS: command + status\n    /*08*/ 0x00000000, // CFRV: class + revision\n    /*0c*/ 0x0000ffff, // CFLT: latency timer + cache line size\n    /*10*/ 0xfffff000, // BAR0\n    /*14*/ 0x00000000, // BAR1:\n    /*18*/ 0x00000000, // BAR2:\n    /*1c*/ 0x00000000, // BAR3:\n    /*20*/ 0x00000000, // BAR4:\n    /*24*/ 0x00000000, // BAR5:\n    /*28*/ 0x00000000, // CCIC: CardBus\n    /*2c*/ 0x00000000, // CSID: subsystem + vendor\n    /*30*/ 0x00000000, // BAR6: expansion rom base\n    /*34*/ 0x00000000, // CCAP: capabilities pointer\n    /*38*/ 0x00000000,\n    /*3c*/ 0x000000ff, // CFIT: interrupt configuration\n    /*40*/ 0x04100000, // TM - test mode register\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0};\n\n/**\n * Constructor.\n **/\nCAliM1543C_usb::CAliM1543C_usb(CConfigurator *cfg, CSystem *c, int pcibus,\n                               int pcidev)\n    : CPCIDevice(cfg, c, pcibus, pcidev) {\n  add_function(0, usb_cfg_data, usb_cfg_mask);\n\n  ResetPCI();\n\n  state.usb_data[0x34 / 4] = 0x2edf;\n  state.usb_data[0x48 / 4] = 0x01000003;\n\n  printf(\n      \"%s: $Id: AliM1543C_usb.cpp,v 1.6 2008/03/14 15:30:50 iamcamiel Exp $\\n\",\n      devid_string);\n}\n\nCAliM1543C_usb::~CAliM1543C_usb() {}\nu32 CAliM1543C_usb::ReadMem_Bar(int func, int bar, u32 address, int dsize) {\n  u32 data = 0;\n  switch (bar) {\n  case 0:\n    data = usb_hci_read(address, dsize);\n    break;\n  default:\n    printf(\"%%USB-W-READBAR: Bad BAR %d selected.\\n\", bar);\n  }\n\n  return data;\n}\n\nvoid CAliM1543C_usb::WriteMem_Bar(int func, int bar, u32 address, int dsize,\n                                  u32 data) {\n  switch (bar) {\n  case 0:\n    usb_hci_write(address, dsize, data);\n    break;\n  default:\n    printf(\"%%USB-W-WRITEBAR: Bad BAR %d selected.\\n\", bar);\n  }\n\n  return;\n}\n\nu64 CAliM1543C_usb::usb_hci_read(u64 address, int dsize) {\n  u64 data = 0;\n  if (dsize != 32)\n    printf(\"%%USB-W-HCIREAD: Non dword read, returning 32 bits anyway.\\n\");\n  switch (address) {\n  case 0: // HcRevision\n    data = 0x00000110;\n    break;\n\n  case 4:     // HcControl\n  case 8:     // HcCommandStatus\n  case 0x0c:  // HcInterruptStatus\n  case 0x10:  // HcInterrupt Enable\n  case 0x14:  // HcInterruptDisable\n  case 0x18:  // HcHCCA (datasheet says 0x17, but that's wrong)\n  case 0x1c:  // HcPeriodCurrentED\n  case 0x20:  // HcControlHeadED\n  case 0x24:  // HcControlCurrentED\n  case 0x28:  // HcBulkHeadED\n  case 0x2c:  // HcBulkCurrentED\n  case 0x30:  // HcDoneHead\n  case 0x34:  // HcFmInterval\n  case 0x38:  // HcFrameRemaining\n  case 0x3c:  // HcFmNumber\n  case 0x40:  // HcPeriodicStart\n  case 0x44:  // HcLSThreshold\n  case 0x48:  // HcRhDescriptorA\n  case 0x4c:  // HcRhDescriptorB\n  case 0x50:  // HcRhStatus\n  case 0x54:  // HcRhPortStatus1\n  case 0x58:  // HcRhPortStatus1\n  case 0x5c:  // HcRhPortStatus1\n  case 0x100: // HceControlRegister\n  case 0x104: // HceInputRegister\n  case 0x108: // HceOutputRegister\n  case 0x10c: // HceStatusRegister\n    data = state.usb_data[address / 4];\n    break;\n\n  default:\n    printf(\"%%USB-W-HCIREAD: Reading from unknown address %x.  Ignoring.\\n\",\n           (int)address);\n  }\n\n  return data;\n}\n\nvoid CAliM1543C_usb::usb_hci_write(u64 address, int dsize, u64 data) {\n  if (dsize != 32)\n    printf(\"%%USB-W-HCIWRITE: Non dword write, writing 32 bits anyway.\\n\");\n  switch (address) {\n  case 4:     // HcControl\n  case 8:     // HcCommandStatus\n  case 0x0c:  // HcInterruptStatus\n  case 0x10:  // HcInterrupt Enable\n  case 0x14:  // HcInterruptDisable\n  case 0x18:  // HcHCCA (datasheet says 0x17, but that's wrong)\n  case 0x1c:  // HcPeriodCurrentED\n  case 0x20:  // HcControlHeadED\n  case 0x24:  // HcControlCurrentED\n  case 0x28:  // HcBulkHeadED\n  case 0x2c:  // HcBulkCurrentED\n  case 0x30:  // HcDoneHead\n  case 0x34:  // HcFmInterval\n  case 0x38:  // HcFrameRemaining\n  case 0x3c:  // HcFmNumber\n  case 0x40:  // HcPeriodicStart\n  case 0x44:  // HcLSThreshold\n  case 0x48:  // HcRhDescriptorA\n  case 0x4c:  // HcRhDescriptorB\n  case 0x50:  // HcRhStatus\n  case 0x54:  // HcRhPortStatus1\n  case 0x58:  // HcRhPortStatus1\n  case 0x5c:  // HcRhPortStatus1\n  case 0x100: // HceControlRegister\n  case 0x104: // HceInputRegister\n  case 0x108: // HceOutputRegister\n  case 0x10c: // HceStatusRegister\n    state.usb_data[address / 4] = data;\n    break;\n\n  default:\n    printf(\"%%USB-W-HCIWRITE: Writing to unknown address %x.  Ignoring.\\n\",\n           (int)address);\n  }\n}\n\nstatic u32 usb_magic1 = 0x9000432B;\nstatic u32 usb_magic2 = 0xB2340009;\n\n/**\n * Save state to a Virtual Machine State file.\n **/\nint CAliM1543C_usb::SaveState(FILE *f) {\n  long ss = sizeof(state);\n  int res;\n\n  if ((res = CPCIDevice::SaveState(f)))\n    return res;\n\n  fwrite(&usb_magic1, sizeof(u32), 1, f);\n  fwrite(&ss, sizeof(long), 1, f);\n  fwrite(&state, sizeof(state), 1, f);\n  fwrite(&usb_magic2, sizeof(u32), 1, f);\n  printf(\"%s: %d bytes saved.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\n/**\n * Restore state from a Virtual Machine State file.\n **/\nint CAliM1543C_usb::RestoreState(FILE *f) {\n  long ss;\n  u32 m1;\n  u32 m2;\n  int res;\n  size_t r;\n\n  if ((res = CPCIDevice::RestoreState(f)))\n    return res;\n\n  r = fread(&m1, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m1 != usb_magic1) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&ss, sizeof(long), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (ss != sizeof(state)) {\n    printf(\"%s: STRUCT SIZE does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&state, sizeof(state), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&m2, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m2 != usb_magic2) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  printf(\"%s: %d bytes restored.\\n\", devid_string, (int)ss);\n  return 0;\n}\n"
  },
  {
    "path": "src/AliM1543C_usb.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_ALIM1543C_USB_H_)\n#define INCLUDED_ALIM1543C_USB_H_\n\n#include \"PCIDevice.hpp\"\n\n/**\n * \\brief Emulated USB part of ALi M1543C multi-function device.\n *\n * \\todo This device is just a stub. Not functional yet.\n *\n * Documentation consulted:\n *  - Ali M1543C B1 South Bridge Version 1.20\n *    (http://mds.gotdns.com/sensors/docs/ali/1543dScb1-120.pdf)\n *  .\n **/\nclass CAliM1543C_usb : public CPCIDevice {\npublic:\n  virtual int SaveState(FILE *f);\n  virtual int RestoreState(FILE *f);\n\n  CAliM1543C_usb(CConfigurator *cfg, class CSystem *c, int pcibus, int pcidev);\n  virtual ~CAliM1543C_usb();\n  virtual void WriteMem_Bar(int func, int bar, u32 address, int dsize,\n                            u32 data);\n  virtual u32 ReadMem_Bar(int func, int bar, u32 address, int dsize);\n\nprivate:\n  u64 usb_hci_read(u64 address, int dsize);\n  void usb_hci_write(u64 address, int dsize, u64 data);\n\n  /// The state structure contains all elements that need to be saved to the\n  /// statefile.\n  struct SUSB_state {\n    u32 usb_data[0x110 / 4];\n  } state;\n};\n#endif // !defined(INCLUDED_ALIM1543C_USB_H)\n"
  },
  {
    "path": "src/AlphaCPU.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Copyright (C) 2012 Dmitry Kalinkin\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"AlphaCPU.hpp\"\n#include \"StdAfx.hpp\"\n#include \"TraceEngine.hpp\"\n#include \"cpu_arith.hpp\"\n#include \"cpu_bwx.hpp\"\n#include \"cpu_control.hpp\"\n#include \"cpu_debug.hpp\"\n#include \"cpu_fp_branch.hpp\"\n#include \"cpu_fp_memory.hpp\"\n#include \"cpu_fp_operate.hpp\"\n#include \"cpu_logical.hpp\"\n#include \"cpu_memory.hpp\"\n#include \"cpu_misc.hpp\"\n#include \"cpu_mvi.hpp\"\n#include \"cpu_pal.hpp\"\n#include \"cpu_vax.hpp\"\n#include \"lockstep.hpp\"\n\n#if !defined(HAVE_NEW_FP)\n#include \"es40_float.hpp\"\n#endif\nvoid CAlphaCPU::release_threads() { mySemaphore.set(); }\n\nvoid CAlphaCPU::run() {\n  try {\n    mySemaphore.wait();\n    while (state.wait_for_start) {\n      if (StopThread)\n        return;\n      std::this_thread::sleep_for(std::chrono::milliseconds(1));\n    }\n    printf(\"*** CPU%d *** STARTING ***\\n\", get_cpuid());\n    for (;;) {\n      if (StopThread)\n        return;\n      for (int i = 0; i < 1000000; i++)\n        execute();\n    }\n  } catch (CException &e) {\n    printf(\"Exception in CPU thread: %s.\\n\", e.displayText().c_str());\n    myThreadDead.store(true);\n    // Let the thread die...\n  }\n}\n\n/**\n * Constructor.\n **/\nCAlphaCPU::CAlphaCPU(CConfigurator *cfg, CSystem *system)\n    : CSystemComponent(cfg, system), mySemaphore(0, 1) {}\n\n/**\n * Initialize the CPU.\n **/\nvoid CAlphaCPU::init() {\n  memset(&state, 0, sizeof(state));\n\n  cpu_hz = myCfg->get_num_value(\"speed\", true, 500000000);\n\n  state.iProcNum = cSystem->RegisterCPU(this);\n\n  state.wait_for_start = (state.iProcNum == 0) ? false : true;\n  icache_enabled = true;\n  flush_icache();\n  icache_enabled = myCfg->get_bool_value(\"icache\", false);\n  skip_memtest_hack = myCfg->get_bool_value(\"skip_memtest_hack\", false);\n  skip_memtest_counter = 0;\n\n  tbia(ACCESS_READ);\n  tbia(ACCESS_EXEC);\n\n  //  state.fpcr = U64(0x8ff0000000000000);\n  state.fpen = true;\n  state.i_ctl_other = U64(0x502086);\n  state.smc = 1;\n\n  // SROM imitation...\n  add_tb(0, 0, U64(0xff61), ACCESS_READ);\n\n#if defined(IDB)\n  bListing = false;\n#endif\n\n  cc_large = 0;\n  prev_cc = 0;\n  start_cc = 0;\n  prev_time = 0;\n  prev_icount = 0;\n  start_icount = 0;\n\n#if defined(CONSTANT_TIME_FACTOR)\n  cc_per_instruction = CONSTANT_TIME_FACTOR;\n#else\n  cc_per_instruction = 70;\n#endif\n  ins_per_timer_int = cpu_hz / 1024;\n  next_timer_int = state.iProcNum ? U64(0xFFFFFFFFFFFFFFFF)\n                                  : ins_per_timer_int; /* only on CPU 0 */\n\n  state.r[22] = state.r[22 + 32] = state.iProcNum;\n\n  printf(\n      \"%s(%d): $Id: AlphaCPU.cpp,v 1.82 2009/03/16 01:33:27 iamcamiel Exp $\\n\",\n      devid_string, state.iProcNum);\n}\n\nvoid CAlphaCPU::start_threads() {\n  char buffer[5];\n  mySemaphore.tryWait(1);\n  if (!myThread) {\n    sprintf(buffer, \"cpu%d\", state.iProcNum);\n    myThread = std::make_unique<std::thread>([this](){ this->run(); });\n    printf(\" %s\", buffer);\n    StopThread = false;\n  }\n}\n\nvoid CAlphaCPU::stop_threads() {\n  char buffer[5];\n  StopThread = true;\n  if (myThread) {\n    sprintf(buffer, \"cpu%d\", state.iProcNum);\n    mySemaphore.set();\n    printf(\" %s\", buffer);\n    myThread->join();\n    myThread = nullptr;\n  }\n\n  mySemaphore.tryWait(1);\n}\n\n/**\n * Destructor.\n **/\nCAlphaCPU::~CAlphaCPU() { stop_threads(); }\n\n#if defined(IDB)\nchar dbg_string[1000];\n#if !defined(LS_MASTER) && !defined(LS_SLAVE)\nchar *dbg_strptr;\n#endif\n\n/**\n * \\brief Do whatever needs to be done to a debug-string.\n *\n * Used in IDB-mode to handle the disassembly- string. In es40_idb, it is\n * written to the standard output.\n *\n * \\param s       Pointer to the debug string.\n **/\nvoid handle_debug_string(char *s) {\n#if defined(LS_SLAVE) || defined(LS_MASTER)\n\n  //    lockstep_compare(s);\n  *dbg_strptr++ = '\\n';\n  *dbg_strptr = '\\0';\n#else\n  if (*s)\n    printf(\"%s\\n\", s);\n#endif\n}\n#endif\n#if defined(MIPS_ESTIMATE)\n\n// MIPS_INTERVAL must take longer than 1 second to execute\n// or estimate will generate a divide-by-zero error\n#define MIPS_INTERVAL 0xfffffff\nstatic time_t saved = 0;\nstatic u64 count;\nstatic double min_mips = 999999999999999.0;\nstatic double max_mips = 0.0;\n#endif\n\n/**\n * Check if threads are still running.\n *\n * Calibrate the CPU timing loop.\n **/\nvoid CAlphaCPU::check_state() {\n  if (myThreadDead.load())\n    FAILURE(Thread, \"CPU thread has died\");\n\n#if !defined(CONSTANT_TIME_FACTOR)\n  if (state.instruction_count > 0) {\n    // correct CPU timing loop...\n    u64 icount = state.instruction_count;\n    u64 cc = cc_large;\n    u64 time = start_time.elapsed();\n    s64 ce = cc_per_instruction;\n\n    u64 cc_aim = time * cpu_hz / 1000000; // microsecond resolution\n    u64 ce_aim = cc_aim / icount;\n\n    s64 icount_lapse = icount - prev_icount;\n    s64 cc_diff = cc_aim - cc;\n    s64 ce_diff = (u64)((float)cc_diff / (float)icount_lapse);\n\n    s64 ce_new = ce_aim + ce_diff;\n    if (ce_new < 0)\n      ce_new = 0;\n    if (ce_new > 200)\n      ce_new = 200;\n\n    if (ce_new != ce) {\n\n      //    printf(\"                                     time %12\" PRId64 \" | prev\n      //    %12\" PRId64 \"  \\n\",time,prev_time); printf(\"          count lapse %12\"\n      //    LL \"d | curr %12\" PRId64 \" | prev %12\" PRId64 \"\n      //    \\n\",icount_lapse,icount,prev_icount); printf(\"cc %12\" PRId64 \" | aim\n      //    %12\" PRId64 \" | diff %12\" PRId64 \" | prev %12\" PRId64 \"\n      //    \\n\",cc,cc_aim,cc_diff,prev_cc); printf(\"ce %12\" PRId64 \" | aim %12\" LL\n      //    \"d | diff %12\" PRId64 \" | new  %12\" PRId64 \"\n      //    \\n\",ce,ce_aim,ce_diff,ce_new);\n      //    printf(\"==========================================================================\n      //    \\n\");\n      cc_per_instruction = ce_new;\n      //    printf(\"cpu %d speed factor: %d\\n\",get_cpuid(),ce_new);\n    }\n\n    prev_cc = cc;\n    prev_icount = icount;\n    prev_time = time;\n  }\n#endif\n  return;\n}\n\n/**\n * Skip SRM memtest.\n *\n * Hack that skips memory check in SRM.\n **/\ninline void CAlphaCPU::skip_memtest() {\n  const char *wrong_memskip = \"warning: wrong memory check skip\\n\";\n  const char *counter_mismatch = \"warning: memory check skip counter mismatch\";\n\n  if (!(state.current_pc & U64(0x8b000)) || (skip_memtest_counter >= 5)) {\n    return;\n  }\n\n  if (state.current_pc == U64(0x8bb90)) {\n    if (state.r[5] != U64(0xaaaaaaaaaaaaaaaa)) {\n      printf(\"%s\", wrong_memskip);\n    } else {\n      if (skip_memtest_counter != 0)\n        printf(\"%s\", counter_mismatch);\n      ++skip_memtest_counter;\n      state.r[0] = state.r[4];\n    }\n  }\n\n  if (state.current_pc == U64(0x8bbe0)) {\n    if (state.r[5] != U64(0xaaaaaaaaaaaaaaaa)) {\n      printf(\"%s\", wrong_memskip);\n    } else {\n      if (skip_memtest_counter != 1)\n        printf(\"%s\", counter_mismatch);\n      ++skip_memtest_counter;\n      state.r[16] = 0;\n    }\n  }\n\n  if (state.current_pc == U64(0x8bc28)) {\n    if (state.r[5] != U64(0xaaaaaaaaaaaaaaaa)) {\n      printf(\"%s\", wrong_memskip);\n    } else {\n      if (skip_memtest_counter != 2)\n        printf(\"%s\", counter_mismatch);\n      ++skip_memtest_counter;\n      state.r[8] = state.r[4];\n    }\n  }\n\n  if (state.current_pc == U64(0x8bc70)) {\n    if (state.r[7] != U64(0x5555555555555555)) {\n      printf(\"%s\", wrong_memskip);\n    } else {\n      if (skip_memtest_counter != 3)\n        printf(\"%s\", counter_mismatch);\n      ++skip_memtest_counter;\n      state.r[0] = 0;\n    }\n  }\n\n  if (state.current_pc == U64(0x8bcb0)) {\n    if (state.r[7] != U64(0x5555555555555555)) {\n      if (skip_memtest_counter != 4)\n        printf(\"%s\", counter_mismatch);\n      printf(\"%s\", wrong_memskip);\n    } else {\n      ++skip_memtest_counter;\n      state.r[3] = state.r[4];\n    }\n  }\n}\n\n/**\n * \\brief Called each clock-cycle.\n *\n * This is where the actual CPU emulation takes place. Each clocktick, one\n *instruction is processed by the processor. The instruction pipeline is not\n *emulated, things are complicated enough as it is. The one exception is the\n *instruction cache, which is implemented, to accomodate self-modifying code.\n *The instruction cache can be disabled if self-modifying code is not expected.\n **/\nvoid CAlphaCPU::execute() {\n  u32 ins;\n  int i;\n  u64 phys_address;\n  u64 temp_64;\n  u64 temp_64_1;\n  u64 temp_64_2;\n\n  bool pbc;\n\n  int opcode;\n  int function;\n\n#if defined(MIPS_ESTIMATE)\n\n  // Calculate simulated performance statistics\n  if (++count >= MIPS_INTERVAL) {\n    time_t current;\n    time(&current);\n    if (saved > 0) {\n      double secs = difftime(current, saved);\n      double ips = MIPS_INTERVAL / secs;\n      double mips = ips / 1000000.0;\n      if (max_mips < mips)\n        max_mips = mips;\n      if (min_mips > mips)\n        min_mips = mips;\n      printf(\"ES40 MIPS (%3.1f sec):: current: %5.3f, min: %5.3f, max: %5.3f\\n\",\n             secs, mips, min_mips, max_mips);\n    }\n\n    saved = current;\n    count = 0;\n  }\n#endif\n#if defined(IDB)\n  char *funcname = 0;\n  dbg_string[0] = '\\0';\n#if !defined(LS_MASTER) && !defined(LS_SLAVE)\n  dbg_strptr = dbg_string;\n#endif\n#endif\n  state.current_pc = state.pc;\n\n  if (skip_memtest_hack)\n    skip_memtest();\n\n  // Service interrupts\n  if (DO_ACTION) {\n\n    // We're actually executing code. Cycle counter should be updated, interrupt\n    // and interrupt timer status needs to be checked, and the next instruction\n    // should be fetched from the instruction cache. Increase the cycle counter\n    // if it is currently enabled.\n    state.instruction_count++;\n    cc_large += cc_per_instruction;\n\n    if (cc_large > next_timer_int) {\n      next_timer_int += ins_per_timer_int;\n      cSystem->interrupt(-1, true);\n    }\n\n    if (state.cc_ena) {\n      state.cc += cc_per_instruction;\n    }\n\n    if (state.check_timers) {\n\n      // There are one or more active delayed irq_h interrupts. Go through the 6\n      // irq_h timers, decrease them as needed, and set the interrupt if the\n      // timer reaches 0.\n      state.check_timers = false;\n      for (int i = 0; i < 6; i++) {\n        if (state.irq_h_timer[i]) {\n\n          // This timer is active. Decrease it, and check if it reached 0.\n          state.irq_h_timer[i]--;\n          if (state.irq_h_timer[i]) {\n\n            // The timer hasn't reached 0 yet; check on the timers again next\n            // clock tick.\n            state.check_timers = true;\n          } else {\n\n            // The timer has reached 0. Set the interrupt status, and set the\n            // flag that we need to check the interrupt status\n            state.eir |= (U64(0x1) << i);\n            state.check_int = true;\n          }\n        }\n      }\n    }\n\n    if (state.check_int && !(state.pc & 1)) {\n\n      // One or more of the variables that affect interrupt status have changed,\n      // and we are not currently inside PALmode. It is not certain that this\n      // means we hava an interrupt to service, but we might have. This needs to\n      // be checked.\n\n      /*\n      if (state.pal_vms) {\n        // PALcode base is set to 0x8000; meaning OpenVMS PALcode is currently\n      active. In this\n        // case, our VMS PALcode replacement routines are valid, and should be\n      used as it is\n        // faster than using the original PALcode.\n\n        if (state.eir & state.eien & 6)\n          if (vmspal_ent_ext_int(state.eir&state.eien & 6))\n            return;\n\n        if (state.sir & state.sien & 0xfffc)\n          if (vmspal_ent_sw_int(state.sir&state.sien))\n            return;\n\n        if (state.asten && (state.aster & state.astrr & ((1<<(state.cm+1))-1) ))\n          if (vmspal_ent_ast_int(state.aster & state.astrr &\n      ((1<<(state.cm+1))-1) )) return;\n\n        if (state.sir & state.sien)\n          if (vmspal_ent_sw_int(state.sir&state.sien))\n            return;\n      } else\n*/\n      {\n\n        // PALcode base is set to an unsupported value. We have no choice but to\n        // transfer control to PALmode at the PALcode interrupt entry point.\n        //        if (state.eir & 8)\n        //        {\n        //          printf(\"%s: IP interrupt received%s...\\n\",devid_string,\n        //          (state.eien&8)?\"(enabled)\":\"(masked)\");\n        //        }\n        if ((state.eien & state.eir) || (state.sien & state.sir) ||\n            (state.asten &&\n             (state.aster & state.astrr & ((1 << (state.cm + 1)) - 1)))) {\n          GO_PAL(INTERRUPT);\n          return;\n        }\n      }\n\n      // This point is reached only if there are no more active interrupts. We\n      // can safely set check_int to false now to save time on the next CPU\n      // clock ticks.\n      state.check_int = false;\n    }\n\n    // If profiling is enabled, increase the profiling counter for the current\n    // block of addresses.\n#if defined(PROFILE)\n    PROFILE_DO(state.pc);\n#endif\n\n    // Get the next instruction from the instruction cache.\n    if (get_icache(state.pc, &ins))\n      return;\n#if defined(IDB)\n    current_pc_physical = state.pc_phys;\n#endif\n  } // if (DO_ACTION)\n  else {\n\n    // We're not really executing any code (DO_ACTION is false); that means that\n    // we're in a debugging session, and just listing instructions at a\n    // particular address. In this case, we treat the program counter as a\n    // physical address.\n    ins = (u32)(cSystem->ReadMem(state.pc, 32, this));\n  }\n\n  // Increase the program counter. The current value is retained in\n  // state.current_pc.\n  next_pc();\n\n  // Clear \"always zero\" registers. The last instruction might have written\n  // something to one of these registers.\n  state.r[31] = 0;\n  state.f[31] = 0;\n\n  // Decode and dispatch opcode. This is kept very compact using the OP-macro\n  // defined in cpu_debug.h. For the normal emulator, this simply calls the\n  // DO_<mnemonic> macro defined in one of the other cpu_*.h files; but for the\n  // interactive debugger, it will also do disassembly, where the second\n  // parameter to the macro (e.g. R12_R3) determines the formatting applied to\n  // the operands. The macro ends with \"return 0;\".\n#if defined(IDB)\n  last_instruction = ins;\n#endif\n  opcode = ins >> 26;\n  switch (opcode) {\n  case 0x00: // CALL_PAL\n    function = ins & 0x1fffffff;\n    OP(CALL_PAL, PAL);\n\n  //    switch (function)\n  //    {\n  //      case 0x123401: OP_FNC(vmspal_int_read_ide, NOP);\n  //      default: OP(CALL_PAL,PAL);\n  //    }\n  case 0x08:\n    OP(LDA, MEM);\n\n  case 0x09:\n    OP(LDAH, MEM);\n\n  case 0x0a:\n    OP(LDBU, MEM);\n\n  case 0x0b:\n    OP(LDQ_U, MEM);\n\n  case 0x0c:\n    OP(LDWU, MEM);\n\n  case 0x0d:\n    OP(STW, MEM);\n\n  case 0x0e:\n    OP(STB, MEM);\n\n  case 0x0f:\n    OP(STQ_U, MEM);\n\n  case 0x10: // INTA* instructions\n    function = (ins >> 5) & 0x7f;\n    switch (function) {\n    case 0x40:\n      OP(ADDL_V, R12_R3);\n    case 0x00:\n      OP(ADDL, R12_R3);\n    case 0x02:\n      OP(S4ADDL, R12_R3);\n    case 0x49:\n      OP(SUBL_V, R12_R3);\n    case 0x09:\n      OP(SUBL, R12_R3);\n    case 0x0b:\n      OP(S4SUBL, R12_R3);\n    case 0x0f:\n      OP(CMPBGE, R12_R3);\n    case 0x12:\n      OP(S8ADDL, R12_R3);\n    case 0x1b:\n      OP(S8SUBL, R12_R3);\n    case 0x1d:\n      OP(CMPULT, R12_R3);\n    case 0x60:\n      OP(ADDQ_V, R12_R3);\n    case 0x20:\n      OP(ADDQ, R12_R3);\n    case 0x22:\n      OP(S4ADDQ, R12_R3);\n    case 0x69:\n      OP(SUBQ_V, R12_R3);\n    case 0x29:\n      OP(SUBQ, R12_R3);\n    case 0x2b:\n      OP(S4SUBQ, R12_R3);\n    case 0x2d:\n      OP(CMPEQ, R12_R3);\n    case 0x32:\n      OP(S8ADDQ, R12_R3);\n    case 0x3b:\n      OP(S8SUBQ, R12_R3);\n    case 0x3d:\n      OP(CMPULE, R12_R3);\n    case 0x4d:\n      OP(CMPLT, R12_R3);\n    case 0x6d:\n      OP(CMPLE, R12_R3);\n    default:\n      UNKNOWN2;\n    }\n    break;\n\n  case 0x11: // INTL* instructions\n    function = (ins >> 5) & 0x7f;\n    switch (function) {\n    case 0x00:\n      OP(AND, R12_R3);\n    case 0x08:\n      OP(BIC, R12_R3);\n    case 0x14:\n      OP(CMOVLBS, R12_R3);\n    case 0x16:\n      OP(CMOVLBC, R12_R3);\n    case 0x20:\n      OP(BIS, R12_R3);\n    case 0x24:\n      OP(CMOVEQ, R12_R3);\n    case 0x26:\n      OP(CMOVNE, R12_R3);\n    case 0x28:\n      OP(ORNOT, R12_R3);\n    case 0x40:\n      OP(XOR, R12_R3);\n    case 0x44:\n      OP(CMOVLT, R12_R3);\n    case 0x46:\n      OP(CMOVGE, R12_R3);\n    case 0x48:\n      OP(EQV, R12_R3);\n    case 0x61:\n      OP(AMASK, R2_R3);\n    case 0x64:\n      OP(CMOVLE, R12_R3);\n    case 0x66:\n      OP(CMOVGT, R12_R3);\n    case 0x6c:\n      OP(IMPLVER, X_R3);\n    default:\n      UNKNOWN2;\n    }\n    break;\n\n  case 0x12: // INTS* instructions\n    function = (ins >> 5) & 0x7f;\n    switch (function) {\n    case 0x02:\n      OP(MSKBL, R12_R3);\n    case 0x06:\n      OP(EXTBL, R12_R3);\n    case 0x0b:\n      OP(INSBL, R12_R3);\n    case 0x12:\n      OP(MSKWL, R12_R3);\n    case 0x16:\n      OP(EXTWL, R12_R3);\n    case 0x1b:\n      OP(INSWL, R12_R3);\n    case 0x22:\n      OP(MSKLL, R12_R3);\n    case 0x26:\n      OP(EXTLL, R12_R3);\n    case 0x2b:\n      OP(INSLL, R12_R3);\n    case 0x30:\n      OP(ZAP, R12_R3);\n    case 0x31:\n      OP(ZAPNOT, R12_R3);\n    case 0x32:\n      OP(MSKQL, R12_R3);\n    case 0x34:\n      OP(SRL, R12_R3);\n    case 0x36:\n      OP(EXTQL, R12_R3);\n    case 0x39:\n      OP(SLL, R12_R3);\n    case 0x3b:\n      OP(INSQL, R12_R3);\n    case 0x3c:\n      OP(SRA, R12_R3);\n    case 0x52:\n      OP(MSKWH, R12_R3);\n    case 0x57:\n      OP(INSWH, R12_R3);\n    case 0x5a:\n      OP(EXTWH, R12_R3);\n    case 0x62:\n      OP(MSKLH, R12_R3);\n    case 0x67:\n      OP(INSLH, R12_R3);\n    case 0x6a:\n      OP(EXTLH, R12_R3);\n    case 0x72:\n      OP(MSKQH, R12_R3);\n    case 0x77:\n      OP(INSQH, R12_R3);\n    case 0x7a:\n      OP(EXTQH, R12_R3);\n    default:\n      UNKNOWN2;\n    }\n    break;\n\n  case 0x13: // INTM* instructions\n    function = (ins >> 5) & 0x7f;\n    switch (function) // ignore /V for now\n    {\n    case 0x40:\n      OP(MULL_V, R12_R3);\n    case 0x00:\n      OP(MULL, R12_R3);\n    case 0x60:\n      OP(MULQ_V, R12_R3);\n    case 0x20:\n      OP(MULQ, R12_R3);\n    case 0x30:\n      OP(UMULH, R12_R3);\n    default:\n      UNKNOWN2;\n    }\n    break;\n\n  case 0x14: // ITFP* instructions\n    function = (ins >> 5) & 0x7ff;\n    switch (function) {\n    case 0x004:\n      OP(ITOFS, R1_F3);\n\n    case 0x00a:\n    case 0x08a:\n    case 0x10a:\n    case 0x18a:\n    case 0x40a:\n    case 0x48a:\n    case 0x50a:\n    case 0x58a:\n      OP(SQRTF, F2_F3);\n\n    case 0x00b:\n    case 0x04b:\n    case 0x08b:\n    case 0x0cb:\n    case 0x10b:\n    case 0x14b:\n    case 0x18b:\n    case 0x1cb:\n    case 0x50b:\n    case 0x54b:\n    case 0x58b:\n    case 0x5cb:\n    case 0x70b:\n    case 0x74b:\n    case 0x78b:\n    case 0x7cb:\n      OP(SQRTS, F2_F3);\n\n    case 0x014:\n      OP(ITOFF, R1_F3);\n\n    case 0x024:\n      OP(ITOFT, R1_F3);\n\n    case 0x02a:\n    case 0x0aa:\n    case 0x12a:\n    case 0x1aa:\n    case 0x42a:\n    case 0x4aa:\n    case 0x52a:\n    case 0x5aa:\n      OP(SQRTG, F2_F3);\n\n    case 0x02b:\n    case 0x06b:\n    case 0x0ab:\n    case 0x0eb:\n    case 0x12b:\n    case 0x16b:\n    case 0x1ab:\n    case 0x1eb:\n    case 0x52b:\n    case 0x56b:\n    case 0x5ab:\n    case 0x5eb:\n    case 0x72b:\n    case 0x76b:\n    case 0x7ab:\n    case 0x7eb:\n      OP(SQRTT, F2_F3);\n\n    default:\n      UNKNOWN2;\n    }\n    break;\n\n  case 0x15: // FLTV* instructions\n    function = (ins >> 5) & 0x7ff;\n    switch (function) {\n    case 0x0a5:\n    case 0x4a5:\n      OP(CMPGEQ, F12_F3);\n\n    case 0x0a6:\n    case 0x4a6:\n      OP(CMPGLT, F12_F3);\n\n    case 0x0a7:\n    case 0x4a7:\n      OP(CMPGLE, F12_F3);\n\n    case 0x03c:\n    case 0x0bc:\n      OP(CVTQF, F2_F3);\n\n    case 0x03e:\n    case 0x0be:\n      OP(CVTQG, F2_F3);\n\n    default:\n      if (function & 0x200) {\n        UNKNOWN2;\n      }\n\n      switch (function & 0x7f) {\n      case 0x000:\n        OP(ADDF, F12_F3);\n      case 0x001:\n        OP(SUBF, F12_F3);\n      case 0x002:\n        OP(MULF, F12_F3);\n      case 0x003:\n        OP(DIVF, F12_F3);\n      case 0x01e:\n        OP(CVTDG, F2_F3);\n      case 0x020:\n        OP(ADDG, F12_F3);\n      case 0x021:\n        OP(SUBG, F12_F3);\n      case 0x022:\n        OP(MULG, F12_F3);\n      case 0x023:\n        OP(DIVG, F12_F3);\n      case 0x02c:\n        OP(CVTGF, F12_F3);\n      case 0x02d:\n        OP(CVTGD, F2_F3);\n      case 0x02f:\n        OP(CVTGQ, F2_F3);\n      default:\n        UNKNOWN2;\n      }\n      break;\n    }\n    break;\n\n  case 0x16: // FLTI* instructions\n    function = (ins >> 5) & 0x7ff;\n    switch (function) {\n    case 0x0a4:\n    case 0x5a4:\n      OP(CMPTUN, F12_F3);\n\n    case 0x0a5:\n    case 0x5a5:\n      OP(CMPTEQ, F12_F3);\n\n    case 0x0a6:\n    case 0x5a6:\n      OP(CMPTLT, F12_F3);\n\n    case 0x0a7:\n    case 0x5a7:\n      OP(CMPTLE, F12_F3);\n\n    case 0x2ac:\n    case 0x6ac:\n      OP(CVTST, F2_F3);\n\n    default:\n      if (((function & 0x600) == 0x200) || ((function & 0x500) == 0x400)) {\n        UNKNOWN2;\n      }\n\n      switch (function & 0x3f) {\n      case 0x00:\n        OP(ADDS, F12_F3);\n      case 0x01:\n        OP(SUBS, F12_F3);\n      case 0x02:\n        OP(MULS, F12_F3);\n      case 0x03:\n        OP(DIVS, F12_F3);\n      case 0x20:\n        OP(ADDT, F12_F3);\n      case 0x21:\n        OP(SUBT, F12_F3);\n      case 0x22:\n        OP(MULT, F12_F3);\n      case 0x23:\n        OP(DIVT, F12_F3);\n      case 0x2c:\n        OP(CVTTS, F2_F3);\n      case 0x2f:\n        OP(CVTTQ, F2_F3);\n      case 0x3c:\n        if ((function & 0x300) == 0x100) {\n          UNKNOWN2;\n        }\n        OP(CVTQS, F2_F3);\n      case 0x3e:\n        if ((function & 0x300) == 0x100) {\n          UNKNOWN2;\n        }\n        OP(CVTQT, F2_F3);\n      default:\n        UNKNOWN2;\n      }\n      break;\n    }\n    break;\n\n  case 0x17: // FLTL* instructions\n    function = (ins >> 5) & 0x7ff;\n    switch (function) {\n    case 0x010:\n      OP(CVTLQ, F2_F3);\n\n    case 0x020:\n      OP(CPYS, F12_F3);\n\n    case 0x021:\n      OP(CPYSN, F12_F3);\n\n    case 0x022:\n      OP(CPYSE, F12_F3);\n\n    case 0x024:\n      OP(MT_FPCR, X_F1);\n\n    case 0x025:\n      OP(MF_FPCR, X_F1);\n\n    case 0x02a:\n      OP(FCMOVEQ, F12_F3);\n\n    case 0x02b:\n      OP(FCMOVNE, F12_F3);\n\n    case 0x02c:\n      OP(FCMOVLT, F12_F3);\n\n    case 0x02d:\n      OP(FCMOVGE, F12_F3);\n\n    case 0x02e:\n      OP(FCMOVLE, F12_F3);\n\n    case 0x02f:\n      OP(FCMOVGT, F12_F3);\n\n    case 0x030:\n    case 0x130:\n    case 0x530:\n      OP(CVTQL, F12_F3);\n\n    default:\n      UNKNOWN2;\n    }\n    break;\n\n  case 0x18: // MISC* instructions\n    function = (ins & 0xffff);\n    switch (function) {\n    case 0x0000:\n      OP(TRAPB, NOP);\n    case 0x0400:\n      OP(EXCB, NOP);\n    case 0x4000:\n      OP(MB, NOP);\n    case 0x4400:\n      OP(WMB, NOP);\n    case 0x8000:\n      OP(FETCH, NOP);\n    case 0xA000:\n      OP(FETCH_M, NOP);\n    case 0xC000:\n      OP(RPCC, X_R1);\n    case 0xE000:\n      OP(RC, X_R1);\n    case 0xE800:\n      OP(ECB, NOP);\n    case 0xF000:\n      OP(RS, X_R1);\n    case 0xF800:\n      OP(WH64, NOP);\n    case 0xFC00:\n      OP(WH64EN, NOP);\n    default:\n      UNKNOWN2;\n    }\n    break;\n\n  case 0x19: // HW_MFPR\n    function = (ins >> 8) & 0xff;\n    OP(HW_MFPR, MFPR);\n\n  case 0x1a: // JSR* instructions\n    OP(JMP, JMP);\n\n  case 0x1b: // PAL reserved - HW_LD\n    function = (ins >> 12) & 0xf;\n    if (function & 1) {\n      OP(HW_LDQ, HW_LD);\n    } else {\n      OP(HW_LDL, HW_LD);\n    }\n\n  case 0x1c: // FPTI* instructions\n    function = (ins >> 5) & 0x7f;\n    switch (function) {\n    case 0x00:\n      OP(SEXTB, R2_R3);\n    case 0x01:\n      OP(SEXTW, R2_R3);\n    case 0x30:\n      OP(CTPOP, R2_R3);\n    case 0x31:\n      OP(PERR, R2_R3);\n    case 0x32:\n      OP(CTLZ, R2_R3);\n    case 0x33:\n      OP(CTTZ, R2_R3);\n    case 0x34:\n      OP(UNPKBW, R2_R3);\n    case 0x35:\n      OP(UNPKBL, R2_R3);\n    case 0x36:\n      OP(PKWB, R2_R3);\n    case 0x37:\n      OP(PKLB, R2_R3);\n    case 0x38:\n      OP(MINSB8, R12_R3);\n    case 0x39:\n      OP(MINSW4, R12_R3);\n    case 0x3a:\n      OP(MINUB8, R12_R3);\n    case 0x3b:\n      OP(MINUW4, R12_R3);\n    case 0x3c:\n      OP(MAXUB8, R12_R3);\n    case 0x3d:\n      OP(MAXUW4, R12_R3);\n    case 0x3e:\n      OP(MAXSB8, R12_R3);\n    case 0x3f:\n      OP(MAXSW4, R12_R3);\n    case 0x70:\n      OP(FTOIT, F1_R3);\n    case 0x78:\n      OP(FTOIS, F1_R3);\n    default:\n      UNKNOWN2;\n    }\n    break;\n\n  case 0x1d: // HW_MTPR\n    function = (ins >> 8) & 0xff;\n    OP(HW_MTPR, MTPR);\n\n  case 0x1e:\n    OP(HW_RET, RET);\n\n  case 0x1f: // HW_ST\n    function = (ins >> 12) & 0xf;\n    if (function & 1) {\n      OP(HW_STQ, HW_ST);\n    } else {\n      OP(HW_STL, HW_ST);\n    }\n\n  case 0x20:\n    OP(LDF, FMEM);\n\n  case 0x21:\n    OP(LDG, FMEM);\n\n  case 0x22:\n    OP(LDS, FMEM);\n\n  case 0x23:\n    OP(LDT, FMEM);\n\n  case 0x24:\n    OP(STF, FMEM);\n\n  case 0x25:\n    OP(STG, FMEM);\n\n  case 0x26:\n    OP(STS, FMEM);\n\n  case 0x27:\n    OP(STT, FMEM);\n\n  case 0x28:\n    OP(LDL, MEM);\n\n  case 0x29:\n    OP(LDQ, MEM);\n\n  case 0x2a:\n    OP(LDL_L, MEM);\n\n  case 0x2b:\n    OP(LDQ_L, MEM);\n\n  case 0x2c:\n    OP(STL, MEM);\n\n  case 0x2d:\n    OP(STQ, MEM);\n\n  case 0x2e:\n    OP(STL_C, MEM);\n\n  case 0x2f:\n    OP(STQ_C, MEM);\n\n  case 0x30:\n    OP(BR, BR);\n\n  case 0x31:\n    OP(FBEQ, FCOND);\n\n  case 0x32:\n    OP(FBLT, FCOND);\n\n  case 0x33:\n    OP(FBLE, FCOND);\n\n  case 0x34:\n    OP(BSR, BSR);\n\n  case 0x35:\n    OP(FBNE, FCOND);\n\n  case 0x36:\n    OP(FBGE, FCOND);\n\n  case 0x37:\n    OP(FBGT, FCOND);\n\n  case 0x38:\n    OP(BLBC, COND);\n\n  case 0x39:\n    OP(BEQ, COND);\n\n  case 0x3a:\n    OP(BLT, COND);\n\n  case 0x3b:\n    OP(BLE, COND);\n\n  case 0x3c:\n    OP(BLBS, COND);\n\n  case 0x3d:\n    OP(BNE, COND);\n\n  case 0x3e:\n    OP(BGE, COND);\n\n  case 0x3f:\n    OP(BGT, COND);\n\n  default:\n    UNKNOWN1;\n  }\n\n  return;\n}\n\n#if defined(IDB)\n\n/**\n * \\brief Produce disassembly-listing without marker\n *\n * \\param from    Address of first instruction to be disassembled.\n * \\param to      Address of instruction following the last instruction to\n *                be disassembled.\n **/\nvoid CAlphaCPU::listing(u64 from, u64 to) { listing(from, to, 0); }\n\n/**\n * \\brief Produce disassembly-listing with marker\n *\n * \\param from    Address of first instruction to be disassembled.\n * \\param to      Address of instruction following the last instruction to\n *                be disassembled.\n * \\param mark    Address of instruction to be underlined with a marker line.\n **/\nvoid CAlphaCPU::listing(u64 from, u64 to, u64 mark) {\n  printf(\"%%CPU-I-LISTNG: Listing from %016\" PRIx64 \" to %016\" PRIx64 \"\\n\", from, to);\n\n  u64 iSavedPC;\n  bool bSavedDebug;\n  iSavedPC = state.pc;\n  bSavedDebug = bDisassemble;\n  bDisassemble = true;\n  bListing = true;\n  for (state.pc = from; state.pc <= to;) {\n    execute();\n    if (state.pc == mark)\n      printf(\"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n\");\n  }\n\n  bListing = false;\n  state.pc = iSavedPC;\n  bDisassemble = bSavedDebug;\n}\n\nu64 CAlphaCPU::get_instruction_count() { return state.instruction_count; }\n#endif\nstatic u32 cpu_magic1 = 0x2126468C;\nstatic u32 cpu_magic2 = 0xC8646212;\n\n/**\n * Save state to a Virtual Machine State file.\n **/\nint CAlphaCPU::SaveState(FILE *f) {\n  long ss = sizeof(state);\n\n  fwrite(&cpu_magic1, sizeof(u32), 1, f);\n  fwrite(&ss, sizeof(long), 1, f);\n  fwrite(&state, sizeof(state), 1, f);\n  fwrite(&cpu_magic2, sizeof(u32), 1, f);\n  printf(\"%s: %d bytes saved.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\n/**\n * Restore state from a Virtual Machine State file.\n **/\nint CAlphaCPU::RestoreState(FILE *f) {\n  long ss;\n  u32 m1;\n  u32 m2;\n  size_t r;\n\n  r = fread(&m1, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m1 != cpu_magic1) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&ss, sizeof(long), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (ss != sizeof(state)) {\n    printf(\"%s: STRUCT SIZE does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&state, sizeof(state), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&m2, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m2 != cpu_magic2) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  printf(\"%s: %d bytes restored.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\n/***************************************************************************/\n\n/**\n * \\name TB\n * Translation Buffer related functions\n ******************************************************************************/\n\n//\\{\n\n/**\n * \\brief Find translation-buffer entry\n *\n * Try to find a translation-buffer entry that maps the page inside which\n * the specified virtual address lies.\n *\n * \\param virt    Virtual address to find in translation buffer.\n * \\param flags   ACCESS_EXEC determines which translation buffer to use.\n * \\return        Number of matching entry, or -1 if no match found.\n **/\nint CAlphaCPU::FindTBEntry(u64 virt, int flags) {\n\n  // Use ITB (tb[1]) if ACCESS_EXEC is set, otherwise use DTB (tb[0])\n  int t = (flags & ACCESS_EXEC) ? 1 : 0;\n  int asn = (flags & ACCESS_EXEC) ? state.asn : state.asn0;\n\n  int rw = (flags & ACCESS_WRITE) ? 1 : 0;\n\n  // Try last match first; this is a good quess, especially in the ITB\n  int i = state.last_found_tb[t][rw];\n  if (state.tb[t][i].valid &&\n      !((state.tb[t][i].virt ^ virt) & state.tb[t][i].match_mask) &&\n      (state.tb[t][i].asm_bit || (state.tb[t][i].asn == asn)))\n    return i;\n\n  // Otherwise, loop through the TB entries to find a match.\n  for (i = 0; i < TB_ENTRIES; i++) {\n    if (state.tb[t][i].valid &&\n        !((state.tb[t][i].virt ^ virt) & state.tb[t][i].match_mask) &&\n        (state.tb[t][i].asm_bit || (state.tb[t][i].asn == asn))) {\n      state.last_found_tb[t][rw] = i;\n      return i;\n    }\n  }\n\n  return -1;\n}\n\n/**\n * \\brief Translate a virtual address to a physical address.\n *\n * Translate a 64-bit virtual address into a 64-bit physical address, using\n * the page table buffers.\n *\n * The following steps are taken to resolve the address:\n *  - See if the address can be found in the translation buffer.\n *  - If not, try to load the right page table entry into the translation\n *    buffer, if this is not possible, trap to the OS.\n *  - Check access privileges.\n *  - Check fault bits.\n *  .\n *\n * \\param virt    Virtual address to be translated.\n * \\param phys    Pointer to where the physical address is to be returned.\n * \\param flags   Set of flags that determine the exact functioning of the\n *                function. A combination of the following flags:\n *                  - ACCESS_READ   Data-read-access.\n *                  - ACCESS_WRITE  Data-write-access.\n *                  - ACCESS_EXEC   Code-read-access.\n *                  - NO_CHECK      Do not perform access checks.\n *                  - VPTE          VPTE access; if this misses, it's a double\n *miss.\n *                  - FAKE          Access is not initiated by executing code,\n *but by the debugger. If a translation can't be found through the translation\n *buffer, don't bother.\n *                  - ALT           Use alt_cm for access checks instead of cm.\n *                  - RECUR         Recursive try. We tried to find this address\n *                                  before, added a TB entry, and now it should\n *sail through.\n *                  - PROBE         Access is for a PROBER or PROBEW access;\n *Don't swap in the page if it is outswapped.\n *                  - PROBEW        Access is for a PROBEW access.\n *                  .\n * \\param asm_bit Status of the ASM (address space match) bit in the\n *page-table-entry. \\param ins     Instruction currently being executed.\n *Important for the correct handling of traps.\n *\n * \\return        0 on success, -1 if address could not be converted without\n *                help (in this case state.pc contains the address of the\n *                next instruction to execute (PALcode or OS entry point).\n **/\nint CAlphaCPU::virt2phys(u64 virt, u64 *phys, int flags, bool *asm_bit,\n                         u32 ins) {\n  int t = (flags & ACCESS_EXEC) ? 1 : 0;\n  int i;\n  int res;\n\n  int spe = (flags & ACCESS_EXEC) ? state.i_ctl_spe : state.m_ctl_spe;\n  int cm = (flags & ALT) ? state.alt_cm : state.cm;\n  bool forreal = !(flags & FAKE);\n\n#if defined IDB\n  if (bListing) {\n    *phys = virt;\n    return 0;\n  }\n#endif\n#if defined(DEBUG_TB)\n  if (forreal)\n#if defined(IDB)\n    if (bTB_Debug)\n#endif\n      printf(\"TB %\" PRIx64 \",%x: \", virt, flags);\n#endif\n\n  // try superpage first.\n  if (spe && !cm) {\n#if defined(DEBUG_TB)\n    if (forreal)\n#if defined(IDB)\n      if (bTB_Debug)\n#endif\n        printf(\"try spe...\");\n#endif\n\n    // HRM 5.3.9: SPE[2], when set, enables superpage mapping when VA[47:46]\n    // = 2. In this mode, VA[43:13] are mapped directly to PA[43:13] and\n    // VA[45:44] are ignored.\n    if (((virt & SPE_2_MASK) == SPE_2_MATCH) && (spe & 4)) {\n      *phys = virt & SPE_2_MAP;\n      if (asm_bit)\n        *asm_bit = false;\n#if defined(DEBUG_TB)\n      if (forreal)\n#if defined(IDB)\n        if (bTB_Debug)\n#endif\n          printf(\"SPE\\n\");\n#endif\n      return 0;\n    }\n\n    // SPE[1], when set, enables superpage mapping when VA[47:41] = 7E. In\n    // this mode, VA[40:13] are mapped directly to PA[40:13] and PA[43:41] are\n    // copies of PA[40] (sign extension).\n    else if (((virt & SPE_1_MASK) == SPE_1_MATCH) && (spe & 2)) {\n      *phys = (virt & SPE_1_MAP) | ((virt & SPE_1_TEST) ? SPE_1_ADD : 0);\n      if (asm_bit)\n        *asm_bit = false;\n#if defined(DEBUG_TB)\n      if (forreal)\n#if defined(IDB)\n        if (bTB_Debug)\n#endif\n          printf(\"SPE\\n\");\n#endif\n      return 0;\n    }\n\n    // SPE[0], when set, enables superpage mapping when VA[47:30] = 3FFFE.\n    // In this mode, VA[29:13] are mapped directly to PA[29:13] and PA[43:30]\n    // are cleared.\n    else if (((virt & SPE_0_MASK) == SPE_0_MATCH) && (spe & 1)) {\n      *phys = virt & SPE_0_MAP;\n      if (asm_bit)\n        *asm_bit = false;\n#if defined(DEBUG_TB)\n      if (forreal)\n#if defined(IDB)\n        if (bTB_Debug)\n#endif\n          printf(\"SPE\\n\");\n#endif\n      return 0;\n    }\n  }\n\n  // try to find it in the translation buffer\n  i = FindTBEntry(virt, flags);\n\n  if (i < 0) // not found, either trap to PALcode, or try to load the TB entry\n             // and try again.\n  {\n    if (!forreal)       // debugger-lookup of the address\n      return -1;        // report failure, and don't look any further\n    if (!state.pal_vms) // unknown PALcode\n    {\n\n      // transfer execution to PALcode\n      state.exc_addr = state.current_pc;\n      if (flags & VPTE) {\n        state.fault_va = virt;\n        state.exc_sum = (u64)REG_1 << 8;\n        set_pc(state.pal_base + DTBM_DOUBLE_3 + 1);\n      } else if (flags & ACCESS_EXEC) {\n        set_pc(state.pal_base + ITB_MISS + 1);\n      } else {\n        state.fault_va = virt;\n        state.exc_sum = (u64)REG_1 << 8;\n\n        u32 opcode = I_GETOP(ins);\n        state.mm_stat =\n            ((opcode == 0x1b || opcode == 0x1f) ? opcode - 0x18 : opcode) << 4 |\n            (flags & ACCESS_WRITE);\n        set_pc(state.pal_base + DTBM_SINGLE + 1);\n      }\n\n      return -1;\n    } else // VMS PALcode\n    {\n      if (flags & RECUR) // we already tried this\n      {\n        printf(\"Translationbuffer RECUR lookup failed!\\n\");\n        return -1;\n      }\n\n      state.exc_addr = state.current_pc;\n      if (flags & VPTE) {\n\n        // try to handle the double miss. If this needs to transfer control\n        // to the OS, it will return non-zero value.\n        if ((res = vmspal_ent_dtbm_double_3(flags)))\n          return res;\n\n        // Double miss succesfully handled. Try to get the physical address\n        // again.\n        return virt2phys(virt, phys, flags | RECUR, asm_bit, ins);\n      } else if (flags & ACCESS_EXEC) {\n\n        // try to handle the ITB miss. If this needs to transfer control\n        // to the OS, it will return non-zero value.\n        if ((res = vmspal_ent_itbm(flags)))\n          return res;\n\n        // ITB miss succesfully handled. Try to get the physical address again.\n        return virt2phys(virt, phys, flags | RECUR, asm_bit, ins);\n      } else {\n        state.fault_va = virt;\n        state.exc_sum = (u64)REG_1 << 8;\n\n        u32 opcode = I_GETOP(ins);\n        state.mm_stat =\n            ((opcode == 0x1b || opcode == 0x1f) ? opcode - 0x18 : opcode) << 4 |\n            (flags & ACCESS_WRITE);\n\n        // try to handle the single miss. If this needs to transfer control\n        // to the OS, it will return non-zero value.\n        if ((res = vmspal_ent_dtbm_single(flags)))\n          return res;\n\n        // Single miss succesfully handled. Try to get the physical address\n        // again.\n        return virt2phys(virt, phys, flags | RECUR, asm_bit, ins);\n      }\n    }\n  }\n\n  // If we get here, the number of the matching TB entry is in i.\n#if defined(DEBUG_TB)\n  else {\n    if (forreal)\n#if defined(IDB)\n      if (bTB_Debug)\n#endif\n        printf(\"entry %d - \", i);\n  }\n#endif\n  if (!(flags & NO_CHECK)) {\n\n    // check if requested access is allowed\n    if (!state.tb[t][i].access[flags & ACCESS_WRITE][cm]) {\n#if defined(DEBUG_TB)\n      if (forreal)\n#if defined(IDB)\n        if (bTB_Debug)\n#endif\n          printf(\"acv\\n\");\n#endif\n      if (flags & ACCESS_EXEC) {\n\n        // handle I-stream access violation\n        state.exc_addr = state.current_pc;\n        state.exc_sum = 0;\n        if (state.pal_vms) {\n          if ((res = vmspal_ent_iacv(flags)))\n            return res;\n        } else {\n          set_pc(state.pal_base + IACV + 1);\n          return -1;\n        }\n      } else {\n\n        // Handle D-stream access violation\n        state.exc_addr = state.current_pc;\n        state.fault_va = virt;\n        state.exc_sum = (u64)REG_1 << 8;\n\n        u32 opcode = I_GETOP(ins);\n        state.mm_stat =\n            ((opcode == 0x1b || opcode == 0x1f) ? opcode - 0x18 : opcode) << 4 |\n            (flags & ACCESS_WRITE) | 2;\n        if (state.pal_vms) {\n          if ((res = vmspal_ent_dfault(flags)))\n            return res;\n        } else {\n          set_pc(state.pal_base + DFAULT + 1);\n          return -1;\n        }\n      }\n    }\n\n    // check if requested access doesn't fault\n    if (state.tb[t][i].fault[flags & ACCESS_MODE]) {\n#if defined(DEBUG_TB)\n      if (forreal)\n#if defined(IDB)\n        if (bTB_Debug)\n#endif\n          printf(\"fault\\n\");\n#endif\n      if (flags & ACCESS_EXEC) {\n\n        // handle I-stream access fault\n        state.exc_addr = state.current_pc;\n        state.exc_sum = 0;\n        if (state.pal_vms) {\n          if ((res = vmspal_ent_iacv(flags)))\n            return res;\n        } else {\n          set_pc(state.pal_base + IACV + 1);\n          return -1;\n        }\n      } else {\n\n        // handle D-stream access fault\n        state.exc_addr = state.current_pc;\n        state.fault_va = virt;\n        state.exc_sum = (u64)REG_1 << 8;\n\n        u32 opcode = I_GETOP(ins);\n        state.mm_stat =\n            ((opcode == 0x1b || opcode == 0x1f) ? opcode - 0x18 : opcode) << 4 |\n            (flags & ACCESS_WRITE) | ((flags & ACCESS_WRITE) ? 8 : 4);\n        if (state.pal_vms) {\n          if ((res = vmspal_ent_dfault(flags)))\n            return res;\n        } else {\n          set_pc(state.pal_base + DFAULT + 1);\n          return -1;\n        }\n      }\n    }\n  }\n\n  // No access violations or faults\n  // Return the converted address\n  *phys = state.tb[t][i].phys | (virt & state.tb[t][i].keep_mask);\n  if (asm_bit)\n    *asm_bit = state.tb[t][i].asm_bit ? true : false;\n\n#if defined(DEBUG_TB)\n  if (forreal)\n#if defined(IDB)\n    if (bTB_Debug)\n#endif\n      printf(\"phys: %\" PRIx64 \" - OK\\n\", *phys);\n#endif\n  return 0;\n}\n\n#define GH_0_MATCH U64(0x000007ffffffe000) /* <42:13> */\n#define GH_0_PHYS U64(0x00000fffffffe000)  /* <43:13> */\n#define GH_0_KEEP U64(0x0000000000001fff)  /* <12:0>  */\n\n#define GH_1_MATCH U64(0x000007ffffff0000)\n#define GH_1_PHYS U64(0x00000fffffff0000)\n#define GH_1_KEEP U64(0x000000000000ffff)\n#define GH_2_MATCH U64(0x000007fffff80000)\n#define GH_2_PHYS U64(0x00000ffffff80000)\n#define GH_2_KEEP U64(0x000000000007ffff)\n#define GH_3_MATCH U64(0x000007ffffc00000)\n#define GH_3_PHYS U64(0x00000fffffc00000)\n#define GH_3_KEEP U64(0x00000000003fffff)\n\n/**\n * \\brief Add translation-buffer entry\n *\n * Add a translation-buffer entry to one of the translation buffers.\n *\n * \\param virt    Virtual address.\n * \\param pte     Translation in DTB_PTE format (see add_tb_d).\n * \\param flags   ACCESS_EXEC determines which translation buffer to use.\n **/\nvoid CAlphaCPU::add_tb(u64 virt, u64 pte_phys, u64 pte_flags, int flags) {\n  int t = (flags & ACCESS_EXEC) ? 1 : 0;\n  int rw = (flags & ACCESS_WRITE) ? 1 : 0;\n  u64 match_mask = 0;\n  u64 keep_mask = 0;\n  u64 phys_mask = 0;\n  int i;\n  int asn = (flags & ACCESS_EXEC) ? state.asn : state.asn0;\n\n  switch (pte_flags & 0x60) // granularity hint\n  {\n  case 0:\n    match_mask = GH_0_MATCH;\n    phys_mask = GH_0_PHYS;\n    keep_mask = GH_0_KEEP;\n    break;\n\n  case 0x20:\n    match_mask = GH_1_MATCH;\n    phys_mask = GH_1_PHYS;\n    keep_mask = GH_1_KEEP;\n    break;\n\n  case 0x40:\n    match_mask = GH_2_MATCH;\n    phys_mask = GH_2_PHYS;\n    keep_mask = GH_2_KEEP;\n    break;\n\n  case 0x60:\n    match_mask = GH_3_MATCH;\n    phys_mask = GH_3_PHYS;\n    keep_mask = GH_3_KEEP;\n    break;\n  }\n\n  i = FindTBEntry(virt, flags);\n\n  if (i < 0) {\n    i = state.next_tb[t];\n    state.next_tb[t]++;\n    if (state.next_tb[t] == TB_ENTRIES)\n      state.next_tb[t] = 0;\n  }\n\n  state.tb[t][i].match_mask = match_mask;\n  state.tb[t][i].keep_mask = keep_mask;\n  state.tb[t][i].virt = virt & match_mask;\n  state.tb[t][i].phys = pte_phys & phys_mask;\n  state.tb[t][i].fault[0] = (int)pte_flags & 2;\n  state.tb[t][i].fault[1] = (int)pte_flags & 4;\n  state.tb[t][i].fault[2] = (int)pte_flags & 8;\n  state.tb[t][i].access[0][0] = (int)pte_flags & 0x100;\n  state.tb[t][i].access[1][0] = (int)pte_flags & 0x1000;\n  state.tb[t][i].access[0][1] = (int)pte_flags & 0x200;\n  state.tb[t][i].access[1][1] = (int)pte_flags & 0x2000;\n  state.tb[t][i].access[0][2] = (int)pte_flags & 0x400;\n  state.tb[t][i].access[1][2] = (int)pte_flags & 0x4000;\n  state.tb[t][i].access[0][3] = (int)pte_flags & 0x800;\n  state.tb[t][i].access[1][3] = (int)pte_flags & 0x8000;\n  state.tb[t][i].asm_bit = (int)pte_flags & 0x10;\n  state.tb[t][i].asn = asn;\n  state.tb[t][i].valid = true;\n  state.last_found_tb[t][rw] = i;\n\n#if defined(DEBUG_TB_)\n#if defined(IDB)\n  if (bTB_Debug)\n#endif\n  {\n    printf(\"Add TB---------------------------------------\\n\");\n    printf(\"Map VIRT    %016\" PRIx64 \"\\n\", state.tb[i].virt);\n    printf(\"Matching    %016\" PRIx64 \"\\n\", state.tb[i].match_mask);\n    printf(\"And keeping %016\" PRIx64 \"\\n\", state.tb[i].keep_mask);\n    printf(\"To PHYS     %016\" PRIx64 \"\\n\", state.tb[i].phys);\n    printf(\"Read : %c%c%c%c %c\\n\", state.tb[i].access[0][0] ? 'K' : '-',\n           state.tb[i].access[0][1] ? 'E' : '-',\n           state.tb[i].access[0][2] ? 'S' : '-',\n           state.tb[i].access[0][3] ? 'U' : '-',\n           state.tb[i].fault[0] ? 'F' : '-');\n    printf(\"Write: %c%c%c%c %c\\n\", state.tb[i].access[1][0] ? 'K' : '-',\n           state.tb[i].access[1][1] ? 'E' : '-',\n           state.tb[i].access[1][2] ? 'S' : '-',\n           state.tb[i].access[1][3] ? 'U' : '-',\n           state.tb[i].fault[1] ? 'F' : '-');\n    printf(\"Exec : %c%c%c%c %c\\n\", state.tb[i].access[1][0] ? 'K' : '-',\n           state.tb[i].access[1][1] ? 'E' : '-',\n           state.tb[i].access[1][2] ? 'S' : '-',\n           state.tb[i].access[1][3] ? 'U' : '-',\n           state.tb[i].fault[1] ? 'F' : '-');\n  }\n#endif\n}\n\n/**\n * \\brief Add translation-buffer entry to the DTB\n *\n * The format of the PTE field is:\n * \\code\n *   63 62           32 31     16  15  14  13  12  11  10  9   8  7 6  5  4  3\n *2   1  0\n *  +--+---------------+---------+---+---+---+---+---+---+---+---+-+----+---+-+---+---+-+\n *  |  |  PA <43:13>   |         |UWE|SWE|EWE|KWE|URE|SRE|ERE|KRE| | GH |ASM|\n *|FOW|FOR| |\n *  +--+---------------+---------+---+---+---+---+---+---+---+---+-+----+---+-+---+---+-+\n *                               +-------------------------------+    |   |\n *+-------+ |        |   |       |\n *  (user,supervisor,executive,kernel)(read,write)enable ----+        |   | |\n *                                              granularity hint -----+   | |\n *                                               address space match -----+ |\n *                                                      fault-on-(read,write)\n *----+ \\endcode\n *\n * \\param virt    Virtual address.\n * \\param pte     Translation in DTB_PTE format.\n **/\nvoid CAlphaCPU::add_tb_d(u64 virt, u64 pte) {\n  add_tb(virt, pte >> (32 - 13), pte, ACCESS_READ);\n}\n\n/**\n * \\brief Add translation-buffer entry to the ITB\n *\n * The format of the PTE field is:\n * \\code\n *   63              44 43           13 12  11  10  9   8  7 6  5  4  3   0\n *  +------------------+---------------+--+---+---+---+---+-+----+---+-----+\n *  |                  |  PA <43:13>   |  |URE|SRE|ERE|KRE| | GH |ASM|     |\n *  +------------------+---------------+--+---+---+---+---+-+----+---+-----+\n *                                        +---------------+    |   |\n *                                                    |        |   |\n *  (user,supervisor,executive,kernel)read enable ----+        |   |\n *                                       granularity hint -----+   |\n *                                        address space match -----+\n *\n * \\endcode\n *\n * \\param virt    Virtual address.\n * \\param pte     Translation in ITB_PTE format.\n **/\nvoid CAlphaCPU::add_tb_i(u64 virt, u64 pte) {\n  add_tb(virt, pte, pte & 0xf70, ACCESS_EXEC);\n}\n\n/**\n * \\brief Invalidate all translation-buffer entries\n *\n * Invalidate all translation-buffer entries in one of the translation buffers.\n *\n * \\param flags   ACCESS_EXEC determines which translation buffer to use.\n **/\nvoid CAlphaCPU::tbia(int flags) {\n  int t = (flags & ACCESS_EXEC) ? 1 : 0;\n  int i;\n  for (i = 0; i < TB_ENTRIES; i++)\n    state.tb[t][i].valid = false;\n  state.last_found_tb[t][0] = 0;\n  state.last_found_tb[t][1] = 0;\n  state.next_tb[t] = 0;\n}\n\n/**\n * \\brief Invalidate all process-specific translation-buffer entries\n *\n * Invalidate all translation-buffer entries that do not have the ASM bit\n * set in one of the translation buffers.\n *\n * \\param flags   ACCESS_EXEC determines which translation buffer to use.\n **/\nvoid CAlphaCPU::tbiap(int flags) {\n  int t = (flags & ACCESS_EXEC) ? 1 : 0;\n  int i;\n  for (i = 0; i < TB_ENTRIES; i++)\n    if (!state.tb[t][i].asm_bit)\n      state.tb[t][i].valid = false;\n}\n\n/**\n * \\brief Invalidate single translation-buffer entry\n *\n * \\param virt    Virtual address for which the entry should be invalidated.\n * \\param flags   ACCESS_EXEC determines which translation buffer to use.\n **/\nvoid CAlphaCPU::tbis(u64 virt, int flags) {\n  int t = (flags & ACCESS_EXEC) ? 1 : 0;\n  int i = FindTBEntry(virt, flags);\n  if (i >= 0)\n    state.tb[t][i].valid = false;\n}\n\n//\\}\n\n/**\n * \\brief Enable i-cache regardles of config file.\n *\n * Required for SRM-ROM decompression.\n **/\nvoid CAlphaCPU::enable_icache() { icache_enabled = true; }\n\n/**\n * \\brief Enable or disable i-cache depending on config file.\n **/\nvoid CAlphaCPU::restore_icache() {\n  bool newval;\n\n  newval = myCfg->get_bool_value(\"icache\", false);\n\n  if (!newval)\n    flush_icache();\n\n  icache_enabled = newval;\n}\n\n#if defined(IDB)\nconst char *PAL_NAME[] = {\n    \"HALT\",       \"CFLUSH\",     \"DRAINA\",     \"LDQP\",\n    \"STQP\",       \"SWPCTX\",     \"MFPR_ASN\",   \"MTPR_ASTEN\",\n    \"MTPR_ASTSR\", \"CSERVE\",     \"SWPPAL\",     \"MFPR_FEN\",\n    \"MTPR_FEN\",   \"MTPR_IPIR\",  \"MFPR_IPL\",   \"MTPR_IPL\",\n    \"MFPR_MCES\",  \"MTPR_MCES\",  \"MFPR_PCBB\",  \"MFPR_PRBR\",\n    \"MTPR_PRBR\",  \"MFPR_PTBR\",  \"MFPR_SCBB\",  \"MTPR_SCBB\",\n    \"MTPR_SIRR\",  \"MFPR_SISR\",  \"MFPR_TBCHK\", \"MTPR_TBIA\",\n    \"MTPR_TBIAP\", \"MTPR_TBIS\",  \"MFPR_ESP\",   \"MTPR_ESP\",\n    \"MFPR_SSP\",   \"MTPR_SSP\",   \"MFPR_USP\",   \"MTPR_USP\",\n    \"MTPR_TBISD\", \"MTPR_TBISI\", \"MFPR_ASTEN\", \"MFPR_ASTSR\",\n    \"28\",         \"MFPR_VPTB\",  \"MTPR_VPTB\",  \"MTPR_PERFMON\",\n    \"2C\",         \"2D\",         \"MTPR_DATFX\", \"2F\",\n    \"30\",         \"31\",         \"32\",         \"33\",\n    \"34\",         \"35\",         \"36\",         \"37\",\n    \"38\",         \"39\",         \"3A\",         \"3B\",\n    \"3C\",         \"3D\",         \"WTINT\",      \"MFPR_WHAMI\",\n    \"-\",          \"-\",          \"-\",          \"-\",\n    \"-\",          \"-\",          \"-\",          \"-\",\n    \"-\",          \"-\",          \"-\",          \"-\",\n    \"-\",          \"-\",          \"-\",          \"-\",\n    \"-\",          \"-\",          \"-\",          \"-\",\n    \"-\",          \"-\",          \"-\",          \"-\",\n    \"-\",          \"-\",          \"-\",          \"-\",\n    \"-\",          \"-\",          \"-\",          \"-\",\n    \"-\",          \"-\",          \"-\",          \"-\",\n    \"-\",          \"-\",          \"-\",          \"-\",\n    \"-\",          \"-\",          \"-\",          \"-\",\n    \"-\",          \"-\",          \"-\",          \"-\",\n    \"-\",          \"-\",          \"-\",          \"-\",\n    \"-\",          \"-\",          \"-\",          \"-\",\n    \"-\",          \"-\",          \"-\",          \"-\",\n    \"-\",          \"-\",          \"-\",          \"-\",\n    \"BPT\",        \"BUGCHK\",     \"CHME\",       \"CHMK\",\n    \"CHMS\",       \"CHMU\",       \"IMB\",        \"INSQHIL\",\n    \"INSQTIL\",    \"INSQHIQ\",    \"INSQTIQ\",    \"INSQUEL\",\n    \"INSQUEQ\",    \"INSQUEL/D\",  \"INSQUEQ/D\",  \"PROBER\",\n    \"PROBEW\",     \"RD_PS\",      \"REI\",        \"REMQHIL\",\n    \"REMQTIL\",    \"REMQHIQ\",    \"REMQTIQ\",    \"REMQUEL\",\n    \"REMQUEQ\",    \"REMQUEL/D\",  \"REMQUEQ/D\",  \"SWASTEN\",\n    \"WR_PS_SW\",   \"RSCC\",       \"READ_UNQ\",   \"WRITE_UNQ\",\n    \"AMOVRR\",     \"AMOVRM\",     \"INSQHILR\",   \"INSQTILR\",\n    \"INSQHIQR\",   \"INSQTIQR\",   \"REMQHILR\",   \"REMQTILR\",\n    \"REMQHIQR\",   \"REMQTIQR\",   \"GENTRAP\",    \"AB\",\n    \"AC\",         \"AD\",         \"CLRFEN\",     \"AF\",\n    \"B0\",         \"B1\",         \"B2\",         \"B3\",\n    \"B4\",         \"B5\",         \"B6\",         \"B7\",\n    \"B8\",         \"B9\",         \"BA\",         \"BB\",\n    \"BC\",         \"BD\",         \"BE\",         \"BF\"};\n\nconst char *IPR_NAME[] = {\n    \"ITB_TAG\",     \"ITB_PTE\",     \"ITB_IAP\",     \"ITB_IA\",       \"ITB_IS\",\n    \"PMPC\",        \"EXC_ADDR\",    \"IVA_FORM\",    \"IER_CM\",       \"CM\",\n    \"IER\",         \"IER_CM\",      \"SIRR\",        \"ISUM\",         \"HW_INT_CLR\",\n    \"EXC_SUM\",     \"PAL_BASE\",    \"I_CTL\",       \"IC_FLUSH_ASM\", \"IC_FLUSH\",\n    \"PCTR_CTL\",    \"CLR_MAP\",     \"I_STAT\",      \"SLEEP\",        \"?0001.1000?\",\n    \"?0001.1001?\", \"?0001.1010?\", \"?0001.1011?\", \"?0001.1100?\",  \"?0001.1101?\",\n    \"?0001.1110?\", \"?0001.1111?\", \"DTB_TAG0\",    \"DTB_PTE0\",     \"?0010.0010?\",\n    \"?0010.0011?\", \"DTB_IS0\",     \"DTB_ASN0\",    \"DTB_ALTMODE\",  \"MM_STAT\",\n    \"M_CTL\",       \"DC_CTL\",      \"DC_STAT\",     \"C_DATA\",       \"C_SHFT\",\n    \"M_FIX\",       \"?0010.1110?\", \"?0010.1111?\", \"?0011.0000?\",  \"?0011.0001?\",\n    \"?0011.0010?\", \"?0011.0011?\", \"?0011.0100?\", \"?0010.0101?\",  \"?0010.0110?\",\n    \"?0010.0111?\", \"?0011.1000?\", \"?0011.1001?\", \"?0011.1010?\",  \"?0011.1011?\",\n    \"?0011.1100?\", \"?0010.1101?\", \"?0010.1110?\", \"?0010.1111?\",  \"PCTX.00000\",\n    \"PCTX.00001\",  \"PCTX.00010\",  \"PCTX.00011\",  \"PCTX.00100\",   \"PCTX.00101\",\n    \"PCTX.00110\",  \"PCTX.00111\",  \"PCTX.01000\",  \"PCTX.01001\",   \"PCTX.01010\",\n    \"PCTX.01011\",  \"PCTX.01100\",  \"PCTX.01101\",  \"PCTX.01110\",   \"PCTX.01111\",\n    \"PCTX.10000\",  \"PCTX.10001\",  \"PCTX.10010\",  \"PCTX.10011\",   \"PCTX.10100\",\n    \"PCTX.10101\",  \"PCTX.10110\",  \"PCTX.10111\",  \"PCTX.11000\",   \"PCTX.11001\",\n    \"PCTX.11010\",  \"PCTX.11011\",  \"PCTX.11100\",  \"PCTX.11101\",   \"PCTX.11110\",\n    \"PCTX.11111\",  \"PCTX.00000\",  \"PCTX.00001\",  \"PCTX.00010\",   \"PCTX.00011\",\n    \"PCTX.00100\",  \"PCTX.00101\",  \"PCTX.00110\",  \"PCTX.00111\",   \"PCTX.01000\",\n    \"PCTX.01001\",  \"PCTX.01010\",  \"PCTX.01011\",  \"PCTX.01100\",   \"PCTX.01101\",\n    \"PCTX.01110\",  \"PCTX.01111\",  \"PCTX.10000\",  \"PCTX.10001\",   \"PCTX.10010\",\n    \"PCTX.10011\",  \"PCTX.10100\",  \"PCTX.10101\",  \"PCTX.10110\",   \"PCTX.10111\",\n    \"PCTX.11000\",  \"PCTX.11001\",  \"PCTX.11010\",  \"PCTX.11011\",   \"PCTX.11100\",\n    \"PCTX.11101\",  \"PCTX.11110\",  \"PCTX.11111\",  \"?1000.0000?\",  \"?1000.0001?\",\n    \"?1000.0010?\", \"?1000.0011?\", \"?1000.0100?\", \"?1000.0101?\",  \"?1000.0110?\",\n    \"?1000.0111?\", \"?1000.1000?\", \"?1000.1001?\", \"?1000.1010?\",  \"?1000.1011?\",\n    \"?1000.1100?\", \"?1000.1101?\", \"?1000.1110?\", \"?1000.1111?\",  \"?1001.0000?\",\n    \"?1001.0001?\", \"?1001.0010?\", \"?1001.0011?\", \"?1001.0100?\",  \"?1001.0101?\",\n    \"?1001.0110?\", \"?1001.0111?\", \"?1001.1000?\", \"?1001.1001?\",  \"?1001.1010?\",\n    \"?1001.1011?\", \"?1001.1100?\", \"?1001.1101?\", \"?1001.1110?\",  \"?1001.1111?\",\n    \"DTB_TAG1\",    \"DTB_PTE1\",    \"DTB_IAP\",     \"DTB_IA\",       \"DTB_IS1\",\n    \"DTB_ASN1\",    \"?1010.0110?\", \"?1010.0111?\", \"?1010.1000?\",  \"?1010.1001?\",\n    \"?1010.1010?\", \"?1010.1011?\", \"?1010.1100?\", \"?1010.1101?\",  \"?1010.1110?\",\n    \"?1010.1111?\", \"?1011.0000?\", \"?1011.0001?\", \"?1011.0010?\",  \"?1011.0011?\",\n    \"?1011.0100?\", \"?1011.0101?\", \"?1011.0110?\", \"?1011.0111?\",  \"?1011.1000?\",\n    \"?1011.1001?\", \"?1011.1010?\", \"?1011.1011?\", \"?1011.1100?\",  \"?1011.1101?\",\n    \"?1011.1110?\", \"?1011.1111?\", \"CC\",          \"CC_CTL\",       \"VA\",\n    \"VA_FORM\",     \"VA_CTL\",      \"?1100.0101?\", \"?1100.0110?\",  \"?1100.0111?\",\n    \"?1100.1000?\", \"?1100.1001?\", \"?1100.1010?\", \"?1100.1011?\",  \"?1100.1100?\",\n    \"?1100.1101?\", \"?1100.1110?\", \"?1100.1111?\", \"?1101.0000?\",  \"?1101.0001?\",\n    \"?1101.0010?\", \"?1101.0011?\", \"?1101.0100?\", \"?1101.0101?\",  \"?1101.0110?\",\n    \"?1101.0111?\", \"?1101.1000?\", \"?1101.1001?\", \"?1101.1010?\",  \"?1101.1011?\",\n    \"?1101.1100?\", \"?1101.1101?\", \"?1101.1110?\", \"?1101.1111?\",  \"?1110.0000?\",\n    \"?1110.0001?\", \"?1110.0010?\", \"?1110.0011?\", \"?1110.0100?\",  \"?1110.0101?\",\n    \"?1110.0110?\", \"?1110.0111?\", \"?1110.1000?\", \"?1110.1001?\",  \"?1110.1010?\",\n    \"?1110.1011?\", \"?1110.1100?\", \"?1110.1101?\", \"?1110.1110?\",  \"?1110.1111?\",\n    \"?1111.0000?\", \"?1111.0001?\", \"?1111.0010?\", \"?1111.0011?\",  \"?1111.0100?\",\n    \"?1111.0101?\", \"?1111.0110?\", \"?1111.0111?\", \"?1111.1000?\",  \"?1111.1001?\",\n    \"?1111.1010?\", \"?1111.1011?\", \"?1111.1100?\", \"?1111.1101?\",  \"?1111.1110?\",\n    \"?1111.1111?\",\n};\n#endif\n"
  },
  {
    "path": "src/AlphaCPU.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified\n * of, and receiving any modifications you may make to the source code that\n * might serve the general public.\n */\n\n#if !defined(INCLUDED_ALPHACPU_H)\n#define INCLUDED_ALPHACPU_H\n\n#include \"System.hpp\"\n#include \"SystemComponent.hpp\"\n#include \"cpu_defs.hpp\"\n\n/// Number of entries in the Instruction Cache\n#define ICACHE_ENTRIES 1024\n// Size of Instruction Cache entries in DWORDS (instructions)\n#define ICACHE_LINE_SIZE 512\n/** These bits should match to have an Instruction Cache hit.\n    This includes bit 0, because it indicates PALmode . */\n#define ICACHE_MATCH_MASK (u64)(U64(0x1) - (ICACHE_LINE_SIZE * 4))\n/// DWORD (instruction) number of an address in an ICache entry.\n#define ICACHE_INDEX_MASK (u64)(ICACHE_LINE_SIZE - U64(0x1))\n/// Byte numer of an address in an ICache entry.\n#define ICACHE_BYTE_MASK (u64)(ICACHE_INDEX_MASK << 2)\n/// Number of entries in each Translation Buffer\n#define TB_ENTRIES 16\n\n/**\n * \\brief Emulated CPU.\n *\n * The CPU emulated is the DECchip 21264CB Alpha Processor (EV68).\n *\n * Documentation consulted:\n *  - Alpha 21264/EV68CB and 21264/EV68DC Microprocessor Hardware Reference\n *Manual [HRM] (http://download.majix.org/dec/21264ev68cb_ev68dc_hrm.pdf)\n *  - DS-0026A-TE: Alpha 21264B Microprocessor Hardware Reference Manual [HRM]\n *(http://ftp.digital.com/pub/Digital/info/semiconductor/literature/21264hrm.pdf)\n *  - Alpha Architecture Reference Manual, fourth edition [ARM]\n *(http://download.majix.org/dec/alpha_arch_ref.pdf)\n *\t.\n **/\nclass CAlphaCPU : public CSystemComponent {\npublic:\n  void flush_icache_asm();\n  virtual int SaveState(FILE *f);\n  virtual int RestoreState(FILE *f);\n  void irq_h(int number, bool assert, int delay);\n  int get_cpuid();\n  void flush_icache();\n\n  void run();\n  void execute();\n  void release_threads();\n\n  void set_PAL_BASE(u64 pb);\n  virtual void check_state();\n  CAlphaCPU(CConfigurator *cfg, CSystem *system);\n  virtual ~CAlphaCPU();\n  u64 get_r(int i, bool translate);\n  u64 get_f(int i);\n  void set_r(int reg, u64 val);\n  void set_f(int reg, u64 val);\n  u64 get_prbr(void);\n  u64 get_hwpcb(void);\n  u64 get_pc();\n  u64 get_pal_base();\n\n  void enable_icache();\n  void restore_icache();\n\n  bool get_waiting() { return state.wait_for_start; };\n  void stop_waiting() { state.wait_for_start = false; };\n#ifdef IDB\n  u64 get_current_pc_physical();\n  u64 get_instruction_count();\n  u32 get_last_instruction();\n  u64 get_last_read_loc() { return last_read_loc; }\n  u64 get_last_write_loc() { return last_write_loc; }\n#endif\n  u64 get_clean_pc();\n  void next_pc();\n  void set_pc(u64 p_pc);\n  void add_pc(u64 a_pc);\n\n  u64 get_speed() { return cpu_hz; };\n\n  u64 va_form(u64 address, bool bIBOX);\n\n#if defined(IDB)\n  void listing(u64 from, u64 to);\n  void listing(u64 from, u64 to, u64 mark);\n#endif\n  int virt2phys(u64 virt, u64 *phys, int flags, bool *asm_bit, u32 instruction);\n\n  virtual void init();\n  virtual void start_threads();\n  virtual void stop_threads();\n\nprivate:\n  std::unique_ptr<std::thread> myThread;\n  std::atomic_bool myThreadDead{false};\n  CSemaphore mySemaphore;\n  bool StopThread;\n\n  int get_icache(u64 address, u32 *data);\n  int FindTBEntry(u64 virt, int flags);\n  void add_tb(u64 virt, u64 pte_phys, u64 pte_flags, int flags);\n  void add_tb_i(u64 virt, u64 pte);\n  void add_tb_d(u64 virt, u64 pte);\n  void tbia(int flags);\n  void tbiap(int flags);\n  void tbis(u64 virt, int flags);\n\n  /* Floating Point routines */\n  u64 ieee_lds(u32 op);\n  u32 ieee_sts(u64 op);\n  u64 ieee_cvtst(u64 op, u32 ins);\n  u64 ieee_cvtts(u64 op, u32 ins);\n  s32 ieee_fcmp(u64 s1, u64 s2, u32 ins, u32 trap_nan);\n  u64 ieee_cvtif(u64 val, u32 ins, u32 dp);\n  u64 ieee_cvtfi(u64 op, u32 ins);\n  u64 ieee_fadd(u64 s1, u64 s2, u32 ins, u32 dp, bool sub);\n  u64 ieee_fmul(u64 s1, u64 s2, u32 ins, u32 dp);\n  u64 ieee_fdiv(u64 s1, u64 s2, u32 ins, u32 dp);\n  u64 ieee_sqrt(u64 op, u32 ins, u32 dp);\n  int ieee_unpack(u64 op, UFP *r, u32 ins);\n  void ieee_norm(UFP *r);\n  u64 ieee_rpack(UFP *r, u32 ins, u32 dp);\n  void ieee_trap(u64 trap, u32 instenb, u64 fpcrdsb, u32 ins);\n  u64 vax_ldf(u32 op);\n  u64 vax_ldg(u64 op);\n  u32 vax_stf(u64 op);\n  u64 vax_stg(u64 op);\n  void vax_trap(u64 mask, u32 ins);\n  void vax_unpack(u64 op, UFP *r, u32 ins);\n  void vax_unpack_d(u64 op, UFP *r, u32 ins);\n  void vax_norm(UFP *r);\n  u64 vax_rpack(UFP *r, u32 ins, u32 dp);\n  u64 vax_rpack_d(UFP *r, u32 ins);\n  int vax_fcmp(u64 s1, u64 s2, u32 ins);\n  u64 vax_cvtif(u64 val, u32 ins, u32 dp);\n  u64 vax_cvtfi(u64 op, u32 ins);\n  u64 vax_fadd(u64 s1, u64 s2, u32 ins, u32 dp, bool sub);\n  u64 vax_fmul(u64 s1, u64 s2, u32 ins, u32 dp);\n  u64 vax_fdiv(u64 s1, u64 s2, u32 ins, u32 dp);\n  u64 vax_sqrt(u64 op, u32 ins, u32 dp);\n\n  /* VMS PALcode call: */\n  void vmspal_call_cflush();\n  void vmspal_call_draina();\n  void vmspal_call_ldqp();\n  void vmspal_call_stqp();\n  void vmspal_call_swpctx();\n  void vmspal_call_mfpr_asn();\n  void vmspal_call_mtpr_asten();\n  void vmspal_call_mtpr_astsr();\n  void vmspal_call_cserve();\n  void vmspal_call_mfpr_fen();\n  void vmspal_call_mtpr_fen();\n  void vmspal_call_mfpr_ipl();\n  void vmspal_call_mtpr_ipl();\n  void vmspal_call_mfpr_mces();\n  void vmspal_call_mtpr_mces();\n  void vmspal_call_mfpr_pcbb();\n  void vmspal_call_mfpr_prbr();\n  void vmspal_call_mtpr_prbr();\n  void vmspal_call_mfpr_ptbr();\n  void vmspal_call_mfpr_scbb();\n  void vmspal_call_mtpr_scbb();\n  void vmspal_call_mtpr_sirr();\n  void vmspal_call_mfpr_sisr();\n  void vmspal_call_mfpr_tbchk();\n  void vmspal_call_mtpr_tbia();\n  void vmspal_call_mtpr_tbiap();\n  void vmspal_call_mtpr_tbis();\n  void vmspal_call_mfpr_esp();\n  void vmspal_call_mtpr_esp();\n  void vmspal_call_mfpr_ssp();\n  void vmspal_call_mtpr_ssp();\n  void vmspal_call_mfpr_usp();\n  void vmspal_call_mtpr_usp();\n  void vmspal_call_mtpr_tbisd();\n  void vmspal_call_mtpr_tbisi();\n  void vmspal_call_mfpr_asten();\n  void vmspal_call_mfpr_astsr();\n  void vmspal_call_mfpr_vptb();\n  void vmspal_call_mtpr_datfx();\n  void vmspal_call_mfpr_whami();\n  void vmspal_call_imb();\n  void vmspal_call_prober();\n  void vmspal_call_probew();\n  void vmspal_call_rd_ps();\n  int vmspal_call_rei();\n  void vmspal_call_swasten();\n  void vmspal_call_wr_ps_sw();\n  void vmspal_call_rscc();\n  void vmspal_call_read_unq();\n  void vmspal_call_write_unq();\n\n  /* VMS PALcode entry: */\n  int vmspal_ent_dtbm_double_3(int flags);\n  int vmspal_ent_dtbm_single(int flags);\n  int vmspal_ent_itbm(int flags);\n  int vmspal_ent_iacv(int flags);\n  int vmspal_ent_dfault(int flags);\n  int vmspal_ent_ext_int(int ei);\n  int vmspal_ent_sw_int(int si);\n  int vmspal_ent_ast_int(int ast);\n\n  /* VMS PALcode internal: */\n  int vmspal_int_initiate_exception();\n  int vmspal_int_initiate_interrupt();\n\n  bool icache_enabled;\n  bool skip_memtest_hack;\n  int skip_memtest_counter;\n\n  // ... ... ...\n  u64 cc_large;\n  u64 start_icount;\n  u64 start_cc;\n  CTimestamp start_time;\n  u64 prev_icount;\n  u64 prev_cc;\n  u64 prev_time;\n  u64 cc_per_instruction;\n  u64 ins_per_timer_int;\n  u64 next_timer_int;\n  u64 cpu_hz;\n\n  /// The state structure contains all elements that need to be saved to the\n  /// statefile\n  struct SCPU_state {\n    bool wait_for_start;\n    u64 pal_base; /**< IPR PAL_BASE [HRM: p 5-15] */\n    u64 pc;       /**< Program counter */\n    u64 cc;       /**< IPR CC: Cycle counter [HRM p 5-3] */\n    u64 r[64];    /**< Integer registers (0-31 normal, 32-63 shadow) */\n    u64 dc_stat;  /**< IPR DC_STAT: Dcache status [HRM p 5-31..32] */\n    bool ppcen; /**< IPR PCTX: ppce (proc perf counting enable) [HRM p 5-21..23]\n                 */\n    u64 i_stat; /**< IPR I_STAT: Ibox status [HRM p 5-18..20] */\n    u64 pctr_ctl;  /**< IPR PCTR_CTL [HRM p 5-23..25] */\n    bool cc_ena;   /**< IPR CC_CTL: Cycle counter enabled [HRM p 5-3] */\n    u32 cc_offset; /**< IPR CC: Cycle counter offset [HRM p 5-3] */\n    u64 dc_ctl;    /**< IPR DC_CTL: Dcache control [HRM p 5-30..31] */\n    int alt_cm;    /**< IPR DTB_ALTMODE: alternative cm for HW_LD/HW_ST [HRM p\n                      5-26..27] */\n    int smc; /**< IPR M_CTL: smc (speculative miss control) [HRM p 5-29..30] */\n    bool fpen;    /**< IPR PCTX: fpe (floating point enable) [HRM p 5-21..23] */\n    bool sde;     /**< IPR I_CTL: sde[1] (PALshadow enable) [HRM p 5-15..18] */\n    u64 fault_va; /**< IPR VA: virtual address of last Dstream miss or fault\n                     [HRM p 5-4] */\n    u64 exc_sum;  /**< IPR EXC_SUM: exception summary [HRM p 5-13..15] */\n    int i_ctl_va_mode;  /**< IPR I_CTL: (va_form_32 + va_48) [HRM p 5-15..17] */\n    int va_ctl_va_mode; /**< IPR VA_CTL: (va_form_32 + va_48) [HRM p 5-4] */\n    u64 i_ctl_vptb;     /**< IPR I_CTL: vptb (virtual page table base) [HRM p\n                           5-15..16] */\n    u64 va_ctl_vptb; /**< IPR VA_CTL: vptb (virtual page table base) [HRM p 5-4]\n                      */\n    int cm;          /**< IPR IER_CM: cm (current mode) [HRM p 5-9..10] */\n    int asn;   /**< IPR PCTX: asn (address space number) [HRM p 5-21..22] */\n    int asn0;  /**< IPR DTB_ASN0: asn (address space number) [HRM p 5-28] */\n    int asn1;  /**< IPR DTB_ASN1: asn (address space number) [HRM p 5-28] */\n    int eien;  /**< IPR IER_CM: eien (external interrupt enable) [HRM p 5-9..10]\n                */\n    int slen;  /**< IPR IER_CM: slen (serial line interrupt enable) [HRM p\n                  5-9..10] */\n    int cren;  /**< IPR IER_CM: cren (corrected read error int enable) [HRM p\n                  5-9..10] */\n    int pcen;  /**< IPR IER_CM: pcen (perf counter interrupt enable) [HRM p\n                  5-9..10] */\n    int sien;  /**< IPR IER_CM: sien (software interrupt enable) [HRM p 5-9..10]\n                */\n    int asten; /**< IPR IER_CM: asten (AST interrupt enable) [HRM p 5-9..10] */\n    int sir; /**< IPR SIRR: sir (software interrupt request) [HRM p 5-10..11] */\n    int eir; /**< external interrupt request */\n    int slr; /**< serial line interrupt request */\n    int crr; /**< corrected read error interrupt */\n    int pcr; /**< perf counter interrupt */\n    int astrr;       /**< IPR PCTX: astrr (AST request) [HRM p 5-21..22] */\n    int aster;       /**< IPR PCTX: aster (AST enable) [HRM p 5-21..22] */\n    u64 i_ctl_other; /**< various bits in IPR I_CTL that have no meaning to the\n                        emulator */\n    u64 mm_stat; /**< IPR MM_STAT: memory management status [HRM p 5-28..29] */\n    bool hwe;    /**< IPR I_CLT: hwe (allow palmode ins in kernel mode) [HRM p\n                    5-15..17] */\n    int m_ctl_spe; /**< IPR M_CTL: spe (Super Page mode enabled) [HRM p\n                      5-29..30] */\n    int i_ctl_spe; /**< IPR I_CTL: spe (Super Page mode enabled) [HRM p\n                      5-15..18] */\n    u64 exc_addr;  /**< IPR EXC_ADDR: address of last exception [HRM p 5-8] */\n    u64 pmpc;\n    u64 fpcr; /**< Floating-Point Control Register [HRM p 2-36] */\n    bool bIntrFlag;\n    u64 current_pc; /**< Virtual address of current instruction */\n\n    /**\n     * \\brief Instruction cache entry.\n     *\n     * An instruction cache entry contains the address and address space number\n     * (ASN) + 16 32-bit instructions. [HRM 2-11]\n     **/\n    struct SICache {\n      int asn;                    /**< Address Space Number */\n      u32 data[ICACHE_LINE_SIZE]; /**< Actual cached instructions  */\n      u64 address;                /**< Address of first instruction */\n      u64 p_address;              /**< Physical address of first instruction */\n      bool asm_bit;               /**< Address Space Match bit */\n      bool valid;                 /**< Valid cache entry */\n    } icache[ICACHE_ENTRIES];     /**< Instruction cache entries [HRM p 2-11] */\n    int next_icache;              /**< Number of next cache entry to use */\n    int last_found_icache;        /**< Number of last cache entry found */\n\n    /**\n     * \\brief Translation Buffer Entry.\n     *\n     * A translation buffer entry provides the mapping from a page of virtual\n     *memory to a page of physical memory.\n     **/\n    struct STBEntry {\n      u64 virt;       /**< Virtual address of page*/\n      u64 phys;       /**< Physical address of page*/\n      u64 match_mask; /**< The virtual address has to match for these bits to be\n                         a hit*/\n      u64 keep_mask;  /**< This part of the virtual address is OR-ed with the\n                         phys address*/\n      int asn;        /**< Address Space Number*/\n      int asm_bit;    /**< Address Space Match bit*/\n      int access[2][4];  /**< Access permitted [read/write][current mode]*/\n      int fault[3];      /**< Fault on access [read/write/execute]*/\n      bool valid;        /**< Valid entry*/\n    } tb[2][TB_ENTRIES]; /**< Translation buffer entries */\n\n    int next_tb[2]; /**< Number of next translation buffer entry to use */\n    int last_found_tb[2]\n                     [2]; /**< Number of last translation buffer entry found */\n    u32 rem_ins_in_page;  /**< Number of instructions remaining in current page\n                           */\n    u64 pc_phys;\n    u64 f[64];    /**< Floating point registers (0-31 normal, 32-63 shadow) */\n    int iProcNum; /**< number of the current processor (0 in a 1-processor\n                     system) */\n    u64 instruction_count; /**< Number of times doclock has been called */\n    u64 last_tb_virt;\n    bool pal_vms; /**< True if the PALcode base is 0x8000 (=VMS PALcode base) */\n    bool check_int;     /**< True if an interrupt may be pending */\n    int irq_h_timer[6]; /**< Timers for delayed IRQ_H[0:5] assertion */\n    bool check_timers;\n  } state; /**< Determines CPU state that needs to be saved to the state file */\n\n#ifdef IDB\n  u64 current_pc_physical; /**< Physical address of current instruction */\n  u32 last_instruction;\n  u64 last_read_loc;\n  u64 last_write_loc;\n#endif\n\n  void skip_memtest();\n};\n\n/** Translate raw register (0..31) number to a number that takes PALshadow\n    registers into consideration (0..63). Considers the program counter\n    (to determine if we're in PALmode), and the SDE (Shadow Enable) bit. */\n#define RREG(a)                                                                \\\n  (((a)&0x1f) + (((state.pc & 1) && (((a)&0xc) == 0x4) && state.sde) ? 32 : 0))\n\n/**\n * Empty the instruction cache.\n **/\ninline void CAlphaCPU::flush_icache() {\n  if (icache_enabled) {\n\n    //  memset(state.icache,0,sizeof(state.icache));\n    int i;\n    for (i = 0; i < ICACHE_ENTRIES; i++) {\n      state.icache[i].valid = false;\n\n      //    state.icache[i].asm_bit = true;\n    }\n\n    state.next_icache = 0;\n    state.last_found_icache = 0;\n  }\n}\n\n/**\n * Empty the instruction cache of lines with the ASM bit clear.\n **/\ninline void CAlphaCPU::flush_icache_asm() {\n  if (icache_enabled) {\n    int i;\n    for (i = 0; i < ICACHE_ENTRIES; i++)\n      if (!state.icache[i].asm_bit)\n        state.icache[i].valid = false;\n  }\n}\n\n/**\n * Set the PALcode BASE register, and determine whether we're running VMS\n *PALcode.\n **/\ninline void CAlphaCPU::set_PAL_BASE(u64 pb) {\n  state.pal_base = pb;\n  state.pal_vms = (pb == U64(0x8000));\n}\n\n/**\n * Get an instruction from the instruction cache.\n * If necessary, fill a new cache block from memory.\n *\n * get_icache checks all cache entries, to see if there is a\n * cache entry that matches the current address space number,\n * and that contains the address we're looking for. If it\n * exists, the instruction is fetched from this cache,\n * otherwise, the physical address for the instruction is\n * calculated, and the cache block is filled.\n *\n * The last cache entry that was a hit is remembered, so that\n * cache entry is checked first on the next instruction. (very\n * likely to be the same cache block)\n *\n * It would be easiest to do without the instruction cache\n * altogether, but unfortunately SRM uses self-modifying\n * code, that relies on the correct instruction stream to\n * remain in the cache.\n **/\ninline int CAlphaCPU::get_icache(u64 address, u32 *data) {\n  int i = state.last_found_icache;\n  u64 v_a;\n  u64 p_a;\n  int result;\n  bool asm_bit;\n\n  if (icache_enabled) {\n    if (state.icache[i].valid &&\n        (state.icache[i].asn == state.asn || state.icache[i].asm_bit) &&\n        state.icache[i].address == (address & ICACHE_MATCH_MASK)) {\n      *data =\n          endian_32(state.icache[i].data[(address >> 2) & ICACHE_INDEX_MASK]);\n#ifdef IDB\n      current_pc_physical =\n          state.icache[i].p_address + (address & ICACHE_BYTE_MASK);\n#endif\n      return 0;\n    }\n\n    for (i = 0; i < ICACHE_ENTRIES; i++) {\n      if (state.icache[i].valid &&\n          (state.icache[i].asn == state.asn || state.icache[i].asm_bit) &&\n          state.icache[i].address == (address & ICACHE_MATCH_MASK)) {\n        state.last_found_icache = i;\n        *data =\n            endian_32(state.icache[i].data[(address >> 2) & ICACHE_INDEX_MASK]);\n\n#ifdef IDB\n        current_pc_physical =\n            state.icache[i].p_address + (address & ICACHE_BYTE_MASK);\n#endif\n        return 0;\n      }\n    }\n\n    v_a = address & ICACHE_MATCH_MASK;\n\n    if (address & 1) {\n      p_a = v_a & ~U64(0x1);\n      asm_bit = true;\n    } else {\n      result = virt2phys(v_a, &p_a, ACCESS_EXEC, &asm_bit, 0);\n      if (result)\n        return result;\n    }\n\n    memcpy(state.icache[state.next_icache].data, cSystem->PtrToMem(p_a),\n           ICACHE_LINE_SIZE * 4);\n\n    state.icache[state.next_icache].valid = true;\n    state.icache[state.next_icache].asn = state.asn;\n    state.icache[state.next_icache].asm_bit = asm_bit;\n    state.icache[state.next_icache].address = address & ICACHE_MATCH_MASK;\n    state.icache[state.next_icache].p_address = p_a;\n\n    *data = endian_32(state.icache[state.next_icache]\n                          .data[(address >> 2) & ICACHE_INDEX_MASK]);\n\n#ifdef IDB\n    current_pc_physical = state.icache[state.next_icache].p_address +\n                          (address & ICACHE_BYTE_MASK);\n#endif\n    state.last_found_icache = state.next_icache;\n    state.next_icache++;\n    if (state.next_icache == ICACHE_ENTRIES)\n      state.next_icache = 0;\n    return 0;\n  }\n\n  // icache disabled\n  if (address & 1) {\n    state.pc_phys = address & ~U64(0x3);\n    state.rem_ins_in_page = 1;\n  } else {\n    if (!state.rem_ins_in_page) {\n      result = virt2phys(address, &state.pc_phys, ACCESS_EXEC, &asm_bit, 0);\n      if (result)\n        return result;\n      state.rem_ins_in_page = 2048 - ((((u32)address) >> 2) & 2047);\n    }\n  }\n\n  *data = (u32)cSystem->ReadMem(state.pc_phys, 32, this);\n  return 0;\n}\n\n/**\n * Convert a virtual address to va_form format.\n * Used for IPR VA_FORM [HRM 5-5..6] and IPR IVA_FORM [HRM 5-9].\n **/\ninline u64 CAlphaCPU::va_form(u64 address, bool bIBOX) {\n  switch (bIBOX ? state.i_ctl_va_mode : state.va_ctl_va_mode) {\n  case 0:\n    return ((bIBOX ? state.i_ctl_vptb : state.va_ctl_vptb) &\n            U64(0xfffffffe00000000)) |\n           ((address >> 10) & U64(0x00000001fffffff8));\n\n  case 1:\n    return ((bIBOX ? state.i_ctl_vptb : state.va_ctl_vptb) &\n            U64(0xfffff80000000000)) |\n           ((address >> 10) & U64(0x0000003ffffffff8)) |\n           (((address >> 10) & U64(0x0000002000000000)) * U64(0x3e));\n\n  case 2:\n    return ((bIBOX ? state.i_ctl_vptb : state.va_ctl_vptb) &\n            U64(0xffffffffc0000000)) |\n           ((address >> 10) & U64(0x00000000003ffff8));\n  }\n\n  return 0;\n}\n\n/**\n * Return processor number.\n **/\ninline int CAlphaCPU::get_cpuid() { return state.iProcNum; }\n\n/**\n * Assert or release an external interrupt line to the cpu.\n **/\ninline void CAlphaCPU::irq_h(int number, bool assert, int delay) {\n  bool active = (state.eir & (U64(0x1) << number)) || state.irq_h_timer[number];\n  if (assert && !active) {\n    if (delay) {\n      state.irq_h_timer[number] = delay;\n      state.check_timers = true;\n    } else {\n      state.eir |= (U64(0x1) << number);\n      state.check_int = true;\n    }\n\n    return;\n  }\n\n  if (!assert && active) {\n    state.eir &= ~(U64(0x1) << number);\n    state.irq_h_timer[number] = 0;\n    state.check_timers = false;\n    for (int i = 0; i < 6; i++) {\n      if (state.irq_h_timer[i])\n        state.check_timers = true;\n    }\n  }\n}\n\n/**\n * Return program counter value.\n **/\ninline u64 CAlphaCPU::get_pc() { return state.pc; }\n\n#ifdef IDB\n\n/**\n * Return the physical address the program counter refers to.\n **/\ninline u64 CAlphaCPU::get_current_pc_physical() { return state.pc_phys; }\n#endif\n\n/**\n * Return program counter value without PALmode bit.\n **/\ninline u64 CAlphaCPU::get_clean_pc() { return state.pc & ~U64(0x3); }\n\n/**\n * Jump to next instruction\n **/\ninline void CAlphaCPU::next_pc() {\n  state.pc += 4;\n  state.pc_phys += 4;\n  if (state.rem_ins_in_page)\n    state.rem_ins_in_page--;\n}\n\n/**\n * Set program counter to a certain value.\n **/\ninline void CAlphaCPU::set_pc(u64 p_pc) {\n  state.pc = p_pc;\n  state.rem_ins_in_page = 0;\n}\n\n/**\n * Add  value to the program counter.\n **/\ninline void CAlphaCPU::add_pc(u64 a_pc) {\n  state.pc += a_pc;\n  state.rem_ins_in_page = 0;\n}\n\n/**\n * Get a register value.\n * If \\a translate is true, use shadow registers if currently enabled.\n **/\ninline u64 CAlphaCPU::get_r(int i, bool translate) {\n  if (translate)\n    return state.r[RREG(i)];\n  else\n    return state.r[i];\n}\n\n/**\n * Get a fp register value.\n **/\ninline u64 CAlphaCPU::get_f(int i) { return state.f[i]; }\n\n/**\n * Set a register value\n **/\ninline void CAlphaCPU::set_r(int reg, u64 value) { state.r[reg] = value; }\n\n/**\n * Set a fp register value\n **/\ninline void CAlphaCPU::set_f(int reg, u64 value) { state.f[reg] = value; }\n\n/**\n * Get the PALcode base register.\n **/\ninline u64 CAlphaCPU::get_pal_base() { return state.pal_base; }\n\n/**\n * Get the processor base register.\n * A bit fuzzy...\n **/\ninline u64 CAlphaCPU::get_prbr(void) {\n  u64 v_prbr; // virtual\n  u64 p_prbr; // physical\n  bool b;\n  if (state.r[21 + 32] && ((u64)(state.r[21 + 32] + 0xaf) <\n                           (u64)((U64(0x1) << cSystem->get_memory_bits()))))\n    v_prbr = cSystem->ReadMem(state.r[21 + 32] + 0xa8, 64, this);\n  else\n    v_prbr = cSystem->ReadMem(0x70a8 + (0x200 * get_cpuid()), 64, this);\n  if (virt2phys(v_prbr, &p_prbr, ACCESS_READ | FAKE | NO_CHECK, &b, 0))\n    p_prbr = v_prbr;\n  if ((u64)p_prbr > (u64)(U64(0x1) << cSystem->get_memory_bits()))\n    p_prbr = 0;\n  return p_prbr;\n}\n\n/**\n * Get the hardware process control block address.\n **/\ninline u64 CAlphaCPU::get_hwpcb(void) {\n  u64 v_pcb; // virtual\n  u64 p_pcb; // physical\n  bool b;\n  if (state.r[21 + 32] && ((u64)(state.r[21 + 32] + 0x17) <\n                           (u64)((U64(0x1) << cSystem->get_memory_bits()))))\n    v_pcb = cSystem->ReadMem(state.r[21 + 32] + 0x10, 64, this);\n  else\n    v_pcb = cSystem->ReadMem(0x7010 + (0x200 * get_cpuid()), 64, this);\n  if (virt2phys(v_pcb, &p_pcb, ACCESS_READ | NO_CHECK | FAKE, &b, 0))\n    p_pcb = v_pcb;\n  if (p_pcb > (u64)(U64(0x1) << cSystem->get_memory_bits()))\n    p_pcb = 0;\n  return p_pcb;\n}\n\n#if defined(IDB)\n/**\n * Return the last instruction executed.\n **/\ninline u32 CAlphaCPU::get_last_instruction(void) { return last_instruction; }\n#endif\nextern bool bTB_Debug;\n#endif // !defined(INCLUDED_ALPHACPU_H)\n"
  },
  {
    "path": "src/AlphaCPU_ieeefloat.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n/* Copyright notice from SimH/alpha/alpha_fpi.c:\n\n   Copyright (c) 2003-2006, Robert M Supnik\n\n   Permission is hereby granted, free of charge, to any person obtaining a\n   copy of this software and associated documentation files (the \"Software\"),\n   to deal in the Software without restriction, including without limitation\n   the rights to use, copy, modify, merge, publish, distribute, sublicense,\n   and/or sell copies of the Software, and to permit persons to whom the\n   Software is furnished to do so, subject to the following conditions:\n\n   The above copyright notice and this permission notice shall be included in\n   all copies or substantial portions of the Software.\n\n   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\n   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n   Except as contained in this notice, the name of Robert M Supnik shall not be\n   used in advertising or otherwise to promote the sale, use or other dealings\n   in this Software without prior written authorization from Robert M Supnik.\n\n   Portions of this module (specifically, the convert floating to integer\n   routine and the square root routine) are a derivative work from SoftFloat,\n   written by John Hauser.  SoftFloat includes the following license terms:\n\n   Written by John R. Hauser.  This work was made possible in part by the\n   International Computer Science Institute, located at Suite 600, 1947 Center\n   Street, Berkeley, California 94704.  Funding was partially provided by the\n   National Science Foundation under grant MIP-9311980.  The original version\n   of this code was written as part of a project to build a fixed-point vector\n   processor in collaboration with the University of California at Berkeley,\n   overseen by Profs. Nelson Morgan and John Wawrzynek.  More information\n   is available through the Web page 'http://www.cs.berkeley.edu/~jhauser/\n   arithmetic/SoftFloat.html'.\n\n   THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort has\n   been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES\n   RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS\n   AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,\n   COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE\n   EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE\n   INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR\n   OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.\n\n   Derivative works are acceptable, even for commercial purposes, so long as\n   (1) the source code for the derivative work includes prominent notice that\n   the work is derivative, and (2) the source code includes prominent notice with\n   these four paragraphs for those parts of this code that are retained.\n*/\n\n#include \"AlphaCPU.hpp\"\n#include \"StdAfx.hpp\"\n#include \"cpu_debug.hpp\"\n\n/***************************************************************************/\n\n/**\n * \\page IEEE IEEE floating point arithmetic\n *\n * \\section IEEE_fmt IEEE Floating-point formats\n * The Alpha processor supports two different floating-point formats; S- and T-\n * floating formats.\n *\n * \\subsection IEEE_S S-Floating\n * An IEEE single precision, or S-Floating, is a 32-bit floating point value.\n * In memory, it's layout is as follows:\n * \\code\n *     31 30      23 22                      0\n *   +---+----------+-------------------------+\n *   | S | Exponent |         Fraction        |\n *   +---+----------+-------------------------+\n * \\endcode\n *\n * In the floating point registers, the S-Floating is left-justified to occupy\n * 64 bits:\n * \\code\n *     63 62          52 51                     29 28                   0\n *   +---+--------------+-------------------------+----------------------+\n *   | S |    Exponent  |         Fraction        |            0         |\n *   +---+--------------+-------------------------+----------------------+\n * \\endcode\n *\n * The exponent is mapped from the 8-bit memory-format exponent to the 11-bit\n * register-format as follows:\n * \\code\n *  +----------------+------------------+--------------------------------+\n *  | Memory <30:23> | Register <62:52> | Meaning                        |\n *  +----------------+------------------+--------------------------------+\n *  |      1 1111111 |    1 111 1111111 | frac <> 0: NaN (not-a-number)  |\n *  |                |                  | frac == 0: +/- Infinity        |\n *  +----------------+------------------+--------------------------------+\n *  |      1 xxxxxxx |    1 000 xxxxxxx | Finite number                  |\n *  |      0 xxxxxxx |    0 111 xxxxxxx | Finite number                  |\n *  +----------------+------------------+--------------------------------+\n *  |      0 0000000 |    0 000 0000000 | frac <> 0: Subnormal finite    |\n *  |                |                  | frac == 0: +/- Zero            |\n *  +----------------+------------------+--------------------------------+\n * \\endcode\n *\n * \\subsection IEEE_T T-Floating\n * An IEEE double precision, or T-Floating, is a 64-bit floating point value.\n * Both in memory, and in the flowting point registers it's layout is as\n * follows:\n * \\code\n *     63 62          52 51                                             0\n *   +---+--------------+------------------------------------------------+\n *   | S |    Exponent  |                   Fraction                     |\n *   +---+--------------+------------------------------------------------+\n * \\endcode\n *\n * The value (V) of a T-Floating value can be determined from the Sign (S),\n * Exponent (E) and Fraction (F) as follows:\n * \\code\n *  +--------------+--------+--------+--------------------------+\n *  | E == 2047    | F <> 0 |        | V = NaN                  |\n *  +--------------+--------+--------+--------------------------+\n *  | E == 2047    | F == 0 | S == 0 | V = + Infinity           |\n *  +--------------+--------+--------+--------------------------+\n *  | E == 2047    | F == 0 | S == 1 | V = - Infinity           |\n *  +--------------+--------+--------+--------------------------+\n *  | 0 < E < 2047 |        | S == 0 | V = + (1.F) * 2^(E-1023) |\n *  +--------------+--------+--------+--------------------------+\n *  | 0 < E < 2047 |        | S == 1 | V = - (1.F) * 2^(E-1023) |\n *  +--------------+--------+--------+--------------------------+\n *  | E == 0       | F <> 0 | S == 0 | V = + (0.F) * 2^(-1022)  |\n *  +--------------+--------+--------+--------------------------+\n *  | E == 0       | F <> 0 | S == 1 | V = - (0.F) * 2^(-1022)  |\n *  +--------------+--------+--------+--------------------------+\n *  | E == 0       | F == 0 | S == 0 | V = + 0                  |\n *  +--------------+--------+--------+--------------------------+\n *  | E == 0       | F == 0 | S == 1 | V = - 0                  |\n *  +--------------+--------+--------+--------------------------+\n * \\endcode\n *\n ******************************************************************************/\n\n/* Register format constants */\n#define QNAN U64(0x0008000000000000)   /* quiet NaN flag */\n#define CQNAN U64(0xFFF8000000000000)  /* canonical quiet NaN */\n#define FPZERO U64(0x0000000000000000) /* plus zero (fp) */\n#define FMZERO U64(0x8000000000000000) /* minus zero (fp) */\n#define FPINF U64(0x7FF0000000000000)  /* plus infinity (fp) */\n#define FMINF U64(0xFFF0000000000000)  /* minus infinity (fp) */\n#define FPMAX U64(0x7FFFFFFFFFFFFFFF)  /* plus MAX (fp) */\n#define FMMAX U64(0xFFFFFFFFFFFFFFFF)  /* minus MAX (fp) */\n#define IPMAX U64(0x7FFFFFFFFFFFFFFF)  /* plus MAX (int) */\n#define IMMAX U64(0x8000000000000000)  /* minus MAX (int) */\n\n/* Unpacked rounding constants */\n#define UF_SRND U64(0x0000008000000000) /* S normal round */\n#define UF_SINF U64(0x000000FFFFFFFFFF) /* S infinity round */\n#define UF_TRND U64(0x0000000000000400) /* T normal round */\n#define UF_TINF U64(0x00000000000007FF) /* T infinity round */\n\n/***************************************************************************/\n\n/**\n * \\name IEEE_fp_load_store\n * IEEE floating point load and store functions.\n ******************************************************************************/\n\n//\\{\n\n/**\n * \\brief Convert an IEEE S-floating from memory format to register format.\n *\n * Adjust the exponent base, and widen the exponent and fraction fields.\n *\n * \\param op\tIEEE S-floating value in memory format.\n * \\return\t\tIEEE S-floating value in register format.\n **/\nu64 CAlphaCPU::ieee_lds(u32 op) {\n  u32 exp = S_GETEXP(op); /* get exponent */\n\n  if (exp == S_NAN)\n    exp = FPR_NAN; /* inf or NaN? */\n  else if (exp != 0)\n    exp = exp + T_BIAS - S_BIAS;                 /* zero or denorm? */\n  return (((u64)(op & S_SIGN)) ? FPR_SIGN : 0) | /* reg format */\n         (((u64)exp) << FPR_V_EXP) |\n         (((u64)(op & ~(S_SIGN | S_EXP))) << S_V_FRAC);\n}\n\n/**\n * \\brief Convert an IEEE S-floating from register format to memory format.\n *\n * Adjust the exponent base, and make the exponent and fraction fields smaller.\n *\n * \\param op  IEEE S-floating value in register format.\n * \\return    IEEE S-floating value in memory format.\n **/\nu32 CAlphaCPU::ieee_sts(u64 op) {\n  u32 sign = FPR_GETSIGN(op) ? S_SIGN : 0;\n  u32 exp = FPR_GETEXP(op);\n  if (exp == FPR_NAN)\n    exp = S_NAN; /* inf or NaN? */\n  else if (exp != 0)\n    exp = exp + S_BIAS - T_BIAS; /* zero or denorm? */\n  exp = (exp << S_V_EXP) & S_EXP;\n\n  u32 frac = ((u32)(op >> S_V_FRAC)) & X64_LONG;\n\n  return sign | exp | (frac & ~(S_SIGN | S_EXP));\n}\n\n//\\}\n\n/***************************************************************************/\n\n/**\n * \\name IEEE_fp_conversion\n * IEEE floating point conversion routines\n ******************************************************************************/\n\n//\\{\n\n/**\n * \\brief Convert an IEEE S-floating to an IEEE T-floating.\n *\n * LDS doesn't handle denorms correctly.\n *\n * \\param op  IEEE S-floating value.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions.\n * \\return\t  IEEE T-floating value.\n **/\nu64 CAlphaCPU::ieee_cvtst(u64 op, u32 ins) {\n  UFP b;\n  u32 ftpb;\n\n  ftpb = ieee_unpack(op, &b, ins); /* unpack; norm dnorm */\n  if (ftpb == UFT_DENORM)          /* denormal? */\n  {\n\n    // i'm not completely sure this is correct...\n    b.exp = b.exp + T_BIAS - S_BIAS;  /* change 0 exp to T */\n    return ieee_rpack(&b, ins, DT_T); /* round, pack */\n  } else\n    return op; /* identity */\n}\n\n/**\n * \\brief Convert an IEEE T-floating to an IEEE S-floating.\n *\n * \\param op  IEEE T-floating value.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions and to determine the rounding mode.\n * \\return\t  IEEE S-floating.\n **/\nu64 CAlphaCPU::ieee_cvtts(u64 op, u32 ins) {\n  UFP b;\n  u32 ftpb;\n\n  ftpb = ieee_unpack(op, &b, ins); /* unpack */\n  if (Q_FINITE(ftpb))\n    return ieee_rpack(&b, ins, DT_S); /* finite? round, pack */\n  if (ftpb == UFT_NAN)\n    return (op | QNAN); /* nan? cvt to quiet */\n  if (ftpb == UFT_INF)\n    return op; /* inf? unchanged */\n  return 0;    /* denorm? 0 */\n}\n\n//\\}\n\n/***************************************************************************/\n\n/**\n * \\name IEEE_fp_operations\n * IEEE floating point operations\n ******************************************************************************/\n\n//\\{\n\n/**\n * \\brief Compare 2 IEEE floating-point values.\n *\n * The following steps are taken:\n *   - Take care of NaNs\n *   - Force -0 to +0\n *   - Then normal compare will work (even on inf and denorms)\n *   .\n *\n * \\param s1  First IEEE floating to be compared.\n * \\param s1  Second IEEE floating to be compared.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions.\n * \\return    0 if s1==s2, 1 if s1>s2, -1 if s1<s2.\n **/\ns32 CAlphaCPU::ieee_fcmp(u64 s1, u64 s2, u32 ins, u32 trap_nan) {\n  UFP a;\n\n  UFP b;\n  u32 ftpa;\n  u32 ftpb;\n\n  ftpa = ieee_unpack(s1, &a, ins);\n  ftpb = ieee_unpack(s2, &b, ins);\n  if ((ftpa == UFT_NAN) || (ftpb == UFT_NAN)) { /* NaN involved? */\n    if (trap_nan)\n      ieee_trap(TRAP_INV, 1, FPCR_INVD, ins);\n    return +1;\n  } /* force failure */\n\n  if (ftpa == UFT_ZERO)\n    a.sign = 0; /* only +0 allowed */\n  if (ftpb == UFT_ZERO)\n    b.sign = 0;\n  if (a.sign != b.sign)\n    return (a.sign ? -1 : +1); /* unequal signs? */\n  if (a.exp != b.exp)\n    return ((a.sign ^ (a.exp < b.exp)) ? -1 : +1);\n  if (a.frac != b.frac)\n    return ((a.sign ^ (a.frac < b.frac)) ? -1 : +1);\n  return 0;\n}\n\n/**\n * \\brief Convert 64-bit signed integer to IEEE floating-point value.\n *\n * \\param val 64-bit signed integer to be converted.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions and to determine the rounding mode.\n * \\param dp  DT_S for S-floating or DT_T for T-floating.\n * \\return    IEEE floating.\n **/\nu64 CAlphaCPU::ieee_cvtif(u64 val, u32 ins, u32 dp) {\n  UFP a;\n\n  if (val == 0)\n    return 0;           /* 0? return +0 */\n  if (((s64)val) < 0) { /* < 0? */\n    a.sign = 1;         /* set sign */\n    val = NEG_Q(val);\n  } /* |val| */\n  else\n    a.sign = 0;\n  a.exp = 63 + T_BIAS;            /* set exp */\n  a.frac = val;                   /* set frac */\n  ieee_norm(&a);                  /* normalize */\n  return ieee_rpack(&a, ins, dp); /* round and pack */\n}\n\n/**\n * \\brief Convert IEEE floating-point value to 64-bit signed integer.\n *\n * Rounding code from SoftFloat.\n *\n * The Alpha architecture specifies return of the low order bits of\n * the true result, whereas the IEEE standard specifies the return\n * of the maximum plus or minus value\n *\n * \\param op  IEEE floating to be converted.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions.\n * \\return    64-bit signed integer.\n **/\nu64 CAlphaCPU::ieee_cvtfi(u64 op, u32 ins) {\n  UFP a;\n  u64 sticky;\n  u32 rndm;\n  u32 ftpa;\n  u32 ovf = 0;\n  s32 ubexp;\n\n  ftpa = ieee_unpack(op, &a, ins); /* unpack */\n  if (!Q_FINITE(ftpa))             /* inf, NaN, dnorm? */\n  {\n    ieee_trap(TRAP_INV, 1, FPCR_INVD, ins); /* inv operation */\n    return 0;\n  }\n\n  if (ftpa == UFT_ZERO)\n    return 0;             /* zero? */\n  ubexp = a.exp - T_BIAS; /* unbiased exp */\n  if (ubexp < 0)          /* < 1? */\n  {\n    if (ubexp == -1)\n      sticky = a.frac; /* [.5,1)? */\n    else\n      sticky = 1; /* (0,.5) */\n    a.frac = 0;\n  } else if (ubexp <= UF_V_NM) /* in range? */\n  {\n    sticky = (a.frac << (64 - (UF_V_NM - ubexp))) & X64_QUAD;\n    a.frac = a.frac >> (UF_V_NM - ubexp); /* result */\n  } else {\n    if ((ubexp - UF_V_NM) > 63)\n      a.frac = 0; /* out of range */\n    else\n      a.frac = (a.frac << (ubexp - UF_V_NM)) & X64_QUAD;\n    ovf = 1;    /* overflow */\n    sticky = 0; /* no rounding */\n  }\n\n  rndm = I_GETFRND(ins);                           /* get round mode */\n  if (((rndm == I_FRND_N) && (sticky & Q_SIGN))    /* nearest? */\n      || ((rndm == I_FRND_P) && !a.sign && sticky) /* +inf and +? */\n      || ((rndm == I_FRND_M) && a.sign && sticky)) /* -inf and -? */\n  {\n    a.frac = (a.frac + 1) & X64_QUAD;\n    if (a.frac == 0)\n      ovf = 1;                                    /* overflow? */\n    if ((rndm == I_FRND_N) && (sticky == Q_SIGN)) /* round nearest hack */\n      a.frac = a.frac & ~1;\n  }\n\n  if (a.frac > (a.sign ? IMMAX : IPMAX))\n    ovf = 1; /* overflow? */\n\n  if (ovf)\n    ieee_trap(TRAP_IOV, ins & I_FTRP_V, 0, 0); /* overflow trap */\n  if (ovf || sticky)                           /* ovflo or round? */\n    ieee_trap(TRAP_INE, Q_SUI(ins), FPCR_INED, ins);\n  return (a.sign ? NEG_Q(a.frac) : a.frac);\n}\n\n/**\n * \\brief Add or subtract 2 IEEE floating-point values.\n *\n * The following steps are taken:\n *   - Take care of NaNs and infinites\n *   - Test for zero (fast exit)\n *   - Sticky logic for floating add\n *\t    - If result normalized, sticky in right place\n *\t    - If result carries out, renormalize, retain sticky\n *      .\n *   - Sticky logic for floating subtract\n *\t    - If shift < guard, no sticky bits; 64b result is exact\n *\t    - If shift <= 1, result may require extensive normalization,\n *\t      but there are no sticky bits to worry about\n *\t    - If shift >= guard, there is a sticky bit,\n *\t      but normalization is at most 1 place, sticky bit is retained\n *\t      for rounding purposes (but not in low order bit)\n *      .\n *   .\n *\n * \\param s1  Augend or minuend.\n * \\param s2  Addend or subtrahend.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions.\n * \\param dp  DT_S for S-floating or DT_T for T-floating.\n * \\param sub subtract if true, add if false.\n * \\return    IEEE floating.\n **/\nu64 CAlphaCPU::ieee_fadd(u64 s1, u64 s2, u32 ins, u32 dp, bool sub) {\n  UFP a;\n\n  UFP b;\n\n  UFP t;\n  u32 ftpa;\n  u32 ftpb;\n  u32 sticky;\n  s32 ediff;\n\n  ftpa = ieee_unpack(s1, &a, ins); /* unpack operands */\n  ftpb = ieee_unpack(s2, &b, ins);\n  if (ftpb == UFT_NAN)\n    return s2 | QNAN; /* B = NaN? quiet B */\n  if (ftpa == UFT_NAN)\n    return s1 | QNAN; /* A = NaN? quiet A */\n  if (sub)\n    b.sign = b.sign ^ 1;                          /* sign of B */\n  if (ftpb == UFT_INF) {                          /* B = inf? */\n    if ((ftpa == UFT_INF) && (a.sign ^ b.sign)) { /* eff sub of inf? */\n      ieee_trap(TRAP_INV, 1, FPCR_INVD, ins);     /* inv op trap */\n      return CQNAN;\n    } /* canonical NaN */\n\n    return (sub ? (s2 ^ FPR_SIGN) : s2);\n  } /* return B */\n\n  if (ftpa == UFT_INF)\n    return s1; /* A = inf? ret A */\n  if (ftpa == UFT_ZERO)\n    a = b;                     /* s1 = 0? */\n  else if (ftpb != UFT_ZERO) { /* s2 != 0? */\n    if ((a.exp < b.exp)        /* s1 < s2? swap */\n        || ((a.exp == b.exp) && (a.frac < b.frac))) {\n      t = a;\n      a = b;\n      b = t;\n    }\n\n    ediff = a.exp - b.exp; /* exp diff */\n    if (ediff > 63)\n      b.frac = 1;     /* >63? retain sticky */\n    else if (ediff) { /* [1,63]? shift */\n      sticky = ((b.frac << (64 - ediff)) & X64_QUAD) ? 1 : 0; /* lost bits */\n      b.frac = ((b.frac >> ediff) & X64_QUAD) | sticky;\n    }\n\n    if (a.sign ^ b.sign) {                   /* eff sub? */\n      a.frac = (a.frac - b.frac) & X64_QUAD; /* subtract fractions */\n      ieee_norm(&a);\n    }                                        /* normalize */\n    else {                                   /* eff add */\n      a.frac = (a.frac + b.frac) & X64_QUAD; /* add frac */\n      if (a.frac < b.frac) {                 /* chk for carry */\n        a.frac = UF_NM | (a.frac >> 1) |     /* shift in carry */\n                 (a.frac & 1);               /* retain sticky */\n        a.exp = a.exp + 1;\n      }\n    } /* skip norm */\n  }   /* end else if */\n\n  return ieee_rpack(&a, ins, dp); /* round and pack */\n}\n\n/**\n * \\brief Multiply 2 IEEE floating-point values.\n *\n * The following steps are taken:\n *   - Take care of NaNs and infinites\n *   - Test for zero operands (fast exit)\n *   - 64b x 64b fraction multiply, yielding 128b result\n *   - Normalize (at most 1 bit)\n *   - Insert \"sticky\" bit in low order fraction, for rounding\n *   .\n *\n * Because IEEE fractions have a range of [1,2), the result can have a range\n * of [1,4).  Results in the range of [1,2) appear to be denormalized by one\n * place, when in fact they are correct.  Results in the range of [2,4) appear\n * to be in correct, when in fact they are 2X larger.  This problem is taken\n * care of in the result exponent calculation.\n *\n * \\param s1  Multiplicand.\n * \\param s2  Multiplier.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions.\n * \\param dp  DT_S for S-floating or DT_T for T-floating.\n * \\return    IEEE floating.\n **/\nu64 CAlphaCPU::ieee_fmul(u64 s1, u64 s2, u32 ins, u32 dp) {\n  UFP a;\n\n  UFP b;\n  u32 ftpa;\n  u32 ftpb;\n  u64 resl;\n\n  ftpa = ieee_unpack(s1, &a, ins); /* unpack operands */\n  ftpb = ieee_unpack(s2, &b, ins);\n  if (ftpb == UFT_NAN)\n    return s2 | QNAN; /* B = NaN? quiet B */\n  if (ftpa == UFT_NAN)\n    return s1 | QNAN;                             /* A = NaN? quiet A */\n  a.sign = a.sign ^ b.sign;                       /* sign of result */\n  if ((ftpa == UFT_ZERO) || (ftpb == UFT_ZERO)) { /* zero operand? */\n    if ((ftpa == UFT_INF) || (ftpb == UFT_INF)) { /* 0 * inf? */\n      ieee_trap(TRAP_INV, 1, FPCR_INVD, ins);     /* inv op trap */\n      return CQNAN;\n    } /* canonical NaN */\n\n    return (a.sign ? FMZERO : FPZERO);\n  } /* return signed 0 */\n\n  if (ftpb == UFT_INF)\n    return (a.sign ? FMINF : FPINF); /* B = inf? */\n  if (ftpa == UFT_INF)\n    return (a.sign ? FMINF : FPINF);       /* A = inf? */\n  a.exp = a.exp + b.exp + 1 - T_BIAS;      /* add exponents */\n  resl = uemul64(a.frac, b.frac, &a.frac); /* multiply fracs */\n  ieee_norm(&a);                           /* normalize */\n  a.frac = a.frac | (resl ? 1 : 0);        /* sticky bit */\n  return ieee_rpack(&a, ins, dp);          /* round and pack */\n}\n\n/**\n * \\brief Divide 2 IEEE floating-point values.\n *\n * The following steps are taken:\n *   - Take care of NaNs and infinites\n *   - Check for zero cases\n *   - Divide fractions (55b to develop a rounding bit)\n *   - Set sticky bit if remainder non-zero\n *   .\n *\n * Because IEEE fractions have a range of [1,2), the result can have a range\n * of (.5,2).  Results in the range of [1,2) are correct.  Results in the\n * range of (.5,1) need to be normalized by one place.\n *\n * \\param s1  Dividend.\n * \\param s2  Divisor.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions.\n * \\param dp  DT_S for S-floating or DT_T for T-floating.\n * \\return    IEEE floating.\n **/\nu64 CAlphaCPU::ieee_fdiv(u64 s1, u64 s2, u32 ins, u32 dp) {\n  UFP a;\n\n  UFP b;\n  u32 ftpa;\n  u32 ftpb;\n  u32 sticky;\n\n  ftpa = ieee_unpack(s1, &a, ins);\n  ftpb = ieee_unpack(s2, &b, ins);\n  if (ftpb == UFT_NAN)\n    return s2 | QNAN; /* B = NaN? quiet B */\n  if (ftpa == UFT_NAN)\n    return s1 | QNAN;                         /* A = NaN? quiet A */\n  a.sign = a.sign ^ b.sign;                   /* sign of result */\n  if (ftpb == UFT_INF) {                      /* B = inf? */\n    if (ftpa == UFT_INF) {                    /* inf/inf? */\n      ieee_trap(TRAP_INV, 1, FPCR_INVD, ins); /* inv op trap */\n      return CQNAN;\n    } /* canonical NaN */\n\n    return (a.sign ? FMZERO : FPZERO);\n  } /* !inf/inf, ret 0 */\n\n  if (ftpa == UFT_INF) {                      /* A = inf? */\n    if (ftpb == UFT_ZERO)                     /* inf/0? */\n      ieee_trap(TRAP_DZE, 1, FPCR_DZED, ins); /* div by 0 trap */\n    return (a.sign ? FMINF : FPINF);\n  } /* return inf */\n\n  if (ftpb == UFT_ZERO) {                     /* B = 0? */\n    if (ftpa == UFT_ZERO) {                   /* 0/0? */\n      ieee_trap(TRAP_INV, 1, FPCR_INVD, ins); /* inv op trap */\n      return CQNAN;\n    } /* canonical NaN */\n\n    ieee_trap(TRAP_DZE, 1, FPCR_DZED, ins); /* div by 0 trap */\n    return (a.sign ? FMINF : FPINF);\n  } /* return inf */\n\n  if (ftpa == UFT_ZERO)\n    return (a.sign ? FMZERO : FPZERO); /* A = 0? */\n  a.exp = a.exp - b.exp + T_BIAS;      /* unbiased exp */\n  a.frac = a.frac >> 1;                /* allow 1 bit left */\n  b.frac = b.frac >> 1;\n  a.frac = ufdiv64(a.frac, b.frac, 55, &sticky); /* divide */\n  ieee_norm(&a);                                 /* normalize */\n  a.frac = a.frac | sticky;                      /* insert sticky */\n  return ieee_rpack(&a, ins, dp);                /* round and pack */\n}\n\n/**\n * \\brief Determine principal square root of a IEEE floating-point value.\n *\n * The following steps are taken:\n *   - Take care of NaNs, +infinite, zero\n *   - Check for negative operand\n *   - Compute result exponent\n *   - Compute sqrt of fraction\n *   .\n *\n * \\param op  IEEE floating.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions.\n * \\param dp  DT_S for S-floating or DT_T for T-floating.\n * \\return    IEEE floating.\n **/\nu64 CAlphaCPU::ieee_sqrt(u64 op, u32 ins, u32 dp) {\n  u32 ftpb;\n  UFP b;\n\n  ftpb = ieee_unpack(op, &b, ins); /* unpack */\n  if (ftpb == UFT_NAN)\n    return op | QNAN; /* NaN? */\n  if ((ftpb == UFT_ZERO) || /* zero? */ ((ftpb == UFT_INF) && !b.sign))\n    return op;                              /* +infinity? */\n  if (b.sign) {                             /* minus? */\n    ieee_trap(TRAP_INV, 1, FPCR_INVD, ins); /* signal inv op */\n    return CQNAN;\n  }\n\n  b.exp = ((b.exp - T_BIAS) >> 1) + T_BIAS; /* result exponent */\n  b.frac = fsqrt64(b.frac, b.exp);          /* result fraction */\n  return ieee_rpack(&b, ins, dp);           /* round and pack */\n}\n\n//\\}\n\n/***************************************************************************/\n\n/**\n * \\name IEEE_fp_support\n * IEEE floating point support functions\n ******************************************************************************/\n\n//\\{\n\n/**\n * \\brief Unpack IEEE floating-point value\n *\n * Converts a IEEE floating-point value to it's sign, exponent and fraction\n * components.\n *\n * \\param op  IEEE floating.\n * \\param r   Pointer to the unpacked-floating-point UFP structure\n *            where the results are to be returned.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions.\n * \\return    Returns the type of value (UFT_ZERO, UFT_FIN, etc.).\n **/\nint CAlphaCPU::ieee_unpack(u64 op, UFP *r, u32 ins) {\n  r->sign = FPR_GETSIGN(op); /* get sign */\n  r->exp = FPR_GETEXP(op);   /* get exponent */\n  r->frac = FPR_GETFRAC(op); /* get fraction */\n  if (r->exp == 0)           /* exponent = 0? */\n  {\n    if (r->frac == 0)\n      return UFT_ZERO;         /* frac = 0? then true 0 */\n    if (state.fpcr & FPCR_DNZ) /* denorms to 0? */\n    {\n      r->frac = 0; /* clear fraction */\n      return UFT_ZERO;\n    }\n\n    r->frac = r->frac << FPR_GUARD;         /* guard fraction */\n    ieee_norm(r);                           /* normalize dnorm */\n    ieee_trap(TRAP_INV, 1, FPCR_INVD, ins); /* signal inv op */\n    return UFT_DENORM;\n  }\n\n  if (r->exp == FPR_NAN) /* exponent = max? */\n  {\n    if (r->frac == 0)\n      return UFT_INF;                         /* frac = 0? then inf */\n    if (!(r->frac & QNAN))                    /* signaling NaN? */\n      ieee_trap(TRAP_INV, 1, FPCR_INVD, ins); /* signal inv op */\n    return UFT_NAN;\n  }\n\n  r->frac = (r->frac | FPR_HB) << FPR_GUARD; /* ins hidden bit, guard */\n  return UFT_FIN;                            /* finite */\n}\n\n/**\n * \\brief Normalize IEEE floating-point value\n *\n * Normalize exponent and fraction components. Input must be zero, finite, or\n *denorm.\n *\n * \\param r   Pointer to the unpacked-floating-point UFP structure\n *            containing the value to be normalized, and where the\n *            results are to be returned.\n **/\nvoid CAlphaCPU::ieee_norm(UFP *r) {\n  s32 i;\n  static u64 normmask[5] = {U64(0xc000000000000000), U64(0xf000000000000000),\n                            U64(0xff00000000000000), U64(0xffff000000000000),\n                            U64(0xffffffff00000000)};\n  static s32 normtab[6] = {1, 2, 4, 8, 16, 32};\n\n  r->frac = r->frac & X64_QUAD;\n  if (r->frac == 0) { /* if fraction = 0 */\n    r->exp = 0;       /* result is signed 0 */\n    return;\n  }\n\n  while ((r->frac & UF_NM) == 0) { /* normalized? */\n    for (i = 0; i < 5; i++) {      /* find first 1 */\n      if (r->frac & normmask[i])\n        break;\n    }\n\n    r->frac = r->frac << normtab[i]; /* shift frac */\n    r->exp = r->exp - normtab[i];\n  } /* decr exp */\n\n  return;\n}\n\n/**\n * \\brief Round and pack IEEE floating-point value\n *\n * Converts sign, exponent and fraction components to an IEEE floating\n * point value.\n *\n * Much of the treachery of the IEEE standard is buried here:\n *   - Rounding modes (chopped, +infinity, nearest, -infinity).\n *   - Inexact (set if there are any rounding bits, regardless of rounding).\n *   - Overflow (result is infinite if rounded, max if not).\n *   - Underflow (no denorms!).\n *   .\n *\n * Underflow handling is particularly complicated:\n *   - Result is always 0.\n *   - UNF and INE are always set in FPCR.\n *   - If /U is set,\n *      - If /S is clear, trap.\n *      - If /S is set, UNFD is set, but UNFZ is clear, ignore UNFD and\n *        trap, because the hardware cannot produce denormals.\n *      - If /S is set, UNFD is set, and UNFZ is set, do not trap.\n *      .\n *   - If /SUI is set, and INED is clear, trap\n *   .\n *\n * \\param r   Pointer to the unpacked-floating-point UFP structure\n *            to be packed.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions and to determine the rounding mode.\n * \\param dp  DT_S for S-floating or DT_T for T-floating.\n * \\return    IEEE floating.\n **/\nu64 CAlphaCPU::ieee_rpack(UFP *r, u32 ins, u32 dp) {\n  static const u64 stdrnd[2] = {UF_SRND, UF_TRND};\n  static const u64 infrnd[2] = {UF_SINF, UF_TINF};\n  static const s32 expmax[2] = {T_BIAS - S_BIAS + S_M_EXP - 1, T_M_EXP - 1};\n  static const s32 expmin[2] = {T_BIAS - S_BIAS, 0};\n  u64 rndadd;\n  u64 rndbits;\n  u64 res;\n  u64 rndm;\n\n  if (r->frac == 0)\n    return (((u64)r->sign) << FPR_V_SIGN); /* result 0? */\n  rndm = I_GETFRND(ins);                   /* inst round mode */\n  if (rndm == I_FRND_D)\n    rndm = FPCR_GETFRND(state.fpcr); /* dynamic? use FPCR */\n  rndbits = r->frac & infrnd[dp];    /* isolate round bits */\n  if (rndm == I_FRND_N)\n    rndadd = stdrnd[dp];                       /* round to nearest? */\n  else if (((rndm == I_FRND_P) && !r->sign)    /* round to inf and */\n           || ((rndm == I_FRND_M) && r->sign)) /* right sign? */\n    rndadd = infrnd[dp];\n  else\n    rndadd = 0;\n  r->frac = (r->frac + rndadd) & X64_QUAD; /* round */\n  if ((r->frac & UF_NM) == 0) {            /* carry out? */\n    r->frac = (r->frac >> 1) | UF_NM;      /* renormalize */\n    r->exp = r->exp + 1;\n  }\n\n  if (rndbits)                                       /* inexact? */\n    ieee_trap(TRAP_INE, Q_SUI(ins), FPCR_INED, ins); /* set inexact */\n  if (r->exp > expmax[dp]) {                         /* ovflo? */\n    ieee_trap(TRAP_OVF, 1, FPCR_OVFD, ins);          /* set overflow trap */\n    ieee_trap(TRAP_INE, Q_SUI(ins), FPCR_INED, ins); /* set inexact */\n    if (rndadd)                                      /* did we round? */\n      return (r->sign ? FMINF : FPINF);              /* return infinity */\n    return (r->sign ? FMMAX : FPMAX);\n  } /* no, return max */\n\n  if (r->exp <= expmin[dp]) {           /* underflow? */\n    ieee_trap(TRAP_UNF, ins & I_FTRP_U, /* set underflow trap */\n              (state.fpcr & FPCR_UNDZ) ? FPCR_UNFD : 0,\n              ins); /* (dsbl only if UNFZ set) */\n    ieee_trap(TRAP_INE, Q_SUI(ins), FPCR_INED, ins); /* set inexact */\n    return 0;\n  } /* underflow to +0 */\n\n  res = (((u64)r->sign) << FPR_V_SIGN) | /* form result */\n        (((u64)r->exp) << FPR_V_EXP) | ((r->frac >> FPR_GUARD) & FPR_FRAC);\n  if ((rndm == I_FRND_N) && (rndbits == stdrnd[dp])) /* nearest and halfway? */\n    res = res & ~1;                                  /* clear lo bit */\n  return res;\n}\n\n/**\n * \\brief Set IEEE floating-point trap\n *\n * Called when a IEEE floating-point operation detects an exception.\n *\n * \\param trap    A bitmask in which the bits are set that correspond to\n *                the exception that occurred.\n * \\param instenb True if the exception is enabled in the instruction.\n * \\param fpcrdsb A bitmask containing the bits that, if set in the floating-\n *                point control register (fpcr), disable the trap.\n * \\param ins     The instruction currently being executed. Used to properly\n *                set some registers for the trap to be handled.\n **/\nvoid CAlphaCPU::ieee_trap(u64 trap, u32 instenb, u64 fpcrdsb, u32 ins) {\n  u64 real_trap = U64(0x0);\n\n  if (~(state.fpcr & (trap << 51))) // trap bit not set in FPCR\n    real_trap |= trap << 41;        // SET trap bit in EXC_SUM\n  if ((instenb != 0)                /* not enabled in inst? ignore */\n      && !((ins & I_FTRP_S) &&\n           (state.fpcr & fpcrdsb))) /* /S and disabled? ignore */\n    real_trap |= trap;              // trap bit in EXC_SUM\n  if (real_trap)\n    ARITH_TRAP(real_trap | ((ins & I_FTRP_S) ? TRAP_SWC : 0), I_GETRC(ins));\n  return;\n}\n\n//\\}\n"
  },
  {
    "path": "src/AlphaCPU_vaxfloat.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n/* Copyright notice from Simh/alpha/alpha_fpv.c:\n\n   Copyright (c) 2003-2006, Robert M Supnik\n\n   Permission is hereby granted, free of charge, to any person obtaining a\n   copy of this software and associated documentation files (the \"Software\"),\n   to deal in the Software without restriction, including without limitation\n   the rights to use, copy, modify, merge, publish, distribute, sublicense,\n   and/or sell copies of the Software, and to permit persons to whom the\n   Software is furnished to do so, subject to the following conditions:\n\n   The above copyright notice and this permission notice shall be included in\n   all copies or substantial portions of the Software.\n\n   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\n   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n   Except as contained in this notice, the name of Robert M Supnik shall not be\n   used in advertising or otherwise to promote the sale, use or other dealings\n   in this Software without prior written authorization from Robert M Supnik.\n*/\n\n#include \"AlphaCPU.hpp\"\n#include \"StdAfx.hpp\"\n#include \"cpu_debug.hpp\"\n\n#define IPMAX U64(0x7FFFFFFFFFFFFFFF) /* plus MAX (int) */\n#define IMMAX U64(0x8000000000000000) /* minus MAX (int) */\n\n/* Unpacked rounding constants */\n#define UF_FRND U64(0x0000008000000000) /* F round */\n#define UF_DRND U64(0x0000000000000080) /* D round */\n#define UF_GRND U64(0x0000000000000400) /* G round */\n\n/***************************************************************************/\n\n/**\n * \\name VAX_fp_load_store\n * VAX floating point load and store functions\n ******************************************************************************/\n\n//\\{\n\n/**\n * \\brief Convert the VAX F-floating memory format to the VAX floating register\n * format.\n *\n * Adjust the exponent base, reorder the bytes of the fraction to compensate for\n * the VAX byte-order, and widen the exponent and fraction fields.\n *\n * \\param op\t32-bit VAX F-floating value in memory format.\n * \\return\t\tThe value op converted to 64-bit VAX floating in\n *register format.\n **/\nu64 CAlphaCPU::vax_ldf(u32 op) {\n  u32 exp = F_GETEXP(op);\n  if (exp != 0)\n    exp = exp + G_BIAS - F_BIAS;                    /* zero? */\n  u64 res = (((u64)(op & F_SIGN)) ? FPR_SIGN : 0) | /* finite non-zero */\n            (((u64)exp) << FPR_V_EXP) |\n            (((u64)SWAP_VAXF(op & ~(F_SIGN | F_EXP))) << F_V_FRAC);\n\n  // printf(\"vax_ldf: %08x -> %016\" PRIx64 \".\\n\", op, res);\n  return res;\n}\n\n/**\n * \\brief Convert the VAX G-floating memory format to the VAX floating register\n * format.\n *\n * Reorder the bytes to compensate for the VAX byte-order.\n *\n * \\param op  64-bit VAX G-floating value in memory format.\n * \\return    The value op converted to 64-bit VAX floating in register format.\n **/\nu64 CAlphaCPU::vax_ldg(u64 op) { return SWAP_VAXG(op); /* swizzle bits */ }\n\n/**\n * \\brief Convert the VAX floating register format to the VAX F-floating memory\n * format.\n *\n * Adjust the exponent base, make the exponent and fraction fields smaller, and\n * reorder the bytes of the fraction to compensate for the VAX byte-order.\n *\n * \\param op  64-bit VAX floating in register format.\n * \\return    The value op converted to 32-bit VAX F-floating value in memory\n *format.\n **/\nu32 CAlphaCPU::vax_stf(u64 op) {\n  u32 sign = FPR_GETSIGN(op) ? F_SIGN : 0;\n\n  // u32 exp = ((u32) (op >> (FPR_V_EXP - F_V_EXP))) & F_EXP;\n  u32 exp = FPR_GETEXP(op);\n  if (exp != 0)\n    exp = exp + F_BIAS - G_BIAS; /* zero? */\n  exp = (exp << F_V_EXP) & F_EXP;\n\n  u32 frac = (u32)(op >> F_V_FRAC);\n\n  u32 res = sign | exp | (SWAP_VAXF(frac) & ~(F_SIGN | F_EXP));\n\n  // printf(\"vax_stf: %016\" PRIx64 \" -> %08x.\\n\", op, res);\n  return res;\n}\n\n/**\n * \\brief Convert the VAX floating register format to the VAX G-floating memory\n * format.\n *\n * Reorder the bytes to compensate for the VAX byte-order.\n *\n * \\param op  64-bit VAX floating in register format.\n * \\return    The value op converted to 64-bit VAX G-floating value in memory\n *format.\n **/\nu64 CAlphaCPU::vax_stg(u64 op) { return SWAP_VAXG(op); /* swizzle bits */ }\n\n//\\}\n\n/***************************************************************************/\n\n/**\n * \\name VAX_fp_operations\n * VAX floating point operations\n ******************************************************************************/\n\n//\\{\n\n/**\n * \\brief Compare 2 VAX floating-point values.\n *\n * \\param s1  First 64-bit VAX floating in register format to be compared.\n * \\param s1  Second 64-bit VAX floating in register format to be compared.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions.\n * \\return    0 if s1==s2, 1 if s1>s2, -1 if s1<s2.\n **/\nint CAlphaCPU::vax_fcmp(u64 s1, u64 s2, u32 ins) {\n  UFP a;\n\n  UFP b;\n\n  vax_unpack(s1, &a, ins);\n  vax_unpack(s2, &b, ins);\n  if (s1 == s2)\n    return 0; /* equal? */\n  if (a.sign != b.sign)\n    return (a.sign ? -1 : +1);             /* opp signs? */\n  return (((s1 < s2) ^ a.sign) ? -1 : +1); /* like signs */\n}\n\n/**\n * \\brief Convert 64-bit signed integer to VAX floating-point value.\n *\n * \\param val 64-bit signed integer to be converted.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions and to determine the rounding mode.\n * \\param dp  DT_F for F-floating or DT_G for G-floating.\n * \\return    64-bit VAX floating in register format.\n **/\nu64 CAlphaCPU::vax_cvtif(u64 val, u32 ins, u32 dp) {\n  s64 num = (s64)val;\n  UFP a;\n\n  if (num == 0)\n    return 0;    /* 0? return +0 */\n  if (num < 0) { /* < 0? */\n    a.sign = 1;  /* set sign */\n    val = NEG_Q(val);\n  } /* |val| */\n  else\n    a.sign = 0;\n  a.exp = 64 + G_BIAS;           /* set exp */\n  a.frac = val;                  /* set frac */\n  vax_norm(&a);                  /* normalize */\n  return vax_rpack(&a, ins, dp); /* round and pack */\n}\n\n/**\n * \\brief Convert VAX floating-point value to 64-bit signed integer.\n *\n * Note that rounding cannot cause a carry unless the fraction has been shifted\n * right at least FP_GUARD places; in which case a carry out is impossible\n *\n * \\param op  64-bit VAX floating in register format to be converted.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions.\n * \\return    64-bit signed integer.\n **/\nu64 CAlphaCPU::vax_cvtfi(u64 op, u32 ins) {\n  UFP a;\n  u32 rndm = I_GETFRND(ins);\n  s32 ubexp;\n\n  vax_unpack(op, &a, ins);\n  ubexp = a.exp - G_BIAS; /* unbiased exp */\n  if (ubexp < 0)\n    return 0;                             /* zero or too small? */\n  if (ubexp <= UF_V_NM) {                 /* in range? */\n    a.frac = a.frac >> (UF_V_NM - ubexp); /* leave rnd bit */\n    if (rndm)\n      a.frac = a.frac + 1;                  /* not chopped, round */\n    a.frac = a.frac >> 1;                   /* now justified */\n    if ((a.frac > (a.sign ? IMMAX : IPMAX)) /* out of range? */\n        && (ins & I_FTRP_V))                /* trap enabled? */\n      vax_trap(TRAP_IOV, ins);\n  } /* set overflow */\n  else {\n    if (ubexp > (UF_V_NM + 64))\n      a.frac = 0; /* out of range */\n    else\n      a.frac = (a.frac << (ubexp - UF_V_NM - 1)) & X64_QUAD; /* no rnd bit */\n    if (ins & I_FTRP_V)                                      /* trap enabled? */\n      vax_trap(TRAP_IOV, ins);\n  } /* set overflow */\n\n  return (a.sign ? NEG_Q(a.frac) : a.frac);\n}\n\n/**\n * \\brief Add or subtract 2 VAX floating-point values.\n *\n * \\param s1  Augend or minuend in 64-bit VAX floating register format.\n * \\param s2  Addend or subtrahend in 64-bit VAX floating register format.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions.\n * \\param dp  DT_F for F-floating or DT_G for G-floating.\n * \\param sub subtract if true, add if false.\n * \\return    64-bit VAX floating in register format.\n **/\nu64 CAlphaCPU::vax_fadd(u64 s1, u64 s2, u32 ins, u32 dp, bool sub) {\n  UFP a;\n\n  UFP b;\n\n  UFP t;\n  u32 sticky;\n  s32 ediff;\n\n  vax_unpack(s1, &a, ins);\n  vax_unpack(s2, &b, ins);\n  if (sub)\n    b.sign = b.sign ^ 1; /* sub? invert b sign */\n  if (a.exp == 0)\n    a = b;        /* s1 = 0? */\n  else if (b.exp) /* s2 != 0? */\n  {\n    if ((a.exp < b.exp) /* |s1| < |s2|? swap */\n        || ((a.exp == b.exp) && (a.frac < b.frac))) {\n      t = a;\n      a = b;\n      b = t;\n    }\n\n    ediff = a.exp - b.exp; /* exp diff */\n    if (a.sign ^ b.sign)   /* eff sub? */\n    {\n      if (ediff > 63)\n        b.frac = 1;   /* >63? retain sticky */\n      else if (ediff) /* [1,63]? shift */\n      {\n        sticky = ((b.frac << (64 - ediff)) & X64_QUAD) ? 1 : 0; /* lost bits */\n        b.frac = (b.frac >> ediff) | sticky;\n      }\n\n      a.frac = (a.frac - b.frac) & X64_QUAD; /* subtract fractions */\n      vax_norm(&a);                          /* normalize */\n    } else                                   /* eff add */\n    {\n      if (ediff > 63)\n        b.frac = 0; /* >63? b disappears */\n      else if (ediff)\n        b.frac = b.frac >> ediff;            /* denormalize */\n      a.frac = (a.frac + b.frac) & X64_QUAD; /* add frac */\n      if (a.frac < b.frac)                   /* chk for carry */\n      {\n        a.frac = UF_NM | (a.frac >> 1); /* shift in carry */\n        a.exp = a.exp + 1;              /* skip norm */\n      }\n    }\n  } /* end else if */\n\n  return vax_rpack(&a, ins, dp); /* round and pack */\n}\n\n/**\n * \\brief Multiply 2 VAX floating-point values.\n *\n * \\param s1  Multiplicand in 64-bit VAX floating register format.\n * \\param s2  Multiplier in 64-bit VAX floating register format.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions.\n * \\param dp  DT_F for F-floating or DT_G for G-floating.\n * \\return    64-bit VAX floating in register format.\n **/\nu64 CAlphaCPU::vax_fmul(u64 s1, u64 s2, u32 ins, u32 dp) {\n  UFP a;\n\n  UFP b;\n\n  vax_unpack(s1, &a, ins);\n  vax_unpack(s2, &b, ins);\n  if ((a.exp == 0) || (b.exp == 0))\n    return 0;                       /* zero argument? */\n  a.sign = a.sign ^ b.sign;         /* sign of result */\n  a.exp = a.exp + b.exp - G_BIAS;   /* add exponents */\n  uemul64(a.frac, b.frac, &a.frac); /* mpy fractions */\n  vax_norm(&a);                     /* normalize */\n  return vax_rpack(&a, ins, dp);    /* round and pack */\n}\n\n/**\n * \\brief Divide 2 VAX floating-point values.\n *\n * Needs to develop at least one rounding bit.  Since the first\n * divide step can fail, develop 2 more bits than the precision of\n * the fraction.\n *\n * \\param s1  Dividend in 64-bit VAX floating register format.\n * \\param s2  Divisor in 64-bit VAX floating register format.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions.\n * \\param dp  DT_F for F-floating or DT_G for G-floating.\n * \\return    64-bit VAX floating in register format.\n **/\nu64 CAlphaCPU::vax_fdiv(u64 s1, u64 s2, u32 ins, u32 dp) {\n  UFP a;\n\n  UFP b;\n\n  vax_unpack(s1, &a, ins);\n  vax_unpack(s2, &b, ins);\n  if (b.exp == 0) {          /* divr = 0? */\n    vax_trap(TRAP_DZE, ins); /* dze trap */\n    return 0;\n  }\n\n  if (a.exp == 0)\n    return 0;                         /* divd = 0? */\n  a.sign = a.sign ^ b.sign;           /* result sign */\n  a.exp = a.exp - b.exp + G_BIAS + 1; /* unbiased exp */\n  a.frac = a.frac >> 1;               /* allow 1 bit left */\n  b.frac = b.frac >> 1;\n  a.frac = ufdiv64(a.frac, b.frac, 55, NULL); /* divide */\n  vax_norm(&a);                               /* normalize */\n  return vax_rpack(&a, ins, dp);              /* round and pack */\n}\n\n/**\n * \\brief Determine principal square root of a VAX floating-point value.\n *\n * \\param op  64-bit VAX floating in register format.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions.\n * \\param dp  DT_F for F-floating or DT_G for G-floating.\n * \\return    64-bit VAX floating in register format.\n **/\nu64 CAlphaCPU::vax_sqrt(u64 op, u32 ins, u32 dp) {\n  UFP b;\n\n  vax_unpack(op, &b, ins);\n  if (b.exp == 0)\n    return 0;                /* zero? */\n  if (b.sign) {              /* minus? */\n    vax_trap(TRAP_INV, ins); /* invalid operand */\n    return 0;\n  }\n\n  b.exp = ((b.exp + 1 - G_BIAS) >> 1) + G_BIAS; /* result exponent */\n  b.frac = fsqrt64(b.frac, b.exp);              /* result fraction */\n  return vax_rpack(&b, ins, dp);                /* round and pack */\n}\n\n//\\}\n\n/***************************************************************************/\n\n/**\n * \\name VAX_fp_support\n * VAX floating point support functions\n ******************************************************************************/\n\n//\\{\n\n/**\n * \\brief Set VAX floating-point trap\n *\n * Called when a VAX floating-point operation detects an exception.\n *\n * \\param mask  A bitmask in which the bits are set that correspond to\n *              the exception that occurred.\n * \\param ins   The instruction currently being executed. Used to properly\n *              set some registers for the trap to be handled.\n **/\nvoid CAlphaCPU::vax_trap(u64 mask, u32 ins) {\n  ARITH_TRAP(mask | ((ins & I_FTRP_S) ? TRAP_SWC : 0), I_GETRC(ins));\n}\n\n/**\n * \\brief Unpack VAX floating-point value\n *\n * Converts a VAX floating-point value to it's sign, exponent and fraction\n * components.\n *\n * \\param op  64-bit VAX floating in register format.\n * \\param r   Pointer to the unpacked-floating-point UFP structure\n *            where the results are to be returned.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions.\n **/\nvoid CAlphaCPU::vax_unpack(u64 op, UFP *r, u32 ins) {\n  r->sign = FPR_GETSIGN(op); /* get sign */\n  r->exp = FPR_GETEXP(op);   /* get exponent */\n  r->frac = FPR_GETFRAC(op); /* get fraction */\n  if (r->exp == 0)           /* exp = 0? */\n  {\n    if (r->sign != 0) /* rsvd op? */\n      vax_trap(TRAP_INV, ins);\n\n    // zero\n    r->frac = r->sign = 0;\n    return;\n  }\n\n  r->frac = (r->frac | FPR_HB) << FPR_GUARD; /* ins hidden bit, guard */\n  return;\n}\n\n/**\n * \\brief Unpack VAX D-floating-point value\n *\n * Converts a VAX D-floating-point value to it's sign, exponent and fraction\n * components.\n *\n * \\param op  64-bit VAX D-floating in register format.\n * \\param r   Pointer to the unpacked-floating-point UFP structure\n *            where the results are to be returned.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions.\n **/\nvoid CAlphaCPU::vax_unpack_d(u64 op, UFP *r, u32 ins) {\n  r->sign = FDR_GETSIGN(op); /* get sign */\n  r->exp = FDR_GETEXP(op);   /* get exponent */\n  r->frac = FDR_GETFRAC(op); /* get fraction */\n  if (r->exp == 0)           /* exp = 0? */\n  {\n    if (op != 0) /* rsvd op? */\n      vax_trap(TRAP_INV, ins);\n    r->frac = r->sign = 0;\n    return;\n  }\n\n  r->exp = r->exp + G_BIAS - D_BIAS;         /* change to G bias */\n  r->frac = (r->frac | FDR_HB) << FDR_GUARD; /* ins hidden bit, guard */\n  return;\n}\n\n/**\n * \\brief Normalize VAX floating-point value\n *\n * Normalize exponent and fraction components.\n *\n * \\param r   Pointer to the unpacked-floating-point UFP structure\n *            containing the value to be normalized, and where the\n *            results are to be returned.\n **/\nvoid CAlphaCPU::vax_norm(UFP *r) {\n  s32 i;\n  static u64 normmask[5] = {U64(0xc000000000000000), U64(0xf000000000000000),\n                            U64(0xff00000000000000), U64(0xffff000000000000),\n                            U64(0xffffffff00000000)};\n  static s32 normtab[6] = {1, 2, 4, 8, 16, 32};\n\n  r->frac = r->frac & X64_QUAD;\n  if (r->frac == 0) {     /* if fraction = 0 */\n    r->sign = r->exp = 0; /* result is 0 */\n    return;\n  }\n\n  while ((r->frac & UF_NM) == 0) { /* normalized? */\n    for (i = 0; i < 5; i++) {      /* find first 1 */\n      if (r->frac & normmask[i])\n        break;\n    }\n\n    r->frac = r->frac << normtab[i]; /* shift frac */\n    r->exp = r->exp - normtab[i];\n  } /* decr exp */\n\n  return;\n}\n\n/**\n * \\brief Round and pack VAX floating-point value\n *\n * Converts sign, exponent and fraction components to a register-format VAX\n * floating point value.\n *\n * \\param r   Pointer to the unpacked-floating-point UFP structure\n *            to be packed.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions and to determine the rounding mode.\n * \\param dp  DT_F for F-floating or DT_G for G-floating.\n * \\return    64-bit VAX floating in register format.\n **/\nu64 CAlphaCPU::vax_rpack(UFP *r, u32 ins, u32 dp) {\n  u32 rndm = I_GETFRND(ins);\n  static const u64 roundbit[2] = {UF_FRND, UF_GRND};\n  static const s32 expmax[2] = {G_BIAS - F_BIAS + F_M_EXP, G_M_EXP};\n  static const s32 expmin[2] = {G_BIAS - F_BIAS, 0};\n\n  if (r->frac == 0)\n    return 0;                                      /* result 0? */\n  if (rndm) {                                      /* round? */\n    r->frac = (r->frac + roundbit[dp]) & X64_QUAD; /* add round bit */\n    if ((r->frac & UF_NM) == 0) {                  /* carry out? */\n      r->frac = (r->frac >> 1) | UF_NM;            /* renormalize */\n      r->exp = r->exp + 1;\n    }\n  }\n\n  if (r->exp > expmax[dp]) { /* ovflo? */\n    vax_trap(TRAP_OVF, ins); /* set trap */\n    r->exp = expmax[dp];\n  } /* return max */\n\n  if (r->exp <= expmin[dp]) { /* underflow? */\n    if (ins & I_FTRP_V)\n      vax_trap(TRAP_UNF, ins); /* enabled? set trap */\n    return 0;\n  } /* underflow to 0 */\n\n  return (((u64)r->sign) << FPR_V_SIGN) | (((u64)r->exp) << FPR_V_EXP) |\n         ((r->frac >> FPR_GUARD) & FPR_FRAC);\n}\n\n/**\n * \\brief Round and pack VAX D-floating-point value\n *\n * Converts sign, exponent and fraction components to a register-format VAX\n * D-floating-point value.\n *\n * \\param r   Pointer to the unpacked-floating-point UFP structure\n *            to be packed.\n * \\param ins The instruction currently being executed. Used to properly\n *            handle exceptions.\n * \\return    64-bit VAX D-floating in register format.\n **/\nu64 CAlphaCPU::vax_rpack_d(UFP *r, u32 ins) {\n  if (r->frac == 0)\n    return 0;                        /* result 0? */\n  r->exp = r->exp + D_BIAS - G_BIAS; /* rebias */\n  if (r->exp > FDR_M_EXP) {          /* ovflo? */\n    vax_trap(TRAP_OVF, ins);         /* set trap */\n    r->exp = FDR_M_EXP;\n  } /* return max */\n\n  if (r->exp <= 0) { /* underflow? */\n    if (ins & I_FTRP_V)\n      vax_trap(TRAP_UNF, ins); /* enabled? set trap */\n    return 0;\n  } /* underflow to 0 */\n\n  return (((u64)r->sign) << FDR_V_SIGN) | (((u64)r->exp) << FDR_V_EXP) |\n         ((r->frac >> FDR_GUARD) & FDR_FRAC);\n}\n\n//\\}\n"
  },
  {
    "path": "src/AlphaCPU_vmspal.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"AlphaCPU.hpp\"\n#include \"StdAfx.hpp\"\n\n#include \"AliM1543C_ide.hpp\"\n#include \"Disk.hpp\"\n#include \"Serial.hpp\"\n\n/***********************************************************\n *                                                         *\n *                      VMS PALcode                        *\n *                                                         *\n ***********************************************************/\n#define p4 state.r[32 + 4]\n#define p5 state.r[32 + 5]\n#define p6 state.r[32 + 6]\n#define p7 state.r[32 + 7]\n\n#define p20 state.r[32 + 20]\n#define p21 state.r[32 + 21]\n#define p22 state.r[32 + 22]\n#define p23 state.r[32 + 23]\n\n#define r0 state.r[0]\n#define r1 state.r[1]\n#define r2 state.r[2]\n#define r3 state.r[3]\n\n//#define r4 state.r[4]\n//#define r5 state.r[5]\n//#define r6 state.r[6]\n//#define r7 state.r[7]\n#define r8 state.r[8]\n#define r9 state.r[9]\n#define r10 state.r[10]\n#define r11 state.r[11]\n#define r12 state.r[12]\n#define r13 state.r[13]\n#define r14 state.r[14]\n#define r15 state.r[15]\n#define r16 state.r[16]\n#define r17 state.r[17]\n#define r18 state.r[18]\n#define r19 state.r[19]\n\n//#define r20 state.r[20]\n//#define r21 state.r[21]\n//#define r22 state.r[22]\n//#define r23 state.r[23]\n#define r24 state.r[24]\n\n//#define r25 state.r[25]\n//#define r26 state.r[26]\n#define r27 state.r[27]\n#define r28 state.r[28]\n#define r29 state.r[29]\n#define r30 state.r[30]\n#define r31 state.r[31]\n\n#define hw_stq(a, b) cSystem->WriteMem(a & ~U64(0x7), 64, b, this)\n#define hw_stl(a, b) cSystem->WriteMem(a & ~U64(0x3), 32, b, this)\n#define stq(a, b)                                                              \\\n  if (virt2phys(a, &phys_address, ACCESS_WRITE, NULL, 0))                      \\\n    return -1;                                                                 \\\n  cSystem->WriteMem(phys_address, 64, b, this);\n#define ldq(a, b)                                                              \\\n  if (virt2phys(a, &phys_address, ACCESS_READ, NULL, 0))                       \\\n    return -1;                                                                 \\\n  b = cSystem->ReadMem(phys_address, 64, this);\n#define stl(a, b)                                                              \\\n  if (virt2phys(a, &phys_address, ACCESS_WRITE, NULL, 0))                      \\\n    return -1;                                                                 \\\n  cSystem->WriteMem(phys_address, 32, b, this);\n#define ldl(a, b)                                                              \\\n  if (virt2phys(a, &phys_address, ACCESS_READ, NULL, 0))                       \\\n    return -1;                                                                 \\\n  b = sext_u64_32(cSystem->ReadMem(phys_address, 32, this));\n#define ldb(a, b)                                                              \\\n  if (virt2phys(a, &phys_address, ACCESS_READ, NULL, 0))                       \\\n    return -1;                                                                 \\\n  b = (char)(cSystem->ReadMem(phys_address, 8, this));\n#define hw_ldq(a, b) b = cSystem->ReadMem(a & ~U64(0x7), 64, this)\n#define hw_ldl(a, b) b = sext_u64_32(cSystem->ReadMem(a & ~U64(0x3), 32, this));\n#define hw_ldbu(a, b) b = cSystem->ReadMem(a, 8, this)\n\n/**\n * Mask for interrupt enabling at IPL's.\n *\n * For each of the 32 IPL's gives the values for eien, slen, cren, pcen,\n * sien and asten.\n *\n * Source: table of IER masks in PALcode at offset 0d00H.\n **/\nstatic int ipl_ier_mask[32][6] = {\n\n    /* ei, sl, cr, pc,     si, ast */\n    {0x3f, 0, 1, 3, 0xfffe, 1}, {0x3f, 0, 1, 3, 0xfffc, 1},\n    {0x3f, 0, 1, 3, 0xfff8, 0}, {0x3f, 0, 1, 3, 0xfff0, 0},\n    {0x3f, 0, 1, 3, 0xffe0, 0}, {0x3f, 0, 1, 3, 0xffc0, 0},\n    {0x3f, 0, 1, 3, 0xff80, 0}, {0x3f, 0, 1, 3, 0xff00, 0},\n    {0x3f, 0, 1, 3, 0xfe00, 0}, {0x3f, 0, 1, 3, 0xfc00, 0},\n    {0x3f, 0, 1, 3, 0xf800, 0}, {0x3f, 0, 1, 3, 0xf000, 0},\n    {0x3f, 0, 1, 3, 0xe000, 0}, {0x3f, 0, 1, 3, 0xc000, 0},\n    {0x3f, 0, 1, 3, 0x8000, 0}, {0x3f, 0, 1, 3, 0, 0},\n    {0x3f, 0, 1, 3, 0, 0},      {0x3f, 0, 1, 3, 0, 0},\n    {0x3f, 0, 1, 3, 0, 0},      {0x3f, 0, 1, 3, 0, 0},\n    {0x3f, 0, 1, 3, 0, 0},      {0x3d, 0, 1, 3, 0, 0},\n    {0x31, 0, 1, 3, 0, 0},      {0x31, 0, 1, 3, 0, 0},\n    {0x31, 0, 1, 3, 0, 0},      {0x31, 0, 1, 3, 0, 0},\n    {0x31, 0, 1, 3, 0, 0},      {0x31, 0, 1, 3, 0, 0},\n    {0x31, 0, 1, 3, 0, 0},      {0x31, 0, 1, 0, 0, 0},\n    {0x31, 0, 1, 3, 0, 0},      {0x10, 0, 1, 3, 0, 0}};\n\n/***************************************************************************/\n\n/**\n * \\name VMS_pal_call\n * VMS PALcode CALL replacement routines.\n ******************************************************************************/\n\n//\\{\n\n/**\n * Implementation of CALL_PAL CFLUSH opcode.\n **/\nvoid CAlphaCPU::vmspal_call_cflush() {\n\n  // don't do anything...\n}\n\n/**\n * Implementation of CALL_PAL DRAINA opcode.\n **/\nvoid CAlphaCPU::vmspal_call_draina() {\n\n  // don't do anything...\n}\n\n/**\n * Implementation of CALL_PAL LDQP opcode.\n **/\nvoid CAlphaCPU::vmspal_call_ldqp() { hw_ldq(r16, r0); }\n\n/**\n * Implementation of CALL_PAL STQP opcode.\n **/\nvoid CAlphaCPU::vmspal_call_stqp() { hw_stq(r16, r17); }\n\n/**\n * Implementation of CALL_PAL SWPCTX opcode.\n **/\nvoid CAlphaCPU::vmspal_call_swpctx() {\n  p23 = state.pc;\n\n  if (r16 & 0x7f) {\n\n    // context pointer not properly aligned...\n    p4 = 0x430;\n    hw_stq(p21 + 0x150, p23);\n    hw_stq(p21 + 0x158, p4);\n    vmspal_int_initiate_exception();\n    return;\n  }\n\n  hw_ldq(r16 + 0x30, p4);\n  hw_ldq(r16 + 0x38, p5);\n  hw_ldq(r16 + 0x28, p6);\n\n  p20 = state.aster | (state.astrr << 4);\n\n  p6 &= 0xff;\n  state.asn0 = (int)p6;\n  state.asn1 = (int)p6;\n  state.asn = (int)p6;\n  state.aster = (int)p4 & 0xf;\n  state.astrr = (int)(p4 >> 4) & 0xf;\n  state.fpen = (int)p5 & 1;\n  state.ppcen = (int)(p5 >> 0x3e) & 1;\n  state.check_int = true;\n\n  hw_ldq(r16 + 0x40, p7);\n  hw_ldq(r16 + 0x20, p6);\n\n  p4 = (state.cc & U64(0xffffffff)) + state.cc_offset;\n  state.cc_offset = ((u32)p7 & 0xffffffff) - (state.cc & U64(0xffffffff));\n\n  p6 <<= 0x0d;\n  hw_stq(p21 + 8, p6);\n  hw_ldq(p21 + 0x10, p5);\n  hw_ldq(r16, p6);\n  hw_stl(p5 + 0x40, p4);\n  hw_stq(p5 + 0x30, p20);\n  hw_stq(p5, r30);\n\n  r30 = p6;\n  hw_stq(p21 + 0x10, r16);\n}\n\n/**\n * Implementation of CALL_PAL MFPR_ASN opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mfpr_asn() { r0 = state.asn; }\n\n/**\n * Implementation of CALL_PAL MTPR_ASTEN opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mtpr_asten() {\n  r0 = state.aster;\n  state.aster &= r16;\n  state.aster |= (r16 >> 4) & 0xf;\n  state.check_int = true;\n}\n\n/**\n * Implementation of CALL_PAL MTPR_ASTSR opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mtpr_astsr() {\n  r0 = state.astrr;\n  state.astrr &= r16;\n  state.astrr |= (r16 >> 4) & 0xf;\n  state.check_int = true;\n}\n\n/**\n * Implementation of CALL_PAL CSERVE opcode.\n **/\nvoid CAlphaCPU::vmspal_call_cserve() {\n  p23 = state.pc;\n\n  switch (r16) {\n  case 0x10:\n    hw_ldl(r17, r0);\n    break;\n  case 0x11:\n    hw_stl(r17, r18);\n    break;\n  case 0x12:\n    set_pc(0x12e21);\n    break;\n  case 0x13:\n    set_pc(0x12f95);\n    break;\n  case 0x14:\n    set_pc(0x13115);\n    break;\n  case 0x15:\n    set_pc(0x131c1);\n    break;\n  case 0x40:\n    set_pc(0x13249);\n    break;\n  case 0x41:\n    hw_ldq(p21 + 0x98, r0);\n    break;\n  case 0x42:\n    set_pc(0x13781);\n    break;\n  case 0x43:\n    set_pc(0x13261);\n    break;\n  case 0x44:\n    set_pc(r17);\n    break;\n  case 0x45:\n    set_pc(0x13289);\n    break;\n  case 0x65:\n    set_pc(0x132bd);\n    break;\n  case 0x3e:\n    set_pc(0x1344d);\n    break;\n  case 0x66:\n    set_pc(0x133e9);\n    break;\n  }\n}\n\n/**\n * Implementation of CALL_PAL MFPR_FEN opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mfpr_fen() { r0 = state.fpen ? 1 : 0; }\n\n/**\n * Implementation of CALL_PAL MTPR_FEN opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mtpr_fen() {\n  hw_ldq(p21 + 0x10, p4);\n  state.fpen = (r16 & 1);\n  hw_stl(p4 + 0x38, r16);\n}\n\n/**\n * Implementation of CALL_PAL MFPR_IPL opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mfpr_ipl() { r0 = (p22 >> 8) & 0x1f; }\n\n/**\n * Implementation of CALL_PAL MTPR_IPL opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mtpr_ipl() {\n  r0 = (p22 >> 8) & 0xff;\n  p22 &= ~U64(0xff00);\n  p22 |= (r16 << 8);\n  state.eien = ipl_ier_mask[r16][0];\n  state.slen = ipl_ier_mask[r16][1];\n  state.cren = ipl_ier_mask[r16][2];\n  state.pcen = ipl_ier_mask[r16][3];\n  state.sien = ipl_ier_mask[r16][4];\n  state.asten = ipl_ier_mask[r16][5];\n  state.check_int = true;\n}\n\n/**\n * Implementation of CALL_PAL MFPR_MCES opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mfpr_mces() { r0 = (p22 >> 16) & 0xff; }\n\n/**\n * Implementation of CALL_PAL MTPR_MCES opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mtpr_mces() {\n  p22 = (p22 & U64(0xffffffffff00ffff)) |\n        (p22 & U64(0x0000000000070000) & ~(r16 << 16)) |\n        ((r16 << 16) & U64(0x0000000000180000));\n}\n\n/**\n * Implementation of CALL_PAL MFPR_PCBB opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mfpr_pcbb() { hw_ldq(p21 + 0x10, r0); }\n\n/**\n * Implementation of CALL_PAL MFPR_PRBR opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mfpr_prbr() { hw_ldq(p21 + 0xa8, r0); }\n\n/**\n * Implementation of CALL_PAL MTPR_PRBR opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mtpr_prbr() { hw_stq(p21 + 0xa8, r16); }\n\n/**\n * Implementation of CALL_PAL MFPR_PTBR opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mfpr_ptbr() {\n  hw_ldq(p21 + 8, r0);\n  r0 >>= 0x0d;\n}\n\n/**\n * Implementation of CALL_PAL MFPR_SCBB opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mfpr_scbb() {\n  hw_ldq(p21 + 0x170, r0);\n  r0 >>= 0x0d;\n}\n\n/**\n * Implementation of CALL_PAL MTPR_SCBB opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mtpr_scbb() {\n  hw_stq(p21 + 0x170, (r16 & U64(0xffffffff)) << 0xd);\n}\n\n/**\n * Implementation of CALL_PAL MTPR_SIRR opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mtpr_sirr() {\n  if (r16 > 0 && r16 < 16) {\n    state.sir |= 1 << r16;\n    state.check_int = true;\n  }\n}\n\n/**\n * Implementation of CALL_PAL MFPR_SISR opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mfpr_sisr() { r0 = state.sir; }\n\n/**\n * Implementation of CALL_PAL MFPR_TBCHK opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mfpr_tbchk() { r0 = U64(0x8000000000000000); }\n\n/**\n * Implementation of CALL_PAL MTPR_TBIA opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mtpr_tbia() {\n  tbia(ACCESS_READ);\n  tbia(ACCESS_EXEC);\n  flush_icache();\n}\n\n/**\n * Implementation of CALL_PAL MTPR_TBIAP opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mtpr_tbiap() {\n  tbiap(ACCESS_READ);\n  tbiap(ACCESS_EXEC);\n  flush_icache_asm();\n}\n\n/**\n * Implementation of CALL_PAL MTPR_TBIS opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mtpr_tbis() {\n  tbis(r16, ACCESS_READ);\n  tbis(r16, ACCESS_EXEC);\n}\n\n/**\n * Implementation of CALL_PAL MFPR_ESP opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mfpr_esp() {\n  u64 t;\n  hw_ldq(p21 + 0x10, t);\n  hw_ldq(t + 8, r0);\n}\n\n/**\n * Implementation of CALL_PAL MTPR_ESP opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mtpr_esp() {\n  u64 t;\n  hw_ldq(p21 + 0x10, t);\n  hw_stq(t + 8, r16);\n}\n\n/**\n * Implementation of CALL_PAL MFPR_SSP opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mfpr_ssp() {\n  u64 t;\n  hw_ldq(p21 + 0x10, t);\n  hw_ldq(t + 0x10, r0);\n}\n\n/**\n * Implementation of CALL_PAL MTPR_SSP opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mtpr_ssp() {\n  u64 t;\n  hw_ldq(p21 + 0x10, t);\n  hw_stq(t + 0x10, r16);\n}\n\n/**\n * Implementation of CALL_PAL MFPR_USP opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mfpr_usp() {\n  u64 t;\n  hw_ldq(p21 + 0x10, t);\n  hw_ldq(t + 0x18, r0);\n}\n\n/**\n * Implementation of CALL_PAL MTPR_USP opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mtpr_usp() {\n  u64 t;\n  hw_ldq(p21 + 0x10, t);\n  hw_stq(t + 0x18, r16);\n}\n\n/**\n * Implementation of CALL_PAL MTPR_TBISD opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mtpr_tbisd() { tbis(r16, ACCESS_READ); }\n\n/**\n * Implementation of CALL_PAL MTPR_TBISI opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mtpr_tbisi() { tbis(r16, ACCESS_EXEC); }\n\n/**\n * Implementation of CALL_PAL MFPR_ASTEN opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mfpr_asten() { r0 = state.aster; }\n\n/**\n * Implementation of CALL_PAL MFPR_ASTSR opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mfpr_astsr() { r0 = state.astrr; }\n\n/**\n * Implementation of CALL_PAL MFPR_VPTB opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mfpr_vptb() { hw_ldq(p21, r0); }\n\n/**\n * Implementation of CALL_PAL MTPR_DATFX opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mtpr_datfx() {\n  u64 t;\n\n  u64 u;\n  hw_ldq(p21 + 0x10, t);\n  hw_ldq(t, u);\n  u |= U64(0x1) << 0x3f;\n  u &= ~(r16 << 0x3f);\n  hw_stq(t, u);\n}\n\n/**\n * Implementation of CALL_PAL MFPR_WHAMI opcode.\n **/\nvoid CAlphaCPU::vmspal_call_mfpr_whami() { hw_ldq(p21 + 0x98, r0); }\n\n/**\n * Implementation of CALL_PAL IMB opcode.\n **/\nvoid CAlphaCPU::vmspal_call_imb() {\n  if (p22 & 0x18) {\n    hw_ldq(p21 + 0x10, p20);\n    hw_ldl(p20 + 0x3c, p5);\n    p5 |= 1;\n    hw_stl(p20 + 0x3c, p5);\n  }\n\n  flush_icache();\n}\n\n/**\n * Implementation of CALL_PAL PROBER opcode.\n **/\nvoid CAlphaCPU::vmspal_call_prober() {\n  u64 pa;\n\n  p23 = state.pc;\n  p4 = r18 & 3; // alt mode\n  p5 = p22 & 0x18;\n  p5 >>= 3; // current mode\n  p6 = p5 - p4;\n  if (p5 > p4)\n    p4 = p5;\n  state.alt_cm = (int)p4;\n  hw_stq(p21 + 0x140, state.pc);\n  hw_stq(p21 + 0x148, p4);\n\n  if (virt2phys(r16, &pa, ACCESS_READ | ALT | PROBE, NULL, 0) < 0)\n    return;\n\n  if (virt2phys(r16 + r17, &pa, ACCESS_READ | ALT | PROBE, NULL, 0) < 0)\n    return;\n\n  r0 = 1;\n  return;\n}\n\n/**\n * Implementation of CALL_PAL PROBEW opcode.\n **/\nvoid CAlphaCPU::vmspal_call_probew() {\n  u64 pa;\n\n  p23 = state.pc;\n  p4 = r18 & 3; // alt mode\n  p5 = p22 & 0x18;\n  p5 >>= 3; // current mode\n  p6 = p5 - p4;\n  if (p5 > p4)\n    p4 = p5;\n  state.alt_cm = (int)p4;\n  hw_stq(p21 + 0x140, state.pc);\n  hw_stq(p21 + 0x148, p4);\n  if (virt2phys(r16, &pa, ACCESS_WRITE | ALT | PROBE | PROBEW, NULL, 0) < 0)\n    return;\n\n  if (virt2phys(r16 + r17, &pa, ACCESS_WRITE | ALT | PROBE | PROBEW, NULL, 0) <\n      0)\n    return;\n\n  r0 = 1;\n  return;\n}\n\n/**\n * Implementation of CALL_PAL RD_PS opcode.\n **/\nvoid CAlphaCPU::vmspal_call_rd_ps() { r0 = p22 & U64(0xffff); }\n\n/**\n * Implementation of CALL_PAL REI opcode.\n **/\nint CAlphaCPU::vmspal_call_rei() {\n  u64 phys_address;\n\n  p23 = state.pc;\n\n  p7 = p22 & 0x18; // old cm\n  hw_stq(p21 + 0x150, p23);\n  if (r30 & 0x3f) {\n\n    // stack not aligned\n    p4 = 0x430;\n    hw_stq(p21 + 0x158, p4);\n    return vmspal_int_initiate_exception();\n  }\n\n  if (p7) {\n\n    // what to do if the next instruction results in a TNV exception?\n    ldq(r30 + 0x38, p20);\n    state.bIntrFlag = false;\n    ldq(r30 + 0x30, p23);\n    p4 = p20 & 0x18; // new cm\n    if ((p4 < p7) || (p20 & ~U64(0x3f0000000000001b))) {\n      p4 = 0x430;\n      hw_stq(p21 + 0x158, p4);\n      vmspal_int_initiate_exception();\n      return 0;\n    }\n\n    ldq(r30 + 0x10, state.r[4]);\n    ldq(r30 + 0x18, state.r[5]);\n    ldq(r30 + 0x20, state.r[6]);\n    ldq(r30 + 0x28, state.r[7]);\n    ldq(r30, r2);\n    ldq(r30 + 8, r3);\n    hw_ldq(p21 + 0x10, p6);\n    p5 = (p20 >> 56) & 0xff;\n    p7 += p6;\n    p6 += p4;\n    p20 &= 0xffff;\n    p22 &= ~U64(0xffff);\n    state.cm = (int)(p4 >> 3) & 3;\n    p22 |= p20;\n    p23 &= ~U64(0x3);\n    p20 = r30 + 0x40;\n    p20 |= p5;\n    hw_stq(p7, p20);\n    hw_ldq(p6, r30);\n    set_pc(p23);\n    return 0;\n  }\n\n  ldq(r30 + 0x38, p20);\n  state.bIntrFlag = false;\n  p7 = (p20 >> 8) & 0xff;\n  ldq(r30 + 0x10, state.r[4]);\n  ldq(r30 + 0x18, state.r[5]);\n  ldq(r30 + 0x20, state.r[6]);\n  ldq(r30 + 0x28, state.r[7]);\n  ldq(r30, r2);\n  ldq(r30 + 8, r3);\n  p4 = p20 & 0x18; // new cm\n  ldq(r30 + 0x30, p23);\n\n  if (p4) {\n    hw_ldq(p21 + 0x10, p7);\n    p7 += p4;\n    state.cm = (int)(p4 >> 3) & 3;\n    p5 = (p20 >> 56) & 0xff;\n    p20 &= 0xff;\n    p22 &= ~U64(0xffff);\n    p22 |= p20;\n    p23 &= ~U64(0x3);\n    p20 = r30 + 0x40;\n    p20 |= p5;\n    hw_ldq(p7, r30);\n    hw_stq(p21 + 0x18, p20);\n    state.eien = ipl_ier_mask[0][0];\n    state.slen = ipl_ier_mask[0][1];\n    state.cren = ipl_ier_mask[0][2];\n    state.pcen = ipl_ier_mask[0][3];\n    state.sien = ipl_ier_mask[0][4];\n    state.asten = ipl_ier_mask[0][5];\n    state.check_int = true;\n    set_pc(p23);\n    return 0;\n  }\n\n  p5 = (p20 >> 56) & 0xff;\n  p20 &= 0xffff;\n  p22 &= ~U64(0xffff);\n  p7 = (p20 >> 8) & 0xff;\n  p22 |= p20;\n  p23 &= ~U64(0x3);\n  p20 = r30 + 0x40;\n  r30 = p20 | p5;\n  state.eien = ipl_ier_mask[p7][0];\n  state.slen = ipl_ier_mask[p7][1];\n  state.cren = ipl_ier_mask[p7][2];\n  state.pcen = ipl_ier_mask[p7][3];\n  state.sien = ipl_ier_mask[p7][4];\n  state.asten = ipl_ier_mask[p7][5];\n  state.check_int = true;\n  set_pc(p23);\n  return 0;\n}\n\n/**\n * Implementation of CALL_PAL SWASTEN opcode.\n **/\nvoid CAlphaCPU::vmspal_call_swasten() {\n  r0 = (state.aster & (1 << ((p22 >> 3) & 3))) ? 1 : 0;\n  if (r16 & 1) {\n    state.aster |= (1 << ((p22 >> 3) & 3));\n    state.check_int = true;\n  } else\n    state.aster &= ~(1 << ((p22 >> 3) & 3));\n}\n\n/**\n * Implementation of CALL_PAL WR_PS_SW opcode.\n **/\nvoid CAlphaCPU::vmspal_call_wr_ps_sw() {\n  p22 &= ~U64(0x3);\n  p22 |= r16 & U64(0x3);\n}\n\n/**\n * Implementation of CALL_PAL RSCC opcode.\n **/\nvoid CAlphaCPU::vmspal_call_rscc() {\n  hw_ldq(p21 + 0xa0, r0);\n  if ((state.cc & U64(0xffffffff)) < (r0 & U64(0x00000000ffffffff)))\n    r0 += U64(0x1) << 0x20;\n  r0 &= U64(0xffffffff00000000);\n  r0 |= (state.cc & U64(0xffffffff));\n  hw_stq(p21 + 0xa0, r0);\n}\n\n/**\n * Implementation of CALL_PAL READ_UNQ opcode.\n **/\nvoid CAlphaCPU::vmspal_call_read_unq() {\n  u64 t;\n  hw_ldq(p21 + 0x10, t);\n  hw_ldq(t + 0x48, r0);\n}\n\n/**\n * Implementation of CALL_PAL WRITE_UNQ opcode.\n **/\nvoid CAlphaCPU::vmspal_call_write_unq() {\n  u64 t;\n  hw_ldq(p21 + 0x10, t);\n  hw_stq(t + 0x48, r16);\n}\n\n//\\}\n\n/***************************************************************************/\n\n/**\n * \\name VMS_pal_int\n * Internal routines used by VMS PALcode replacement.\n ******************************************************************************/\n\n//\\{\n\n/**\n * Pass control to the OS for handling the exception.\n **/\nint CAlphaCPU::vmspal_int_initiate_exception() {\n  u64 phys_address;\n\n  p4 = p22 & U64(0x18);\n  hw_ldq(p21 + U64(0x10), p20);\n  if (p4) {\n\n    // change mode to kernel\n    state.cm = 0;\n\n    // switch to kernel stack\n    p20 += p4;\n    hw_stq(p20, r30);\n    hw_ldq(p21 + U64(0x18), r30);\n  }\n\n  p20 = r30 & U64(0x3f);\n  r30 &= ~U64(0x3f);\n  stq(r30 - U64(0x40), r2);\n  stq(r30 - U64(0x38), r3);\n  hw_stq(p21 + U64(0xf0), r1);\n  r3 = p21;\n  stq(r30 - U64(0x30), state.r[4]);\n  stq(r30 - U64(0x28), state.r[5]);\n  stq(r30 - U64(0x20), state.r[6]);\n  stq(r30 - U64(0x18), state.r[7]);\n  hw_ldq(state.r[3] + U64(0x160), state.r[4]);\n  hw_ldq(state.r[3] + U64(0x168), state.r[5]);\n  hw_ldq(p21 + U64(0xf0), r1);\n  hw_ldq(p21 + U64(0x170), p4);\n  hw_ldq(p21 + U64(0x158), p5);\n  p7 = p22 & U64(0xffff);\n  p20 <<= 0x38;\n  p20 |= p7;\n  p4 += p5;\n  hw_ldq(p4 + U64(0x00), r2);\n  hw_ldq(p4 + U64(0x08), r3);\n  p22 &= ~U64(0x1b);\n  r30 -= U64(0x40);\n  hw_ldq(p21 + U64(0x150), p6);\n  r2 &= ~U64(0x3);\n  stq(r30 + U64(0x38), p20);\n  stq(r30 + U64(0x30), p6);\n\n  set_pc(r2);\n  return -1;\n}\n\n/**\n * Pass control to the OS for handling the interrupt.\n **/\nint CAlphaCPU::vmspal_int_initiate_interrupt() {\n  u64 phys_address;\n\n  p4 = p22 & U64(0x18);\n  hw_ldq(p21 + U64(0x10), p20);\n  if (p4) {\n\n    // change mode to kernel\n    state.cm = 0;\n\n    // switch to kernel stack\n    p20 += p4;\n    hw_stq(p20, r30);\n    hw_ldq(p21 + U64(0x18), r30);\n  }\n\n  p20 = r30 & U64(0x3f);\n  r30 &= ~U64(0x3f);\n  stq(r30 - U64(0x40), r2);\n  stq(r30 - U64(0x38), r3);\n  hw_stq(p21 + U64(0xf0), r1);\n  r3 = p21;\n  stq(r30 - U64(0x30), state.r[4]);\n  stq(r30 - U64(0x28), state.r[5]);\n  stq(r30 - U64(0x20), state.r[6]);\n  stq(r30 - U64(0x18), state.r[7]);\n  hw_ldq(state.r[3] + U64(0x160), state.r[4]);\n  hw_ldq(state.r[3] + U64(0x168), state.r[5]);\n  hw_ldq(p21 + U64(0xf0), r1);\n  hw_ldq(p21 + U64(0x170), p4);\n  hw_ldq(p21 + U64(0x158), p5);\n  p7 = p22 & U64(0xffff);\n  p20 <<= 0x38;\n  p20 |= p7;\n  p4 += p5;\n  hw_ldq(p4, r2);\n  hw_ldq(p4 + U64(0x08), r3);\n  hw_ldq(p21 + U64(0x128), p4);\n  p22 &= ~U64(0xffff);\n  p22 |= p4;\n  r30 -= U64(0x40);\n  hw_ldq(p21 + U64(0x150), p6);\n  r2 &= ~U64(0x3);\n  stq(r30 + U64(0x38), p20);\n  stq(r30 + U64(0x30), p6);\n\n  set_pc(r2);\n  return -1;\n}\n\n//\\}\n\n/***************************************************************************/\n\n/**\n * \\name VMS_pal_ent\n * VMS PALcode replacement trap/exception entry-points.\n ******************************************************************************/\n\n//\\{\n\n/**\n * Interrupt entry point for Software Interrupts.\n **/\nint CAlphaCPU::vmspal_ent_sw_int(int si) {\n  int x;\n\n  state.exc_addr = state.current_pc;\n  p23 = state.current_pc;\n  for (x = 15; x >= 0; x--) {\n    if (si & (1 << x))\n      break;\n  }\n\n  if (x <= 0)\n    return 0;\n\n  p7 = x;\n  p4 = (u64)x << 4;\n  p5 = p4 + 0x500;\n  hw_stq(p21 + 0x158, p5);\n  hw_stq(p21 + 0x150, state.current_pc);\n  state.sir &= ~(1 << x);\n  state.eien = ipl_ier_mask[x][0];\n  state.slen = ipl_ier_mask[x][1];\n  state.cren = ipl_ier_mask[x][2];\n  state.pcen = ipl_ier_mask[x][3];\n  state.sien = ipl_ier_mask[x][4];\n  state.asten = ipl_ier_mask[x][5];\n  state.check_int = true;\n  p20 = (u64)x << 8;\n  p20 |= 4;\n  hw_stq(p21 + 0x128, p20);\n  return vmspal_int_initiate_interrupt();\n}\n\n/**\n * Interrupt entry point for External Interrupts.\n **/\nint CAlphaCPU::vmspal_ent_ext_int(int ei) {\n  bool do_11670 = false;\n\n  state.exc_addr = state.current_pc;\n  p23 = state.current_pc;\n  p7 = ei;\n  if (ei & 0x04) {\n\n    // TIMER interrupt\n    cSystem->clear_clock_int(state.iProcNum);\n    p6 = cSystem->get_c_misc();\n\n    p22 += U64(0x0000010000000000);\n    p22 &= U64(0xffff0fffffffffff);\n\n    hw_ldq(p21 + 0xa0, p20);\n    p6 = U64(0x1) << 0x20;\n    p4 = (state.cc & U64(0xffffffff));\n    p5 = p20 & U64(0xffffffff);\n    p20 &= U64(0xffffffff00000000);\n    p7 = p4 - p5;\n    if (((s64)p7) < 0)\n      p20 += p6;\n    p20 |= (state.cc & U64(0xffffffff));\n    hw_stq(p21 + 0xa0, p20);\n    hw_stq(p21 + 0x1c8, 0);\n    p20 = 0x600;\n    p7 = 0x16;\n\n    do_11670 = true;\n  } else if (ei & 0x02) {\n    p5 = cSystem->get_c_dir(state.iProcNum);\n    if (test_bit_64(p5, 0x32))\n      FAILURE(NotImplemented, \"Can't handle IRQ 50\");\n\n    p4 = 0x100;\n    p20 = 8;\n    while (p20 < 0x30) {\n      if (p4 & p5)\n        break;\n      p4 *= 2;\n      p20++;\n    }\n\n    if (p4 & p5) {\n      p20 <<= 4;\n      p20 += 0x900;\n      p7 = 0x15;\n\n      do_11670 = true;\n    } else if (test_bit_64(p5, 0x37)) {\n\n      // irq 55 - PIC - isa\n      p5 = U64(0x00000801f8000000);\n\n      // pic_read_vector\n      hw_ldl(p5, p5);\n      p4 = p5 & 0xff;\n      if (p4 == 0x07)\n        FAILURE(NotImplemented, \"Can't handle PIC interrupt 7\");\n\n      if (p4 >= 0x10)\n        return 0;\n\n      p4 <<= 4;\n      p20 = p4 + 0x800;\n      hw_ldq(0x148, p5);\n      if (!p5 || p20 != U64(0x830)) {\n        p7 = 0x15;\n        do_11670 = true;\n      } else {\n        hw_stq(0x150, p20);\n        p4 = U64(0x00000801a0000000);\n        p5 = U64(0x2000);\n        hw_stq(p4 + 0x80, p5);\n        hw_ldq(p4 + 0x80, p5);\n        return 0;\n      }\n    } else {\n      p6 = p5 & U64(0x0060000000000000);\n      if (p6)\n        cSystem->set_c_dim(state.iProcNum,\n                           cSystem->get_c_dim(state.iProcNum) & ~p6);\n      return 0;\n    }\n  }\n\n  if (do_11670) {\n    hw_stq(p21 + 0x150, state.current_pc);\n    hw_stq(p21 + 0x158, p20);\n    hw_stq(p21 + 0x1d8, p20);\n    state.eien = ipl_ier_mask[p7][0];\n    state.slen = ipl_ier_mask[p7][1];\n    state.cren = ipl_ier_mask[p7][2];\n    state.pcen = ipl_ier_mask[p7][3];\n    state.sien = ipl_ier_mask[p7][4];\n    state.asten = ipl_ier_mask[p7][5];\n    state.check_int = true;\n    p20 = p7 << 8;\n    p20 |= 4;\n    hw_stq(p21 + 0x128, p20);\n\n    return vmspal_int_initiate_interrupt();\n  }\n\n  return 0;\n}\n\n/**\n * Interrupt entry point for Asynchronous System Traps.\n **/\nint CAlphaCPU::vmspal_ent_ast_int(int ast) {\n  int x;\n\n  state.exc_addr = state.current_pc;\n  p23 = state.current_pc;\n\n  for (x = 0; x < 4; x++) {\n    if (ast & (1 << x))\n      break;\n  }\n\n  state.asten = 0;\n  state.sien &= ~7;\n  p4 = (u64)x << 4;\n  p5 = 0x240 + p4;\n  hw_stq(p21 + 0x158, p5);\n  hw_stq(p21 + 0x150, p23);\n  state.astrr &= ~(1 << x);\n  p20 = (p22 & 4) + 0x200;\n  hw_stq(p21 + 0x128, p20);\n  return vmspal_int_initiate_interrupt();\n}\n\n/**\n * Entry point for Single Data Translation Buffer Miss.\n **/\nint CAlphaCPU::vmspal_ent_dtbm_single(int flags) {\n  u64 pte_phys;\n  u64 t25;\n  u64 t26;\n\n  p23 = state.exc_addr;\n  p4 = va_form(state.fault_va, false);\n  p5 = state.mm_stat;\n  p7 = state.exc_sum;\n  p6 = state.fault_va;\n  p7 &= ~U64(0x1);\n  if (test_bit_64(p22, 63)) {\n\n    // 1-ON-1 translations\n    p5 = 0xff01;\n    p4 = p6 >> 0x0d;\n    if (!test_bit_64(p6, 43)) {\n      p4 &= ~U64(0xffffffffbfc00000);\n      if ((p4 >= 0x400a0000 && p4 <= 0x400bffff) ||\n          (p4 >= 0x400c8000 && p4 <= 0x400cffff) ||\n          (p4 >= 0x400e0000 && p4 <= 0x400fbfff) ||\n          (p4 >= 0x400ff800 && p4 <= 0x400fffff) ||\n          (p4 >= 0x40180000 && p4 <= 0x401bffff) ||\n          (p4 >= 0x401c8000 && p4 <= 0x401fbfff) ||\n          (p4 >= 0x401fb000 && p4 <= 0x401fffff) ||\n          (p4 >= 0x40200000 && p4 <= 0x403fffff))\n        p5 = U64(0x1);\n    }\n\n    p4 <<= 0x20;\n    p4 |= p5;\n    add_tb_d(p6, p4);\n    return 0;\n  }\n\n  p4 &= ~U64(0x7);\n  if (virt2phys(p4, &pte_phys,\n                ACCESS_READ | NO_CHECK | VPTE | (flags & (PROBE | PROBEW)),\n                NULL, 0))\n    return -1;\n  p4 = cSystem->ReadMem(pte_phys, 64, this);\n\n  if (!test_bit_64(p4, 0)) {\n    if (flags & PROBE) {\n      t25 = U64(0x30000);\n      p4 |= t25;\n      t26 = p5 & 1; // write or read?\n      t26 *= 4;\n      t25 = ((p22 >> 3) & 3) | 8;\n      t26 += t25;\n      t25 = p4 >> 0x10;\n      if (!(t25 & 1))\n        t26 = 8;\n      t26 = (t25 << t26) & p4;\n      p7 = t26 ? 0x90 : 0x80; // page fault or acv\n      hw_stq(p21 + 0x158, p7);\n      t26 = p23 & ~U64(0x3);\n      hw_ldq(p21 + 0x148, p7);\n      if (test_bit_64(p4, (int)(8 + p7 + ((flags & PROBEW) ? 4 : 0))))\n        return 1;\n      r0 = 0;\n      return -1;\n    }\n\n    if (state.current_pc & 1) {\n      t25 = U64(0x30000);\n      p4 |= t25;\n      t26 = p5 & 1; // write or read?\n      t26 *= 4;\n      t25 = ((p22 >> 3) & 3) | 8;\n      t26 += t25;\n      t25 = p4 >> 0x10;\n      if (!(t25 & 1))\n        t26 = 8;\n      t26 = (t25 << t26) & p4;\n      p7 = t26 ? 0x90 : 0x80; // page fault or acv\n      hw_stq(p21 + 0x158, p7);\n      t26 = p23 & ~U64(0x3);\n\n      hw_stq(p21 + 0x118, state.r[25]);\n      hw_stq(p21 + 0x120, state.r[26]);\n      state.r[25] = t25;\n      state.r[26] = t26;\n      set_pc(0xd981);\n      return -1;\n\n      // return vmspal_int_dfault_in_palmode();\n    }\n\n    hw_stq(p21 + U64(0x150), p23);\n    hw_stq(p21 + U64(0x160), p6);\n    p20 = ((p22 >> 3) & 3) + 8;\n    if ((test_bit_64(p5, 0) && ((p5 >> 4) & 0x3f) == 0x18) ||\n        (!test_bit_64(p5, 0) && ((p7 >> 8) & 0x1f) == 0x1f)) {\n\n      // write \"MISC\" or read to R31\n      set_pc(state.current_pc + 4);\n      return -1;\n    }\n\n    p5 &= U64(0x1);\n    p7 = p5 << 0x3f;\n    p6 = 4 * p5;\n    hw_stq(p21 + U64(0x168), p7);\n    p6 += p20;\n    p6 = U64(0x1) << p6;\n    p6 &= p4;\n    p20 = (p6) ? 0x90 : 0x80;\n    hw_stq(p21 + U64(0x158), p20);\n    return vmspal_int_initiate_exception();\n  }\n\n  add_tb_d(p6, p4);\n  return 0;\n}\n\n/**\n * Entry point for Instruction Translation Buffer Miss.\n **/\nint CAlphaCPU::vmspal_ent_itbm(int flags) {\n  u64 pte_phys;\n\n  p4 = va_form(state.exc_addr, true);\n  p23 = state.exc_addr;\n  p6 = p23;\n  if (test_bit_64(p22, 63)) {\n\n    // 1-ON-1 translations enabled\n    p6 = p23 >> 0x0d;\n    p5 = 0xf01;\n    p6 <<= 0x0d;\n    p6 |= p5;\n    add_tb_i(p23, p6);\n    return 0;\n  }\n\n  p4 &= ~U64(0x7);\n  if (virt2phys(p4, &pte_phys, ACCESS_READ | NO_CHECK | VPTE, NULL, 0))\n    return -1;\n  p4 = cSystem->ReadMem(pte_phys, 64, this);\n\n  p6 = 0xfff;\n  p5 = p4 & p6;\n  p6 = p4 >> 0x20;\n  p6 <<= 0x0d;\n  if (!(p4 & 1) || (p4 & 8)) {\n    p20 = (p4 & 1) ? 0xc0 : 0x90;\n\n    p6 = p22 >> 3;\n    hw_stq(p21 + 0x160, p23);\n    hw_stq(p21 + 0x150, p23);\n    p6 &= U64(0x3);\n    p5 = 1;\n    p6 += 8;\n    hw_stq(p21 + 0x168, p5);\n    p6 = p5 << p6;\n    p6 &= p4;\n\n    // Access Violation\n    if (!p6)\n      p20 = 0x80;\n    hw_stq(p21 + 0x158, p20);\n    return vmspal_int_initiate_exception();\n  }\n\n  p6 |= p5;\n  add_tb_i(p23, p6);\n  return 0;\n}\n\n/**\n * Entry point for Double Data Translation Buffer Miss.\n **/\nint CAlphaCPU::vmspal_ent_dtbm_double_3(int flags) {\n  u64 t25;\n  u64 t26;\n\n  p7 &= 0xffff;\n  p5 <<= 16;\n  p7 |= p5;\n  p5 = state.exc_addr;\n  p7 |= 1;\n  hw_ldq(p21 + 8, t25);       // PTBR\n  t26 = (p4 << 0x1f) >> 0x33; // L1 index\n  t25 += t26;\n  hw_ldq(t25, t25);\n  t26 = (p4 << 0x29) >> 0x33;\n  if (t25 & 1) {\n    t25 >>= 0x20;\n    t25 <<= 0x0d;\n    t25 += t26;\n    hw_ldq(t25, t25);\n    if (t25 & 1) {\n      add_tb_d(p4, t25);\n      return 0;\n    }\n  }\n\n  // PAGE FAULT...\n  p4 = p5; // return address...\n  p5 = p7 >> 0x10;\n  t26 = state.pal_base;\n\n  if (flags & PROBE) // in PALmode!!\n  {\n    p4 = t25 & ~U64(0x30000);\n    t26 = p5 & 1; // write or read?\n    t26 *= 4;\n    t25 = ((p22 >> 3) & 3) | 8;\n    t26 += t25;\n    t25 = p4 >> 16;\n    if (!(t25 & 1))\n      t26 = 8;\n    t26 = (U64(0x1) << t26) & p4;\n    p7 = t26 ? 0x90 : 0x80; // page fault or acv\n    hw_stq(p21 + 0x158, p7);\n\n    if (p7 != 0x80) {\n      p5 = (flags & PROBEW) ? U64(0x8000000000000000) : 0;\n      hw_stq(p21 + 0x160, p6);\n      hw_stq(p21 + 0x168, p5);\n      hw_stq(p21 + 0x150, state.current_pc);\n      return vmspal_int_initiate_exception();\n    }\n\n    r0 = 0;\n    return -1;\n  }\n\n  if (p23 & 1) // in PALmode!!\n  {\n    p4 = t25 & ~U64(0x30000);\n    t26 = p5 & 1; // write or read?\n    t26 *= 4;\n    t25 = ((p22 >> 3) & 3) | 8;\n    t26 += t25;\n    t25 = p4 >> 16;\n    if (!(t25 & 1))\n      t26 = 8;\n    t26 = (U64(0x1) << t26) & p4;\n    p7 = t26 ? 0x90 : 0x80; // page fault or acv\n    hw_stq(p21 + 0x158, p7);\n    t26 = p23 & ~U64(0x3);\n\n    hw_stq(p21 + 0x118, state.r[25]);\n    hw_stq(p21 + 0x120, state.r[26]);\n    state.r[25] = t25;\n    state.r[26] = t26;\n    set_pc(0xd981);\n    return -1;\n  }\n\n  p20 = p4 & ~U64(0x3);\n  p4 = t25 & 0x100;\n  hw_stq(p21 + 0x150, p23);\n  p20 = t26 - p20;\n  t26 = p20 + 0x590;\n  if (!t26) {\n    p5 = 1;\n    hw_stq(p21 + 0x160, p23);\n    p20 = p4 ? 0x90 : 0x80;\n    hw_stq(p21 + 0x168, p5);\n    hw_stq(p21 + 0x158, p20);\n    return vmspal_int_initiate_exception();\n  }\n\n  if ((test_bit_64(p5, 0) && ((p5 >> 4) & 0x3f) == 0x18) ||\n      (!test_bit_64(p5, 0) && ((p7 >> 8) & 0x1f) == 0x1f)) {\n    set_pc(p23 + 4);\n    return -1;\n  }\n\n  p5 <<= 0x3f;\n  p20 = p4 ? 0x90 : 0x80;\n  hw_stq(p21 + 0x168, p5);\n  hw_stq(p21 + 0x160, p6);\n  hw_stq(p21 + 0x158, p20);\n  return vmspal_int_initiate_exception();\n}\n\n/**\n * Entry point for IStream Access Violation\n **/\nint CAlphaCPU::vmspal_ent_iacv(int flags) {\n  p6 = state.current_pc;\n  p4 = 1;\n  p5 = 0x80;\n  hw_stq(p21 + 0x168, p4);\n  hw_stq(p21 + 0x158, p5);\n  if (state.current_pc & 1) {\n    p7 = state.current_pc;\n    p20 = 5;\n    hw_stq(p21 + 0xc8, p20);\n    p23 = state.current_pc;\n    set_pc(0xde01);\n    return -1;\n  }\n\n  hw_stq(p21 + 0x160, state.current_pc);\n  hw_stq(p21 + 0x150, state.current_pc);\n  return vmspal_int_initiate_exception();\n}\n\n/**\n * Entry point for DStream Fault.\n **/\nint CAlphaCPU::vmspal_ent_dfault(int flags) {\n  u64 t25;\n\n  u64 t26;\n  p6 = state.current_pc;\n  p7 = state.exc_sum;\n  p5 = state.mm_stat;\n  if (flags & PROBE) {\n    hw_stq(p21 + 0xd0, p23);\n    p23 = p6;\n    t26 = p6 & ~U64(0x3);\n    p6 = state.fault_va;\n    t25 = p5 & 2;\n    p7 = 0x80;\n    if (!t25) {\n      t25 = p5 & 8;\n      p7 = t25 ? 0xb0 : 0xa0;\n      tbis(p6, ACCESS_READ);\n    }\n\n    hw_stq(p21 + 0x158, p7);\n    p4 = 1;\n    hw_ldq(p21 + 0x158, p7);\n    if (p7 == 0xa0 || p7 == 0xb0) {\n      return 1;\n    }\n\n    r0 = 0;\n    return -1;\n  }\n\n  if (state.current_pc & 1) {\n    hw_stq(p21 + 0xd0, p23);\n    p23 = p6;\n    t26 = p6 & ~U64(0x3);\n    p6 = state.fault_va;\n    t25 = p5 & 2;\n    p7 = 0x80;\n    if (!t25) {\n      t25 = p5 & 8;\n      p7 = t25 ? 0xb0 : 0xa0;\n      tbis(p6, ACCESS_READ);\n    }\n\n    hw_stq(p21 + 0x158, p7);\n    p4 = 1;\n    hw_stq(p21 + 0x118, state.r[25]);\n    hw_stq(p21 + 0x120, state.r[26]);\n    state.r[25] = t25;\n    state.r[26] = t26;\n    set_pc(0xd981);\n    return -1;\n  }\n\n  p20 = state.fault_va;\n  if (((state.mm_stat & 1) && (((state.mm_stat >> 4) & 0x3f) == 0x18)) ||\n      (!(state.mm_stat & 1) && (((state.exc_sum >> 8) & 0x1f) == 0x1f))) {\n    set_pc(state.current_pc + 4);\n    return -1;\n  }\n\n  p7 = 0x80;\n  if (!(state.mm_stat & 2)) {\n    p7 = (state.mm_stat & 4) ? 0xa0 : 0xb0;\n    tbis(p20, ACCESS_READ);\n  }\n\n  hw_stq(p21 + 0x158, p7);\n  hw_stq(p21 + 0x160, p20);\n  p5 <<= 0x3f;\n  hw_stq(p21 + 0x168, p5);\n  hw_stq(p21 + 0x150, p6);\n  return vmspal_int_initiate_exception();\n}\n\n//\\}\n"
  },
  {
    "path": "src/AlphaSim.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"DPR.hpp\"\n#include \"Flash.hpp\"\n#include \"StdAfx.hpp\"\n#include \"System.hpp\"\n\n#include \"lockstep.hpp\"\n\n#if defined(HAVE_SDL)\n#include \"SDL/SDL.h\"\n#endif\n\n/// \"standard\" locations for a configuration file.  This will be port specific.\nconst char *path[] = {\n#if defined(_WIN32)\n    \".\\\\es40.cfg\", \"c:\\\\es40.cfg\", \"c:\\\\windows\\\\es40.cfg\",\n#elif defined(__VMS)\n    \"[]ES40.CFG\",\n#else\n    \"./es40.cfg\", \"/etc/es40.cfg\", \"/usr/etc/es40.cfg\",\n    \"/usr/local/etc/es40.cfg\",\n#endif\n    0};\n\n#ifdef DEBUG_BACKTRACE\n#ifdef __GNUG__\n#include <execinfo.h>\n#include <signal.h>\n#define HAS_BACKTRACE\n\n#define BTCOUNT 100\nvoid *btbuffer[BTCOUNT];\n\nvoid segv_handler(int signum) {\n  int nptrs = backtrace(btbuffer, BTCOUNT);\n  char **strings;\n\n  printf(\"%%SYS-F-SEGFAULT: The Alpha Simulator has Segfaulted.\\n\");\n  printf(\"-SYS-F-SEGFAULT: Backtrace follows.\\n\");\n\n  printf(\"backtrace() returned %d addresses.\\n\", nptrs);\n  strings = backtrace_symbols(btbuffer, nptrs);\n  if (strings == NULL) {\n    perror(\"backtrace_symbols\");\n    exit(1);\n  }\n\n  for (int i = 0; i < nptrs; i++) {\n    printf(\"%3d %s\\n\", nptrs - i, strings[i]);\n  }\n\n  free(strings);\n  if (signum == SIGSEGV)\n    _exit(1);\n}\n\n#else\n#warning \"Your compiler isn't configured to support backtraces.\"\n#endif // __GNUG__\n#endif\n\n/**\n * Entry point for simulation.\n *\n * Does the following:\n *  - Try to find the configuration file.\n *  - Reads the configuration file, and uses the configurator to instantiate all\n *system components.\n *  - Creates the trace-engine if in debug mode.\n *  - Runs the emulator.\n *  - Cleans up.\n *  .\n **/\nint main_sim(int argc, char *argv[]) {\n  const char *filename = 0;\n  FILE *f;\n\n#ifdef HAS_BACKTRACE\n  signal(SIGSEGV, &segv_handler);\n  signal(SIGUSR1, &segv_handler);\n#endif\n  try {\n#if defined(IDB) && (defined(LS_MASTER) || defined(LS_SLAVE))\n    lockstep_init();\n#endif\n#if defined(IDB)\n    if ((argc == 2 || argc == 3) && argv[1][0] != '@')\n#else\n    if (argc == 2)\n#endif\n    {\n      filename = argv[1];\n    } else {\n      for (int i = 0; path[i]; i++) {\n        filename = path[i];\n        f = fopen(filename, \"r\");\n        if (f != NULL) {\n          fclose(f);\n          filename = path[i];\n          break;\n        } else {\n          filename = NULL;\n        }\n      }\n      if (filename == NULL)\n        FAILURE(FileNotFound, \"configuration file\");\n    }\n    char *ch1;\n    size_t ll1;\n    f = fopen(filename, \"rb\");\n    if (f == NULL)\n      FAILURE(File, \"configuration file\");\n    fseek(f, 0, SEEK_END);\n    ll1 = ftell(f);\n    ch1 = (char *)calloc(ll1, 1);\n    fseek(f, 0, SEEK_SET);\n    ll1 = fread(ch1, 1, ll1, f);\n    new CConfigurator(0, 0, 0, ch1, ll1);\n    fclose(f);\n    free(ch1);\n\n    if (!theSystem)\n      FAILURE(Configuration, \"no system initialized\");\n\n#if defined(IDB)\n    trc = new CTraceEngine(theSystem);\n#endif\n    theSystem->LoadROM();\n    theDPR->init();\n\n#if defined(PROFILE)\n    {\n      u64 p_i;\n      for (p_i = PROFILE_FROM; p_i < PROFILE_TO; p_i += (4 * PROFILE_BUCKSIZE))\n        PROFILE_BUCKET(p_i) = 0;\n      profiled_insts = 0;\n    }\n#endif\n#if defined(IDB)\n    theSystem->start_threads();\n\n    if (argc > 1 && argc < 4 && argv[argc - 1][0] == '@')\n      trc->run_script(argv[argc - 1] + 1);\n    else\n      trc->run_script(NULL);\n#else\n    theSystem->Run();\n#endif\n  } catch (CGracefulException &e) {\n    printf(\"Exiting gracefully: %s\\n\", e.displayText().c_str());\n\n    theSystem->stop_threads();\n\n    // save flash and dpr rom only if not terminated with a fatal error\n    theSROM->SaveStateF();\n    theDPR->SaveStateF();\n\n#if defined(PROFILE)\n    {\n      FILE *p_fp;\n      u64 p_max = 0;\n      u64 p_i;\n      int p_j;\n\n      printf(\"Writing profile to profile.txt\");\n\n      p_fp = fopen(\"profile.txt\", \"w\");\n      for (p_i = PROFILE_FROM; p_i < PROFILE_TO;\n           p_i += (4 * PROFILE_BUCKSIZE)) {\n        if (PROFILE_BUCKET(p_i) > p_max)\n          p_max = PROFILE_BUCKET(p_i);\n      }\n      fprintf(p_fp, \"p_max = %10\" PRId64 \"; %10\" PRId64 \" profiled instructions.\\n\\n\",\n              p_max, profiled_insts);\n      for (p_i = PROFILE_FROM; p_i < PROFILE_TO;\n           p_i += (4 * PROFILE_BUCKSIZE)) {\n        if (PROFILE_BUCKET(p_i)) {\n          fprintf(p_fp, \"%016\" PRIx64 \": %10\" PRId64 \" \", p_i, PROFILE_BUCKET(p_i));\n          for (p_j = 0;\n               p_j < (((float)PROFILE_BUCKET(p_i) / (float)p_max) * 100); p_j++)\n            fprintf(p_fp, \"*\");\n          fprintf(p_fp, \"\\n\");\n        }\n      }\n      fclose(p_fp);\n    }\n#endif\n    delete theSystem;\n  } catch (CException &e) {\n    printf(\"Emulator Failure: %s\\n\", e.displayText().c_str());\n    if (theSystem) {\n      theSystem->stop_threads();\n      delete theSystem;\n    }\n  }\n  return 0;\n}\n"
  },
  {
    "path": "src/Cirrus.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"Cirrus.hpp\"\n#include \"AliM1543C.hpp\"\n#include \"StdAfx.hpp\"\n#include \"System.hpp\"\n#include \"gui/gui.hpp\"\n\nstatic unsigned old_iHeight = 0, old_iWidth = 0, old_MSL = 0;\n\nstatic const u8 ccdat[16][4] = {\n    {0x00, 0x00, 0x00, 0x00}, {0xff, 0x00, 0x00, 0x00},\n    {0x00, 0xff, 0x00, 0x00}, {0xff, 0xff, 0x00, 0x00},\n    {0x00, 0x00, 0xff, 0x00}, {0xff, 0x00, 0xff, 0x00},\n    {0x00, 0xff, 0xff, 0x00}, {0xff, 0xff, 0xff, 0x00},\n    {0x00, 0x00, 0x00, 0xff}, {0xff, 0x00, 0x00, 0xff},\n    {0x00, 0xff, 0x00, 0xff}, {0xff, 0xff, 0x00, 0xff},\n    {0x00, 0x00, 0xff, 0xff}, {0xff, 0x00, 0xff, 0xff},\n    {0x00, 0xff, 0xff, 0xff}, {0xff, 0xff, 0xff, 0xff},\n};\n\n/**\n * Set a specific tile's updated variable.\n *\n * Only reference the array if the tile numbers are within the bounds\n * of the array.  If out of bounds, do nothing.\n **/\n#define SET_TILE_UPDATED(xtile, ytile, value)                                  \\\n  do {                                                                         \\\n    if (((xtile) < BX_NUM_X_TILES) && ((ytile) < BX_NUM_Y_TILES))              \\\n      state.vga_tile_updated[(xtile)][(ytile)] = value;                        \\\n  } while (0)\n\n/**\n * Get a specific tile's updated variable.\n *\n * Only reference the array if the tile numbers are within the bounds\n * of the array.  If out of bounds, return 0.\n **/\n#define GET_TILE_UPDATED(xtile, ytile)                                         \\\n  ((((xtile) < BX_NUM_X_TILES) && ((ytile) < BX_NUM_Y_TILES))                  \\\n       ? state.vga_tile_updated[(xtile)][(ytile)]                              \\\n       : 0)\n\n/**\n * Thread entry point.\n *\n * The thread first initializes the GUI, and then starts looping the\n * following actions until interrupted (by StopThread being set to true)\n *   - Handle any GUI events (mouse moves, keypresses)\n *   - Update the GUI to match the screen buffer\n *   - Flush the updated GUI content to the screen\n *   .\n **/\nvoid CCirrus::run() {\n  try {\n    // initialize the GUI (and let it know our tilesize)\n    bx_gui->init(state.x_tilesize, state.y_tilesize);\n    for (;;) {\n      // Terminate thread if StopThread is set to true\n      if (StopThread)\n        return;\n      // Handle GUI events (100 times per second)\n      for (int i = 0; i < 10; i++) {\n        bx_gui->lock();\n        bx_gui->handle_events();\n        bx_gui->unlock();\n        std::this_thread::sleep_for(std::chrono::milliseconds(10));\n      }\n      // Update the screen (10 times per second)\n      bx_gui->lock();\n      update();\n      bx_gui->flush();\n      bx_gui->unlock();\n    }\n  }\n\n  catch (CException &e) {\n    printf(\"Exception in Cirrus thread: %s.\\n\", e.displayText().c_str());\n    myThreadDead.store(true);\n    // Let the thread die...\n  }\n}\n\n/** Size of ROM image */\nstatic unsigned int rom_max;\n\n/** ROM image */\nstatic u8 option_rom[65536];\n\n/** PCI Configuration Space data block */\nstatic u32 cirrus_cfg_data[64] = {\n    /*00*/ 0x00a81013, // CFID: vendor + device\n    /*04*/ 0x011f0000, // CFCS: command + status\n    /*08*/ 0x03000002, // CFRV: class + revision\n    /*0c*/ 0x00000000, // CFLT: latency timer + cache line size\n    /*10*/ 0xf8000000, // BAR0: FB\n    /*14*/ 0x00000000, // BAR1:\n    /*18*/ 0x00000000, // BAR2:\n    /*1c*/ 0x00000000, // BAR3:\n    /*20*/ 0x00000000, // BAR4:\n    /*24*/ 0x00000000, // BAR5:\n    /*28*/ 0x00000000, // CCIC: CardBus\n    /*2c*/ 0x00000000, // CSID: subsystem + vendor\n    /*30*/ 0x00000000, // BAR6: expansion rom base\n    /*34*/ 0x00000000, // CCAP: capabilities pointer\n    /*38*/ 0x00000000,\n    /*3c*/ 0x281401ff, // CFIT: interrupt configuration\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0};\n\n/** PCI Configuration Space mask block */\nstatic u32 cirrus_cfg_mask[64] = {\n    /*00*/ 0x00000000, // CFID: vendor + device\n    /*04*/ 0x0000ffff, // CFCS: command + status\n    /*08*/ 0x00000000, // CFRV: class + revision\n    /*0c*/ 0x0000ffff, // CFLT: latency timer + cache line size\n    /*10*/ 0xfc000000, // BAR0: FB\n    /*14*/ 0x00000000, // BAR1:\n    /*18*/ 0x00000000, // BAR2:\n    /*1c*/ 0x00000000, // BAR3:\n    /*20*/ 0x00000000, // BAR4:\n    /*24*/ 0x00000000, // BAR5:\n    /*28*/ 0x00000000, // CCIC: CardBus\n    /*2c*/ 0x00000000, // CSID: subsystem + vendor\n    /*30*/ 0x00000000, // BAR6: expansion rom base\n    /*34*/ 0x00000000, // CCAP: capabilities pointer\n    /*38*/ 0x00000000,\n    /*3c*/ 0x000000ff, // CFIT: interrupt configuration\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0};\n\n/**\n * Constructor.\n *\n **/\nCCirrus::CCirrus(CConfigurator *cfg, CSystem *c, int pcibus, int pcidev)\n    : CVGA(cfg, c, pcibus, pcidev) {\n  // initialize state\n  memset(&state, 1, sizeof(struct SCirrus_state));\n}\n\n/**\n * Initialize the Cirrus device.\n **/\nvoid CCirrus::init() {\n  // Register PCI device\n  add_function(0, cirrus_cfg_data, cirrus_cfg_mask);\n\n  // Initialize all state variables to 0\n  memset((void *)&state, 0, sizeof(state));\n\n  // Register VGA I/O ports at 3b4, 3b5, 3ba, 3c0..cf, 3d4, 3d5, 3da\n  add_legacy_io(1, 0x3b4, 2);\n  add_legacy_io(3, 0x3ba, 2);\n  add_legacy_io(2, 0x3c0, 16);\n  add_legacy_io(8, 0x3d4, 2);\n  add_legacy_io(9, 0x3da, 1);\n\n  /* The VGA BIOS we use sends text messages to port 0x500.\n     We listen for these messages at port 500. */\n  add_legacy_io(7, 0x500, 1);\n  bios_message_size = 0;\n  bios_message[0] = '\\0';\n\n  // Legacy video address space: A0000 -> bffff\n  add_legacy_mem(4, 0xa0000, 128 * 1024);\n\n  // Reset the base PCI device\n  ResetPCI();\n\n  /* The configuration file variable \"rom\" should point to a VGA BIOS\n     image. If not, try \"vgabios.bin\". */\n  FILE *rom = fopen(myCfg->get_text_value(\"rom\", \"vgabios.bin\"), \"rb\");\n  if (!rom) {\n    FAILURE_1(FileNotFound, \"cirrus rom file %s not found.\",\n              myCfg->get_text_value(\"rom\", \"vgabios.bin\"));\n  }\n\n  rom_max = (unsigned)fread(option_rom, 1, 65536, rom);\n  fclose(rom);\n\n  // Option ROM address space: C0000\n  add_legacy_mem(5, 0xc0000, rom_max);\n\n  state.vga_enabled = 1;\n  state.misc_output.color_emulation = 1;\n  state.misc_output.enable_ram = 1;\n  state.misc_output.horiz_sync_pol = 1;\n  state.misc_output.vert_sync_pol = 1;\n\n  state.attribute_ctrl.mode_ctrl.enable_line_graphics = 1;\n\n  state.line_offset = 80;\n  state.line_compare = 1023;\n  state.vertical_display_end = 399;\n\n  state.attribute_ctrl.video_enabled = 1;\n  state.attribute_ctrl.color_plane_enable = 0x0f;\n\n  state.pel.dac_state = 0x01;\n  state.pel.mask = 0xff;\n\n  state.graphics_ctrl.memory_mapping = 2; // monochrome text mode\n\n  state.sequencer.reset1 = 1;\n  state.sequencer.reset2 = 1;\n  state.sequencer.extended_mem = 1; // display mem greater than 64K\n  state.sequencer.odd_even = 1;     // use sequential addressing mode\n\n  state.memsize = 0x40000;\n  state.memory = new u8[state.memsize];\n  memset(state.memory, 0, state.memsize);\n\n  state.last_bpp = 8;\n\n  state.CRTC.reg[0x09] = 16;\n  state.graphics_ctrl.memory_mapping = 3; // color text mode\n  state.vga_mem_updated = 1;\n\n  printf(\"%s: $Id: Cirrus.cpp,v 1.23 2008/05/31 15:47:09 iamcamiel Exp $\\n\",\n         devid_string);\n}\n\n/**\n * Create and start thread.\n **/\nvoid CCirrus::start_threads() {\n  if (!myThread) {\n    printf(\" cirrus\");\n    StopThread = false;\n    myThread = std::make_unique<std::thread>([this](){ this->run(); });\n  }\n}\n\n/**\n * Stop and destroy thread.\n **/\nvoid CCirrus::stop_threads() {\n  // Signal the thread to stop\n  StopThread = true;\n  if (myThread) {\n    printf(\" cirrus\");\n    // Wait for the thread to end execution\n    myThread->join();\n    // And delete the Thread object\n    myThread = nullptr;\n  }\n}\n\n/**\n * Destructor.\n **/\nCCirrus::~CCirrus() { stop_threads(); }\n\n/**\n * Read from one of the Legacy (fixed-address) memory ranges.\n **/\nu32 CCirrus::ReadMem_Legacy(int index, u32 address, int dsize) {\n  u32 data = 0;\n  switch (index) {\n  // IO Port 0x3b4\n  case 1:\n    data = io_read(address + 0x3b4, dsize);\n    break;\n\n  // IO Port 0x3c0..0x3cf\n  case 2:\n    data = io_read(address + 0x3c0, dsize);\n    break;\n\n  // IO Port 0x3ba\n  case 3:\n    data = io_read(address + 0x3ba, dsize);\n    break;\n\n  // VGA Memory\n  case 4:\n    data = legacy_read(address, dsize);\n    break;\n\n  // ROM\n  case 5:\n    data = rom_read(address, dsize);\n    break;\n\n  // IO Port 0x3d4\n  case 8:\n    data = io_read(address + 0x3d4, dsize);\n    break;\n\n  // IO Port 0x3da\n  case 9:\n    data = io_read(address + 0x3da, dsize);\n    break;\n  }\n\n  return data;\n}\n\n/**\n * Write to one of the Legacy (fixed-address) memory ranges.\n **/\nvoid CCirrus::WriteMem_Legacy(int index, u32 address, int dsize, u32 data) {\n  switch (index) {\n  // IO Port 0x3b4\n  case 1:\n    io_write(address + 0x3b4, dsize, data);\n    return;\n\n  // IO Port 0x3c0..0x3cf\n  case 2:\n    io_write(address + 0x3c0, dsize, data);\n    return;\n\n  // IO Port 0x3ba\n  case 3:\n    io_write(address + 0x3ba, dsize, data);\n    return;\n\n  // VGA Memory\n  case 4:\n    legacy_write(address, dsize, data);\n    return;\n\n  // BIOS Message IO Port (0x500)\n  case 7:\n    bios_message[bios_message_size++] = (char)data & 0xff;\n    if (((data & 0xff) == 0x0a) || ((data & 0xff) == 0x0d)) {\n      if (bios_message_size > 1) {\n        bios_message[bios_message_size - 1] = '\\0';\n        printf(\"cirrus: %s\\n\", bios_message);\n      }\n\n      bios_message_size = 0;\n    }\n\n    return;\n\n  // IO Port 0x3d4\n  case 8: /* io port */\n    io_write(address + 0x3d4, dsize, data);\n    return;\n\n  // IO Port 0x3da\n  case 9:\n    io_write(address + 0x3da, dsize, data);\n    return;\n  }\n}\n\n/**\n * Read from one of the PCI BAR (configurable address) memory ranges.\n **/\nu32 CCirrus::ReadMem_Bar(int func, int bar, u32 address, int dsize) {\n  switch (bar) {\n  // PCI memory range\n  case 0:\n    return mem_read(address, dsize);\n  }\n\n  return 0;\n}\n\n/**\n * Write to one of the PCI BAR (configurable address) memory ranges.\n **/\nvoid CCirrus::WriteMem_Bar(int func, int bar, u32 address, int dsize,\n                           u32 data) {\n  switch (bar) {\n  // PCI Memory range\n  case 0:\n    mem_write(address, dsize, data);\n    return;\n  }\n}\n\n/**\n * Check if threads are still running.\n **/\nvoid CCirrus::check_state() {\n  if (myThreadDead.load())\n    FAILURE(Thread, \"Cirrus thread has died\");\n}\n\nstatic u32 cirrus_magic1 = 0xC1AA4500;\nstatic u32 cirrus_magic2 = 0x0054AA1C;\n\n/**\n * Save state to a Virtual Machine State file.\n **/\nint CCirrus::SaveState(FILE *f) {\n  long ss = sizeof(state);\n  int res;\n\n  if ((res = CPCIDevice::SaveState(f)))\n    return res;\n\n  fwrite(&cirrus_magic1, sizeof(u32), 1, f);\n  fwrite(&ss, sizeof(long), 1, f);\n  fwrite(&state, sizeof(state), 1, f);\n  fwrite(&cirrus_magic2, sizeof(u32), 1, f);\n  printf(\"%s: %d bytes saved.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\n/**\n * Restore state from a Virtual Machine State file.\n **/\nint CCirrus::RestoreState(FILE *f) {\n  long ss;\n  u32 m1;\n  u32 m2;\n  int res;\n  size_t r;\n\n  if ((res = CPCIDevice::RestoreState(f)))\n    return res;\n\n  r = fread(&m1, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m1 != cirrus_magic1) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&ss, sizeof(long), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (ss != sizeof(state)) {\n    printf(\"%s: STRUCT SIZE does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&state, sizeof(state), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&m2, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m2 != cirrus_magic2) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  printf(\"%s: %d bytes restored.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\n/**\n * Read from Framebuffer.\n *\n * Not functional.\n **/\nu32 CCirrus::mem_read(u32 address, int dsize) {\n  u32 data = 0;\n\n  // printf(\"cirrus: mem read: %\" PRIx64 \", %d, %\" PRIx64 \"   \\n\", address, dsize,\n  // data);\n  return data;\n}\n\n/**\n * Write to Framebuffer.\n *\n * Not functional.\n **/\nvoid CCirrus::mem_write(u32 address, int dsize, u32 data) {\n\n  // printf(\"cirrus: mem write: %\" PRIx64 \", %d, %\" PRIx64 \"   \\n\", address, dsize,\n  // data);\n  switch (dsize) {\n  case 8:\n  case 16:\n  case 32:\n    break;\n  }\n}\n\n/**\n * Read from Legacy VGA Memory\n *\n * Calls vga_mem_read to read the data 1 byte at a time.\n **/\nu32 CCirrus::legacy_read(u32 address, int dsize) {\n  u32 data = 0;\n  switch (dsize) {\n  case 32:\n    data |= (u64)vga_mem_read((u32)address + 0xA0003) << 24;\n    data |= (u64)vga_mem_read((u32)address + 0xA0002) << 16;\n\n  case 16:\n    data |= (u64)vga_mem_read((u32)address + 0xA0001) << 8;\n\n  case 8:\n    data |= (u64)vga_mem_read((u32)address + 0xA0000);\n  }\n\n  //  //printf(\"cirrus: legacy read: %\" PRIx64 \", %d, %\" PRIx64 \"   \\n\", address,\n  //  dsize, data);\n  return data;\n}\n\n/**\n * Write to Legacy VGA Memory\n *\n * Calls vga_mem_write to write the data 1 byte at a time.\n **/\nvoid CCirrus::legacy_write(u32 address, int dsize, u32 data) {\n\n  //  //printf(\"cirrus: legacy write: %\" PRIx64 \", %d, %\" PRIx64 \"   \\n\", address,\n  //  dsize, data);\n  switch (dsize) {\n  case 32:\n    vga_mem_write((u32)address + 0xA0002, (u8)(data >> 16));\n    vga_mem_write((u32)address + 0xA0003, (u8)(data >> 24));\n\n  case 16:\n    vga_mem_write((u32)address + 0xA0001, (u8)(data >> 8));\n\n  case 8:\n    vga_mem_write((u32)address + 0xA0000, (u8)(data));\n  }\n}\n\n/**\n * Read from Option ROM\n */\nu32 CCirrus::rom_read(u32 address, int dsize) {\n  u32 data = 0x00;\n  u8 *x = (u8 *)option_rom;\n  if (address <= rom_max) {\n    x += address;\n    switch (dsize) {\n    case 8:\n      data = (u32)endian_8((*((u8 *)x)) & 0xff);\n      break;\n    case 16:\n      data = (u32)endian_16((*((u16 *)x)) & 0xffff);\n      break;\n    case 32:\n      data = (u32)endian_32((*((u32 *)x)) & 0xffffffff);\n      break;\n    }\n\n    // printf(\"cirrus: rom read: %\" PRIx64 \", %d, %\" PRIx64 \"\\n\", address,\n    // dsize,data);\n  } else {\n    printf(\"cirrus: (BAD) rom read: %\" PRIu32 \"x, %d, %\" PRIu32 \"x\\n\", address,\n           dsize, data);\n  }\n\n  return data;\n}\n\n/**\n * Read from I/O Port\n */\nu32 CCirrus::io_read(u32 address, int dsize) {\n  u32 data = 0;\n  if (dsize != 8)\n    FAILURE(InvalidArgument, \"Unsupported dsize!\\n\");\n\n  switch (address) {\n  case 0x3c0:\n    data = read_b_3c0();\n    break;\n\n  case 0x3c1:\n    data = read_b_3c1();\n    break;\n\n  case 0x3c2:\n    data = read_b_3c2();\n    break;\n\n  case 0x3c3:\n    data = read_b_3c3();\n    break;\n\n  case 0x3c4:\n    data = read_b_3c4();\n    break;\n\n  case 0x3c5:\n    data = read_b_3c5();\n    break;\n\n  case 0x3c9:\n    data = read_b_3c9();\n    break;\n\n  case 0x3ca:\n    data = read_b_3ca();\n    break;\n\n  case 0x3cc:\n    data = read_b_3cc();\n    break;\n\n  case 0x3cf:\n    data = read_b_3cf();\n    break;\n\n  case 0x3b4:\n  case 0x3d4:\n    data = read_b_3d4();\n    break;\n\n  case 0x3b5:\n  case 0x3d5:\n    data = read_b_3d5();\n    break;\n\n  case 0x3ba:\n  case 0x3da:\n    data = read_b_3da();\n    break;\n\n  default:\n    FAILURE_1(NotImplemented, \"Unhandled port %x read\", address);\n  }\n\n  // printf(\"cirrus: io read: %\" PRIx64 \", %d, %\" PRIx64 \"   \\n\", address+VGA_BASE,\n  // dsize, data);\n  return data;\n}\n\n/**\n * Write to I/O Port\n *\n * Calls io_write_b to write the data 1 byte at a time.\n */\nvoid CCirrus::io_write(u32 address, int dsize, u32 data) {\n\n  //  printf(\"cirrus: io write: %\" PRIx64 \", %d, %\" PRIx64 \"   \\n\", address+VGA_BASE,\n  //  dsize, data);\n  switch (dsize) {\n  case 8:\n    io_write_b(address, (u8)data);\n    break;\n\n  case 16:\n    io_write_b(address, (u8)data);\n    io_write_b(address + 1, (u8)(data >> 8));\n    break;\n\n  default:\n    FAILURE(InvalidArgument, \"Weird IO size!\");\n  }\n}\n\n/**\n * Write one byte to a VGA I/O port.\n **/\nvoid CCirrus::io_write_b(u32 address, u8 data) {\n  switch (address) {\n  case 0x3c0:\n    write_b_3c0(data);\n    break;\n\n  case 0x3c2:\n    write_b_3c2(data);\n    break;\n\n  case 0x3c4:\n    write_b_3c4(data);\n    break;\n\n  case 0x3c5:\n    write_b_3c5(data);\n    break;\n\n  case 0x3c6:\n    write_b_3c6(data);\n    break;\n\n  case 0x3c7:\n    write_b_3c7(data);\n    break;\n\n  case 0x3c8:\n    write_b_3c8(data);\n    break;\n\n  case 0x3c9:\n    write_b_3c9(data);\n    break;\n\n  case 0x3ce:\n    write_b_3ce(data);\n    break;\n\n  case 0x3cf:\n    write_b_3cf(data);\n    break;\n\n  case 0x3b4:\n  case 0x3d4:\n    write_b_3d4(data);\n    break;\n\n  case 0x3b5:\n  case 0x3d5:\n    write_b_3d5(data);\n    break;\n\n  default:\n    FAILURE_1(NotImplemented, \"Unhandled port %x write\", address);\n  }\n}\n\n/**\n * Write to the attribute controller I/O port (0x3c0)\n *\n * The attribute controller registers are used to select the 16 color\n * and 64 color palettes used for EGA/CGA compatibility.\n *\n * The attribute registers are accessed in an indexed fashion.\n * The address register is read and written via port 3C0h.\n * The data register is written to port 3C0h and read from port 3C1h.\n * The index and the data are written to the same port, one after\n * another. A flip-flop inside the card keeps track of whether the\n * next write will be handled is an index or data. Because there is\n * no standard method of determining the state of this flip-flop, the\n * ability to reset the flip-flop such that the next write will be\n * handled as an index is provided. This is accomplished by reading\n * the Input Status #1 Register (normally port 3DAh) (the data\n * received is not important.)\n *\n * Attribute registers:\n *   - Palette Index registers (index 0x00 - 0x0f)\n *   - Attribute Mode Control register (index 0x10)\n *   - Overscan Color register (index 0x11)\n *   - Color Plane Enable register (index 0x12)\n *   - Horizontal Pixel Panning register (index 0x13)\n *   - Color Select register (index 0x14)\n *   .\n *\n * \\code\n * Attribute Address Register(3C0h)\n * +---+-+---------+\n * |   |5|4 3 2 1 0|\n * +---+-+---------+\n *      ^     ^\n *      |     +-- 0..4: Attribute Address: This field specifies the index\n *      |               value of the attribute register to be read or written\n *      +----------- 5: Palette Address Source: This bit is set to 0 to load\n *                      color values to the registers in the internal palette.\n *                      It is set to 1 for normal operation of the attribute\n *                      controller.\n *\n * Palette Index Registers (index 0x00 - 0x0f)\n * +---+-----------+\n * |   |5 4 3 2 1 0|\n * +---+-----------+\n *           ^\n *           +--- 0..5: Internal Palette Index: These 6-bit registers allow a\n *                      dynamic mapping between the text attribute or graphic\n *                      color input value and the display color on the CRT\n *                      screen. These internal palette values are sent off-chip\n *                      to the video DAC, where they serve as addresses into\n *                      the DAC registers.\n *\n * Attribute Mode Control Register (index 0x10)\n * +-+-+-+-+-+-+-+-+\n * |7|6|5| |3|2|1|0|\n * +-+-+-+-+-+-+-+-+\n *  ^ ^ ^   ^ ^ ^ ^\n *  | | |   | | | +- 0: ATGE - Attribute Controller Graphics Enable:\n *  | | |   | | |         0: Disables the graphics mode of operation.\n *  | | |   | | |         1: Selects the graphics mode of operation.\n *  | | |   | | +--- 1: MONO - Monochrome Emulation: This bit is present and\n *  | | |   | |         programmable in all of the hardware but it apparently\n *  | | |   | |         does nothing.\n *  | | |   | +----- 2: LGE - Line Graphics Enable: This field is used in 9\n *  | | |   |           bit wide character modes to provide continuity for the\n *  | | |   |           horizontal line characters in the range C0h-DFh:\n *  | | |   |             0: the 9th column is replicated from the 8th column.\n *  | | |   |             1: the 9th column is set to the background.\n *  | | |   +------- 3: BLINK - Blink Enable:\n *  | | |                 0: Bit 7 of the attribute selects the background\n *  | | |                    intensity (allows 16 colors for background).\n *  | | |                 1: Bit 7 of the attribute enables blinking.\n *  | | +----------- 5: PPM -- Pixel Panning Mode: Allows the upper half of\n *  | |                 the screen to pan independently of the lower screen.\n *  | |                   0: nothing special occurs during a successful line\n *  | |                      compare (see the Line Compare field.)\n *  | |                   1: upon a successful line compare, the bottom portion\n *  | |                      of the screen is displayed as if the Pixel Shift\n *  | |                      Count and Byte Panning fields are set to 0.\n *  | +------------- 6: 8BIT -- 8-bit Color Enable:\n *  |                     1: The video data is sampled so that eight bits are\n *  |                        available to select a color in the 256-color mode.\n *  |                     0: All other modes.\n *  +--------------- 7: P54S -- Palette Bits 5-4 Select: Selects the source for\n *                      the P5 and P4 video bits that act as inputs to the video\n *                      DAC.\n *                        0: P5 and P4 are the outputs of the Internal Palette\n *                           registers.\n *                        1: P5 and P4 are bits 1 and 0 of the Color Select\n *                           register.\n *\n * Overscan Color Register (index 0x11)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n *         +----- 0..7: Overscan Palette Index: Selects a color from one of the\n *                      DAC registers for the border.\n *\n * Color Plane Enable Register (index 0x12)\n * +-------+-------+\n * |       |3 2 1 0|\n * +-------+-------+\n *             ^\n *             +- 0..3: Color Plane Enable: Setting a bit to 1 enables the\n *                      corresponding display-memory color plane.\n *\n * Horizontal Pixel Panning Register (index 0x13)\n * +-------+-------+\n * |       |3 2 1 0|\n * +-------+-------+\n *             ^\n *             +- 0..3: Pixel Shift Count: These bits select the number of pels\n *                      that the video data is shifted to the left.\n *\n * Color Select Register (index 0x14)\n * +-------+---+---+\n * |       |3 2|1 0|\n * +-------+---+---+\n *           ^   ^\n *           |   +- 0..1: Color Select 5-4: These bits can be used in place of\n *           |            the P4 and P5 bits from the Internal Palette registers\n *           |            to form the  8-bit digital color value to the video\n *DAC. |            Selecting these bits is done in the Attribute Mode | Control\n *register (index 0x10).\n *           +----- 2..3: Color Select 7-6: In modes other than mode 0x13\n *                        (256-color VGA), these are the two most-significant\n *bits of the 8-bit digital color value to the video DAC. \\endcode\n **/\nvoid CCirrus::write_b_3c0(u8 value) {\n  // Variables to save old state (to detect transitions)\n  bool prev_video_enabled;\n  bool prev_line_graphics;\n  bool prev_int_pal_size;\n\n  /* The flip-flop determines whether the write goes to the index-register\n     (address) or the data-register. */\n  if (state.attribute_ctrl.flip_flop == 0) {\n    // Write goes to the index-register.\n\n    /* The index register also has a bit that controls whether video\n       output is enabled or not.\n       We check this bit, and compare it to it's previous state, to\n       determine whether we need to perform an enable or disable\n       transition. */\n    prev_video_enabled = state.attribute_ctrl.video_enabled;\n    state.attribute_ctrl.video_enabled = (value >> 5) & 0x01;\n#if defined(DEBUG_VGA)\n    printf(\"io write 3c0: video_enabled = %u   \\n\",\n           (unsigned)state.attribute_ctrl.video_enabled);\n#endif\n    if (state.attribute_ctrl.video_enabled == 0) {\n      if (prev_video_enabled) {\n#if defined(DEBUG_VGA)\n        printf(\"found disable transition   \\n\");\n#endif\n        // Video output has been disabled. Clear the screen.\n        bx_gui->lock();\n        bx_gui->clear_screen();\n        bx_gui->unlock();\n      }\n    } else if (!prev_video_enabled) {\n#if defined(DEBUG_VGA)\n      printf(\"found enable transition   \\n\");\n#endif\n      // Video output has been enabled. Draw the screen.\n      redraw_area(0, 0, old_iWidth, old_iHeight);\n    }\n\n    // Determine what register should be addressed.\n    value &= 0x1f; /* address = bits 0..4 */\n    state.attribute_ctrl.address = value;\n\n    /* Registers 0x00..0x0f are palette selection registers.\n       Write a debugging message for all other registers. */\n#if defined(DEBUG_VGA)\n    if (value > 0x0f)\n      printf(\"io write 3c0: address mode reg=%u   \\n\", (unsigned)value);\n#endif\n  } else {\n    // Write should go to the data-register.\n\n    // Registers 0x00..0x0f are palette selection registers.\n    if (state.attribute_ctrl.address <= 0x0f) {\n      // Update palette selection only of there is a change.\n      if (value !=\n          state.attribute_ctrl.palette_reg[state.attribute_ctrl.address]) {\n        // Update the palette selection.\n        state.attribute_ctrl.palette_reg[state.attribute_ctrl.address] = value;\n        // Requires redrawing the screen.\n        redraw_area(0, 0, old_iWidth, old_iHeight);\n      }\n    } else {\n      switch (state.attribute_ctrl.address) {\n      // Mode control register\n      case 0x10:\n        prev_line_graphics =\n            state.attribute_ctrl.mode_ctrl.enable_line_graphics;\n        prev_int_pal_size =\n            state.attribute_ctrl.mode_ctrl.internal_palette_size;\n        state.attribute_ctrl.mode_ctrl.graphics_alpha = (value >> 0) & 0x01;\n        state.attribute_ctrl.mode_ctrl.display_type = (value >> 1) & 0x01;\n        state.attribute_ctrl.mode_ctrl.enable_line_graphics =\n            (value >> 2) & 0x01;\n        state.attribute_ctrl.mode_ctrl.blink_intensity = (value >> 3) & 0x01;\n        state.attribute_ctrl.mode_ctrl.pixel_panning_compat =\n            (value >> 5) & 0x01;\n        state.attribute_ctrl.mode_ctrl.pixel_clock_select = (value >> 6) & 0x01;\n        state.attribute_ctrl.mode_ctrl.internal_palette_size =\n            (value >> 7) & 0x01;\n        if (((value >> 2) & 0x01) != prev_line_graphics) {\n          bx_gui->lock();\n          bx_gui->set_text_charmap(\n              &state.memory[0x20000 + state.charmap_address]);\n          bx_gui->unlock();\n          state.vga_mem_updated = 1;\n        }\n\n        if (((value >> 7) & 0x01) != prev_int_pal_size) {\n          redraw_area(0, 0, old_iWidth, old_iHeight);\n        }\n\n#if defined(DEBUG_VGA)\n        printf(\"io write 3c0: mode control: %02x h   \\n\", (unsigned)value);\n#endif\n        break;\n\n      // Overscan Color Register\n      case 0x11:\n        /* We don't do anything with this. Our display doesn't\n           show the overscan part of the normal monitor. */\n        state.attribute_ctrl.overscan_color = (value & 0x3f);\n#if defined(DEBUG_VGA)\n        printf(\"io write 3c0: overscan color = %02x   \\n\", (unsigned)value);\n#endif\n        break;\n\n      // Color Plane Enable Register\n      case 0x12:\n        state.attribute_ctrl.color_plane_enable = (value & 0x0f);\n        redraw_area(0, 0, old_iWidth, old_iHeight);\n#if defined(DEBUG_VGA)\n        printf(\"io write 3c0: color plane enable = %02x   \\n\", (unsigned)value);\n#endif\n        break;\n\n      // Horizontal Pixel Panning Register\n      case 0x13:\n        state.attribute_ctrl.horiz_pel_panning = (value & 0x0f);\n        redraw_area(0, 0, old_iWidth, old_iHeight);\n#if defined(DEBUG_VGA)\n        printf(\"io write 3c0: horiz pel panning = %02x   \\n\", (unsigned)value);\n#endif\n        break;\n\n      // Color Select Register\n      case 0x14:\n        state.attribute_ctrl.color_select = (value & 0x0f);\n        redraw_area(0, 0, old_iWidth, old_iHeight);\n#if defined(DEBUG_VGA)\n        printf(\"io write 3c0: color select = %02x   \\n\",\n               (unsigned)state.attribute_ctrl.color_select);\n#endif\n        break;\n\n      default:\n        FAILURE_1(NotImplemented, \"io write 3c0: data-write mode %02x h\",\n                  (unsigned)state.attribute_ctrl.address);\n      }\n    }\n  }\n\n  // Flip the flip-flop\n  state.attribute_ctrl.flip_flop = !state.attribute_ctrl.flip_flop;\n}\n\n/**\n * Write to the VGA Miscellaneous Output Register (0x3c2)\n *\n * \\code\n * +-+-+-+-+---+-+-+\n * |7|6|5| |3 2|1|0|\n * +-+-+-+-+---+-+-+\n *  ^ ^ ^    ^  ^ ^\n *  | | |    |  | +- 0: I/OAS -- Input/Output Address Select: Selects the CRT\n *  | | |    |  |       controller addresses.\n *  | | |    |  |         0: Compatibility with monochrome adapter\n *  | | |    |  |            (0x3b4,0x3b5,0x03ba)\n *  | | |    |  |         1: Compatibility with color graphics adapter (CGA)\n *  | | |    |  |            (0x3d4,0x3d5,0x03da)\n *  | | |    |  +--- 1: RAM Enable: Controls access from the system:\n *  | | |    |            0: Disables access to the display buffer\n *  | | |    |            1: Enables access to the display buffer\n *  | | |    +--- 2..3: Clock Select: Controls the selection of the dot clocks\n *  | | |               used in driving the display timing:\n *  | | |                 00: Select 25 Mhz clock (320/640 pixel wide modes)\n *  | | |                 01: Select 28 Mhz clock (360/720 pixel wide modes)\n *  | | |                 10: Undefined (possible external clock)\n *  | | |                 11: Undefined (possible external clock)\n *  | | +----------- 5: Odd/Even Page Select: Selects the upper/lower 64K page\n *  | |                 of memory when the system is in an even/odd mode.\n *  | |                   0: Selects the low page.\n *  | |                   1: Selects the high page.\n *  | +------------- 6: Horizontal Sync Polarity\n *  |                     0: Positive sync pulse.\n *  |                     1: Negative sync pulse.\n *  +--------------- 7: Vertical Sync Polarity\n *                        0: Positive sync pulse.\n *                        1: Negative sync pulse.\n * \\endcode\n **/\nvoid CCirrus::write_b_3c2(u8 value) {\n  state.misc_output.color_emulation = (value >> 0) & 0x01;\n  state.misc_output.enable_ram = (value >> 1) & 0x01;\n  state.misc_output.clock_select = (value >> 2) & 0x03;\n  state.misc_output.select_high_bank = (value >> 5) & 0x01;\n  state.misc_output.horiz_sync_pol = (value >> 6) & 0x01;\n  state.misc_output.vert_sync_pol = (value >> 7) & 0x01;\n#if defined(DEBUG_VGA)\n  printf(\"io write 3c2:   \\n\");\n  printf(\"  color_emulation = %u   \\n\",\n         (unsigned)state.misc_output.color_emulation);\n  printf(\"  enable_ram = %u   \\n\", (unsigned)state.misc_output.enable_ram);\n  printf(\"  clock_select = %u   \\n\", (unsigned)state.misc_output.clock_select);\n  printf(\"  select_high_bank = %u   \\n\",\n         (unsigned)state.misc_output.select_high_bank);\n  printf(\"  horiz_sync_pol = %u   \\n\",\n         (unsigned)state.misc_output.horiz_sync_pol);\n  printf(\"  vert_sync_pol = %u   \\n\",\n         (unsigned)state.misc_output.vert_sync_pol);\n#endif\n}\n\n/**\n * Write to the VGA sequencer index register (0x3c4)\n *\n * The Sequencer registers control how video data is sent to the DAC.\n *\n * The Sequencer registers are accessed in an indexed fashion. By writing a byte\n * to the Sequencer Index Register (0x3c4) equal to the index of the particular\n * sub-register you wish to access, one can address the data pointed to by that\n * index by reading and writing the Sequencer Data Register (0x3c5).\n *\n * Sequencer registers:\n *   - Reset register (index 0x00)\n *   - Clocking Mode register (index 0x01)\n *   - Map Mask register (index 0x02)\n *   - Character Map Select register (index 0x03)\n *   - Memory Mode register (index 0x04)\n *   .\n *\n * \\code\n * Reset register (index 0x00)\n * +-----------+-+-+\n * |           |1|0|\n * +-----------+-+-+\n *              ^ ^\n *              | +- 0: Asynchronous Reset:\n *              |         0: Commands the sequencer to asynchronously clear and\n *              |            halt. Resetting the sequencer with this bit can\n *              |            cause loss of video data.\n *              |         1: Allows the sequencer to function normally.\n *              +--- 1: Sychnronous Reset:\n *                        0: Commands the sequencer to synchronously clear and\n *                           halt.\n *                        1: Allows the sequencer to function normally.\n * Bits 1 and 0 must be 1 to allow the sequencer to operate.\n * To prevent the loss of data, bit 1 must be set to 0 during the active display\n * interval before changing the clock selection. The clock is changed through\n *the Clocking Mode register or the Miscellaneous Output register.\n *\n * Clocking Mode register (index 0x01)\n * +---+-+-+-+-+-+-+\n * |   |5|4|3|2| |0|\n * +---+-+-+-+-+-+-+\n *      ^ ^ ^ ^   ^\n *      | | | |   +- 0: 9/8 Dot Mode: Selects whether a character is 8 or 9 dots\n *      | | | |         wide. This can be used to select between 720 and 640\n *      | | | |         pixel modes (or 360 and 320) and also is used to provide\n *      | | | |         9 bit wide character fonts in text mode:\n *      | | | |           0: Selects 9 dots per character.\n *      | | | |           1: Selects 8 dots per character.\n *      | | | +----- 2: Shift/Load Rate:\n *      | | |             0: Video serializers are loaded every character clock.\n *      | | |             1: Video serializers are loaded every other character\n *      | | |                clock, which is useful when 16 bits are fetched per\n *      | | |                cycle and chained together in the shift registers.\n *      | | +------- 3: Dot Clock Rate:\n *      | |               0: Selects the normal dot clocks derived from the\n *      | |                  sequencer master clock input.\n *      | |               1: The master clock will be divided by 2 to generate\n *      | |                  the dot clock. All other timings are affected\n *      | |                  because they are derived from the dot clock. The\n *dot | |                  clock divided by 2 is used for 320 and 360 horizontal\n *      | |                  PEL modes.\n *      | +--------- 4: Shift Four Enable:\n *      |                 0: Video serializers are loaded every character clock.\n *      |                 1: Video serializers are loaded every fourth character\n *      |                    clock, which is useful when 32 bits are fetched per\n *      |                    cycle and chained together in the shift registers.\n *      +----------- 5: Screen Disable:\n *                        0: Display enabled.\n *                        1: Display blanked. Maximum memory bandwidth assigned\n *to the system.\n *\n * Map Mask register (index 0x02)\n * +-------+-------+\n * |       |3 2 1 0|\n * +-------+-------+\n *             ^\n *             +- 0..3: Memory Plane Write Enable: If a bit is set, then write\n *                      operations will modify the respective plane of display\n *                      memory. If a bit is not set then write operations will\n *not affect the respective plane of display memory.\n *\n * Character Map Select register (index 0x03)\n * +---+-+-+---+---+\n * |   |5|4|3 2|1 0|\n * +---+-+-+---+---+\n *      ^ ^  ^   ^\n *      | +--|---+- 0..1,4: Character Set B Select: This field is used to select\n *the |    |              font that is used in text mode when bit 3 of the\n *attribute |    |              byte for a character is set to 0. (*)\n *      +----+----- 2..3,5: Character Set A Select: This field is used to select\n *the font that is used in text mode when bit 3 of the attribute byte for a\n *character is set to 1. (*)\n *\n * (*) Note that this field is not contiguous in order to provide EGA\n *compatibility. The font selected resides in plane 2 of display memory at the\n *address specified by this field, as follows:\n * +------+---------------+\n * |  val | font at       |\n * +------+---------------+\n * | 000b | 0000h - 1FFFh |\n * | 001b | 4000h - 5FFFh |\n * | 010b | 8000h - 9FFFh |\n * | 011b | C000h - DFFFh |\n * | 100b | 2000h - 3FFFh |\n * | 101b | 6000h - 7FFFh |\n * | 110b | A000h - BFFFh |\n * | 111b | E000h - FFFFh |\n * +------+---------------+\n *\n * Memory Mode register (index 0x04)\n * +-------+-+-+-+-+\n * |       |3|2|1| |\n * +-------+-+-+-+-+\n *          ^ ^ ^\n *          | | +--- 1: Extended Memory:\n *          | |           0: 64 KB of video memory enabled\n *          | |           1: 256 KB of video memory enabled. This bit must be\n *set to 1 to | |              enable the character map selection described for\n *the | |              previous register. | +----- 2: Odd/Even Host Memory Write\n *Adressing Disable: |             0: Even system addresses access maps 0 and 2,\n *while odd system |                addresses access maps 1 and 3. | 1: System\n *addresses sequentially access data within a bit map, |                and the\n *maps are accessed according to the value in the Map |                Mask\n *register (index 0x02).\n *          +------- 3: Chain 4 Enable: This bit controls the map selected\n *during system read operations. 0: Enables system addresses to sequentially\n *access data within a bit map by using the Map Mask register. 1: Causes the two\n *low-order bits to select the map accessed as shown below:\n *                           +----+----+--------------+\n *                           | A0 | A1 | Map Selected |\n *                           +----+----+--------------+\n *                           |  0 |  0 | 0            |\n *                           |  0 |  1 | 1            |\n *                           |  1 |  0 | 2            |\n *                           |  1 |  1 | 3            |\n *                           +----+----+--------------+\n * \\endcode\n **/\nvoid CCirrus::write_b_3c4(u8 value) { state.sequencer.index = value; }\n\n/**\n * Write to the VGA sequencer data register (0x3c5)\n *\n * For a description of the Sequencer registers, see CCirrus::write_b_3c4\n **/\nvoid CCirrus::write_b_3c5(u8 value) {\n  unsigned i;\n  u8 charmap1;\n  u8 charmap2;\n\n  switch (state.sequencer.index) {\n  // Sequencer: reset register\n  case 0:\n#if defined(DEBUG_VGA)\n    printf(\"write 0x3c5: sequencer reset: value=0x%02x   \\n\", (unsigned)value);\n#endif\n    if (state.sequencer.reset1 && ((value & 0x01) == 0)) {\n      state.sequencer.char_map_select = 0;\n      state.charmap_address = 0;\n      bx_gui->lock();\n      bx_gui->set_text_charmap(&state.memory[0x20000 + state.charmap_address]);\n      bx_gui->unlock();\n      state.vga_mem_updated = 1;\n    }\n\n    state.sequencer.reset1 = (value >> 0) & 0x01;\n    state.sequencer.reset2 = (value >> 1) & 0x01;\n    break;\n\n  // Sequencer: clocking mode register\n  case 1:\n#if defined(DEBUG_VGA)\n    printf(\"io write 3c5=%02x: clocking mode reg: ignoring   \\n\",\n           (unsigned)value);\n#endif\n    state.sequencer.reg1 = value & 0x3f;\n    state.x_dotclockdiv2 = ((value & 0x08) > 0);\n    break;\n\n  // Sequencer: map mask register\n  case 2:\n    state.sequencer.map_mask = (value & 0x0f);\n    for (i = 0; i < 4; i++)\n      state.sequencer.map_mask_bit[i] = (value >> i) & 0x01;\n    break;\n\n  // Sequencer: character map select register\n  case 3:\n    state.sequencer.char_map_select = value;\n    charmap1 = value & 0x13;\n    if (charmap1 > 3)\n      charmap1 = (charmap1 & 3) + 4;\n    charmap2 = (value & 0x2C) >> 2;\n    if (charmap2 > 3)\n      charmap2 = (charmap2 & 3) + 4;\n    if (state.CRTC.reg[0x09] > 0) {\n      state.charmap_address = (charmap1 << 13);\n      bx_gui->lock();\n      bx_gui->set_text_charmap(&state.memory[0x20000 + state.charmap_address]);\n      bx_gui->unlock();\n      state.vga_mem_updated = 1;\n    }\n\n    if (charmap2 != charmap1)\n      printf(\"char map select: #2=%d (unused)   \\n\", charmap2);\n    break;\n\n  // Sequencer: memory mode register\n  case 4:\n    state.sequencer.extended_mem = (value >> 1) & 0x01;\n    state.sequencer.odd_even = (value >> 2) & 0x01;\n    state.sequencer.chain_four = (value >> 3) & 0x01;\n\n#if defined(DEBUG_VGA)\n    printf(\"io write 3c5: index 4:   \\n\");\n    printf(\"  extended_mem %u   \\n\", (unsigned)state.sequencer.extended_mem);\n    printf(\"  odd_even %u   \\n\", (unsigned)state.sequencer.odd_even);\n    printf(\"  chain_four %u   \\n\", (unsigned)state.sequencer.chain_four);\n#endif\n    break;\n\n  default:\n    FAILURE_1(NotImplemented, \"io write 3c5: index %u unhandled\",\n              (unsigned)state.sequencer.index);\n  }\n}\n\n/**\n * Write to VGA DAC Pixel Mask register (0x3c6)\n *\n * The pixel inputs (R, G and B) are anded with this value. Set to FFh\n * for normal operation.\n **/\nvoid CCirrus::write_b_3c6(u8 value) {\n  state.pel.mask = value;\n#if defined(DEBUG_VGA)\n  if (state.pel.mask != 0xff)\n    printf(\"io write 3c6: PEL mask=0x%02x != 0xFF   \\n\", value);\n#endif\n\n  // state.pel.mask should be and'd with final value before\n  // indexing into color register state.pel.data[]\n}\n\n/**\n * Write VGA DAC Address Read Mode register (0x3c7)\n *\n * The Color Registers in the standard VGA provide a mapping between the\n * palette of between 2 and 256 colors to a larger 18-bit color space.\n * This capability allows for efficient use of video memory while\n * providing greater flexibility in color choice. The standard VGA has\n * 256 palette entries containing six bits each of red, green, and blue\n * values. The palette RAM is accessed via a pair of address registers\n * and a data register.\n *\n * To write a palette entry, output the palette entry's index value to\n * the DAC Address Write Mode Register (0x3c8) then perform 3 writes to\n * the DAC Data Register (0x3c9), loading the red, green, then blue\n * values into the palette RAM. The internal write address automatically\n * advances allowing the next value's RGB values to be loaded without\n * having to reprogram the DAC Address Write Mode Register. This allows\n * the entire palette to be loaded in one write operation.\n *\n * To read a palette entry, output the palette entry's index to the DAC\n * Address Read Mode Register (0x3c7). Then perform 3 reads from the DAC\n * Data Register (0x3c9), loading the red, green, then blue values from\n * palette RAM. The internal read address automatically advances\n * allowing the next RGB values to be read without having to reprogram\n * the DAC Address Read Mode Register.\n *\n * The data values are 6-bits each.\n **/\nvoid CCirrus::write_b_3c7(u8 value) {\n  state.pel.read_data_register = value;\n  state.pel.read_data_cycle = 0;\n  state.pel.dac_state = 0x03;\n}\n\n/**\n * Write VGA DAC Address Write Mode register (0x3c8)\n *\n * For a description of DAC registers see CCirrus::write_b_3c7\n **/\nvoid CCirrus::write_b_3c8(u8 value) {\n  state.pel.write_data_register = value;\n  state.pel.write_data_cycle = 0;\n  state.pel.dac_state = 0x00;\n}\n\n/**\n * Write VGA DAC Data register (0x3c9)\n *\n * For a description of DAC registers see CCirrus::write_b_3c7\n **/\nvoid CCirrus::write_b_3c9(u8 value) {\n  switch (state.pel.write_data_cycle) {\n  case 0:\n    state.pel.data[state.pel.write_data_register].red = value;\n    break;\n\n  case 1:\n    state.pel.data[state.pel.write_data_register].green = value;\n    break;\n\n  case 2: {\n    state.pel.data[state.pel.write_data_register].blue = value;\n    // Palette write complete. Check if value has changed\n    bx_gui->lock();\n    bool changed = bx_gui->palette_change(\n        state.pel.write_data_register,\n        state.pel.data[state.pel.write_data_register].red << 2,\n        state.pel.data[state.pel.write_data_register].green << 2,\n        state.pel.data[state.pel.write_data_register].blue << 2);\n    bx_gui->unlock();\n    // If palette value has changed, redraw the screen.\n    if (changed)\n      redraw_area(0, 0, old_iWidth, old_iHeight);\n  } break;\n  }\n\n  // Move on to next RGB component\n  state.pel.write_data_cycle++;\n\n  // palette entry complete, move on to next one\n  if (state.pel.write_data_cycle >= 3) {\n\n    // BX_INFO((\"state.pel.data[%u] {r=%u, g=%u, b=%u}\",\n    //  (unsigned) state.pel.write_data_register,\n    //  (unsigned) state.pel.data[state.pel.write_data_register].red,\n    //  (unsigned) state.pel.data[state.pel.write_data_register].green,\n    //  (unsigned) state.pel.data[state.pel.write_data_register].blue);\n    state.pel.write_data_cycle = 0;\n    state.pel.write_data_register++;\n  }\n}\n\n/**\n * Write to VGA Graphics Controller Index Register (0x3ce)\n *\n * The Graphics Controller registers control how the system accesses video RAM.\n *\n * The Graphics registers are accessed in an indexed fashion. By writing a byte\n * to the Graphics Index Register (0x3ce) equal to the index of the particular\n * sub-register you wish to access, one can address the data pointed to by that\n * index by reading and writing the Graphics Data Register (0x3cf).\n *\n * Graphics registers:\n *   - Set/Reset register (index 0x00)\n *   - Enable Set/Reset register (index 0x01)\n *   - Color Compare register (index 0x02)\n *   - Data Rotate register (index 0x03)\n *   - Read Map Select register (index 0x04)\n *   - Graphics Mode register (index 0x05)\n *   - Miscellaneous Graphics register (index 0x06)\n *   - Color Don't Care register (index 0x07)\n *   - Bit Mask register (index 0x08)\n *   .\n *\n * \\code\n * Set/Reset register (index 0x00)\n * +-------+-------+\n * |       |3 2 1 0|\n * +-------+-------+\n *             ^\n *             +- 0..3: Set/Reset: Bits 3-0 of this field represent planes 3-0\n *of the VGA display memory. This field is used by Write Mode 0 and Write Mode 3\n *(See the Write Mode field.) In Write Mode 0, if the corresponding bit in the\n *Enable Set/Reset field is set, and in Write Mode 3 regardless of the Enable\n *                      Set/Reset field, the value of the bit in this field is\n *                      expanded to 8 bits and substituted for the data of the\n *                      respective plane and passed to the next stage in the\n *                      graphics pipeline, which for Write Mode 0 is the Logical\n *                      Operation unit and for Write Mode 3 is the Bit Mask\n *unit.\n *\n * Enable Set/Reset Register (index 0x01)\n * +-------+-------+\n * |       |3 2 1 0|\n * +-------+-------+\n *             ^\n *             +- 0..3: Enable Set/Reset: Bits 3-0 of this field represent\n *planes 3-0 of the VGA display memory. This field is used in Write Mode 0 (See\n *the Write Mode field) to select whether data for each plane is derived from\n *host data or from expansion of the respective bit in the Set/Reset field.\n *\n * Color Compare Register (index 0x02)\n * +-------+-------+\n * |       |3 2 1 0|\n * +-------+-------+\n *             ^\n *             +- 0..3: Color Compare: Bits 3-0 of this field represent planes\n *3-0 of the VGA display memory. This field holds a reference color that is used\n *by Read Mode 1 (See the Read Mode field.) Read Mode 1 returns the result of\n *the comparison between this value and a location of display memory, modified\n *by the Color Don't Care field.\n *\n * Data Rotate Register (index 0x03)\n * +-----+---+-----+\n * |     |4 3|2 1 0|\n * +-----+---+-----+\n *         ^    ^\n *         |    +- 0..2: Rotate Count:\n *         |             This field is used in Write Mode 0 and Write Mode 3\n *(See |             the Write Mode field.) In these modes, the host data is |\n *rotated to the right by the value specified by the value of |             this\n *field. A rotation operation consists of moving bits |             7-1 right\n *one position to bits 6-0, simultaneously |             wrapping bit 0 around\n *to bit 7, and is repeated the number |             of times specified by this\n *field.\n *         +------ 3..4: Logical Operation:\n *                       This field is used in Write Mode 0 and Write Mode 2\n *(See the Write Mode field.) The logical operation stage of the graphics\n *pipeline is 32 bits wide (1 byte * 4 planes) and performs the operations on\n *its inputs from the previous stage in the graphics pipeline and the latch\n *register. The latch register remains unchanged and the result is passed on to\n *the next stage in the pipeline. The results based on the value of this field\n *are: 00: Result is input from previous stage unmodified. 01: Result is input\n *from previous stage logical ANDed with latch register. 10: Result is input\n *from previous stage logical ORed with latch register. 11: Result is input from\n *previous stage logical XORed with latch register.\n *\n * Read Map Select register (index 0x04)\n * +-----------+---+\n * |           |1 0|\n * +-----------+---+\n *               ^\n *               +- 0..1: Read Map Select: The value of this field is used in\n *Read Mode 0 (see the Read Mode field) to specify the display memory plane to\n *transfer data from. Due to the arrangement of video memory, this field must be\n *modified four times to read one or more pixels values in the planar video\n *modes.\n *\n * Graphics Mode Register (index 0x05)\n * +-+-+-+-+-+-+---+\n * | |6|5|4|3| |1 0|\n * +-+-+-+-+-+-+---+\n *    ^ ^ ^ ^    ^\n *    | | | |    +- 0..1: Write Mode\n *    | | | |             This field selects between four write modes, simply\n *known | | | |             as Write Modes 0-3, based upon the value of this\n *field: | | | |               00: Write Mode 0: In this mode, the host data is\n *first | | | |                   rotated as per the Rotate Count field, then\n *the | | | |                   Enable Set/Reset mechanism selects data from\n *this or | | | |                   the Set/Reset field. Then the selected\n *Logical | | | |                   Operation is performed on the resulting data\n *and the | | | |                   data in the latch register. Then the Bit\n *Mask field | | | |                   is used to select which bits come from\n *the resulting | | | |                   data and which come from the latch\n *register. Finally, | | | |                   only the bit planes enabled by\n *the Memory Plane Write | | | |                   Enable field are written to\n *memory. | | | |               01: Write Mode 1: In this mode, data is\n *transferred directly | | | |                   from the 32 bit latch register\n *to display memory, | | | |                   affected only by the Memory Plane\n *Write Enable field. | | | |                   The host data is not used in\n *this mode. | | | |               10: Write Mode 2: In this mode, the bits 3-0\n *of the host | | | |                   data are replicated across all 8 bits of\n *their | | | |                   respective planes. Then the selected Logical\n *Operation | | | |                   is performed on the resulting data and the\n *data in the | | | |                   latch register. Then the Bit Mask field\n *is used to | | | |                   select which bits come from the resulting\n *data and which | | | |                   come from the latch register.\n *Finally, only the bit | | | |                   planes enabled by the Memory\n *Plane Write Enable field | | | |                   are written to memory. | |\n *| |               11: Write Mode 3: In this mode, the data in the Set/Reset |\n *| | |                   field is used as if the Enable Set/Reset field were\n *set | | | |                   to 1111b. Then the host data is first rotated as\n *per the | | | |                   Rotate Count field, then logical ANDed with\n *the value of | | | |                   the Bit Mask field. The resulting value\n *is used on the | | | |                   data obtained from the Set/Reset\n *field in the same way | | | |                   that the Bit Mask field would\n *ordinarily be used. to | | | |                   select which bits come from\n *the expansion of the | | | |                   Set/Reset field and which come\n *from the latch register. | | | |                   Finally, only the bit\n *planes enabled by the Memory Plane | | | |                   Write Enable\n *field are written to memory. | | | +--------- 3: Read Mode: | | | This field\n *selects between two read modes, simply known as Read | | |               Mode\n *0, and Read Mode 1, based upon the value of this field: | | | 0: Read Mode 0:\n *In this mode, a byte from one of the four | | |                    planes is\n *returned on read operations. The plane from | | |                    which the\n *data is returned is determined by the value of | | |                    the\n *Read Map Select field. | | |                 1: Read Mode 1: In this mode, a\n *comparison is made between | | |                    display memory and a\n *reference color defined by the Color | | |                    Compare field.\n *Bit planes not set in the Color Don't Care | | |                    field then\n *the corresponding color plane is not considered | | |                    in\n *the comparison. Each bit in the returned result | | | represents one\n *comparison between the reference color, with | | |                    the bit\n *being set if the comparison is true. | | +----------- 4: Host Odd/Even Memory\n *Read Addressing Enable: | |                   0: Selects the standard\n *addressing mode. | |                   1: Selects the odd/even addressing mode\n *used by the IBM CGA | |                      Adapter. | | Normally, the value\n *here follows the value of Memory Mode | |                 register bit 2 in\n *the sequencer.\" | +------------- 5: Shift Register Interleave Mode: | 1:\n *Directs the shift registers in the graphics controller to | format the serial\n *data stream with even-numbered bits from |                        both maps on\n *even-numbered maps, and odd-numbered bits from |                        both\n *maps on the odd-numbered maps. This bit is used for | modes 4 and 5.\n *    +--------------- 6: 256-Color Shift Mode:\n *                          0: Allows bit 5 to control the loading of the shift\n *registers. 1: Causes the shift registers to be loaded in a manner that\n *                             supports the 256-color mode.\n *\n * Miscellaneous Graphics register (index 0x06)\n * +-------+---+-+-+\n * |       |3 2|1|0|\n * +-------+---+-+-+\n *           ^  ^ ^\n *           |  | +- 0: Alphanumeric Mode Disable:\n *           |  |       This bit controls alphanumeric mode addressing.\n *           |  |         0: Text mode.\n *           |  |         1: Graphics modes, disables character generator\n *latches. |  +--- 1: Chain Odd/Even Enable |            1: Directs the system\n *address bit, A0, to be replaced by a |               higher-order bit. The odd\n *map is then selected when A0 is 1, |               and the even map when A0 is\n *0.\n *           +--- 2..3: Memory Map Select\n *                      This field specifies the range of host memory addresses\n *that is decoded by the VGA hardware and mapped into display memory accesses.\n *The values of this field and their corresponding host memory ranges are: 00:\n *A0000h-BFFFFh (128K region) 01: A0000h-AFFFFh (64K region) 10: B0000h-B7FFFh\n *(32K region) 11: B8000h-BFFFFh (32K region)\n *\n * Color Don't Care register (index 0x07)\n * +-------+-------+\n * |       |3 2 1 0|\n * +-------+-------+\n *             ^\n *             +- 0..3: Color Don't Care: Bits 3-0 of this field represent\n *planes 3-0 of the VGA display memory. This field selects the planes that are\n *used in the comparisons made by Read Mode 1 (See the Read Mode field.) Read\n *Mode 1 returns the result of the comparison between the value of the Color\n *                      Compare field and a location of display memory. If a bit\n *                      in this field is set, then the corresponding display\n *                      plane is considered in the comparison. If it is not set,\n *                      then that plane is ignored for the results of the\n *                      comparison.\n *\n * Bit Mask register (index 0x08)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n *         +----- 0..7: Bit Mask: This field is used in Write Modes 0, 2, and 3\n *                      (See the Write Mode field.) It it is applied to one byte\n *                      of data in all four display planes. If a bit is set,\n *                      then the value of corresponding bit from the previous\n *                      stage in the graphics pipeline is selected; otherwise\n *                      the value of the corresponding bit in the latch register\n *                      is used instead. In Write Mode 3, the incoming data\n *byte, after being rotated is logical ANDed with this byte and the resulting\n *value is used in the same way this field would normally be used by itself.\n * \\endcode\n **/\nvoid CCirrus::write_b_3ce(u8 value) {\n#if defined(DEBUG_VGA)\n  if (value > 0x08) /* ??? */\n    printf(\"io write: 3ce: value > 8   \\n\");\n#endif\n  state.graphics_ctrl.index = value;\n}\n\n/**\n * Write to VGA Graphics Controller Data Register (0x3cf)\n *\n * For a description of the Graphics registers, see CCirrus::write_b_3ce\n **/\nvoid CCirrus::write_b_3cf(u8 value) {\n  u8 prev_memory_mapping;\n  bool prev_graphics_alpha;\n  bool prev_chain_odd_even;\n\n  /* Graphics Controller Registers 00..08 */\n  switch (state.graphics_ctrl.index) {\n  case 0: /* Set/Reset */\n    state.graphics_ctrl.set_reset = value & 0x0f;\n    break;\n\n  case 1: /* Enable Set/Reset */\n    state.graphics_ctrl.enable_set_reset = value & 0x0f;\n    break;\n\n  case 2: /* Color Compare */\n    state.graphics_ctrl.color_compare = value & 0x0f;\n    break;\n\n  case 3: /* Data Rotate */\n    state.graphics_ctrl.data_rotate = value & 0x07;\n\n    /* ??? is this bits 3..4 or 4..5 */\n    state.graphics_ctrl.raster_op = (value >> 3) & 0x03; /* ??? */\n    break;\n\n  case 4: /* Read Map Select */\n    state.graphics_ctrl.read_map_select = value & 0x03;\n#if defined(DEBUG_VGA)\n    printf(\"io write to 03cf = %02x (RMS)   \\n\", (unsigned)value);\n#endif\n    break;\n\n  case 5: /* Mode */\n    state.graphics_ctrl.write_mode = value & 0x03;\n    state.graphics_ctrl.read_mode = (value >> 3) & 0x01;\n    state.graphics_ctrl.odd_even = (value >> 4) & 0x01;\n    state.graphics_ctrl.shift_reg = (value >> 5) & 0x03;\n\n#if defined(DEBUG_VGA)\n    if (state.graphics_ctrl.odd_even)\n      printf(\"io write: 3cf: reg 05: value = %02xh   \\n\", (unsigned)value);\n    if (state.graphics_ctrl.shift_reg)\n      printf(\"io write: 3cf: reg 05: value = %02xh   \\n\", (unsigned)value);\n#endif\n    break;\n\n  case 6: /* Miscellaneous */\n    prev_graphics_alpha = state.graphics_ctrl.graphics_alpha;\n    prev_chain_odd_even = state.graphics_ctrl.chain_odd_even;\n    prev_memory_mapping = state.graphics_ctrl.memory_mapping;\n\n    state.graphics_ctrl.graphics_alpha = value & 0x01;\n    state.graphics_ctrl.chain_odd_even = (value >> 1) & 0x01;\n    state.graphics_ctrl.memory_mapping = (value >> 2) & 0x03;\n#if defined(DEBUG_VGA)\n    printf(\"memory_mapping set to %u   \\n\",\n           (unsigned)state.graphics_ctrl.memory_mapping);\n    printf(\"graphics mode set to %u   \\n\",\n           (unsigned)state.graphics_ctrl.graphics_alpha);\n    printf(\"odd_even mode set to %u   \\n\",\n           (unsigned)state.graphics_ctrl.odd_even);\n    printf(\"io write: 3cf: reg 06: value = %02xh   \\n\", (unsigned)value);\n#endif\n    if (prev_memory_mapping != state.graphics_ctrl.memory_mapping) {\n      redraw_area(0, 0, old_iWidth, old_iHeight);\n    }\n\n    if (prev_graphics_alpha != state.graphics_ctrl.graphics_alpha) {\n      redraw_area(0, 0, old_iWidth, old_iHeight);\n      old_iHeight = 0;\n    }\n    break;\n\n  case 7: /* Color Don't Care */\n    state.graphics_ctrl.color_dont_care = value & 0x0f;\n    break;\n\n  case 8: /* Bit Mask */\n    state.graphics_ctrl.bitmask = value;\n    break;\n\n  default:\n\n    /* ??? */\n    FAILURE_1(NotImplemented, \"io write: 3cf: index %u unhandled\",\n              (unsigned)state.graphics_ctrl.index);\n  }\n}\n\n/**\n * Write to VGA CRTC Index Register (0x3b4 or 0x3d4)\n *\n * The VGA CRTC Registers control how the video is output to the display.\n *\n * The CRTC registers are accessed in an indexed fashion. By writing a byte\n * to the CRTC Index Register (0x3d4) equal to the index of the particular\n * sub-register you wish to access, one can address the data pointed to by that\n * index by reading and writing the CRTC Data Register (0x3d5).\n *\n * CRTC registers:\n *   - Horizontal Total Register (index 0x00)\n *   - End Horizontal Display Register (index 0x01)\n *   - Start Horizontal Blanking Register (index 0x02)\n *   - End Horizontal Blanking Register (index 0x03)\n *   - Start Horizontal Retrace Register (index 0x04)\n *   - End Horizontal Retrace Register (index 0x05)\n *   - Vertical Total Register (index 0x06)\n *   - Overflow Register (index 0x07)\n *   - Preset Row Scan Register (index 0x08)\n *   - Maximum Scan Line Register (index 0x09)\n *   - Cursor Start Register (index 0x0a)\n *   - Cursor End Register (index 0x0b)\n *   - Start Address High Register (index 0x0c)\n *   - Start Address Low Register (index 0x0d)\n *   - Cursor Location High Register (index 0x0e)\n *   - Cursor Location Low Register (index 0x0f)\n *   - Vertical Retrace Start Register (index 0x10)\n *   - Vertical Retrace End Register (index 0x11)\n *   - Vertical Display End Register (index 0x12)\n *   - Offset Register (index 0x13)\n *   - Underline Location Register (index 0x14)\n *   - Start Vertical Blanking Register (index 0x15)\n *   - End Vertical Blanking (index 0x16)\n *   - CRTC Mode Control Register (index 0x17)\n *   - Line Compare Register (index 0x18)\n *   .\n *\n * \\code\n * Horizontal Total register (index 0x00)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Horizontal Total:\n * This field is used to specify the number of character clocks per scan line.\n * This field, along with the dot rate selected, controls the horizontal\n * refresh rate of the VGA by specifying the amount of time one scan line\n * takes.  This field is not programmed with the actual number of character\n * clocks, however. Due to timing factors of the VGA hardware (which, for\n * compatibility purposes has been emulated by VGA compatible chipsets), the\n * actual horizontal total is 5 character clocks more than the value stored in\n * this field, thus one needs to subtract 5 from the actual horizontal total\n * value desired before programming it into this register.\n *\n * End Horizontal Display register (index 0x01)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: End Horizontal Display:\n * This field is used to control the point that the sequencer stops outputting\n * pixel values from display memory, and sequences the pixel value specified by\n * the Overscan Palette Index field for the remainder of the scan line. The\n * overscan begins the character clock after the the value programmed into this\n * field. This register should be programmed with the number of character\n * clocks in the active display - 1. Note that the active display may be\n * affected by the Display Enable Skew field.\n *\n * Start Horizontal Blanking register (index 0x02)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Start Horizontal Blanking:\n * This field is used to specify the character clock at which the horizontal\n * blanking period begins.  During the horizontal blanking period, the VGA\n * hardware forces the DAC into a blanking state, where all of the intensities\n * output are at minimum value, no matter what color information the attribute\n * controller is sending to the DAC.  This field works in conjunction with the\n * End Horizontal Blanking field to specify the horizontal blanking period.\n * Note that the horizontal blanking can be programmed to appear anywhere within\n * the scan line, as well as being programmed to a value greater than the\n * Horizontal Total field preventing the horizontal blanking from occurring at\n * all.\n *\n * End Horizontal Blanking register (index 0x03)\n * +-+---+---------+\n * |7|6 5|4 3 2 1 0|\n * +-+---+---------+\n *  ^  ^      ^\n *  |  |      +-- 0..4: End Horizontal Blanking:\n *  |  |                Contains bits 4-0 of the End Horizontal Blanking field\n *  |  |                which specifies the end of the horizontal blanking\n *  |  |                period.  Bit 5 is located in bit 7 of the End Horizontal\n *  |  |                Retrace register (index 0x05). After the period has\n *  |  |                begun as specified by the Start Horizontal Blanking\n *  |  |                field, the 6-bit value of this field is compared against\n *  |  |                the lower 6 bits of the character clock. When a match\n *  |  |                occurs, the horizontal blanking signal is disabled. This\n *  |  |                provides from 1 to 64 character clocks although some\n *  |  |                implementations may match in the character clock\n *  |  |                specified by the Start Horizontal Blanking field, in\n *which |  |                case the range is 0 to 63.  Note that if blanking\n *extends |  |                past the end of the scan line, it will end on the\n *first |  |                match of this field on the next scan line. |\n *+--------- 5..6: Display Enable Skew: |                   This field affects\n *the timings of the display enable |                   circuitry in the VGA.\n *The value of this field is the number |                   of character clocks\n *that the display enable \"signal\" is |                   delayed. In all known\n *VGA cards, this field is always |                   programmed to 0.\n *Programming it to non-zero values results |                   in the overscan\n *being displayed over the number of |                   characters programmed\n *into this field at the beginning of |                   the scan line, as well\n *as the end of the active display |                   being shifted the number\n *of characters programmed into this |                   field. The characters\n *that extend past the normal end of the |                   active display can\n *be garbled in certain circumstances that |                   is dependent on\n *the particular VGA implementation. According |                   to\n *documentation from IBM, \"This skew control is needed to | provide sufficient\n *time for the CRT controller to read a |                   character and\n *attribute code from the video buffer, to gain |                   access to\n *the character generator, and go through the |                   Horizontal PEL\n *Panning register in the attribute controller. |                   Each access\n *requires the 'display enable' signal to be |                   skewed one\n *character clock so that the video output is |                   synchronized\n *with the horizontal and vertical retrace |                   signals.\" as well\n *as \"Note: Character skew is not adjustable |                   on the Type 2\n *video and the bits are ignored; however, |                   programs should\n *set these bits for the appropriate skew to |                   maintain\n *compatibility.\"  This may be required for some early |                   IBM\n *VGA implementations or may be simply an unused \"feature\" | carried over along\n *with its register description from the IBM |                   EGA\n *implementations that require the use of this field.\n *  +--------------- 7: Enable Vertical Retrace Access:\n *                      This field was used in the IBM EGA to provide access to\n *the light pen input values as the light pen registers were mapped over CRTC\n *indexes 10h-11h. The VGA lacks capability for light pen input, thus this field\n *is normally forced to 1 (although always writing it as 1 might be a good idea\n *for compatibility), which in the EGA would enable access to the vertical\n *retrace fields instead of the light pen fields.\n *\n * Start Horizontal Retrace register (index 0x04)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Start Horizontal Retrace:\n * This field specifies the character clock at which the VGA begins sending the\n * horizontal synchronization pulse to the display which signals the monitor to\n *retrace back to the left side of the screen. The end of this pulse is\n *controlled by the End Horizontal Retrace field. This pulse may appear anywhere\n *in the scan line, as well as set to a position beyond the Horizontal Total\n *field which effectively disables the horizontal synchronization pulse.\n *\n * End Horizontal Retrace register (index 0x05)\n * +-+---+---------+\n * |7|6 5|4 3 2 1 0|\n * +-+---+---------+\n *  ^  ^      ^\n *  |  |      +-- 0..4: End Horizontal Retrace:\n *  |  |                This field specifies the end of the horizontal retrace\n *period, |  |                which begins at the character clock specified in\n *the Start |  |                Horizontal Retrace field.  The horizontal\n *retrace signal is |  |                enabled until the lower 5 bits of the\n *character counter match |  |                the 5 bits of this field.  This\n *provides for a horizontal |  |                retrace period from 1 to 32\n *character clocks.  Note that some |  |                implementations may\n *match immediately instead of 32 clocks |  |                away, making the\n *effective range 0 to 31 character clocks. |  +--------- 5..6: Horizontal\n *Retrace Skew: |                   This field delays the start of the\n *horizontal retrace period |                   by the number of character\n *clocks equal to the value of this |                   field.  From\n *observation, this field is programmed to 0, with |                   the\n *exception of the 40 column text modes where this field is | set to 1.  The VGA\n *hardware simply acts as if this value is |                   added to the\n *Start Horizontal Retrace field. According to IBM | documentation, \"For certain\n *modes, the 'horizontal retrace' |                   signal takes up the entire\n *blanking interval. Some internal |                   timings are generated by\n *the falling edge of the 'horizontal |                   retrace' signal. To\n *ensure that the signals are latched |                   properly, the\n *'retrace' signal is started before the end of |                   the 'display\n *enable' signal and then skewed several character |                   clock\n *times to provide the proper screen centering.\" This does | not appear to be\n *the case, leading me to believe this is yet |                   another\n *holdout from the IBM EGA implementations that do |                   require\n *the use of this field.\n *  +--------------- 7: End Horizontal Blanking (bit 5):\n *                      This contains bit 5 of the End Horizontal Blanking field\n *in the End Horizontal Blanking register (index 0x03).\n *\n * Vertical Total register (index 0x06)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Vertical Total\n * This contains the lower 8 bits of the Vertical Total field. Bits 9-8 of this\n *field are located in the Overflow Register (index 0x07). This field determines\n *the number of scanlines in the active display and thus the length of each\n *vertical retrace. This field contains the value of the scanline counter at the\n *beginning of the last scanline in the vertical period.\n *\n * Overflow register (index 0x07)\n * +-+-+-+-+-+-+-+-+\n * |7|6|5|4|3|2|1|0|\n * +-+-+-+-+-+-+-+-+\n *  ^ ^ ^ ^ ^ ^ ^ ^\n *  | | +-|-|-|-|-+- 0,5: Bit 8,9 of Vertical Total (index 0x06)\n *  | +---|-|-|-+--- 1,6: Bit 8,9 of Vertical Display End (index 0x12)\n *  +-----|-|-+----- 2,7: Bit 8,9 of Vertical Retrace Start (index 0x10)\n *        | +--------- 3: Bit 8 of Start Vertical Blanking (index 0x15)\n *        +----------- 4: Bit 8 of Line Compare (index 0x18)\n *\n * Preset Row Scan register (index 0x08)\n * +-+---+---------+\n * | |6 5|4 3 2 1 0|\n * +-+---+---------+\n *     ^      ^\n *     |      +-- 0..4: Preset Row Scan:\n *     |                This field is used when using text mode or any mode with\n *a non-zero |                Maximum Scan Line field (index 0x09) to provide\n *for more precise |                vertical scrolling than the Start Address\n *Register provides. The |                value of this field specifies how many\n *scan lines to scroll the |                display upwards. Valid values range\n *from 0 to the value of the |                Maximum Scan Line field. Invalid\n *values may cause undesired effects |                and seem to be dependent\n *upon the particular VGA implementation.\n *     +--------- 5..6: Byte Panning:\n *                      The value of this field is added to the Start Address\n *Register when calculating the display memory address for the upper left hand\n *pixel or character of the screen. This allows for a maximum shift of 15, 31,\n *or 35 pixels without having to reprogram the Start Address Register.\n *\n * Maximum Scan Line register (index 0x09)\n * +-+-+-+---------+\n * |7|6|5|4 3 2 1 0|\n * +-+-+-+---------+\n *  ^ ^ ^     ^\n *  | | |     +-- 0..4: Maximum Scan Line:\n *  | | |               In text modes, this field is programmed with the\n *character height - 1 | | |               (scan line numbers are zero based.)\n *In graphics modes, a non-zero | | |               value in this field will\n *cause each scan line to be repeated by the | | |               value of this\n *field + 1. | | +----------- 5: Bit 9 of Start Vertical Blanking (index 0x15)\n *  | +------------- 6: Bit 9 of Line Compare (index 0x18)\n *  +--------------- 7: Scan Doubling:\n *                      When this bit is set to 1, 200-scan-line video data is\n *converted to 400-scan-line output. To do this, the clock in the row scan\n *counter is divided by 2, which allows the 200-line modes to be displayed as\n *400 lines on the display (this is called double scanning; each line is\n *                      displayed twice). When this bit is set to 0, the clock\n *to the row scan counter is equal to the horizontal scan rate.\n *\n * Cursor Start Register (index 0x0a)\n * +---+-+---------+\n * |   |5|4 3 2 1 0|\n * +---+-+---------+\n *      ^     ^\n *      |     +-- 0..4: Cursor Scan Line Start:\n *      |               This field controls the appearance of the text-mode\n *cursor by |               specifying the scan line location within a character\n *cell at which |               the cursor should begin, with the top-most scan\n *line in a character |               cell being 0 and the bottom being with the\n *value of the Maximum Scan |               Line field.\n *      +------------5: Cursor Disable:\n *                      This field controls whether or not the text-mode cursor\n *is displayed: 0: Cursor Enabled. 1: Cursor Disabled.\n *\n * Cursor End Register (index 0x0b)\n * +-+---+---------+\n * | |6 5|4 3 2 1 0|\n * +-+---+---------+\n *     ^      ^\n *     |      +-- 0..4: Cursor Scan Line End:\n *     |                This field controls the appearance of the text-mode\n *cursor by |                specifying the scan line location within a\n *character cell at which |                the cursor should end, with the\n *top-most scan line in a character |                cell being 0 and the bottom\n *being with the value of the Maximum Scan |                Line field. If this\n *field is less than the Cursor Scan Line Start |                field, the\n *cursor is not drawn. Some graphics adapters, such as the |                IBM\n *EGA display a split-block cursor instead.\n *     +------------ 5: Cursor Skew:\n *                      This field was necessary in the EGA to synchronize the\n *cursor with internal timing. In the VGA it basically is added to the cursor\n *                      location. In some cases when this value is non-zero and\n *the cursor is near the left or right edge of the screen, the cursor will not\n *appear at all, or a second cursor above and to the left of the actual one may\n *                      appear. This behavior may not be the same on all VGA\n *compatible adapter cards.\n *\n * Start Address High register (index 0x0c)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Bits 8..15 of the Start Address.\n * Bits 0..7 are in the Start Address Low register (index 0x0d). The Start\n *Address field specifies the display memory address of the upper left pixel or\n *character of the screen. Because the standard VGA has a maximum of 256K of\n *memory, and memory is accessed 32 bits at a time, this 16-bit field is\n *sufficient to allow the screen to start at any memory address. Normally this\n *field is programmed to 0h, except when using virtual resolutions, paging,\n * and/or split-screen operation. Note that the VGA display will wrap around in\n *display memory if the starting address is too high. (This may or may not be\n *desirable, depending on your intentions.)\n *\n * Start Address Low register (index 0x0d)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Bits 0..7 of the Start Address. See Start Address High register (index\n *0x0c)\n *\n * Cursor Location High register (index 0x0e)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Bits 8..15 of the Cursor Location.\n * Bits 0..7 are in the Cursor Location Low register (index 0x0d). When the VGA\n *hardware is displaying text mode and the text-mode cursor is enabled, the\n *hardware compares the address of the character currently being displayed with\n *sum of value of this field and the sum of the Cursor Skew field. If the values\n *equal then the scan lines in that character specified by the Cursor Scan Line\n *Start field and the Cursor Scan Line End field are replaced with the\n * foreground color.\n *\n * Cursor Location Low register (index 0x0f)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Bits 0..7 of the Cursor Location. See Cursor Location High register\n *(index 0x0f)\n *\n * Vertical Retrace Start register (index 0x10)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Bits 0..7 of Vertical Retrace Start\n * Bits 8 and 9 are in the Overflow Register (index 0x07). This field controls\n *the start of the vertical retrace pulse which signals the display to move up\n *to the beginning of the active display. This field contains the value of the\n *vertical scanline counter at the beginning of the first scanline where the\n *vertical retrace signal is asserted.\n *\n * Vertical Retrace End register (index 0x11)\n * +-+-+---+-------+\n * |7|6|5|4|3 2 1 0|\n * +-+-+---+-------+\n *  ^ ^ ^ ^   ^\n *  | | | |   +-- 0..3: Vertical Retrace End:\n *  | | | |             This field determines the end of the vertical retrace\n *pulse, and thus its | | | |             length. This field contains the lower\n *four bits of the vertical scanline | | | |             counter at the\n *beginning of the scanline immediately after the last | | | | scanline where\n *the vertical retrace signal is asserted. | | | +--------- 4: End Vertical\n *Interrupt | | +----------- 5: Enable Vertical Interrupt | +------------- 6:\n *Memory Refresh Bandwidth: |                   Nearly all video chipsets\n *include a few registers that control memory, bus, |                   or other\n *timings not directly related to the output of the video card. Most | VGA/SVGA\n *implementations ignore the value of this field; however, in the | least, IBM\n *VGA adapters do utilize it and thus for compatibility with these | chipsets\n *this field should be programmed. This register is used in the IBM | VGA\n *hardware to control the number of DRAM refresh cycles per scan line. | The\n *three refresh cycles per scanline is appropriate for the IBM VGA | horizontal\n *frequency of approximately 31.5 kHz. For horizontal frequencies | greater than\n *this, this setting will work as the DRAM will be refreshed more | often.\n *However, refreshing not often enough for the DRAM can cause memory | loss.\n *Thus at some point slower than 31.5 kHz the five refresh cycle setting |\n *should be used. At which particular point this should occur, would require |\n *better knowledge of the IBM VGA's schematics than I have available. |\n *According to IBM documentation, \"Selecting five refresh cycles allows use of\n *  |                   the VGA chip with 15.75 kHz displays.\" which isn't\n *really enough to go by |                   unless the mode you are defining\n *has a 15.75 kHz horizontal frequency.\n *  +--------------- 7: CRTC Registers Protect Enable:\n *                      This field is used to protect the video timing registers\n *from being changed by programs written for earlier graphics chipsets that\n *attempt to program these registers with values unsuitable for VGA timings.\n *When this field is set to 1, the CRTC register indexes 00h-07h ignore write\n *access, with the exception of bit 4 of the Overflow Register, which holds bit\n *8 of the Line Compare field.\n *\n * Vertical Display End register (index 0x12)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Bits 0..7 of Vertical Display End\n * Bits 8 and 9 are in the Overflow Register (index 0x07). This field contains\n *the value of the vertical scanline counter at the beggining of the scanline\n *immediately after the last scanline of active display.\n *\n * Offset register (index 0x13)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Offset:\n * This field specifies the address difference between consecutive scan lines or\n *two lines of characters. Beginning with the second scan line, the starting\n *scan line is increased by twice the value of this register multiplied by the\n *current memory address size (byte = 1, word = 2, double-word = 4) each line.\n *For text modes the following equation is used: Offset = Width / (\n *MemoryAddressSize * 2 ) and in graphics mode, the following equation is used:\n *       Offset = Width / ( PixelsPerAddress * MemoryAddressSize * 2 )\n * where Width is the width in pixels of the screen. This register can be\n *modified to provide for a virtual resolution, in which case Width is the width\n *is the width in pixels of the virtual screen. PixelsPerAddress is the number\n *of pixels stored in one display memory address, and MemoryAddressSize is the\n *current memory addressing size.\n *\n * Underline Location register (index 0x14)\n * +-+-+-+---------+\n * | |6|5|4 3 2 1 0|\n * +-+-+-+---------+\n *    ^ ^     ^\n *    | |     +-- 0..4: Underline Location\n *    | |               These bits specify the horizontal scan line of a\n *character row on which an | |               underline occurs. The value\n *programmed is the scan line desired minus 1. | +----------- 5: Divide Memory\n *Address Clock by 4: |                   1: The memory-address counter is\n *clocked with the character clock divided |                      by 4, which is\n *used when doubleword addresses are used.\n *    +------------- 6: Double-Word Addressing:\n *                        1: Memory addresses are doubleword addresses. See the\n *description of the word/byte mode bit (bit 6) in the CRT Mode Control Register\n *(index 0x17)\n *\n * Start Vertical Blanking register (index 0x15)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Bits 0..7 of Start Vertical Blanking\n * Bit 8 is in the Overflow Register (index 0x07), and bit 9 is in the Maximum\n *Scan Line register (index 0x09). This field determines when the vertical\n *blanking period begins, and contains the value of the vertical scanline\n *counter at the beginning of the first vertical scanline of blanking.\n *\n * End Vertical Blanking register (index 0x16)\n * +-+-------------+\n * | |6 5 4 3 2 1 0|\n * +-+-------------+\n *          ^\n *          +---- 0..6: End Vertical Blanking:\n *                      This field determines when the vertical blanking period\n *ends, and contains the value of the vertical scanline counter at the beginning\n *of the vertical scanline immediately after the last scanline of blanking.\n *\n * CRTC Mode Control Register (index 0x17)\n * +-+-+-+-+-+-+-+-+\n * |7|6|5| |3|2|1|0|\n * +-+-+-+-+-+-+-+-+\n *  ^ ^ ^   ^ ^ ^ ^\n *  | | |   | | | +- 0: Map Display Address 13:\n *  | | |   | | |       This bit selects the source of bit 13 of the output\n *multiplexer: | | |   | | |         0: Bit 0 of the row scan counter is the\n *source. | | |   | | |         1: Bit 13 of the address counter is the source.\n *  | | |   | | |       The CRT controller used on the IBM Color/Graphics\n *Adapter was capable of | | |   | | |       using 128 horizontal scan-line\n *addresses. For the VGA to obtain 640-by-200 | | |   | | |       graphics\n *resolution, the CRT controller is programmed for 100 horizontal | | |   | | |\n *scan lines with two scan-line addresses per character row. Row scan address |\n *| |   | | |       bit 0 becomes the most-significant address bit to the\n *display buffer. | | |   | | |       Successive scan lines of the display image\n *are displaced in 8KB of memory. | | |   | | |       This bit allows\n *compatibility with the graphics modes of earlier adapters. | | |   | | +--- 1:\n *Map Display Address 14: | | |   | |         This bit selects the source of bit\n *14 of the output multiplexer: | | |   | |           0: Bit 1 of the row scan\n *counter is the source. | | |   | |           1: Bit 14 of the address counter\n *is the source. | | |   | +----- 2: Divide Scan Line clock by 2: | | |   | This\n *bit selects the clock that controls the vertical timing counter: | | |   | 0:\n *The horizontal retrace clock. | | |   |             1: The horizontal retrace\n *clock divided by 2. | | |   |           Dividing the clock effectively doubles\n *the vertical resolution of the CRT | | |   |           controller. The\n *vertical counter has a maximum resolution of 1024 scan lines | | |   | because\n *the vertical total value is 10-bits wide. If the vertical counter is | | |   |\n *clocked with the horizontal retrace divided by 2, the vertical resolution is\n *  | | |   |           doubled to 2048 scan lines.\"\n *  | | |   +------- 3: Divide Memory Address clock by 2:\n *  | | |               This bit selects the clock that controlls the address\n *counter: | | |                 0: The character clock. | | | 1: The character\n *clock divided by 2. | | |               This bit is used to create either a\n *byte or word refresh address for the | | |               display buffer. | |\n *+----------- 5: Address Wrap Select: | |                 This bit selects the\n *memory-address bit, bit MA 13 or MA 15, that appears on | | the output pin MA\n *0, in the word address mode. If the VGA is not in the word | | address mode,\n *bit 0 from the address counter appears on the output pin, MA 0. | | 0: Selects\n *MA 13. Used in applications where only 64KB of video memory is | | present. |\n *|                   1: Selects MA 15. In odd/even mode, this bit should be set\n *to 1 because | |                      256KB of video memory is installed on\n *the system board. | |                 This function maintains compatibility\n *with the IBM Color/Graphics Monitor | |                 Adapter. |\n *+------------- 6: Word/Byte Mode Select: |                     0: Selects the\n *word address mode. The word mode shifts the memory-address | counter bits to\n *the left by one bit; the most-significant bit of the | counter appears on the\n *least-significant bit of the memory address |                        outputs.\n *  |                     1: Selects the byte address mode.\n *  |                   The doubleword bit in the Underline Location register\n *(index 0x14) also |                   controls the addressing. When the\n *doubleword bit is 0, the word/byte bit |                   selects the mode.\n *When the doubleword bit is set to 1, the addressing is | shifted by two bits.\n *  +--------------- 7: Sync Enable:\n *                        0: Disables the horizontal and vertical retrace\n *signals and forces them to an inactive level. 1: Enables the horizontal and\n *vertical retrace signals. This bit does not reset any other registers or\n *signal outputs.\n *\n * Line Compare register (index 0x18)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Bits 0..7 of Line Compare\n * Bit 8 is in the Overflow Register (index 0x07), and bit 9 is in the Maximum\n *Scan Line register (index 0x09). The Line Compare field specifies the scan\n *line at which a horizontal division can occur, providing for split-screen\n *operation. If no horizontal division is required, this field should be set to\n *3FFh. When the scan line counter reaches the value in the Line Compare field,\n *the current scan line address is reset to 0 and the Preset Row Scan is\n *presumed to be 0. If the Pixel Panning Mode field is set to 1 then the Pixel\n *Shift Count and Byte Panning fields are reset to 0 for the remainder of the\n *display cycle. \\endcode\n **/\nvoid CCirrus::write_b_3d4(u8 value) {\n  state.CRTC.address = value & 0x7f;\n#if defined(DEBUG_VGA)\n  if (state.CRTC.address > 0x18)\n    printf(\"write: invalid CRTC register 0x%02x selected\",\n           (unsigned)state.CRTC.address);\n#endif\n}\n\n/**\n * Write to VGA CRTC Data Register (0x3b5 or 0x3d5)\n *\n * For a description of CRTC Registers, see CCirrus::write_b_3d4.\n **/\nvoid CCirrus::write_b_3d5(u8 value) {\n\n  /* CRTC Registers */\n  if (state.CRTC.address > 0x18) {\n#if defined(DEBUG_VGA)\n    printf(\"write: invalid CRTC register 0x%02x ignored\",\n           (unsigned)state.CRTC.address);\n#endif\n    return;\n  }\n\n  if (state.CRTC.write_protect && (state.CRTC.address < 0x08)) {\n    if (state.CRTC.address == 0x07) {\n      state.CRTC.reg[state.CRTC.address] &= ~0x10;\n      state.CRTC.reg[state.CRTC.address] |= (value & 0x10);\n      state.line_compare &= 0x2ff;\n      if (state.CRTC.reg[0x07] & 0x10)\n        state.line_compare |= 0x100;\n      redraw_area(0, 0, old_iWidth, old_iHeight);\n      return;\n    } else {\n      return;\n    }\n  }\n\n  if (value != state.CRTC.reg[state.CRTC.address]) {\n    state.CRTC.reg[state.CRTC.address] = value;\n    switch (state.CRTC.address) {\n    case 0x07:\n      state.vertical_display_end &= 0xff;\n      if (state.CRTC.reg[0x07] & 0x02)\n        state.vertical_display_end |= 0x100;\n      if (state.CRTC.reg[0x07] & 0x40)\n        state.vertical_display_end |= 0x200;\n      state.line_compare &= 0x2ff;\n      if (state.CRTC.reg[0x07] & 0x10)\n        state.line_compare |= 0x100;\n      redraw_area(0, 0, old_iWidth, old_iHeight);\n      break;\n\n    case 0x08:\n\n      // Vertical pel panning change\n      redraw_area(0, 0, old_iWidth, old_iHeight);\n      break;\n\n    case 0x09:\n      state.y_doublescan = ((value & 0x9f) > 0);\n      state.line_compare &= 0x1ff;\n      if (state.CRTC.reg[0x09] & 0x40)\n        state.line_compare |= 0x200;\n      redraw_area(0, 0, old_iWidth, old_iHeight);\n      break;\n\n    case 0x0A:\n    case 0x0B:\n    case 0x0E:\n    case 0x0F:\n\n      // Cursor size / location change\n      state.vga_mem_updated = 1;\n      break;\n\n    case 0x0C:\n    case 0x0D:\n\n      // Start address change\n      if (state.graphics_ctrl.graphics_alpha) {\n        redraw_area(0, 0, old_iWidth, old_iHeight);\n      } else {\n        state.vga_mem_updated = 1;\n      }\n      break;\n\n    case 0x12:\n      state.vertical_display_end &= 0x300;\n      state.vertical_display_end |= state.CRTC.reg[0x12];\n      break;\n\n    case 0x13:\n    case 0x14:\n    case 0x17:\n\n      // Line offset change\n      state.line_offset = state.CRTC.reg[0x13] << 1;\n      if (state.CRTC.reg[0x14] & 0x40)\n        state.line_offset <<= 2;\n      else if ((state.CRTC.reg[0x17] & 0x40) == 0)\n        state.line_offset <<= 1;\n      redraw_area(0, 0, old_iWidth, old_iHeight);\n      break;\n\n    case 0x18:\n      state.line_compare &= 0x300;\n      state.line_compare |= state.CRTC.reg[0x18];\n      redraw_area(0, 0, old_iWidth, old_iHeight);\n      break;\n    }\n  }\n}\n\n/**\n * Read from the attribute controller index register (0x3c0)\n *\n * For a description of the attribute controller registers, see\n *CCirrus::write_b_3c0.\n **/\nu8 CCirrus::read_b_3c0() {\n  if (state.attribute_ctrl.flip_flop == 0) {\n\n    // BX_INFO((\"io read: 0x3c0: flip_flop = 0\"));\n    return (state.attribute_ctrl.video_enabled << 5) |\n           state.attribute_ctrl.address;\n  } else {\n    FAILURE(NotImplemented, \"io read: 0x3c0: flip_flop != 0\");\n  }\n}\n\n/**\n * Read from the attribute controller data register (0x3c1)\n *\n * For a description of the attribute controller registers, see\n *CCirrus::write_b_3c0.\n **/\nu8 CCirrus::read_b_3c1() {\n  u8 retval;\n  switch (state.attribute_ctrl.address) {\n  case 0x00:\n  case 0x01:\n  case 0x02:\n  case 0x03:\n  case 0x04:\n  case 0x05:\n  case 0x06:\n  case 0x07:\n  case 0x08:\n  case 0x09:\n  case 0x0a:\n  case 0x0b:\n  case 0x0c:\n  case 0x0d:\n  case 0x0e:\n  case 0x0f:\n    retval = state.attribute_ctrl.palette_reg[state.attribute_ctrl.address];\n    return (retval);\n    break;\n\n  case 0x10: /* mode control register */\n    retval = (state.attribute_ctrl.mode_ctrl.graphics_alpha << 0) |\n             (state.attribute_ctrl.mode_ctrl.display_type << 1) |\n             (state.attribute_ctrl.mode_ctrl.enable_line_graphics << 2) |\n             (state.attribute_ctrl.mode_ctrl.blink_intensity << 3) |\n             (state.attribute_ctrl.mode_ctrl.pixel_panning_compat << 5) |\n             (state.attribute_ctrl.mode_ctrl.pixel_clock_select << 6) |\n             (state.attribute_ctrl.mode_ctrl.internal_palette_size << 7);\n    return (retval);\n    break;\n\n  case 0x11: /* overscan color register */\n    return (state.attribute_ctrl.overscan_color);\n    break;\n\n  case 0x12: /* color plane enable */\n    return (state.attribute_ctrl.color_plane_enable);\n    break;\n\n  case 0x13: /* horizontal PEL panning register */\n    return (state.attribute_ctrl.horiz_pel_panning);\n    break;\n\n  case 0x14: /* color select register */\n    return (state.attribute_ctrl.color_select);\n    break;\n\n  default:\n    FAILURE_1(NotImplemented, \"io read: 0x3c1: unknown register 0x%02x\",\n              (unsigned)state.attribute_ctrl.address);\n  }\n}\n\n/**\n * Read from the VGA Input Status register (0x3c2)\n *\n * \\code\n * +-----+-+-------+\n * |     |4|       |\n * +-----+-+-------+\n *        ^\n *        +--------- 4: Switch Sense:\n *                      Returns the status of the four sense switches as\n *selected by the Clock Select field of the Miscellaneous Output Register (See\n *                      CCirrus::write_b_3c2)\n * \\endcode\n **/\nu8 CCirrus::read_b_3c2() {\n  return 0; // input status register\n}\n\n/**\n * Read from the VGA Enable register (0x3c3)\n *\n * (Not sure where this comes from; doesn't seem to be in the VGA specs.)\n **/\nu8 CCirrus::read_b_3c3() { return state.vga_enabled; }\n\n/**\n * Read from the VGA sequencer index register (0x3c4)\n *\n * For a description of the Sequencer registers, see CCirrus::write_b_3c4\n **/\nu8 CCirrus::read_b_3c4() { return state.sequencer.index; }\n\n/**\n * Read from the VGA sequencer data register (0x3c5)\n *\n * For a description of the Sequencer registers, see CCirrus::write_b_3c4\n **/\nu8 CCirrus::read_b_3c5() {\n  switch (state.sequencer.index) {\n  case 0: /* sequencer: reset */\n#if defined(DEBUG_VGA)\n    BX_DEBUG((\"io read 0x3c5: sequencer reset\"));\n#endif\n    return (state.sequencer.reset1 ? 1 : 0) | (state.sequencer.reset2 ? 2 : 0);\n    break;\n\n  case 1: /* sequencer: clocking mode */\n#if defined(DEBUG_VGA)\n    BX_DEBUG((\"io read 0x3c5: sequencer clocking mode\"));\n#endif\n    return state.sequencer.reg1;\n    break;\n\n  case 2: /* sequencer: map mask register */\n    return state.sequencer.map_mask;\n    break;\n\n  case 3: /* sequencer: character map select register */\n    return state.sequencer.char_map_select;\n    break;\n\n  case 4: /* sequencer: memory mode register */\n    return (state.sequencer.extended_mem << 1) |\n           (state.sequencer.odd_even << 2) | (state.sequencer.chain_four << 3);\n    break;\n\n  default:\n    FAILURE_1(NotImplemented, \"io read 0x3c5: index %u unhandled\",\n              (unsigned)state.sequencer.index);\n  }\n}\n\n/**\n * Read from VGA DAC Data register (0x3c9)\n *\n * For a description of DAC registers see CCirrus::write_b_3c7\n **/\nu8 CCirrus::read_b_3c9() {\n  u8 retval;\n  if (state.pel.dac_state == 0x03) {\n    switch (state.pel.read_data_cycle) {\n    case 0:\n      retval = state.pel.data[state.pel.read_data_register].red;\n      break;\n    case 1:\n      retval = state.pel.data[state.pel.read_data_register].green;\n      break;\n    case 2:\n      retval = state.pel.data[state.pel.read_data_register].blue;\n      break;\n    default:\n      retval = 0; // keep compiler happy\n    }\n\n    state.pel.read_data_cycle++;\n    if (state.pel.read_data_cycle >= 3) {\n      state.pel.read_data_cycle = 0;\n      state.pel.read_data_register++;\n    }\n  } else {\n    retval = 0x3f;\n  }\n\n  return retval;\n}\n/**\n * Read from the VGA Feature Control register (index 0x3ca)\n *\n * \\code\n * +-----------+-+-+\n * |           |1|0|\n * +-----------+-+-+\n *              ^ ^\n *              | +- 0: Feature Control 0 (reserved)\n *              +--- 1: Feature Control 1 (reserved)\n * \\endcode\n **/\nu8 CCirrus::read_b_3ca() { return 0; }\n\n/**\n * Write to the VGA Miscellaneous Output Register (0x3cc)\n *\n * For a description of the Miscellaneous Output register, see\n *CCirrus::write_b_3c2\n **/\nu8 CCirrus::read_b_3cc() {\n\n  /* Miscellaneous Output / Graphics 1 Position ??? */\n  return ((state.misc_output.color_emulation & 0x01) << 0) |\n         ((state.misc_output.enable_ram & 0x01) << 1) |\n         ((state.misc_output.clock_select & 0x03) << 2) |\n         ((state.misc_output.select_high_bank & 0x01) << 5) |\n         ((state.misc_output.horiz_sync_pol & 0x01) << 6) |\n         ((state.misc_output.vert_sync_pol & 0x01) << 7);\n}\n\n/**\n * Read from VGA Graphics Controller Data Register (0x3cf)\n *\n * For a description of the Graphics registers, see CCirrus::write_b_3ce\n **/\nu8 CCirrus::read_b_3cf() {\n  u8 retval;\n  switch (state.graphics_ctrl.index) {\n  case 0: /* Set/Reset */\n    return (state.graphics_ctrl.set_reset);\n    break;\n\n  case 1: /* Enable Set/Reset */\n    return (state.graphics_ctrl.enable_set_reset);\n    break;\n\n  case 2: /* Color Compare */\n    return (state.graphics_ctrl.color_compare);\n    break;\n\n  case 3: /* Data Rotate */\n    retval = ((state.graphics_ctrl.raster_op & 0x03) << 3) |\n             ((state.graphics_ctrl.data_rotate & 0x07) << 0);\n    return (retval);\n    break;\n\n  case 4: /* Read Map Select */\n    return (state.graphics_ctrl.read_map_select);\n    break;\n\n  case 5: /* Mode */\n    retval = ((state.graphics_ctrl.shift_reg & 0x03) << 5) |\n             ((state.graphics_ctrl.odd_even & 0x01) << 4) |\n             ((state.graphics_ctrl.read_mode & 0x01) << 3) |\n             ((state.graphics_ctrl.write_mode & 0x03) << 0);\n\n#if defined(DEBUG_VGA)\n    if (state.graphics_ctrl.odd_even || state.graphics_ctrl.shift_reg)\n      BX_DEBUG((\"io read 0x3cf: reg 05 = 0x%02x\", (unsigned)retval));\n#endif\n    return (retval);\n    break;\n\n  case 6: /* Miscellaneous */\n    return ((state.graphics_ctrl.memory_mapping & 0x03) << 2) |\n           ((state.graphics_ctrl.odd_even & 0x01) << 1) |\n           ((state.graphics_ctrl.graphics_alpha & 0x01) << 0);\n    break;\n\n  case 7: /* Color Don't Care */\n    return (state.graphics_ctrl.color_dont_care);\n    break;\n\n  case 8: /* Bit Mask */\n    return (state.graphics_ctrl.bitmask);\n    break;\n\n  default:\n    FAILURE_1(NotImplemented, \"io read: 0x3cf: index %u unhandled\",\n              (unsigned)state.graphics_ctrl.index);\n  }\n}\n\n/**\n * Read from VGA CRTC Index Register (0x3b5 or 0x3d5)\n *\n * For a description of CRTC Registers, see CCirrus::write_b_3d4.\n **/\nu8 CCirrus::read_b_3d4() { return state.CRTC.address; }\n\n/**\n * Read from VGA CRTC Data Register (0x3b5 or 0x3d5)\n *\n * For a description of CRTC Registers, see CCirrus::write_b_3d4.\n **/\nu8 CCirrus::read_b_3d5() {\n  if (state.CRTC.address > 0x18) {\n    FAILURE_1(NotImplemented, \"io read: invalid CRTC register 0x%02x   \\n\",\n              (unsigned)state.CRTC.address);\n  }\n\n  return state.CRTC.reg[state.CRTC.address];\n}\n\n/**\n * Read from the VGA Input Status 1 register (0x3ba or 0x3da)\n *\n * \\code\n * +-------+-+---+-+\n * |       |3|   |0|\n * +-------+-+---+-+\n *          ^     ^\n *          |     +- 0: Display Disabled:\n *          |             1: Indicates a horizontal or vertical retrace\n *interval. This |                bit is the real-time status of the inverted\n *'display |                enable' signal. Programs have used this status bit\n *to |                restrict screen updates to the inactive display intervals\n *          |                in order to reduce screen flicker. The video\n *subsystem is |                designed to eliminate this software requirement;\n *screen |                updates may be made at any time without screen\n *degradation.\n *          +------- 1: Vertical Retrace:\n *                        1: Indicates that the display is in a vertical retrace\n *interval. This bit can be programmed, through the Vertical Retrace End\n *                           register, to generate an interrupt at the start of\n *the vertical retrace. \\endcode\n **/\nu8 CCirrus::read_b_3da() {\n\n  /* Input Status 1 (color emulation modes) */\n  u8 retval = 0;\n\n  // bit3: Vertical Retrace\n  //       0 = display is in the display mode\n  //       1 = display is in the vertical retrace mode\n  // bit0: Display Enable\n  //       0 = display is in the display mode\n  //       1 = display is not in the display mode; either the\n  //           horizontal or vertical retrace period is active\n  // using 72 Hz vertical frequency\n\n  /*** TO DO ??? ***\n       usec = bx_pc_system.time_usec();\n       switch ( ( state.misc_output.vert_sync_pol << 1) |\n     state.misc_output.horiz_sync_pol )\n       {\n         case 0: vertres = 200; break;\n         case 1: vertres = 400; break;\n         case 2: vertres = 350; break;\n         default: vertres = 480; break;\n       }\n       if ((usec % 13888) < 70) {\n         vert_retrace = 1;\n       }\n       if ((usec % (13888 / vertres)) == 0) {\n         horiz_retrace = 1;\n       }\n\n       if (horiz_retrace || vert_retrace)\n         retval = 0x01;\n       if (vert_retrace)\n         retval |= 0x08;\n\n       *** TO DO ??? ***/\n\n  /* reading this port resets the flip-flop to address mode */\n  state.attribute_ctrl.flip_flop = 0;\n  return retval;\n}\n\nu8 CCirrus::get_actl_palette_idx(u8 index) {\n  return state.attribute_ctrl.palette_reg[index];\n}\n\nvoid CCirrus::redraw_area(unsigned x0, unsigned y0, unsigned width,\n                          unsigned height) {\n  unsigned xti;\n\n  unsigned yti;\n\n  unsigned xt0;\n\n  unsigned xt1;\n\n  unsigned yt0;\n\n  unsigned yt1;\n\n  unsigned xmax;\n\n  unsigned ymax;\n\n  if ((width == 0) || (height == 0)) {\n    return;\n  }\n\n  state.vga_mem_updated = 1;\n\n  if (state.graphics_ctrl.graphics_alpha) {\n\n    // graphics mode\n    xmax = old_iWidth;\n    ymax = old_iHeight;\n    xt0 = x0 / X_TILESIZE;\n    yt0 = y0 / Y_TILESIZE;\n    if (x0 < xmax) {\n      xt1 = (x0 + width - 1) / X_TILESIZE;\n    } else {\n      xt1 = (xmax - 1) / X_TILESIZE;\n    }\n\n    if (y0 < ymax) {\n      yt1 = (y0 + height - 1) / Y_TILESIZE;\n    } else {\n      yt1 = (ymax - 1) / Y_TILESIZE;\n    }\n\n    for (yti = yt0; yti <= yt1; yti++) {\n      for (xti = xt0; xti <= xt1; xti++) {\n        SET_TILE_UPDATED(xti, yti, 1);\n      }\n    }\n  } else {\n\n    // text mode\n    memset(state.text_snapshot, 0, sizeof(state.text_snapshot));\n  }\n}\n\nvoid CCirrus::update(void) {\n  unsigned iHeight;\n\n  unsigned iWidth;\n\n  /* no screen update necessary */\n  if (state.vga_mem_updated == 0)\n    return;\n\n  /* skip screen update when vga/video is disabled or the sequencer is in reset\n   * mode */\n  if (!state.vga_enabled || !state.attribute_ctrl.video_enabled ||\n      !state.sequencer.reset2 || !state.sequencer.reset1)\n    return;\n\n  // fields that effect the way video memory is serialized into screen output:\n  // GRAPHICS CONTROLLER:\n  //   state.graphics_ctrl.shift_reg:\n  //     0: output data in standard VGA format or CGA-compatible 640x200 2 color\n  //        graphics mode (mode 6)\n  //     1: output data in CGA-compatible 320x200 4 color graphics mode\n  //        (modes 4 & 5)\n  //     2: output data 8 bits at a time from the 4 bit planes\n  //        (mode 13 and variants like modeX)\n  // if (state.vga_mem_updated==0 || state.attribute_ctrl.video_enabled == 0)\n  if (state.graphics_ctrl.graphics_alpha) {\n    u8 color;\n    unsigned bit_no;\n    unsigned r;\n    unsigned c;\n    unsigned x;\n    unsigned y;\n    unsigned long byte_offset;\n    unsigned long start_addr;\n    unsigned xc;\n    unsigned yc;\n    unsigned xti;\n    unsigned yti;\n\n    start_addr = (state.CRTC.reg[0x0c] << 8) | state.CRTC.reg[0x0d];\n\n    // BX_DEBUG((\"update: shiftreg=%u, chain4=%u, mapping=%u\",\n    //  (unsigned) state.graphics_ctrl.shift_reg,\n    //  (unsigned) state.sequencer.chain_four,\n    //  (unsigned) state.graphics_ctrl.memory_mapping);\n    determine_screen_dimensions(&iHeight, &iWidth);\n    if ((iWidth != old_iWidth) || (iHeight != old_iHeight) ||\n        (state.last_bpp > 8)) {\n      bx_gui->dimension_update(iWidth, iHeight);\n      old_iWidth = iWidth;\n      old_iHeight = iHeight;\n      state.last_bpp = 8;\n    }\n\n    switch (state.graphics_ctrl.shift_reg) {\n    case 0:\n      u8 attribute, palette_reg_val, DAC_regno;\n\n      unsigned long line_compare;\n      u8 *plane0;\n      u8 *plane1;\n      u8 *plane2;\n      u8 *plane3;\n\n      if (state.graphics_ctrl.memory_mapping == 3) { // CGA 640x200x2\n        for (yc = 0, yti = 0; yc < iHeight; yc += Y_TILESIZE, yti++) {\n          for (xc = 0, xti = 0; xc < iWidth; xc += X_TILESIZE, xti++) {\n            if (GET_TILE_UPDATED(xti, yti)) {\n              for (r = 0; r < Y_TILESIZE; r++) {\n                y = yc + r;\n                if (state.y_doublescan)\n                  y >>= 1;\n                for (c = 0; c < X_TILESIZE; c++) {\n                  x = xc + c;\n\n                  /* 0 or 0x2000 */\n                  byte_offset = start_addr + ((y & 1) << 13);\n\n                  /* to the start of the line */\n                  byte_offset += (320 / 4) * (y / 2);\n\n                  /* to the byte start */\n                  byte_offset += (x / 8);\n\n                  bit_no = 7 - (x % 8);\n                  palette_reg_val =\n                      (((state.memory[byte_offset]) >> bit_no) & 1);\n                  DAC_regno = state.attribute_ctrl.palette_reg[palette_reg_val];\n                  state.tile[r * X_TILESIZE + c] = DAC_regno;\n                }\n              }\n\n              SET_TILE_UPDATED(xti, yti, 0);\n              bx_gui->graphics_tile_update(state.tile, xc, yc);\n            }\n          }\n        }\n      } else { // output data in serial fashion with each display plane\n        // output on its associated serial output.  Standard EGA/VGA format\n        plane0 = &state.memory[0 << 16];\n        plane1 = &state.memory[1 << 16];\n        plane2 = &state.memory[2 << 16];\n        plane3 = &state.memory[3 << 16];\n        line_compare = state.line_compare;\n        if (state.y_doublescan)\n          line_compare >>= 1;\n\n        for (yc = 0, yti = 0; yc < iHeight; yc += Y_TILESIZE, yti++) {\n          for (xc = 0, xti = 0; xc < iWidth; xc += X_TILESIZE, xti++) {\n            if (GET_TILE_UPDATED(xti, yti)) {\n              for (r = 0; r < Y_TILESIZE; r++) {\n                y = yc + r;\n                if (state.y_doublescan)\n                  y >>= 1;\n                for (c = 0; c < X_TILESIZE; c++) {\n                  x = xc + c;\n                  if (state.x_dotclockdiv2)\n                    x >>= 1;\n                  bit_no = 7 - (x % 8);\n                  if (y > line_compare) {\n                    byte_offset =\n                        x / 8 + ((y - line_compare - 1) * state.line_offset);\n                  } else {\n                    byte_offset = start_addr + x / 8 + (y * state.line_offset);\n                  }\n\n                  attribute = (((plane0[byte_offset] >> bit_no) & 0x01) << 0) |\n                              (((plane1[byte_offset] >> bit_no) & 0x01) << 1) |\n                              (((plane2[byte_offset] >> bit_no) & 0x01) << 2) |\n                              (((plane3[byte_offset] >> bit_no) & 0x01) << 3);\n\n                  attribute &= state.attribute_ctrl.color_plane_enable;\n\n                  // undocumented feature ???: colors 0..7 high intensity,\n                  // colors 8..15 blinking using low/high intensity. Blinking is\n                  // not implemented yet.\n                  if (state.attribute_ctrl.mode_ctrl.blink_intensity)\n                    attribute ^= 0x08;\n                  palette_reg_val = state.attribute_ctrl.palette_reg[attribute];\n                  if (state.attribute_ctrl.mode_ctrl.internal_palette_size) {\n\n                    // use 4 lower bits from palette register\n                    // use 4 higher bits from color select register\n                    // 16 banks of 16-color registers\n                    DAC_regno = (palette_reg_val & 0x0f) |\n                                (state.attribute_ctrl.color_select << 4);\n                  } else {\n\n                    // use 6 lower bits from palette register\n                    // use 2 higher bits from color select register\n                    // 4 banks of 64-color registers\n                    DAC_regno =\n                        (palette_reg_val & 0x3f) |\n                        ((state.attribute_ctrl.color_select & 0x0c) << 4);\n                  }\n\n                  // DAC_regno &= video DAC mask register ???\n                  state.tile[r * X_TILESIZE + c] = DAC_regno;\n                }\n              }\n\n              SET_TILE_UPDATED(xti, yti, 0);\n              bx_gui->graphics_tile_update(state.tile, xc, yc);\n            }\n          }\n        }\n      }\n      break; // case 0\n\n    case 1: // output the data in a CGA-compatible 320x200 4 color graphics\n      // mode.  (modes 4 & 5)\n\n      /* CGA 320x200x4 start */\n      for (yc = 0, yti = 0; yc < iHeight; yc += Y_TILESIZE, yti++) {\n        for (xc = 0, xti = 0; xc < iWidth; xc += X_TILESIZE, xti++) {\n          if (GET_TILE_UPDATED(xti, yti)) {\n            for (r = 0; r < Y_TILESIZE; r++) {\n              y = yc + r;\n              if (state.y_doublescan)\n                y >>= 1;\n              for (c = 0; c < X_TILESIZE; c++) {\n                x = xc + c;\n                if (state.x_dotclockdiv2)\n                  x >>= 1;\n\n                /* 0 or 0x2000 */\n                byte_offset = start_addr + ((y & 1) << 13);\n\n                /* to the start of the line */\n                byte_offset += (320 / 4) * (y / 2);\n\n                /* to the byte start */\n                byte_offset += (x / 4);\n\n                attribute = 6 - 2 * (x % 4);\n                palette_reg_val = (state.memory[byte_offset]) >> attribute;\n                palette_reg_val &= 3;\n                DAC_regno = state.attribute_ctrl.palette_reg[palette_reg_val];\n                state.tile[r * X_TILESIZE + c] = DAC_regno;\n              }\n            }\n\n            SET_TILE_UPDATED(xti, yti, 0);\n            bx_gui->graphics_tile_update(state.tile, xc, yc);\n          }\n        }\n      }\n\n      /* CGA 320x200x4 end */\n      break; // case 1\n\n    case 2: // output the data eight bits at a time from the 4 bit plane\n\n    // (format for VGA mode 13 hex)\n    case 3: // FIXME: is this really the same ???\n      if (state.sequencer.chain_four) {\n        unsigned long pixely;\n\n        unsigned long pixelx;\n\n        unsigned long plane;\n\n        if (state.misc_output.select_high_bank != 1) {\n          FAILURE(NotImplemented, \"update: select_high_bank != 1   \\n\");\n        }\n\n        for (yc = 0, yti = 0; yc < iHeight; yc += Y_TILESIZE, yti++) {\n          for (xc = 0, xti = 0; xc < iWidth; xc += X_TILESIZE, xti++) {\n            if (GET_TILE_UPDATED(xti, yti)) {\n              for (r = 0; r < Y_TILESIZE; r++) {\n                pixely = yc + r;\n                if (state.y_doublescan)\n                  pixely >>= 1;\n                for (c = 0; c < X_TILESIZE; c++) {\n                  pixelx = (xc + c) >> 1;\n                  plane = (pixelx % 4);\n                  byte_offset = start_addr + (plane * 65536) +\n                                (pixely * state.line_offset) + (pixelx & ~0x03);\n                  color = state.memory[byte_offset];\n                  state.tile[r * X_TILESIZE + c] = color;\n                }\n              }\n\n              SET_TILE_UPDATED(xti, yti, 0);\n              bx_gui->graphics_tile_update(state.tile, xc, yc);\n            }\n          }\n        }\n      } else { // chain_four == 0, modeX\n        unsigned long pixely;\n\n        // chain_four == 0, modeX\n        unsigned long pixelx;\n\n        // chain_four == 0, modeX\n        unsigned long plane;\n\n        for (yc = 0, yti = 0; yc < iHeight; yc += Y_TILESIZE, yti++) {\n          for (xc = 0, xti = 0; xc < iWidth; xc += X_TILESIZE, xti++) {\n            if (GET_TILE_UPDATED(xti, yti)) {\n              for (r = 0; r < Y_TILESIZE; r++) {\n                pixely = yc + r;\n                if (state.y_doublescan)\n                  pixely >>= 1;\n                for (c = 0; c < X_TILESIZE; c++) {\n                  pixelx = (xc + c) >> 1;\n                  plane = (pixelx % 4);\n                  byte_offset = (plane * 65536) + (pixely * state.line_offset) +\n                                (pixelx >> 2);\n                  color = state.memory[start_addr + byte_offset];\n                  state.tile[r * X_TILESIZE + c] = color;\n                }\n              }\n\n              SET_TILE_UPDATED(xti, yti, 0);\n              bx_gui->graphics_tile_update(state.tile, xc, yc);\n            }\n          }\n        }\n      }\n      break; // case 2\n\n    default:\n      FAILURE_1(NotImplemented, \"update: shift_reg == %u   \\n\",\n                (unsigned)state.graphics_ctrl.shift_reg);\n    }\n\n    state.vga_mem_updated = 0;\n    return;\n  } else { // text mode\n    unsigned long start_address;\n    unsigned long cursor_address;\n    unsigned long cursor_x;\n    unsigned long cursor_y;\n    bx_vga_tminfo_t tm_info;\n    unsigned VDE;\n    unsigned MSL;\n    unsigned cols;\n    unsigned rows;\n    unsigned cWidth;\n\n    tm_info.start_address =\n        2 * ((state.CRTC.reg[12] << 8) + state.CRTC.reg[13]);\n    tm_info.cs_start = state.CRTC.reg[0x0a] & 0x3f;\n    tm_info.cs_end = state.CRTC.reg[0x0b] & 0x1f;\n    tm_info.line_offset = state.CRTC.reg[0x13] << 2;\n    tm_info.line_compare = state.line_compare;\n    tm_info.h_panning = state.attribute_ctrl.horiz_pel_panning & 0x0f;\n    tm_info.v_panning = state.CRTC.reg[0x08] & 0x1f;\n    tm_info.line_graphics = state.attribute_ctrl.mode_ctrl.enable_line_graphics;\n    tm_info.split_hpanning =\n        state.attribute_ctrl.mode_ctrl.pixel_panning_compat;\n    if ((state.sequencer.reg1 & 0x01) == 0) {\n      if (tm_info.h_panning >= 8)\n        tm_info.h_panning = 0;\n      else\n        tm_info.h_panning++;\n    } else {\n      tm_info.h_panning &= 0x07;\n    }\n\n    // Verticle Display End: find out how many lines are displayed\n    VDE = state.vertical_display_end;\n\n    // Maximum Scan Line: height of character cell\n    MSL = state.CRTC.reg[0x09] & 0x1f;\n    if (MSL == 0) {\n#if defined(DEBUG_VGA)\n      BX_ERROR((\"character height = 1, skipping text update\"));\n#endif\n      return;\n    }\n\n    cols = state.CRTC.reg[1] + 1;\n    if ((MSL == 1) && (VDE == 399)) {\n\n      // emulated CGA graphics mode 160x100x16 colors\n      MSL = 3;\n    }\n\n    rows = (VDE + 1) / (MSL + 1);\n    if (rows > BX_MAX_TEXT_LINES) {\n      BX_PANIC((\"text rows>%d: %d\", BX_MAX_TEXT_LINES, rows));\n      return;\n    }\n\n    cWidth = ((state.sequencer.reg1 & 0x01) == 1) ? 8 : 9;\n    iWidth = cWidth * cols;\n    iHeight = VDE + 1;\n    if ((iWidth != old_iWidth) || (iHeight != old_iHeight) ||\n        (MSL != old_MSL) || (state.last_bpp > 8)) {\n      bx_gui->dimension_update(iWidth, iHeight, MSL + 1, cWidth);\n      old_iWidth = iWidth;\n      old_iHeight = iHeight;\n      old_MSL = MSL;\n      state.last_bpp = 8;\n    }\n\n    // pass old text snapshot & new VGA memory contents\n    start_address = 2 * ((state.CRTC.reg[12] << 8) + state.CRTC.reg[13]);\n    cursor_address = 2 * ((state.CRTC.reg[0x0e] << 8) + state.CRTC.reg[0x0f]);\n    if (cursor_address < start_address) {\n      cursor_x = 0xffff;\n      cursor_y = 0xffff;\n    } else {\n      cursor_x = ((cursor_address - start_address) / 2) % (iWidth / cWidth);\n      cursor_y = ((cursor_address - start_address) / 2) / (iWidth / cWidth);\n    }\n\n    bx_gui->text_update(state.text_snapshot, &state.memory[start_address],\n                        cursor_x, cursor_y, tm_info, rows);\n\n    // screen updated, copy new VGA memory contents into text snapshot\n    memcpy(state.text_snapshot, &state.memory[start_address], 2 * cols * rows);\n    state.vga_mem_updated = 0;\n  }\n}\n\nvoid CCirrus::determine_screen_dimensions(unsigned *piHeight,\n                                          unsigned *piWidth) {\n  int ai[0x20];\n  int i;\n  int h;\n  int v;\n  for (i = 0; i < 0x20; i++)\n    ai[i] = state.CRTC.reg[i];\n\n  h = (ai[1] + 1) * 8;\n  v = (ai[18] | ((ai[7] & 0x02) << 7) | ((ai[7] & 0x40) << 3)) + 1;\n\n  if (state.graphics_ctrl.shift_reg == 0) {\n    *piWidth = 640;\n    *piHeight = 480;\n\n    if (state.CRTC.reg[6] == 0xBF) {\n      if (state.CRTC.reg[23] == 0xA3 && state.CRTC.reg[20] == 0x40 &&\n          state.CRTC.reg[9] == 0x41) {\n        *piWidth = 320;\n        *piHeight = 240;\n      } else {\n        if (state.x_dotclockdiv2)\n          h <<= 1;\n        *piWidth = h;\n        *piHeight = v;\n      }\n    } else if ((h >= 640) && (v >= 480)) {\n      *piWidth = h;\n      *piHeight = v;\n    }\n  } else if (state.graphics_ctrl.shift_reg == 2) {\n    if (state.sequencer.chain_four) {\n      *piWidth = h;\n      *piHeight = v;\n    } else {\n      *piWidth = h;\n      *piHeight = v;\n    }\n  } else {\n    if (state.x_dotclockdiv2)\n      h <<= 1;\n    *piWidth = h;\n    *piHeight = v;\n  }\n}\n\nu8 CCirrus::vga_mem_read(u32 addr) {\n  u32 offset;\n  u8 *plane0;\n  u8 *plane1;\n  u8 *plane2;\n  u8 *plane3;\n  u8 retval = 0;\n\n  switch (state.graphics_ctrl.memory_mapping) {\n  case 1: // 0xA0000 .. 0xAFFFF\n    if (addr > 0xAFFFF)\n      return 0xff;\n    offset = addr & 0xFFFF;\n    break;\n\n  case 2: // 0xB0000 .. 0xB7FFF\n    if ((addr < 0xB0000) || (addr > 0xB7FFF))\n      return 0xff;\n    offset = addr & 0x7FFF;\n    break;\n\n  case 3: // 0xB8000 .. 0xBFFFF\n    if (addr < 0xB8000)\n      return 0xff;\n    offset = addr & 0x7FFF;\n    break;\n\n  default: // 0xA0000 .. 0xBFFFF\n    offset = addr & 0x1FFFF;\n  }\n\n  if (state.sequencer.chain_four) {\n\n    // Mode 13h: 320 x 200 256 color mode: chained pixel representation\n    return state.memory[(offset & ~0x03) + (offset % 4) * 65536];\n  }\n\n  plane0 = &state.memory[0 << 16];\n  plane1 = &state.memory[1 << 16];\n  plane2 = &state.memory[2 << 16];\n  plane3 = &state.memory[3 << 16];\n\n  /* addr between 0xA0000 and 0xAFFFF */\n  if (state.graphics_ctrl.read_mode) {\n    u8 color_compare;\n\n    u8 color_dont_care;\n    u8 latch0;\n    u8 latch1;\n    u8 latch2;\n    u8 latch3;\n\n    color_compare = state.graphics_ctrl.color_compare & 0x0f;\n    color_dont_care = state.graphics_ctrl.color_dont_care & 0x0f;\n    latch0 = state.graphics_ctrl.latch[0] = plane0[offset];\n    latch1 = state.graphics_ctrl.latch[1] = plane1[offset];\n    latch2 = state.graphics_ctrl.latch[2] = plane2[offset];\n    latch3 = state.graphics_ctrl.latch[3] = plane3[offset];\n\n    latch0 ^= ccdat[color_compare][0];\n    latch1 ^= ccdat[color_compare][1];\n    latch2 ^= ccdat[color_compare][2];\n    latch3 ^= ccdat[color_compare][3];\n\n    latch0 &= ccdat[color_dont_care][0];\n    latch1 &= ccdat[color_dont_care][1];\n    latch2 &= ccdat[color_dont_care][2];\n    latch3 &= ccdat[color_dont_care][3];\n\n    retval = ~(latch0 | latch1 | latch2 | latch3);\n  } else {\n    state.graphics_ctrl.latch[0] = plane0[offset];\n    state.graphics_ctrl.latch[1] = plane1[offset];\n    state.graphics_ctrl.latch[2] = plane2[offset];\n    state.graphics_ctrl.latch[3] = plane3[offset];\n    retval = state.graphics_ctrl.latch[state.graphics_ctrl.read_map_select];\n  }\n\n  return retval;\n}\n\n/**\n * Write to Legacy VGA Memory\n **/\n\nvoid CCirrus::vga_mem_write(u32 addr, u8 value) {\n  u32 offset;\n  u8 new_val[4];\n  unsigned start_addr;\n  u8 *plane0;\n  u8 *plane1;\n  u8 *plane2;\n  u8 *plane3;\n\n  /* The memory_mapping bits of the graphics controller determine\n   * what window of VGA memory is available.\n   *\n   *  00: 0xA0000 .. 0xBFFFF (128K)\n   *  01: 0xA0000 .. 0xAFFFF (64K) (also used for VGA text mode)\n   *  02: 0xB0000 .. 0xB7FFF (32K)\n   *  03: 0xB8000 .. 0xBFFFF (32K) (also used for CGA text mode)\n   */\n  switch (state.graphics_ctrl.memory_mapping) {\n  // 0xA0000 .. 0xAFFFF\n  case 1:\n    if (addr > 0xAFFFF)\n      return;\n    offset = addr - 0xA0000;\n    break;\n\n  // 0xB0000 .. 0xB7FFF\n  case 2:\n    if ((addr < 0xB0000) || (addr > 0xB7FFF))\n      return;\n    offset = addr - 0xB0000;\n    break;\n\n  // 0xB8000 .. 0xBFFFF\n  case 3:\n    if (addr < 0xB8000)\n      return;\n    offset = addr - 0xB8000;\n    break;\n\n  // 0xA0000 .. 0xBFFFF\n  default:\n    offset = addr - 0xA0000;\n  }\n\n  start_addr = (state.CRTC.reg[0x0c] << 8) | state.CRTC.reg[0x0d];\n\n  if (state.graphics_ctrl.graphics_alpha) {\n    if (state.graphics_ctrl.memory_mapping == 3) {\n      // Text mode, and memory 0xB8000 .. 0xBFFFF selected => CGA text mode\n      unsigned x_tileno;\n      unsigned x_tileno2;\n      unsigned y_tileno;\n\n      /* CGA 320x200x4 / 640x200x2 start */\n      state.memory[offset] = value;\n      offset -= start_addr;\n      if (offset >= 0x2000) {\n        y_tileno = offset - 0x2000;\n        y_tileno /= (320 / 4);\n        y_tileno <<= 1; // 2 * y_tileno;\n        y_tileno++;\n        x_tileno = (offset - 0x2000) % (320 / 4);\n        x_tileno <<= 2; //*= 4;\n      } else {\n        y_tileno = offset / (320 / 4);\n        y_tileno <<= 1; // 2 * y_tileno;\n        x_tileno = offset % (320 / 4);\n        x_tileno <<= 2; //*=4;\n      }\n\n      x_tileno2 = x_tileno;\n      if (state.graphics_ctrl.shift_reg == 0) {\n        x_tileno *= 2;\n        x_tileno2 += 7;\n      } else {\n        x_tileno2 += 3;\n      }\n\n      if (state.x_dotclockdiv2) {\n        x_tileno /= (X_TILESIZE / 2);\n        x_tileno2 /= (X_TILESIZE / 2);\n      } else {\n        x_tileno /= X_TILESIZE;\n        x_tileno2 /= X_TILESIZE;\n      }\n\n      if (state.y_doublescan) {\n        y_tileno /= (Y_TILESIZE / 2);\n      } else {\n        y_tileno /= Y_TILESIZE;\n      }\n\n      state.vga_mem_updated = 1;\n      SET_TILE_UPDATED(x_tileno, y_tileno, 1);\n      if (x_tileno2 != x_tileno) {\n        SET_TILE_UPDATED(x_tileno2, y_tileno, 1);\n      }\n\n      return;\n\n      /* CGA 320x200x4 / 640x200x2 end */\n    }\n\n    if (state.graphics_ctrl.memory_mapping != 1) {\n      FAILURE_1(NotImplemented, \"mem_write: graphics: mapping = %u  \\n\",\n                (unsigned)state.graphics_ctrl.memory_mapping);\n    }\n\n    if (state.sequencer.chain_four) {\n      unsigned x_tileno;\n\n      unsigned y_tileno;\n\n      // 320 x 200 256 color mode: chained pixel representation\n      state.memory[(offset & ~0x03) + (offset % 4) * 65536] = value;\n      if (state.line_offset > 0) {\n        offset -= start_addr;\n        x_tileno = (offset % state.line_offset) / (X_TILESIZE / 2);\n        if (state.y_doublescan) {\n          y_tileno = (offset / state.line_offset) / (Y_TILESIZE / 2);\n        } else {\n          y_tileno = (offset / state.line_offset) / Y_TILESIZE;\n        }\n\n        state.vga_mem_updated = 1;\n        SET_TILE_UPDATED(x_tileno, y_tileno, 1);\n      }\n\n      return;\n    }\n  }\n\n  /* addr between 0xA0000 and 0xAFFFF */\n  plane0 = &state.memory[0 << 16];\n  plane1 = &state.memory[1 << 16];\n  plane2 = &state.memory[2 << 16];\n  plane3 = &state.memory[3 << 16];\n\n  switch (state.graphics_ctrl.write_mode) {\n    unsigned i;\n  // Write mode 0\n  case 0: {\n    /* Write Mode 0 is the standard and most general write mode.\n     * While the other write modes are designed to perform a specific\n     * task, this mode can be used to perform most tasks as all five\n     * operations are performed on the data:\n     *   - The data byte from the host is first rotated as specified\n     *     by the Rotate Count field, then is replicated across all\n     *     four planes.\n     *   - Then the Enable Set/Reset field selects which planes will\n     *     receive their values from the host data and which will\n     *     receive their data from that plane's Set/Reset field\n     *     location.\n     *   - Then the operation specified by the Logical Operation\n     *     field is performed on the resulting data and the data in\n     *     the read latches.\n     *   - The Bit Mask field is then used to select between the\n     *     resulting data and data from the latch register.\n     *   - Finally, the resulting data is written to the display\n     *     memory planes enabled in the Memory Plane Write Enable\n     *     field.\n     *   .\n     */\n    const u8 bitmask = state.graphics_ctrl.bitmask;\n    const u8 set_reset = state.graphics_ctrl.set_reset;\n    const u8 enable_set_reset = state.graphics_ctrl.enable_set_reset;\n\n    /* perform rotate on CPU data in case its needed */\n    if (state.graphics_ctrl.data_rotate) {\n      value = (value >> state.graphics_ctrl.data_rotate) |\n              (value << (8 - state.graphics_ctrl.data_rotate));\n    }\n\n    new_val[0] = state.graphics_ctrl.latch[0] & ~bitmask;\n    new_val[1] = state.graphics_ctrl.latch[1] & ~bitmask;\n    new_val[2] = state.graphics_ctrl.latch[2] & ~bitmask;\n    new_val[3] = state.graphics_ctrl.latch[3] & ~bitmask;\n    switch (state.graphics_ctrl.raster_op) {\n    case 0: // replace\n      new_val[0] |= ((enable_set_reset & 1) ? ((set_reset & 1) ? bitmask : 0)\n                                            : (value & bitmask));\n      new_val[1] |= ((enable_set_reset & 2) ? ((set_reset & 2) ? bitmask : 0)\n                                            : (value & bitmask));\n      new_val[2] |= ((enable_set_reset & 4) ? ((set_reset & 4) ? bitmask : 0)\n                                            : (value & bitmask));\n      new_val[3] |= ((enable_set_reset & 8) ? ((set_reset & 8) ? bitmask : 0)\n                                            : (value & bitmask));\n      break;\n\n    case 1: // AND\n      new_val[0] |=\n          ((enable_set_reset & 1)\n               ? ((set_reset & 1) ? (state.graphics_ctrl.latch[0] & bitmask)\n                                  : 0)\n               : (value & state.graphics_ctrl.latch[0]) & bitmask);\n      new_val[1] |=\n          ((enable_set_reset & 2)\n               ? ((set_reset & 2) ? (state.graphics_ctrl.latch[1] & bitmask)\n                                  : 0)\n               : (value & state.graphics_ctrl.latch[1]) & bitmask);\n      new_val[2] |=\n          ((enable_set_reset & 4)\n               ? ((set_reset & 4) ? (state.graphics_ctrl.latch[2] & bitmask)\n                                  : 0)\n               : (value & state.graphics_ctrl.latch[2]) & bitmask);\n      new_val[3] |=\n          ((enable_set_reset & 8)\n               ? ((set_reset & 8) ? (state.graphics_ctrl.latch[3] & bitmask)\n                                  : 0)\n               : (value & state.graphics_ctrl.latch[3]) & bitmask);\n      break;\n\n    case 2: // OR\n      new_val[0] |=\n          ((enable_set_reset & 1)\n               ? ((set_reset & 1) ? bitmask\n                                  : (state.graphics_ctrl.latch[0] & bitmask))\n               : ((value | state.graphics_ctrl.latch[0]) & bitmask));\n      new_val[1] |=\n          ((enable_set_reset & 2)\n               ? ((set_reset & 2) ? bitmask\n                                  : (state.graphics_ctrl.latch[1] & bitmask))\n               : ((value | state.graphics_ctrl.latch[1]) & bitmask));\n      new_val[2] |=\n          ((enable_set_reset & 4)\n               ? ((set_reset & 4) ? bitmask\n                                  : (state.graphics_ctrl.latch[2] & bitmask))\n               : ((value | state.graphics_ctrl.latch[2]) & bitmask));\n      new_val[3] |=\n          ((enable_set_reset & 8)\n               ? ((set_reset & 8) ? bitmask\n                                  : (state.graphics_ctrl.latch[3] & bitmask))\n               : ((value | state.graphics_ctrl.latch[3]) & bitmask));\n      break;\n\n    case 3: // XOR\n      new_val[0] |=\n          ((enable_set_reset & 1)\n               ? ((set_reset & 1) ? (~state.graphics_ctrl.latch[0] & bitmask)\n                                  : (state.graphics_ctrl.latch[0] & bitmask))\n               : (value ^ state.graphics_ctrl.latch[0]) & bitmask);\n      new_val[1] |=\n          ((enable_set_reset & 2)\n               ? ((set_reset & 2) ? (~state.graphics_ctrl.latch[1] & bitmask)\n                                  : (state.graphics_ctrl.latch[1] & bitmask))\n               : (value ^ state.graphics_ctrl.latch[1]) & bitmask);\n      new_val[2] |=\n          ((enable_set_reset & 4)\n               ? ((set_reset & 4) ? (~state.graphics_ctrl.latch[2] & bitmask)\n                                  : (state.graphics_ctrl.latch[2] & bitmask))\n               : (value ^ state.graphics_ctrl.latch[2]) & bitmask);\n      new_val[3] |=\n          ((enable_set_reset & 8)\n               ? ((set_reset & 8) ? (~state.graphics_ctrl.latch[3] & bitmask)\n                                  : (state.graphics_ctrl.latch[3] & bitmask))\n               : (value ^ state.graphics_ctrl.latch[3]) & bitmask);\n      break;\n\n    default:\n      FAILURE_1(NotImplemented, \"vga_mem_write: write mode 0: op = %u\",\n                (unsigned)state.graphics_ctrl.raster_op);\n    }\n  } break;\n\n  // Write mode 1\n  case 1:\n    /* Write Mode 1 is used to transfer the data in the latches\n     * register directly to the screen, affected only by the\n     * Memory Plane Write Enable field. This can facilitate\n     * rapid transfer of data on byte boundaries from one area\n     * of video memory to another or filling areas of the\n     * display with a pattern of 8 pixels.\n     * When Write Mode 0 is used with the Bit Mask field set to\n     * 00000000b the operation of the hardware is identical to\n     * this mode.\n     */\n    for (i = 0; i < 4; i++) {\n      new_val[i] = state.graphics_ctrl.latch[i];\n    }\n    break;\n\n  // Write mode 2\n  case 2: {\n    /* Write Mode 2 is used to unpack a pixel value packed into\n     * the lower 4 bits of the host data byte into the 4 display\n     * planes:\n     *   - In the byte from the host, the bit representing each\n     *     plane will be replicated across all 8 bits of the\n     *     corresponding planes.\n     *   - Then the operation specified by the Logical Operation\n     *     field is performed on the resulting data and the data\n     *     in the read latches.\n     *   - The Bit Mask field is then used to select between the\n     *     resulting data and data from the latch register.\n     *   - Finally, the resulting data is written to the display\n     *     memory planes enabled in the Memory Plane Write Enable\n     *     field.\n     *   .\n     */\n    const u8 bitmask = state.graphics_ctrl.bitmask;\n\n    new_val[0] = state.graphics_ctrl.latch[0] & ~bitmask;\n    new_val[1] = state.graphics_ctrl.latch[1] & ~bitmask;\n    new_val[2] = state.graphics_ctrl.latch[2] & ~bitmask;\n    new_val[3] = state.graphics_ctrl.latch[3] & ~bitmask;\n    switch (state.graphics_ctrl.raster_op) {\n    case 0: // write\n      new_val[0] |= (value & 1) ? bitmask : 0;\n      new_val[1] |= (value & 2) ? bitmask : 0;\n      new_val[2] |= (value & 4) ? bitmask : 0;\n      new_val[3] |= (value & 8) ? bitmask : 0;\n      break;\n\n    case 1: // AND\n      new_val[0] |= (value & 1) ? (state.graphics_ctrl.latch[0] & bitmask) : 0;\n      new_val[1] |= (value & 2) ? (state.graphics_ctrl.latch[1] & bitmask) : 0;\n      new_val[2] |= (value & 4) ? (state.graphics_ctrl.latch[2] & bitmask) : 0;\n      new_val[3] |= (value & 8) ? (state.graphics_ctrl.latch[3] & bitmask) : 0;\n      break;\n\n    case 2: // OR\n      new_val[0] |=\n          (value & 1) ? bitmask : (state.graphics_ctrl.latch[0] & bitmask);\n      new_val[1] |=\n          (value & 2) ? bitmask : (state.graphics_ctrl.latch[1] & bitmask);\n      new_val[2] |=\n          (value & 4) ? bitmask : (state.graphics_ctrl.latch[2] & bitmask);\n      new_val[3] |=\n          (value & 8) ? bitmask : (state.graphics_ctrl.latch[3] & bitmask);\n      break;\n\n    case 3: // XOR\n      new_val[0] |= (value & 1) ? (~state.graphics_ctrl.latch[0] & bitmask)\n                                : (state.graphics_ctrl.latch[0] & bitmask);\n      new_val[1] |= (value & 2) ? (~state.graphics_ctrl.latch[1] & bitmask)\n                                : (state.graphics_ctrl.latch[1] & bitmask);\n      new_val[2] |= (value & 4) ? (~state.graphics_ctrl.latch[2] & bitmask)\n                                : (state.graphics_ctrl.latch[2] & bitmask);\n      new_val[3] |= (value & 8) ? (~state.graphics_ctrl.latch[3] & bitmask)\n                                : (state.graphics_ctrl.latch[3] & bitmask);\n      break;\n    }\n  } break;\n\n  // Write mode 3\n  case 3: {\n    /* Write Mode 3 is used when the color written is fairly\n     * constant but the Bit Mask field needs to be changed\n     * frequently, such as when drawing single color lines or\n     * text:\n     *   - The value of the Set/Reset field is expanded as if\n     *     the Enable Set/Reset field were set to 1111b,\n     *     regardless of its actual value.\n     *   - The host data is first rotated as specified by the\n     *     Rotate Count field, then is ANDed with the Bit\n     *     Mask field.\n     *   - The resulting value is used where the Bit Mask\n     *     field normally would be used, selecting data from\n     *     either the expansion of the Set/Reset field or the\n     *     latch register.\n     *   - Finally, the resulting data is written to the\n     *     display memory planes enabled in the Memory Plane\n     *     Write Enable field.\n     *   .\n     */\n    const u8 bitmask = state.graphics_ctrl.bitmask & value;\n    const u8 set_reset = state.graphics_ctrl.set_reset;\n\n    /* perform rotate on CPU data */\n    if (state.graphics_ctrl.data_rotate) {\n      value = (value >> state.graphics_ctrl.data_rotate) |\n              (value << (8 - state.graphics_ctrl.data_rotate));\n    }\n\n    new_val[0] = state.graphics_ctrl.latch[0] & ~bitmask;\n    new_val[1] = state.graphics_ctrl.latch[1] & ~bitmask;\n    new_val[2] = state.graphics_ctrl.latch[2] & ~bitmask;\n    new_val[3] = state.graphics_ctrl.latch[3] & ~bitmask;\n\n    value &= bitmask;\n\n    switch (state.graphics_ctrl.raster_op) {\n    case 0: // write\n      new_val[0] |= (set_reset & 1) ? value : 0;\n      new_val[1] |= (set_reset & 2) ? value : 0;\n      new_val[2] |= (set_reset & 4) ? value : 0;\n      new_val[3] |= (set_reset & 8) ? value : 0;\n      break;\n\n    case 1: // AND\n      new_val[0] |=\n          ((set_reset & 1) ? value : 0) & state.graphics_ctrl.latch[0];\n      new_val[1] |=\n          ((set_reset & 2) ? value : 0) & state.graphics_ctrl.latch[1];\n      new_val[2] |=\n          ((set_reset & 4) ? value : 0) & state.graphics_ctrl.latch[2];\n      new_val[3] |=\n          ((set_reset & 8) ? value : 0) & state.graphics_ctrl.latch[3];\n      break;\n\n    case 2: // OR\n      new_val[0] |=\n          ((set_reset & 1) ? value : 0) | state.graphics_ctrl.latch[0];\n      new_val[1] |=\n          ((set_reset & 2) ? value : 0) | state.graphics_ctrl.latch[1];\n      new_val[2] |=\n          ((set_reset & 4) ? value : 0) | state.graphics_ctrl.latch[2];\n      new_val[3] |=\n          ((set_reset & 8) ? value : 0) | state.graphics_ctrl.latch[3];\n      break;\n\n    case 3: // XOR\n      new_val[0] |=\n          ((set_reset & 1) ? value : 0) ^ state.graphics_ctrl.latch[0];\n      new_val[1] |=\n          ((set_reset & 2) ? value : 0) ^ state.graphics_ctrl.latch[1];\n      new_val[2] |=\n          ((set_reset & 4) ? value : 0) ^ state.graphics_ctrl.latch[2];\n      new_val[3] |=\n          ((set_reset & 8) ? value : 0) ^ state.graphics_ctrl.latch[3];\n      break;\n    }\n  } break;\n\n  default:\n    FAILURE_1(NotImplemented, \"vga_mem_write: write mode %u ?\",\n              (unsigned)state.graphics_ctrl.write_mode);\n  }\n\n  // state.sequencer.map_mask determines which bitplanes the write should\n  // actually go to\n  if (state.sequencer.map_mask & 0x0f) {\n    state.vga_mem_updated = 1;\n    if (state.sequencer.map_mask & 0x01)\n      plane0[offset] = new_val[0];\n    if (state.sequencer.map_mask & 0x02)\n      plane1[offset] = new_val[1];\n    if (state.sequencer.map_mask & 0x04) {\n      // Plane 2 contains the character map\n      if ((offset & 0xe000) == state.charmap_address) {\n\n        // printf(\"Updating character map %04x with %02x...\\n  \", (offset &\n        // 0x1fff), new_val[2]);\n        bx_gui->lock();\n        bx_gui->set_text_charbyte((u16)(offset & 0x1fff), new_val[2]);\n        bx_gui->unlock();\n      }\n\n      plane2[offset] = new_val[2];\n    }\n\n    if (state.sequencer.map_mask & 0x08)\n      plane3[offset] = new_val[3];\n\n    unsigned x_tileno;\n\n    unsigned y_tileno;\n\n    if (state.graphics_ctrl.shift_reg == 2) {\n      offset -= start_addr;\n      x_tileno = (offset % state.line_offset) * 4 / (X_TILESIZE / 2);\n      if (state.y_doublescan) {\n        y_tileno = (offset / state.line_offset) / (Y_TILESIZE / 2);\n      } else {\n        y_tileno = (offset / state.line_offset) / Y_TILESIZE;\n      }\n\n      SET_TILE_UPDATED(x_tileno, y_tileno, 1);\n    } else {\n      if (state.line_compare < state.vertical_display_end) {\n        if (state.line_offset > 0) {\n          if (state.x_dotclockdiv2) {\n            x_tileno = (offset % state.line_offset) / (X_TILESIZE / 16);\n          } else {\n            x_tileno = (offset % state.line_offset) / (X_TILESIZE / 8);\n          }\n\n          if (state.y_doublescan) {\n            y_tileno =\n                ((offset / state.line_offset) * 2 + state.line_compare + 1) /\n                Y_TILESIZE;\n          } else {\n            y_tileno = ((offset / state.line_offset) + state.line_compare + 1) /\n                       Y_TILESIZE;\n          }\n\n          SET_TILE_UPDATED(x_tileno, y_tileno, 1);\n        }\n      }\n\n      if (offset >= start_addr) {\n        offset -= start_addr;\n        if (state.line_offset > 0) {\n          if (state.x_dotclockdiv2) {\n            x_tileno = (offset % state.line_offset) / (X_TILESIZE / 16);\n          } else {\n            x_tileno = (offset % state.line_offset) / (X_TILESIZE / 8);\n          }\n\n          if (state.y_doublescan) {\n            y_tileno = (offset / state.line_offset) / (Y_TILESIZE / 2);\n          } else {\n            y_tileno = (offset / state.line_offset) / Y_TILESIZE;\n          }\n\n          SET_TILE_UPDATED(x_tileno, y_tileno, 1);\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/Cirrus.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_Cirrus_H_)\n#define INCLUDED_Cirrus_H_\n\n#include \"VGA.hpp\"\n#include \"gui/vga.hpp\"\n\n/* video card has 4M of ram */\n#define VIDEO_RAM_SIZE 22\n#define CRTC_MAX 0x57\n\n/**\n * \\brief Cirrus Video Card\n *\n * Documentation consulted:\n *  - VGADOC4b\n *   (http://home.worldonline.dk/~finth/)\n *  .\n **/\nclass CCirrus : public CVGA {\npublic:\n  virtual int SaveState(FILE *f);\n  virtual int RestoreState(FILE *f);\n  virtual void check_state();\n  virtual void WriteMem_Legacy(int index, u32 address, int dsize, u32 data);\n  virtual u32 ReadMem_Legacy(int index, u32 address, int dsize);\n\n  virtual void WriteMem_Bar(int func, int bar, u32 address, int dsize,\n                            u32 data);\n  virtual u32 ReadMem_Bar(int func, int bar, u32 address, int dsize);\n\n  CCirrus(CConfigurator *cfg, class CSystem *c, int pcibus, int pcidev);\n  virtual ~CCirrus();\n\n  void update(void);\n  void run(void);\n\n  virtual void init();\n  virtual void start_threads();\n  virtual void stop_threads();\n\n  virtual u8 get_actl_palette_idx(u8 index);\n  virtual void redraw_area(unsigned x0, unsigned y0, unsigned width,\n                           unsigned height);\n\nprivate:\n  u32 mem_read(u32 address, int dsize);\n  void mem_write(u32 address, int dsize, u32 data);\n\n  u32 io_read(u32 address, int dsize);\n  void io_write(u32 address, int dsize, u32 data);\n\n  void io_write_b(u32 address, u8 data);\n\n  void write_b_3c0(u8 data);\n  void write_b_3c2(u8 data);\n  void write_b_3c4(u8 data);\n  void write_b_3c5(u8 data);\n  void write_b_3c6(u8 data);\n  void write_b_3c7(u8 data);\n  void write_b_3c8(u8 data);\n  void write_b_3c9(u8 data);\n  void write_b_3ce(u8 data);\n  void write_b_3cf(u8 data);\n  void write_b_3d4(u8 data);\n  void write_b_3d5(u8 data);\n\n  u8 read_b_3c0();\n  u8 read_b_3c1();\n  u8 read_b_3c2();\n  u8 read_b_3c3();\n  u8 read_b_3c4();\n  u8 read_b_3c5();\n  u8 read_b_3c9();\n  u8 read_b_3ca();\n  u8 read_b_3cc();\n  u8 read_b_3cf();\n  u8 read_b_3d4();\n  u8 read_b_3d5();\n  u8 read_b_3da();\n\n  u32 legacy_read(u32 address, int dsize);\n  void legacy_write(u32 address, int dsize, u32 data);\n\n  u32 rom_read(u32 address, int dsize);\n\n  void determine_screen_dimensions(unsigned *piHeight, unsigned *piWidth);\n\n  char bios_message[200];\n  int bios_message_size;\n\n  void vga_mem_write(u32 addr, u8 value);\n  u8 vga_mem_read(u32 addr);\n\n  std::unique_ptr<std::thread> myThread;\n  std::atomic_bool myThreadDead{false};\n  bool StopThread;\n\n  /// The state structure contains all elements that need to be saved to the\n  /// statefile\n  struct SCirrus_state {\n    //      u8 disabled;\n    //      u8 framebuffer[1<<VIDEO_RAM_SIZE];\n    //      u8 legacybuffer[131072];\n    //      u64 video_base;\n    bool vga_enabled;\n    bool vga_mem_updated;\n    u16 charmap_address;\n    bool x_dotclockdiv2;\n    bool y_doublescan;\n    unsigned line_offset;\n    unsigned line_compare;\n    unsigned vertical_display_end;\n\n    //      u8 vga_memory[256 * 1024];\n    u8 text_snapshot[32 * 1024]; // current text snapshot\n    bool vga_tile_updated[BX_NUM_X_TILES][BX_NUM_Y_TILES];\n    u8 *memory;\n    u32 memsize;\n    u8 last_bpp;\n    u8 tile[X_TILESIZE * Y_TILESIZE *\n            4]; /**< Currently allocates the tile as large as needed. */\n    unsigned x_tilesize;\n    unsigned y_tilesize;\n\n    struct SCirrus_attr {\n      bool flip_flop;   /* 0 = address, 1 = data-write */\n      unsigned address; /* register number */\n      bool video_enabled;\n      u8 palette_reg[16];\n      u8 overscan_color;\n      u8 color_plane_enable;\n      u8 horiz_pel_panning;\n      u8 color_select;\n      struct SCirrus_mode {\n        bool graphics_alpha;\n        bool display_type;\n        bool enable_line_graphics;\n        bool blink_intensity;\n        bool pixel_panning_compat;\n        bool pixel_clock_select;\n        bool internal_palette_size;\n      } mode_ctrl;\n    } attribute_ctrl;\n\n    struct SCirrus_misc {\n      bool color_emulation; // 1=color emulation, base address = 3Dx\n\n      // 0=mono emulation,  base address = 3Bx\n      bool enable_ram;       // enable CPU access to video memory if set\n      u8 clock_select;       // 0=25Mhz 1=28Mhz\n      bool select_high_bank; // when in odd/even modes, select\n\n      // high 64k bank if set\n      bool horiz_sync_pol; // bit6: negative if set\n      bool vert_sync_pol;  // bit7: negative if set\n\n      //   bit7,bit6 represent number of lines on display:\n      //   0 = reserved\n      //   1 = 400 lines\n      //   2 = 350 lines\n      //   3 - 480 lines\n    } misc_output;\n\n    struct SCirrus_seq {\n      u8 index;\n      u8 map_mask;\n      bool map_mask_bit[4];\n      bool reset1;\n      bool reset2;\n      u8 reg1;\n      u8 char_map_select;\n      bool extended_mem;\n      bool odd_even;\n      bool chain_four;\n    } sequencer;\n\n    struct SCirus_pel {\n      u8 write_data_register;\n      u8 write_data_cycle; /* 0, 1, 2 */\n      u8 read_data_register;\n      u8 read_data_cycle; /* 0, 1, 2 */\n      u8 dac_state;\n      struct SCirrus_peldata {\n        u8 red;\n        u8 green;\n        u8 blue;\n      } data[256];\n      u8 mask;\n    } pel;\n\n    struct SCirrus_gfx {\n      u8 index;\n      u8 set_reset;\n      u8 enable_set_reset;\n      u8 color_compare;\n      u8 data_rotate;\n      u8 raster_op;\n      u8 read_map_select;\n      u8 write_mode;\n      bool read_mode;\n      bool odd_even;\n      bool chain_odd_even;\n      u8 shift_reg;\n      bool graphics_alpha;\n      u8 memory_mapping; /* 0 = use A0000-BFFFF\n                          * 1 = use A0000-AFFFF EGA/VGA graphics modes\n                          * 2 = use B0000-B7FFF Monochrome modes\n                          * 3 = use B8000-BFFFF CGA modes\n                          */\n      u8 color_dont_care;\n      u8 bitmask;\n      u8 latch[4];\n    } graphics_ctrl;\n\n    struct SCirrus_crtc {\n      u8 address;\n      u8 reg[0x20];\n      bool write_protect;\n    } CRTC;\n  } state;\n};\n#endif // !defined(INCLUDED_Cirrus_H_)\n"
  },
  {
    "path": "src/Configurator.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"Configurator.hpp\"\n#include \"AliM1543C.hpp\"\n#include \"AliM1543C_ide.hpp\"\n#include \"AliM1543C_usb.hpp\"\n#include \"AlphaCPU.hpp\"\n#include \"Cirrus.hpp\"\n#include \"DMA.hpp\"\n#include \"DPR.hpp\"\n#include \"DiskDevice.hpp\"\n#include \"DiskFile.hpp\"\n#include \"DiskRam.hpp\"\n#include \"Flash.hpp\"\n#include \"FloppyController.hpp\"\n#include \"Keyboard.hpp\"\n#include \"Port80.hpp\"\n#include \"S3Trio64.hpp\"\n#include \"Serial.hpp\"\n#include \"StdAfx.hpp\"\n#include \"System.hpp\"\n#if defined(HAVE_RADEON)\n#include \"Radeon.h\"\n#endif\n#include \"gui/plugin.hpp\"\n#if defined(HAVE_PCAP)\n#include \"DEC21143.hpp\"\n#endif\n#include \"Sym53C810.hpp\"\n#include \"Sym53C895.hpp\"\n\n/**\n * Constructor.\n *\n * The portion of the configuration file that corresponds with the device we are\n *the configurator for is passed as text, with a length of textlen. We parse\n *this text portion, creating values and children configurators as needed. If\n *parent is NULL, we are the master configurator, and we will call initialize\n *for our children (probably GUI and System) so they can instantiate the classes\n *that correspond to the devices that they configure for. The children will in\n *turn initialize their children.\n *\n * \\bug This needs to be more robust! As it is now, this code was more or less\n *\"hacked together\" in a few minutes. Also, more comments should be provided to\n *make it more readable.\n **/\nCConfigurator::CConfigurator(class CConfigurator *parent, char *name,\n                             char *value, char *text, size_t textlen) {\n  if (parent == 0) {\n\n    /* Phase 1:  Basic Syntax Check & Strip [first pass only]\n     * - Make sure quotes and comments are closed.\n     * - Make sure braces are balanced\n     * - remove everything except configuration data.\n     */\n    char *dst = (char *)malloc(textlen + 1);\n    char *p = dst;\n    char *q = text;\n\n    int cbrace = 0;\n    enum {\n      STATE_NONE,\n      STATE_C_COMMENT,\n      STATE_CC_COMMENT,\n      STATE_STRING\n    }\n\n    state = STATE_NONE;\n\n    int state_start = 0;\n    int line = 1;\n    int col = 1;\n    for (unsigned int i = 0; i < textlen; i++, q++, col++) {\n      if (*q == 0x0a) {\n        line++;\n        col = 1;\n      }\n\n      switch (state) {\n      case STATE_NONE:\n        switch (*q) {\n        case '\"':\n          state = STATE_STRING;\n          state_start = line;\n          *p++ = *q;\n          break;\n\n        case '/':\n          if (i == textlen - 1)\n            FAILURE_2(Configuration,\n                      \"Configuration file ends in mid-token at line %d, col %d\",\n                      line, col);\n\n          if (*(q + 1) == '/') {\n            state = STATE_CC_COMMENT;\n            state_start = line;\n          } else if (*(q + 1) == '*') {\n            state = STATE_C_COMMENT;\n            state_start = line;\n          }\n          break;\n\n        case '{':\n          cbrace++;\n          *p++ = *q;\n          break;\n\n        case '}':\n          if (cbrace == 0)\n            FAILURE_2(Configuration,\n                      \"Too many closed braces at line %d, col %d\", line, col);\n          cbrace--;\n          *p++ = *q;\n          break;\n\n        default:\n          if (!isspace(*q)) {\n            if (isalnum(*q) || *q == '_' || *q == '.' || *q == '=' ||\n                *q == ';') {\n              *p++ = *q;\n            } else\n              FAILURE_3(Configuration,\n                        \"Illegal character %c at line %d, col %d\", *q, line,\n                        col);\n          }\n        }\n        break;\n\n      case STATE_CC_COMMENT: // c++ comment\n        if (*q == 0x0d || *q == 0x0a) {\n          state = STATE_NONE;\n          state_start = line;\n        }\n        break;\n\n      case STATE_C_COMMENT: // c comment\n        if (*q == '*') {\n          if (i == textlen - 1)\n            FAILURE_2(\n                Configuration,\n                \"Configuration file ends in mid-comment at line %d, col %d\",\n                line, col);\n          if (*(q + 1) == '/') {\n            state = STATE_NONE;\n            state_start = line;\n          }\n        }\n        break;\n\n      case STATE_STRING: // string\n        if (*q == '\"') {\n          if (i == textlen - 1)\n            FAILURE_2(\n                Configuration,\n                \"Configuration file ends in mid-string at line %d, col %d\",\n                line, col);\n          if (*(q + 1) != '\"') {\n            state_start = line;\n            state = STATE_NONE;\n          } else {\n            *p++ = *q;\n            i++;\n            q++;\n          }\n        } else if (*q == 0x0a || *q == 0x0d)\n          FAILURE_2(Configuration,\n                    \"Multi-line strings are forbidden at line %d, col %d\", line,\n                    col);\n        *p++ = *q;\n        break;\n      }\n    }\n\n    *p++ = 0;\n\n    if (state != 0 && state != 1) {\n      printf(\"%%SYS-E-PARSE: unclosed %s.  Started on line %d.\\n\",\n             state == STATE_C_COMMENT ? \"comment\" : \"string\", state_start);\n    }\n\n    if (cbrace != 0) {\n      printf(\"%%SYS-E-PARSE: unclosed brace in file.\\n\");\n    }\n\n    textlen = strlen(dst);\n    memcpy(text, dst, textlen + 1);\n    free(dst);\n  }\n\n  /* Phase 2: Parse the file [every time]\n   * The data is in a very compressed form at this point.  We also\n   * know some important things about the data:\n   * - There is no whitespace (except in strings)\n   * - the braces are all closed\n   * - comments have been removed.\n   * - strings are valid.\n   */\n  enum {\n    STATE_NONE,\n    STATE_NAME,\n    STATE_IS,\n    STATE_VALUE,\n    STATE_QUOTE,\n    STATE_CHILD\n  }\n\n  state = STATE_NONE;\n\n  char *cur_name;\n  char *cur_value;\n\n  int child_depth = 0;\n\n  size_t name_start = 0;\n  size_t name_len = 0;\n\n  size_t value_start = 0;\n  size_t value_len = 0;\n\n  size_t child_start = 0;\n  size_t child_len = 0;\n\n  pParent = parent;\n  iNumChildren = 0;\n  iNumValues = 0;\n  myName = name;\n  myValue = value;\n\n  for (size_t curtext = 0; curtext < textlen; curtext++) {\n    switch (state) {\n    case STATE_NONE:\n      if (isalnum((unsigned char)text[curtext]) || text[curtext] == '.' ||\n          text[curtext] == '_') {\n        name_start = curtext;\n        state = STATE_NAME;\n      }\n      break;\n\n    case STATE_NAME:\n      if (text[curtext] == '=') {\n        state = STATE_IS;\n        name_len = curtext - name_start;\n      }\n      break;\n\n    case STATE_IS:\n      if (isalnum((unsigned char)text[curtext]) || text[curtext] == '.' ||\n          text[curtext] == '_') {\n        value_start = curtext;\n        value_len = 1;\n        state = STATE_VALUE;\n      }\n\n      if (text[curtext] == '\\\"') {\n        value_start = curtext;\n        state = STATE_QUOTE;\n\n        // curtext--;\n      }\n      break;\n\n    case STATE_VALUE:\n      if (text[curtext] == ';') {\n        value_len = curtext - value_start;\n        cur_name = (char *)malloc(name_len + 1);\n        memcpy(cur_name, &text[name_start], name_len);\n        cur_name[name_len] = '\\0';\n        cur_value = (char *)malloc(value_len + 1);\n        memcpy(cur_value, &text[value_start], value_len);\n        cur_value[value_len] = '\\0';\n\n        //        printf(\"Calling strip_string for  <%s>. \\n\",cur_value);\n        strip_string(cur_value);\n        add_value(cur_name, cur_value);\n\n        state = STATE_NONE;\n      } else if (text[curtext] == '{') {\n        value_len = curtext - value_start;\n        state = STATE_CHILD;\n        child_start = curtext + 1;\n        child_depth = 1;\n      }\n      break;\n\n    case STATE_QUOTE:\n      if ((text[curtext] == '\\\"') && (text[curtext + 1] == '\\\"')) {\n        curtext++;\n      } else if (text[curtext] == '\\\"') {\n        state = STATE_VALUE;\n      }\n      break;\n\n    case STATE_CHILD:\n      if (text[curtext] == '{')\n        child_depth++;\n      else if (text[curtext] == '}') {\n        child_depth--;\n        if (!child_depth) {\n          cur_name = (char *)malloc(name_len + 1);\n          memcpy(cur_name, &text[name_start], name_len);\n          cur_name[name_len] = '\\0';\n          cur_value = (char *)malloc(value_len + 1);\n          memcpy(cur_value, &text[value_start], value_len);\n          cur_value[value_len] = '\\0';\n          child_len = curtext - child_start;\n          state = STATE_NONE;\n\n          strip_string(cur_value);\n\n          pChildren[iNumChildren++] = new CConfigurator(\n              this, cur_name, cur_value, &text[child_start], child_len);\n        }\n      }\n    }\n  }\n\n  int i;\n  if (parent == 0) {\n    myFlags = 0;\n    for (i = 0; i < iNumChildren; i++) {\n      pChildren[i]->initialize();\n    }\n  }\n}\n\n/**\n * Destructor.\n *\n * \\bug This does nothing now; it should:\n *       - if we are a top-level component (System or GUI) delete the component\n *(which will delete the components children).\n *       - delete our children.\n *       - free memory we allocated for values.\n *       .\n **/\nCConfigurator::~CConfigurator(void) {}\n\n/**\n * Reduce a quoted string to it's real value.\n * Some values are enclosed in double quotes(\"), in this case, we take off the\n *quotes, and replace all double double quotes (\"\") with single double quotes\n *(\"). Quoting values is particularly useful if values contain forbidden\n *characters such as spaces, quotes, semicolons, etc. e.g. a text like\n *   \"c:\\program files\\putty\\putty.exe\" telnet://localhost:8000\n * should be quoted as\n *   \"\"\"c:\\program files\\putty\\putty.exe\"\" telnet://localhost:8000\"\n **/\nchar *CConfigurator::strip_string(char *c) {\n  char *pos = c;\n  char *org = c + 1;\n  bool end_it = false;\n\n  if (c[0] == '\\\"') {\n    while (!end_it) {\n      if (*org == '\\\"') {\n        org++;\n        if (*org == '\\\"')\n          *pos++ = *org++;\n        else\n          end_it = true;\n      } else\n        *pos++ = *org++;\n    }\n\n    *pos = '\\0';\n  }\n\n  return c;\n}\n\n/**\n * Add a value to our list of values.\n **/\nvoid CConfigurator::add_value(char *n, char *v) {\n  pValues[iNumValues].name = n;\n  pValues[iNumValues].value = v;\n  iNumValues++;\n}\n\n/**\n * Return a text value, if the name of the value can't be found in\n * our list of values, return def.\n **/\nchar *CConfigurator::get_text_value(const char *n, const char *def) {\n  int i;\n  for (i = 0; i < iNumValues; i++) {\n    if (!strcmp(pValues[i].name, n))\n      return pValues[i].value;\n  }\n\n  return (char *)def;\n}\n\n/**\n * Return a boolean value, if the name of the value can't be found in\n * our list of values, or if the value isn't valid, return def.\n *\n * Valid values are strings that have a first character of:\n *  - t (true)\n *  - y (yes, evaluates to true)\n *  - 1 (evaluates to true)\n *  - f (false)\n *  - n (no, evaluates to false)\n *  - 0 (evaluates to false)\n *  .\n **/\nbool CConfigurator::get_bool_value(const char *n, bool def) {\n  int i;\n  for (i = 0; i < iNumValues; i++) {\n    if (!strcmp(pValues[i].name, n)) {\n      switch (pValues[i].value[0]) {\n      case 't':\n      case 'T':\n      case 'y':\n      case 'Y':\n      case '1':\n        return true;\n\n      case 'f':\n      case 'F':\n      case 'n':\n      case 'N':\n      case '0':\n        return false;\n\n      default:\n        FAILURE_2(Configuration, \"Illegal boolean value (%s) for %s\",\n                  pValues[i].value, n);\n      }\n    }\n  }\n\n  return def;\n}\n\n/**\n * Return a numeric value, if the name of the value can't be found in\n * our list of values, return def.\n **/\nu64 CConfigurator::get_num_value(const char *n, bool decimal, u64 def) {\n  int i;\n  u64 multiplier = decimal ? 1000 : 1024;\n  for (i = 0; i < iNumValues; i++) {\n    if (!strcmp(pValues[i].name, n)) {\n      u64 retval = 0;\n      u64 partval = 0;\n      char *val = pValues[i].value;\n      int j = 0;\n      for (;;) {\n        while (val[j] && strchr(\"0123456789\", val[j])) {\n          partval *= 10;\n          partval += val[j] - '0';\n          j++;\n        }\n\n        switch (val[j]) {\n        case 'T':\n          partval *= multiplier;\n\n        case 'G':\n          partval *= multiplier;\n\n        case 'M':\n          partval *= multiplier;\n\n        case 'K':\n          retval += partval * multiplier;\n          partval = 0;\n          j++;\n          break;\n\n        case '\\0':\n          retval += partval;\n          return retval;\n\n        default:\n          FAILURE_2(Configuration, \"Illegal numeric value (%s) for %s\",\n                    pValues[i].value, n);\n        }\n      }\n    }\n  }\n\n  return def;\n}\n\n// THIS IS WHERE THINGS GET COMPLICATED...\n#define NO_FLAGS 0\n\n#define IS_CS 1\n#define ON_CS 2\n\n#define HAS_PCI 4\n#define IS_PCI 8\n\n#define HAS_ISA 16\n#define IS_ISA 32\n\n#define HAS_DISK 64\n#define IS_DISK 128\n\n#define IS_GUI 256\n#define ON_GUI 512\n\n#define IS_NIC 1024\n\n#define N_P 2048 // no parent\ntypedef struct {\n  const char *name;\n  classid id;\n  int flags;\n} classinfo;\n\nclassinfo classes[] = {{\"tsunami\", c_tsunami, N_P | IS_CS | HAS_PCI},\n                       {\"ev68cb\", c_ev68cb, ON_CS},\n                       {\"ali\", c_ali, IS_PCI | HAS_ISA},\n                       {\"ali_ide\", c_ali_ide, IS_PCI | HAS_DISK},\n                       {\"ali_usb\", c_ali_usb, IS_PCI},\n                       {\"serial\", c_serial, ON_CS},\n                       {\"s3\", c_s3, IS_PCI | ON_GUI},\n                       {\"cirrus\", c_cirrus, IS_PCI | ON_GUI},\n                       {\"radeon\", c_radeon, IS_PCI | ON_GUI},\n                       {\"dec21143\", c_dec21143, IS_PCI | IS_NIC},\n                       {\"sym53c895\", c_sym53c895, IS_PCI | HAS_DISK},\n                       {\"sym53c810\", c_sym53c810, IS_PCI | HAS_DISK},\n                       {\"floppy\", c_floppy, ON_CS | HAS_DISK},\n                       {\"file\", c_file, IS_DISK},\n                       {\"device\", c_device, IS_DISK},\n                       {\"ramdisk\", c_ramdisk, IS_DISK},\n                       {\"sdl\", c_sdl, N_P | IS_GUI},\n                       {\"win32\", c_win32, N_P | IS_GUI},\n                       {\"X11\", c_x11, N_P | IS_GUI},\n                       {0, c_none, 0}};\n\n/**\n * Determine what device this configurator represents, and instantiate it;\n * then call initialize for our children.\n **/\nvoid CConfigurator::initialize() {\n  myClassId = c_none;\n\n  int i = 0;\n  int pcibus = 0;\n  int pcidev = 0;\n  int idedev = 0;\n  int idebus = 0;\n  int fdcbus = 0;\n  int number;\n  char *pt;\n\n  for (i = 0; classes[i].id != c_none; i++) {\n    if (!strcmp(myValue, classes[i].name)) {\n      myClassId = classes[i].id;\n      myFlags = classes[i].flags;\n      break;\n    }\n  }\n\n  if (myClassId == c_none)\n    FAILURE_2(Configuration, \"Class %s for %s not known\", myValue, myName);\n\n  if (myFlags & N_P) {\n    if (pParent->get_flags())\n      FAILURE_2(Configuration, \"Class %s for %s needs a parent\", myValue,\n                myName);\n  }\n\n  if (myFlags & ON_CS) {\n    if (!(pParent->get_flags() & IS_CS))\n      FAILURE_2(Configuration, \"Class %s for %s needs a chipset parent\",\n                myValue, myName);\n  }\n\n  if (myFlags & ON_GUI) {\n    if (!bx_gui)\n      FAILURE_2(Configuration, \"Class %s for %s needs a GUI\", myValue, myName);\n  }\n\n  if (myFlags & IS_GUI) {\n    if (bx_gui)\n      FAILURE_2(Configuration, \"Class %s for %s already found a gui\", myValue,\n                myName);\n  }\n\n#if !defined(HAVE_PCAP)\n  if (myFlags & IS_NIC)\n    FAILURE_2(Configuration,\n              \"Class %s for %s needs compilation with libpcap support\", myValue,\n              myName);\n#endif\n  if (myFlags & IS_PCI) {\n    if (strncmp(myName, \"pci\", 3))\n      FAILURE_2(Configuration,\n                \"Name %s for class %s should be pci<bus>.<device>\", myName,\n                myValue);\n    if (!(pParent->get_flags() & HAS_PCI)) {\n      FAILURE_2(Configuration,\n                \"Class %s for %s should have a pci-bus capable parent device\",\n                myValue, myName);\n    }\n\n    pt = &myName[3];\n    pcibus = atoi(pt);\n    pt = strchr(pt, '.');\n    if (!pt)\n      FAILURE_2(Configuration,\n                \"Name %s for class %s should be pci<bus>.<device>\", myName,\n                myValue);\n    pt++;\n    pcidev = atoi(pt);\n\n    // Validate PCI slot assignments.\n    // On the Tsunami chipset, certain PCI slots are reserved for system-internal\n    // devices (ali, ali_ide, ali_usb). User devices (SCSI controllers, VGA, NIC)\n    // must go on free slots: pci0.1-pci0.4 or pci1.1-pci1.6.\n    // Placing devices on wrong slots causes the SRM firmware to malfunction\n    // (e.g. SCSI disks not detected, device conflicts).\n    if (pcibus == 0) {\n      bool is_system_device = (myClassId == c_ali || myClassId == c_ali_ide ||\n                               myClassId == c_ali_usb);\n      if (!is_system_device) {\n        if (pcidev == 0)\n          FAILURE_2(Configuration,\n                    \"%s (%s): PCI slot pci0.0 is reserved and cannot be used for \"\n                    \"add-in devices. Use pci0.1 through pci0.4\",\n                    myName, myValue);\n        if (pcidev == 7 || pcidev == 15 || pcidev == 19)\n          FAILURE_3(Configuration,\n                    \"%s (%s): PCI slot pci0.%d is reserved for a system-internal \"\n                    \"device. Use pci0.1 through pci0.4 for add-in devices\",\n                    myName, myValue, pcidev);\n      }\n    }\n  }\n\n  if (myClassId == c_floppy) {\n    if (strncmp(myName, \"fdc\", 3))\n      FAILURE_2(Configuration, \"Name %s for class %s should be fdc<bus>\",\n                myName, myValue);\n\n    pt = &myName[3];\n    fdcbus = atoi(pt);\n  }\n\n  if (myFlags & IS_DISK) {\n    if (strncmp(myName, \"disk\", 4))\n      FAILURE_2(Configuration,\n                \"Name %s for class %s should be disk<bus>.<device>\", myName,\n                myValue);\n    if (!(pParent->get_flags() & HAS_DISK)) {\n      FAILURE_2(Configuration,\n                \"Class %s for %s should have a disk-controller parent device\",\n                myValue, myName);\n    }\n\n    pt = &myName[4];\n    idebus = atoi(pt);\n    pt = strchr(pt, '.');\n    if (!pt)\n      FAILURE_2(Configuration,\n                \"Name %s for class %s should be disk<bus>.<device>\", myName,\n                myValue);\n    pt++;\n    idedev = atoi(pt);\n  }\n\n  switch (myClassId) {\n  case c_tsunami:\n    myDevice = new CSystem(this);\n    new CDPR(this, (CSystem *)myDevice);\n    new CFlash(this, (CSystem *)myDevice);\n    break;\n\n  case c_ev68cb:\n    myDevice = new CAlphaCPU(this, (CSystem *)pParent->get_device());\n    break;\n\n  case c_ali:\n    myDevice =\n        new CAliM1543C(this, (CSystem *)pParent->get_device(), pcibus, pcidev);\n    new CPort80(this, (CSystem *)pParent->get_device());\n    new CKeyboard(this, (CSystem *)pParent->get_device());\n    new CDMA(this, (CSystem *)pParent->get_device());\n    break;\n\n  case c_floppy:\n    /* For disk controllers, myDevice points to the\n     * CDiskController part of the class as it's used\n     * to register disks to.\n     */\n    myDevice = (CDiskController *)new CFloppyController(\n        this, (CSystem *)pParent->get_device(), fdcbus);\n    break;\n\n  case c_ali_ide:\n    /* For disk controllers, myDevice points to the\n     * CDiskController part of the class as it's used\n     * to register disks to.\n     */\n    myDevice = (CDiskController *)new CAliM1543C_ide(\n        this, (CSystem *)pParent->get_device(), pcibus, pcidev);\n    break;\n\n  case c_ali_usb:\n    myDevice = new CAliM1543C_usb(this, (CSystem *)pParent->get_device(),\n                                  pcibus, pcidev);\n    break;\n\n  case c_s3:\n    myDevice =\n        new CS3Trio64(this, (CSystem *)pParent->get_device(), pcibus, pcidev);\n    break;\n\n  case c_cirrus:\n    myDevice =\n        new CCirrus(this, (CSystem *)pParent->get_device(), pcibus, pcidev);\n    break;\n\n  case c_radeon:\n#if defined(HAVE_RADEON)\n    myDevice =\n        new CRadeon(this, (CSystem *)pParent->get_device(), pcibus, pcidev);\n#else\n    FAILURE_2(Configuration,\n              \"Class %s for %s needs compilation with Radeon support\", myValue,\n              myName);\n#endif\n    break;\n\n#if defined(HAVE_PCAP)\n\n  case c_dec21143:\n    myDevice =\n        new CDEC21143(this, (CSystem *)pParent->get_device(), pcibus, pcidev);\n    break;\n#endif\n\n  case c_sym53c895:\n    /* For disk controllers, myDevice points to the\n     * CDiskController part of the class as it's used\n     * to register disks to.\n     */\n    myDevice = (CDiskController *)new CSym53C895(\n        this, (CSystem *)pParent->get_device(), pcibus, pcidev);\n    break;\n\n  case c_sym53c810:\n    /* For disk controllers, myDevice points to the\n     * CDiskController part of the class as it's used\n     * to register disks to.\n     */\n    myDevice = (CDiskController *)new CSym53C810(\n        this, (CSystem *)pParent->get_device(), pcibus, pcidev);\n    break;\n\n  case c_file:\n    myDevice =\n        new CDiskFile(this, theSystem, (CDiskController *)pParent->get_device(),\n                      idebus, idedev);\n    break;\n\n  case c_device:\n    myDevice = new CDiskDevice(this, theSystem,\n                               (CDiskController *)pParent->get_device(), idebus,\n                               idedev);\n    break;\n\n  case c_ramdisk:\n    myDevice =\n        new CDiskRam(this, theSystem, (CDiskController *)pParent->get_device(),\n                     idebus, idedev);\n    break;\n\n  case c_serial:\n    number = 0;\n    if (!strncmp(myName, \"serial\", 6)) {\n      pt = &myName[6];\n      number = atoi(pt);\n    }\n\n    myDevice = new CSerial(this, (CSystem *)pParent->get_device(), number);\n    break;\n\n  case c_sdl:\n#if defined(HAVE_SDL)\n    PLUG_load_plugin(this, sdl);\n#else\n    FAILURE_2(Configuration,\n              \"Class %s for %s needs compilation with SDL support\", myValue,\n              myName);\n#endif\n    break;\n\n  case c_win32:\n#if defined(_WIN32)\n    //PLUG_load_plugin(this, win32);\n#else\n    FAILURE_2(Configuration, \"Class %s for %s needs a Win32 platform\", myValue,\n              myName);\n#endif\n    break;\n\n  case c_x11:\n#if defined(HAVE_X11)\n    PLUG_load_plugin(this, x11);\n#else\n    FAILURE_2(Configuration, \"Class %s for %s needs an X11 platform\", myValue,\n              myName);\n#endif\n    break;\n\n  case c_none:\n    break;\n  }\n\n  for (i = 0; i < iNumChildren; i++)\n    pChildren[i]->initialize();\n\n  if (myFlags & IS_CS)\n    ((CSystem *)myDevice)->init();\n}\n"
  },
  {
    "path": "src/Configurator.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(__CONFIGURATOR_H__)\n#define __CONFIGURATOR_H__\n\n#define CFG_MAX_CHILDREN 25\n#define CFG_MAX_VALUES 50\n\n#include \"StdAfx.hpp\"\n\ntypedef enum {\n  c_none,\n\n  // chipsets\n  c_tsunami,\n\n  // system devices\n  c_ev68cb,\n  c_serial,\n  c_floppy,\n\n  // pci devices\n  c_ali,\n  c_ali_ide,\n  c_ali_usb,\n  c_s3,\n  c_cirrus,\n  c_radeon,\n  c_dec21143,\n  c_sym53c895,\n  c_sym53c810,\n\n  // disk devices\n  c_file,\n  c_device,\n  c_ramdisk,\n\n  // gui's\n  c_sdl,\n  c_win32,\n  c_x11\n} classid;\n\nclass CConfigurator {\npublic:\n  CConfigurator(class CConfigurator *parent, char *name, char *value,\n                char *text, size_t textlen);\n  ~CConfigurator(void);\n\n  char *strip_string(char *c);\n  void add_value(char *n, char *v);\n\n  char *get_text_value(const char *n) { return get_text_value(n, (char *)0); };\n  char *get_text_value(const char *n, const char *def);\n\n  bool get_bool_value(const char *n) { return get_bool_value(n, false); };\n  bool get_bool_value(const char *n, bool def);\n\n  u64 get_num_value(const char *n, bool decimal_suffixes) {\n    return get_num_value(n, decimal_suffixes, 0);\n  };\n  u64 get_num_value(const char *n, bool decimal_suffixes, u64 def);\n\n  classid get_class_id() { return myClassId; };\n  void *get_device() { return myDevice; };\n  int get_flags() { return myFlags; };\n\n  char *get_myName() { return myName; };\n  char *get_myValue() { return myValue; };\n  CConfigurator *get_myParent() { return pParent; };\n\n  void initialize();\n\nprivate:\n  class CConfigurator *pParent;\n  class CConfigurator *pChildren[CFG_MAX_CHILDREN];\n  int iNumChildren;\n  char *myName;\n  char *myValue;\n  void *myDevice;\n  classid myClassId;\n  int myFlags;\n  int iNumValues;\n  struct SCfg_Value {\n    char *name;\n    char *value;\n  } pValues[CFG_MAX_VALUES];\n};\n#endif //! defined(__CONFIGURATOR_H__)\n"
  },
  {
    "path": "src/DEC21143.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Copyright (C) 2021 Dietmar M. Zettl\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon GXemul, which is Copyright (C) 2004-2007\n * Anders Gavare.  All rights reserved.\n */\n\n#include \"StdAfx.hpp\"\n\n#if defined(HAVE_PCAP)\n#include \"DEC21143.hpp\"\n#include \"System.hpp\"\n\n#if defined(DEBUG_NIC)\n#define DEBUG_NIC_FILTER\n#define DEBUG_NIC_SROM\n#endif\n\n/*  Internal states during MII data stream decode:  */\n#define MII_STATE_RESET 0\n#define MII_STATE_START_WAIT 1\n#define MII_STATE_READ_OP 2\n#define MII_STATE_READ_PHYADDR_REGADDR 3\n#define MII_STATE_A 4\n#define MII_STATE_D 5\n#define MII_STATE_IDLE 6\n\n/**\n * Thread entry point.\n **/\nvoid CDEC21143::run() {\n  try {\n    for (;;) {\n      if (StopThread)\n        return;\n      receive_process();\n\n      bool asserted;\n\n      if ((state.reg[CSR_OPMODE / 8] & OPMODE_ST))\n        while (dec21143_tx())\n          ;\n\n      /*  Normal and Abnormal interrupt summary:  */\n      state.reg[CSR_STATUS / 8] &= ~(STATUS_NIS | STATUS_AIS);\n      if (state.reg[CSR_STATUS / 8] & state.reg[CSR_INTEN / 8] & 0x00004845)\n        state.reg[CSR_STATUS / 8] |= STATUS_NIS;\n      if (state.reg[CSR_STATUS / 8] & state.reg[CSR_INTEN / 8] & 0x0c0037ba)\n        state.reg[CSR_STATUS / 8] |= STATUS_AIS;\n\n      asserted = (state.reg[CSR_STATUS / 8] & state.reg[CSR_INTEN / 8] &\n                  0x0c01ffff) != 0;\n\n      if (asserted != state.irq_was_asserted) {\n        if (do_pci_interrupt(0, asserted))\n          state.irq_was_asserted = asserted;\n      }\n\n      std::this_thread::sleep_for(std::chrono::milliseconds(20));\n    }\n  }\n\n  catch (CException &e) {\n    printf(\"Exception in NIC thread: %s.\\n\", e.displayText().c_str());\n    myThreadDead.store(true);\n    // Let the thread die...\n  }\n}\n\nu32 dec21143_cfg_data[64] = {\n    /*00*/ 0x00191011, // CFID: vendor + device\n    /*04*/ 0x02800000, // CFCS: command + status\n    /*08*/ 0x02000030, // CFRV: class + revision   //dth:was 41\n    /*0c*/ 0x00000000, // CFLT: latency timer + cache line size\n    /*10*/ 0x00000001, // BAR0: CBIO\n    /*14*/ 0x00000000, // BAR1: CBMA\n    /*18*/ 0x00000000, // BAR2:\n    /*1c*/ 0x00000000, // BAR3:\n    /*20*/ 0x00000000, // BAR4:\n    /*24*/ 0x00000000, // BAR5:\n    /*28*/ 0x00000000, // CCIC: CardBus\n    /*2c*/ 0x500b1011, // CSID: subsystem + vendor\n    /*30*/ 0x00000000, // BAR6: expansion rom base\n    /*34*/ 0x00000000, // CCAP: capabilities pointer\n    /*38*/ 0x00000000,\n    /*3c*/ 0x281401ff, // CFIT: interrupt configuration\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0};\n\nu32 dec21143_cfg_mask[64] = {\n    /*00*/ 0x00000000, // CFID: vendor + device\n    /*04*/ 0x0000ffff, // CFCS: command + status\n    /*08*/ 0x00000000, // CFRV: class + revision\n    /*0c*/ 0x0000ffff, // CFLT: latency timer + cache line size\n    /*10*/ 0xffffff00, // BAR0\n    /*14*/ 0xffffff00, // BAR1: CBMA\n    /*18*/ 0x00000000, // BAR2:\n    /*1c*/ 0x00000000, // BAR3:\n    /*20*/ 0x00000000, // BAR4:\n    /*24*/ 0x00000000, // BAR5:\n    /*28*/ 0x00000000, // CCIC: CardBus\n    /*2c*/ 0x00000000, // CSID: subsystem + vendor\n    /*30*/ 0x00000000, // BAR6: expansion rom base\n    /*34*/ 0x00000000, // CCAP: capabilities pointer\n    /*38*/ 0x00000000,\n    /*3c*/ 0x000000ff, // CFIT: interrupt configuration\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0};\n\nint CDEC21143::nic_num = 0;\n\n/**\n * Constructor.\n **/\nCDEC21143::CDEC21143(CConfigurator *confg, CSystem *c, int pcibus, int pcidev)\n    : CPCIDevice(confg, c, pcibus, pcidev) {}\n\n/**\n * Initialize the network device.\n **/\nvoid CDEC21143::init() {\n  pcap_if_t *alldevs;\n\n  pcap_if_t *d;\n  u_int inum;\n  u_int i = 0;\n  char errbuf[PCAP_ERRBUF_SIZE];\n  char *cfg;\n\n  add_function(0, dec21143_cfg_data, dec21143_cfg_mask);\n\n  cfg = myCfg->get_text_value(\"adapter\");\n  if (!cfg) {\n    printf(\"\\n%s: Choose a network adapter to connect to:\\n\", devid_string);\n    if (pcap_findalldevs(&alldevs, errbuf) == -1) {\n      FAILURE_1(Runtime, \"Error in pcap_findalldevs_ex: %s\", errbuf);\n    }\n\n    /* Print the list */\n    for (d = alldevs; d; d = d->next) {\n      printf(\"%d. %s\\n    \", ++i, d->name);\n      if (d->description)\n        printf(\" (%s)\\n\", d->description);\n      else\n        printf(\" (No description available)\\n\");\n    }\n\n    if (i == 0)\n      FAILURE(Runtime, \"No network interfaces found\");\n\n    if (i == 1)\n      inum = 1;\n    else {\n      inum = 0;\n      while (inum < 1 || inum > i) {\n        printf(\"%%NIC-Q-NICNO: Enter the interface number (1-%d):\", i);\n        (void)!scanf(\"%d\", &inum);\n      }\n    }\n\n    /* Jump to the selected adapter */\n    for (d = alldevs, i = 0; i < inum - 1; d = d->next, i++)\n      ;\n\n    cfg = d->name;\n  }\n\n#if defined(WIN32)\n\n  // Opening with pcap_open on Windows allows specification of\n  // PCAP_OPENFLAG_NOCAPTURE_LOCAL, which stops the pcap device from seeing it's\n  // own transmitted packets.\n  //\n  // This is important because:\n  //    1. Real ethernet cards don't reflect packets except while in loopback\n  //    mode(s).\n  //    2. Reflecting all packets increases inbound packet processing and host\n  //    load.\n  //    3. DECNET Phase IV will think a reflected packet is from another node\n  //            that has the same DECNET Phase IV address (AA-xx-xx-xx-xx-xx),\n  //            and will panic on startup and abort.\n  //    4. Libpcap doesn't reflect packets, and we want winpcap/libpcap\n  //    processing to be identical.\n  // Loopback packets are handled via direct entry in the receive queue.\n  if ((fp = pcap_open(cfg, 65536 /*snaplen: capture entire packets */,\n                      PCAP_OPENFLAG_PROMISCUOUS |\n                          PCAP_OPENFLAG_NOCAPTURE_LOCAL /*promiscuous */,\n                      10 /*read timeout: 10ms. */, 0 /* auth structure */,\n                      errbuf)) == NULL) // connect to pcap...\n#else\n  if ((fp = pcap_open_live(cfg, 65536 /*snaplen: capture entire packets */,\n                           1 /*promiscuous */, 1 /*read timeout: 1ms. */,\n                           errbuf)) == nullptr) // connect to pcap...\n#endif\n    FAILURE_2(Runtime, \"Error opening adapter %s:\\n %s\", cfg, errbuf);\n\n  if (pcap_setnonblock(fp, 1, errbuf) == PCAP_ERROR)\n    FAILURE_2(Runtime, \"Error setting adapter %s non-blocking:\\n %s\", cfg,\n              errbuf);\n\n  // set default mac = Digital ethernet prefix: 08-00-2B + hexified \"ES40\" + nic\n  // number\n  state.mac[0] = 0x08;\n  state.mac[1] = 0x00;\n  state.mac[2] = 0x2B;\n  state.mac[3] = 0xE5;\n  state.mac[4] = 0x40;\n  state.mac[5] = nic_num++;\n\n  // set assigned mac\n  cfg = myCfg->get_text_value(\"mac\");\n  if (cfg) {\n    const char *mac_chars = \"0123456789abcdefABCDEF-.:\";\n    const char *hex_chars = \"0123456789abcdefABCDEF\";\n    const char *hex_scanf = \"%hx\";\n    bool mac_replaced = false;\n    if ((strlen(cfg) == 17) && (strspn(cfg, mac_chars) == 17)) {\n      char newmac[18];\n      strcpy(newmac, cfg);\n      newmac[2] = newmac[5] = newmac[8] = newmac[11] = newmac[14] = 0;\n      if ((strspn(&newmac[0], hex_chars) == 2) &&\n          (strspn(&newmac[3], hex_chars) == 2) &&\n          (strspn(&newmac[6], hex_chars) == 2) &&\n          (strspn(&newmac[9], hex_chars) == 2) &&\n          (strspn(&newmac[12], hex_chars) == 2) &&\n          (strspn(&newmac[15], hex_chars) == 2)) {\n        short unsigned int num;\n        sscanf(&newmac[0], hex_scanf, &num);\n        state.mac[0] = num & 0xff;\n        sscanf(&newmac[3], hex_scanf, &num);\n        state.mac[1] = num & 0xff;\n        sscanf(&newmac[6], hex_scanf, &num);\n        state.mac[2] = num & 0xff;\n        sscanf(&newmac[9], hex_scanf, &num);\n        state.mac[3] = num & 0xff;\n        sscanf(&newmac[12], hex_scanf, &num);\n        state.mac[4] = num & 0xff;\n        sscanf(&newmac[15], hex_scanf, &num);\n        state.mac[5] = num & 0xff;\n        mac_replaced = true;\n      }\n    }\n\n    if (mac_replaced) {\n      printf(\"%s: MAC set to %s\\n\", devid_string, cfg);\n    } else {\n      FAILURE_1(Configuration,\n                \"MAC address (%s) should have xx-xx-xx-xx-xx-xx format\", cfg);\n    }\n  } else {\n    char mac[18];\n    sprintf(mac, \"%02X-%02X-%02X-%02X-%02X-%02X\", state.mac[0], state.mac[1],\n            state.mac[2], state.mac[3], state.mac[4], state.mac[5]);\n    printf(\"%s: MAC defaulted to %s\\n\", devid_string, mac);\n  }\n\n  rx_queue = new CPacketQueue(\"rx_queue\",\n                              (int)myCfg->get_num_value(\"queue\", false, 100));\n  calc_crc = myCfg->get_bool_value(\"crc\", false);\n\n  state.rx.cur_buf = NULL;\n  state.tx.cur_buf = (unsigned char *)malloc(1514);\n  state.irq_was_asserted = false;\n  state.tx.idling = 0;\n\n  ResetPCI();\n\n  printf(\"%s: $Id: DEC21143.cpp,v 1.36 2008/05/31 15:47:09 iamcamiel Exp $\\n\",\n         devid_string);\n}\n\nvoid CDEC21143::start_threads() {\n  if (!myThread) {\n    printf(\" nic\");\n    StopThread = false;\n    myThread = std::make_unique<std::thread>([this](){ this->run(); });\n  }\n}\n\nvoid CDEC21143::stop_threads() {\n  StopThread = true;\n  if (myThread) {\n    printf(\" nic\");\n    myThread->join();\n    myThread = nullptr;\n  }\n}\n\n/**\n * Destructor.\n **/\nCDEC21143::~CDEC21143() {\n  stop_threads();\n\n  pcap_close(fp);\n  delete rx_queue;\n}\n\nu32 CDEC21143::ReadMem_Bar(int func, int bar, u32 address, int dsize) {\n  switch (bar) {\n  case 0: // CBIO\n  case 1: // CBMA\n    return nic_read(address, dsize);\n  }\n\n  printf(\"21143: ReadMem_Bar: unsupported bar %d\\n\", bar);\n  return 0;\n}\n\nvoid CDEC21143::WriteMem_Bar(int func, int bar, u32 address, int dsize,\n                             u32 data) {\n  switch (bar) {\n  case 0: // CBIO\n  case 1: // CBMA\n    nic_write(address, dsize, (u32)endian_bits(data, dsize));\n    return;\n  }\n\n  printf(\"21143: WriteMem_Bar: unsupported bar %d\\n\", bar);\n}\n\n/**\n * Check if threads are still running.\n **/\nvoid CDEC21143::check_state() {\n  if (myThreadDead.load())\n    FAILURE(Thread, \"NIC thread has died\");\n}\n\nvoid CDEC21143::receive_process() {\n  struct pcap_pkthdr *packet_header;\n  const u_char *packet_data = NULL;\n\n  // if receive process active\n  if (state.reg[CSR_OPMODE / 8] & OPMODE_SR) {\n\n    // get packets from host nic if not in internal loopback mode\n    if (!(state.reg[CSR_OPMODE / 8] & OPMODE_OM_INTLOOP)) {\n      while (pcap_next_ex(fp, &packet_header, &packet_data) > 0) {\n        rx_queue->add_tail(packet_data, packet_header->caplen, calc_crc, true);\n        state.reg[CSR_SIASTAT / 8] |= SIASTAT_TRA; // set 10bT activity\n      }\n    }\n\n    // process a receive descriptor until we run out of\n    // descriptors or packets to process\n    while (dec21143_rx())\n      ;\n  }\n}\n\n/**\n * Read from the NIC registers.\n **/\nu32 CDEC21143::nic_read(u32 address, int dsize) {\n  u32 data = 0;\n\n  int regnr = (int)(address >> 3);\n\n  if ((address & 7) == 0 && regnr < 32) {\n    data = state.reg[regnr];\n  } else\n    printf(\"dec21143: WARNING! unaligned access (0x%x) \\n\", (int)address);\n#if defined(DEBUG_NIC)\n  printf(\"21143: nic_read - CSR(%d), value: %08x\\n\", regnr, data);\n#endif\n  return data;\n}\n\n/**\n * Write to the NIC registers.\n **/\nvoid CDEC21143::nic_write(u32 address, int dsize, u32 data) {\n  uint32_t oldreg = 0;\n\n  int regnr = (int)(address >> 3);\n\n#if defined(DEBUG_NIC)\n  printf(\"21143: nic_write - CSR(%d), value: %08x\\n\", regnr, data);\n#endif\n\n  // printf(\"21143: rx_queue->name= %s\\n\", rx_queue->name);\n  if ((address & 7) == 0 && regnr < 32) {\n    oldreg = state.reg[regnr];\n    switch (regnr) {\n    case CSR_STATUS / 8: /*  Zero-on-write  */\n      state.reg[regnr] &= ~((u32)data & 0x0c01ffff);\n      break;\n\n    case CSR_MISSED / 8: /*  Read only  */\n      break;\n\n    default:\n      state.reg[regnr] = (u32)data;\n    }\n  } else\n    printf(\"[ dec21143: WARNING! unaligned access (0x%x) ]\\n\", (int)address);\n\n  switch (address) {\n  case CSR_BUSMODE: /*  csr0  */\n    if (data & BUSMODE_SWR) {\n      ResetNIC();\n      data &= ~BUSMODE_SWR;\n    }\n\n    // calculate descriptor skip length in bytes\n    state.descr_skip = ((data & BUSMODE_DSL) >> 2) * 4;\n    break;\n\n  case CSR_TXPOLL: /*  csr1  */\n    /* CaVa interpretation... */\n    state.reg[CSR_STATUS / 8] &= ~STATUS_TU;\n    state.tx.suspend = false;\n    state.tx.idling = state.tx.idling_threshold;\n\n    //        DoClock();\n    break;\n\n  case CSR_RXPOLL: /*  csr2  */\n    //        DoClock();\n    break;\n\n  case CSR_RXLIST: /*  csr3  */\n    /* debug(\"[ dec21143: setting RXLIST to 0x%x ]\\n\", (int)data); */\n    if (data & 0x3)\n      printf(\"[ dec21143: WARNING! RXLIST not aligned? (0x%x) ]\\n\", data);\n    data &= ~0x3;\n    state.rx.cur_addr = data;\n    break;\n\n  case CSR_TXLIST: /*  csr4  */\n    /* debug(\"[ dec21143: setting TXLIST to 0x%x ]\\n\", (int)data); */\n    if (data & 0x3)\n      printf(\"[ dec21143: WARNING! TXLIST not aligned? (0x%x) ]\\n\", data);\n    data &= ~0x3;\n    state.tx.cur_addr = data;\n    break;\n\n  case CSR_STATUS: /*  csr5  */\n  case CSR_INTEN:  /*  csr7  */\n    /*  Recalculate interrupt assertion.  */\n\n    //              DoClock();\n    break;\n\n  case CSR_OPMODE: /*  csr6:  */\n    if (data & 0x02000000) {\n\n      /*  A must-be-one bit.  */\n      data &= ~0x02000000;\n    }\n\n    if (data & OPMODE_ST) {\n\n      // data &= ~OPMODE_ST;\n    } else {\n\n      /*  Turned off TX? Then idle:  */\n\n      //      state.reg[CSR_STATUS/8] |= STATUS_TPS;\n    }\n\n    if (data & OPMODE_SR) {\n\n      // data &= ~OPMODE_SR;\n    } else {\n\n      /*  Turned off RX? Then go to stopped state:  */\n\n      // state.reg[CSR_STATUS/8] &= ~STATUS_RS;\n    }\n\n    // Did Start/Stop Transmission change state ?\n    if ((data ^ oldreg) & OPMODE_ST) {\n      if (data & OPMODE_ST) { // ST went high\n        set_tx_state(STATUS_TS_SUSPENDED);\n      } else { // ST went low\n        set_tx_state(STATUS_TS_STOPPED);\n      }\n    }\n\n    // Did Start/Stop Receive change state ?\n    if ((data ^ oldreg) & OPMODE_SR) {\n      if (data & OPMODE_SR) { // SR went high\n        set_rx_state(STATUS_RS_WAIT);\n      } else { // SR went low\n        set_tx_state(STATUS_RS_STOPPED);\n      }\n    }\n\n    data &= ~(OPMODE_HBD | OPMODE_SCR | OPMODE_PCS | OPMODE_PS | OPMODE_SF |\n              OPMODE_TTM | OPMODE_FD | OPMODE_TR | OPMODE_OM);\n\n    //              if (data & OPMODE_PNIC_IT) {\n    //                      data &= ~OPMODE_PNIC_IT;\n    //                  state.tx.idling = state.tx.idling_threshold;\n    //              }\n    //              if (data != 0) {\n    //                      printf(\"[ dec21143: UNIMPLEMENTED OPMODE bits:\n    //                      0x%08x ]\\n\", (int)data);\n    //              }\n    //              DoClock();\n    break;\n\n  case CSR_MISSED: /*  csr8  */\n    break;\n\n  case CSR_MIIROM: /*  csr9  */\n    if (data & MIIROM_MDC)\n      mii_access(oldreg, (u32)data);\n    else\n      srom_access(oldreg, (u32)data);\n    break;\n\n  case CSR_SIASTAT: /*  csr12  */\n    if (((data & SIASTAT_ANS) == SIASTAT_ANS_START) &&\n        (state.reg[CSR_SIATXRX / 8] & SIATXRX_ANE)) {\n\n      // autonegotiation restart... completes immediately in our emulated\n      // environment.\n      state.reg[CSR_SIASTAT / 8] &= ~SIASTAT_ANS;\n      state.reg[CSR_SIASTAT / 8] |=\n          (SIASTAT_ANS_FLPGOOD | SIASTAT_LPN | SIASTAT_LPC);\n      state.reg[CSR_STATUS / 8] |= STATUS_LNPANC;\n      state.reg[CSR_SIATXRX / 8] &= ~(SIATXRX_TH | SIATXRX_THX | SIATXRX_T4);\n      state.reg[CSR_SIATXRX / 8] |= SIATXRX_TXF;\n\n      //          DoClock();\n    } else {\n      state.reg[CSR_SIASTAT / 8] = oldreg;\n    }\n    break;\n\n  case CSR_SIATXRX: /*  csr14  */\n    break;\n\n  case CSR_SIACONN: /*  csr13  */\n    if ((data & SIACONN_SRL) && (state.reg[CSR_SIATXRX / 8] & SIATXRX_ANE)) {\n\n      // SIA started with autonegotiation... completes immediately in our\n      // emulated environment.\n      state.reg[CSR_SIASTAT / 8] &= ~SIASTAT_ANS;\n      state.reg[CSR_SIASTAT / 8] |=\n          (SIASTAT_ANS_FLPGOOD | SIASTAT_LPN | SIASTAT_LPC);\n      state.reg[CSR_STATUS / 8] |= STATUS_LNPANC;\n      state.reg[CSR_SIATXRX / 8] &= ~(SIATXRX_TH | SIATXRX_THX | SIATXRX_T4);\n      state.reg[CSR_SIATXRX / 8] |= SIATXRX_TXF;\n\n      //          DoClock();\n    }\n    break;\n\n  case CSR_SIAGEN: /*  csr15  */\n    break;\n\n  default:\n    printf(\"[ dec21143: write to unimplemented 0x%02x: 0x%02x ]\\n\",\n           (int)address, (int)data);\n  }\n}\n\nvoid CDEC21143::set_tx_state(int tx_state) {\n  state.reg[CSR_STATUS / 8] &= ~STATUS_TS;\n  state.reg[CSR_STATUS / 8] |= (tx_state & STATUS_TS);\n}\n\nvoid CDEC21143::set_rx_state(int rx_state) {\n  state.reg[CSR_STATUS / 8] &= ~STATUS_RS;\n  state.reg[CSR_STATUS / 8] |= (rx_state & STATUS_RS);\n}\n\n/**\n *  This function handles accesses to the MII. Data streams seem to be of the\n *  following format:\n *\n *      vv---- starting delimiter\n *  ... 01 xx yyyyy zzzzz a[a] dddddddddddddddd\n *         ^---- I am starting with mii_bit = 0 here\n *\n *  where x = opcode (10 = read, 01 = write)\n *        y = PHY address\n *        z = register address\n *        a = on Reads: ACK bit (returned, should be 0)\n *            on Writes: _TWO_ dummy bits (10)\n *        d = 16 bits of data (MSB first)\n **/\nvoid CDEC21143::mii_access(uint32_t oldreg, uint32_t idata) {\n  int obit;\n\n  int ibit = 0;\n  uint16_t tmp;\n\n  /*  Only care about data during clock cycles:  */\n  if (!(idata & MIIROM_MDC))\n    return;\n\n  if (idata & MIIROM_MDC && oldreg & MIIROM_MDC)\n    return;\n\n  /*  printf(\"[ mii_access(): 0x%08x ]\\n\", (int)idata);  */\n  if (idata & MIIROM_BR) {\n    printf(\"[ mii_access(): MIIROM_BR: TODO ]\\n\");\n    return;\n  }\n\n  obit = idata & MIIROM_MDO ? 1 : 0;\n\n  if (state.mii.state >= MII_STATE_START_WAIT &&\n      state.mii.state <= MII_STATE_READ_PHYADDR_REGADDR &&\n      idata & MIIROM_MIIDIR)\n    printf(\"[ mii_access(): bad dir? ]\\n\");\n\n  switch (state.mii.state) {\n  case MII_STATE_RESET:\n\n    /*  Wait for a starting delimiter (0 followed by 1).  */\n    if (obit)\n      return;\n    if (idata & MIIROM_MIIDIR)\n      return;\n\n    /*  printf(\"[ mii_access(): got a 0 delimiter ]\\n\");  */\n    state.mii.state = MII_STATE_START_WAIT;\n    state.mii.opcode = 0;\n    state.mii.phyaddr = 0;\n    state.mii.regaddr = 0;\n    break;\n\n  case MII_STATE_START_WAIT:\n\n    /*  Wait for a starting delimiter (0 followed by 1).  */\n    if (!obit)\n      return;\n    if (idata & MIIROM_MIIDIR) {\n      state.mii.state = MII_STATE_RESET;\n      return;\n    }\n\n    /*  printf(\"[ mii_access(): got a 1 delimiter ]\\n\");  */\n    state.mii.state = MII_STATE_READ_OP;\n    state.mii.bit = 0;\n    break;\n\n  case MII_STATE_READ_OP:\n    if (state.mii.bit == 0) {\n      state.mii.opcode = obit << 1;\n\n      /*  printf(\"[ mii_access(): got first opcode bit (%i) ]\\n\", obit);  */\n    } else {\n      state.mii.opcode |= obit;\n\n      /*  printf(\"[ mii_access(): got opcode = %i ]\\n\", state.mii.opcode);  */\n      state.mii.state = MII_STATE_READ_PHYADDR_REGADDR;\n    }\n\n    state.mii.bit++;\n    break;\n\n  case MII_STATE_READ_PHYADDR_REGADDR:\n\n    /*  printf(\"[ mii_access(): got phy/reg addr bit nr %i (%i)\"\n       \" ]\\n\", state.mii.bit - 2, obit);  */\n    if (state.mii.bit <= 6)\n      state.mii.phyaddr |= obit << (6 - state.mii.bit);\n    else\n      state.mii.regaddr |= obit << (11 - state.mii.bit);\n    state.mii.bit++;\n    if (state.mii.bit >= 12) {\n\n      /*  printf(\"[ mii_access(): phyaddr=0x%x regaddr=0x\"\n         \"%x ]\\n\", state.mii.phyaddr, state.mii.regaddr);  */\n      state.mii.state = MII_STATE_A;\n    }\n    break;\n\n  case MII_STATE_A:\n    switch (state.mii.opcode) {\n    case MII_COMMAND_WRITE:\n      if (state.mii.bit >= 13)\n        state.mii.state = MII_STATE_D;\n      break;\n\n    case MII_COMMAND_READ:\n      ibit = 0;\n      state.mii.state = MII_STATE_D;\n      break;\n\n    default:\n      printf(\"[ mii_access(): UNIMPLEMENTED MII opcode %i (probably just a bug \"\n             \"in GXemul's MII data stream handling) ]\\n\",\n             state.mii.opcode);\n      state.mii.state = MII_STATE_RESET;\n    }\n\n    state.mii.bit++;\n    break;\n\n  case MII_STATE_D:\n    switch (state.mii.opcode) {\n    case MII_COMMAND_WRITE:\n      if (idata & MIIROM_MIIDIR)\n        printf(\"[ mii_access(): write: bad dir? ]\\n\");\n      obit = obit ? (0x8000 >> (state.mii.bit - 14)) : 0;\n      tmp = state.mii.phy_reg[(state.mii.phyaddr << 5) + state.mii.regaddr] |\n            obit;\n      if (state.mii.bit >= 29) {\n        state.mii.state = MII_STATE_IDLE;\n\n        //                              debug(\"[ mii_access(): WRITE to\n        //                              phyaddr=0x%x regaddr=0x%x: 0x%04x ]\\n\",\n        //                              state.mii.phyaddr, state.mii.regaddr,\n        //                              tmp);\n      }\n      break;\n\n    case MII_COMMAND_READ:\n      if (!(idata & MIIROM_MIIDIR))\n        break;\n      tmp = state.mii.phy_reg[(state.mii.phyaddr << 5) + state.mii.regaddr];\n\n      //                      if (state.mii.bit == 13)\n      //                              debug(\"[ mii_access(): READ phyaddr=0x%x\n      //                              regaddr=0x%x: 0x%04x ]\\n\",\n      //                              state.mii.phyaddr, state.mii.regaddr,\n      //                              tmp);\n      ibit = tmp & (0x8000 >> (state.mii.bit - 13));\n      if (state.mii.bit >= 28)\n        state.mii.state = MII_STATE_IDLE;\n      break;\n    }\n\n    state.mii.bit++;\n    break;\n\n  case MII_STATE_IDLE:\n    state.mii.bit++;\n    if (state.mii.bit >= 31)\n      state.mii.state = MII_STATE_RESET;\n    break;\n  }\n\n  state.reg[CSR_MIIROM / 8] &= ~MIIROM_MDI;\n  if (ibit)\n    state.reg[CSR_MIIROM / 8] |= MIIROM_MDI;\n}\n\n/**\n *  This function handles reads from the Ethernet Address ROM. This is not a\n *  100% correct implementation, as it was reverse-engineered from OpenBSD\n *  sources; it seems to work with OpenBSD, NetBSD, and Linux, though.\n *\n *  Each transfer (if I understood this correctly) is of the following format:\n *\n *\t1xx yyyyyy zzzzzzzzzzzzzzzz\n *\n *  where 1xx    = operation (6 means a Read),\n *        yyyyyy = ROM address\n *        zz...z = data\n *\n *  y and z are _both_ read and written to at the same time; this enables the\n *  operating system to sense the number of bits in y (when reading, all y bits\n *  are 1 except the last one).\n **/\nvoid CDEC21143::srom_access(uint32_t oldreg, uint32_t idata) {\n  int obit;\n\n  int ibit;\n\n  /*  debug(\"CSR9 WRITE! 0x%08x\\n\", (int)idata);  */\n\n  /*  New selection? Then reset internal state.  */\n  if (idata & MIIROM_SR && !(oldreg & MIIROM_SR)) {\n    state.srom.curbit = 0;\n    state.srom.opcode = 0;\n    state.srom.opcode_has_started = 0;\n    state.srom.addr = 0;\n  }\n\n  /*  Only care about data during clock cycles:  */\n  if (!(idata & MIIROM_SROMSK))\n    return;\n\n  obit = 0;\n  ibit = idata & MIIROM_SROMDI ? 1 : 0;\n\n  /*  debug(\"CLOCK CYCLE! (bit %i): \", state.srom.curbit);  */\n\n  /*\n   *  Linux sends more zeroes before starting the actual opcode, than\n   *  OpenBSD and NetBSD. Hopefully this is correct. (I'm just guessing\n   *  that all opcodes should start with a 1, perhaps that's not really\n   *  the case.)\n   */\n  if (!ibit && !state.srom.opcode_has_started)\n    return;\n\n  if (state.srom.curbit < 3) {\n    state.srom.opcode_has_started = 1;\n    state.srom.opcode <<= 1;\n    state.srom.opcode |= ibit;\n\n    /*  debug(\"opcode input '%i'\\n\", ibit);  */\n  } else {\n    switch (state.srom.opcode) {\n    case TULIP_SROM_OPC_READ:\n      if (state.srom.curbit < 6 + 3) {\n        obit = state.srom.curbit < 6 + 2;\n        state.srom.addr <<= 1;\n        state.srom.addr |= ibit;\n      } else {\n        uint16_t romword = state.srom.data[state.srom.addr * 2] +\n                           (state.srom.data[state.srom.addr * 2 + 1] << 8);\n\n        //                              if (state.srom.curbit == 6 + 3)\n        //                                      debug(\"[ dec21143: ROM read from\n        //                                      offset 0x%03x: 0x%04x ]\\n\",\n        //                                      state.srom.addr, romword);\n        obit = romword & (0x8000 >> (state.srom.curbit - 6 - 3)) ? 1 : 0;\n#if defined(DEBUG_NIC_SROM)\n        printf(\"%%NIC-I-SROMREAD: Read %04x from %04x\\n\", romword,\n               state.srom.addr);\n#endif\n      }\n      break;\n\n    default:\n      printf(\"[ dec21243: unimplemented SROM/EEPROM opcode %i ]\\n\",\n             state.srom.opcode);\n    }\n\n    state.reg[CSR_MIIROM / 8] &= ~MIIROM_SROMDO;\n    if (obit)\n      state.reg[CSR_MIIROM / 8] |= MIIROM_SROMDO;\n\n    /*  debug(\"input '%i', output '%i'\\n\", ibit, obit);  */\n  }\n\n  state.srom.curbit++;\n\n  /*\n   *  Done opcode + addr + data? Then restart. (At least NetBSD does\n   *  sequential reads without turning selection off and then on.)\n   */\n  if (state.srom.curbit >= 3 + 6 + 16) {\n    state.srom.curbit = 0;\n    state.srom.opcode = 0;\n    state.srom.opcode_has_started = 0;\n    state.srom.addr = 0;\n  }\n}\n\n/*\nbool CDEC21143:acquire_rx_descriptor(u32 status_true, u32 status_false) {\n        // get current receive descriptor\n    do_pci_read(state.rx.cur_addr, descr, 4, 4);\n\n        if (rdes0 & TDSTAT_OWN) {\t// 21143 owns descriptor\n                state.reg[CSR_STATUS/8] &= ~STATUS_RU;\t// clear buffers\nunavailable if (state.reg[CSR_OPMODE/8] & OPMODE_SR) {\t// if receive start\n                        state.reg[CSR_STATUS/8] = (state.reg[CSR_STATUS/8] &\n~STATUS_RS) | STATUS_RS_WAIT; } else {\n                }\n                return true;\t\t// indicate nothing was processed\n        } else {\n                state.reg[CSR_STATUS/8] = (state.reg[CSR_STATUS/8] & ~(STATUS_RS\n| STATUS_RU)) | STATUS_R return true;\n        }\n}\n*/\n\n/**\n *  Receive a packet. (If there is no current packet, then check for newly\n *  arrived ones. If the current packet couldn't be fully transfered the\n *  last time, then continue on that packet.)\n **/\nint CDEC21143::dec21143_rx() {\n  static u32 descr[4];\n  static u32 &rdes0 = descr[0];\n  static u32 &rdes1 = descr[1];\n  static u32 &rdes2 = descr[2];\n  static u32 &rdes3 = descr[3];\n\n  u32 bufaddr;\n  int bufsize;\n  int buf1_size;\n  int buf2_size;\n  int to_xfer;\n\n  /*  Is current packet finished? Then check for new ones.  */\n  if (state.rx.current.used >= state.rx.current.len) {\n\n    /*  Nothing available? Then abort.  */\n    if (rx_queue->count() == 0)\n      return 0; // indicate nothing was processed\n\n    //      printf(\"pcap recv: %d bytes (%d captured) for\n    //      %02x:%02x:%02x:%02x:%02x:%02x  \\n\",packet_header->len,\n    //      packet_header->caplen,packet_data[0],packet_data[1],packet_data[2],packet_data[3],packet_data[4],packet_data[5]);\n    // get next packet from receive queue\n    rx_queue->get_head(state.rx.current);\n\n    /*  Append a 4 byte CRC:  */\n\n    // state.rx.cur_buf_len += 4;\n    // CHECK_REALLOCATION(state.rx.cur_buf, realloc(state.rx.cur_buf,\n    // state.rx.cur_buf_len), unsigned char);\n\n    /*  Get the next packet into our buffer:  */\n\n    // memcpy(state.rx.cur_buf, packet_data, state.rx.cur_buf_len);\n\n    /*  Well... the CRC is just zeros, for now.  */\n\n    // memset(state.rx.cur_buf + state.rx.cur_buf_len - 4, 0, 4);\n    // state.rx.cur_offset = 0;\n  }\n\n  // read current descriptor\n  do_pci_read(state.rx.cur_addr, descr, 4, 4);\n\n  // rdes0 = descr[0] + (descr[1]<<8) + (descr[2]<<16) + (descr[3]<<24);\n  // rdes1 = descr[4] + (descr[5]<<8) + (descr[6]<<16) + (descr[7]<<24);\n  // rdes2 = descr[8] + (descr[9]<<8) + (descr[10]<<16) + (descr[11]<<24);\n  // rdes3 = descr[12] + (descr[13]<<8) + (descr[14]<<16) + (descr[15]<<24);\n\n  /*  Only use descriptors owned by the 21143:  */\n  if (!(rdes0 & TDSTAT_OWN)) {\n\n    // set recive buffers unavailable and receive state to suspended\n    state.reg[CSR_STATUS / 8] = (state.reg[CSR_STATUS / 8] & ~STATUS_RS) |\n                                STATUS_RU | STATUS_RS_SUSPENDED;\n    return 0; // indicate nothing was processed\n  }\n\n  buf1_size = rdes1 & TDCTL_SIZE1;\n  buf2_size = (rdes1 & TDCTL_SIZE2) >> TDCTL_SIZE2_SHIFT;\n  bufaddr = buf1_size ? rdes2 : rdes3;\n  bufsize = buf1_size ? buf1_size : buf2_size;\n\n  // state.reg[CSR_STATUS/8] &= ~STATUS_RS; // dth: wrong, this is receive state\n  // stopped\n  //  printf(\"{ dec21143_rx: base = 0x%08x }\\n\", (int)addr);\n  //      debug(\"{ RX (%llx): 0x%08x 0x%08x 0x%x 0x%x: buf %i bytes at 0x%x\n  //      }\\n\",\n  //          (long long)addr, rdes0, rdes1, rdes2, rdes3, bufsize,\n  //          (int)bufaddr);\n  // Turn off all status bits, and give up ownership\n  rdes0 = 0x00000000;\n\n  //  Is this the first buffer of the frame?\n  if (state.rx.current.used == 0)\n    rdes0 |= TDSTAT_Rx_FS;\n\n  // use buffer 1, if length is non-zero\n  if (buf1_size > 0) {\n    to_xfer = state.rx.current.len - state.rx.current.used;\n    if (to_xfer > buf1_size)\n      to_xfer = buf1_size;\n\n    // DMA bytes from the packet into buffer 1\n    do_pci_write(rdes2, &state.rx.current.frame[state.rx.current.used], 1,\n                 to_xfer);\n\n    // update used\n    state.rx.current.used += to_xfer;\n  }\n\n  // use buffer 2, if length is non-zero and not a chain buffer\n  if ((buf2_size > 0) && (!(rdes1 & TDCTL_CH))) {\n    to_xfer = state.rx.current.len - state.rx.current.used;\n    if (to_xfer > buf2_size)\n      to_xfer = buf2_size;\n\n    // DMA bytes from the packet into buffer 2\n    do_pci_write(rdes3, state.rx.current.frame + state.rx.current.used, 1,\n                 to_xfer);\n\n    // update used\n    state.rx.current.used += to_xfer;\n  }\n\n  //  Frame completed?\n  if (state.rx.current.used >= state.rx.current.len) {\n\n    //        debug(\"frame complete.\\n\");\n    rdes0 |= TDSTAT_Rx_LS;\n\n    /*  Set the frame length:  */\n    rdes0 |= (state.rx.current.len << 16) & TDSTAT_Rx_FL;\n\n    /*  Frame too long? (1518 is max ethernet frame length)  */\n    if (state.rx.current.len > 1518)\n      rdes0 |= TDSTAT_Rx_TL;\n\n    // set receive interrupt and receive state to waiting-for-packet\n    state.reg[CSR_STATUS / 8] =\n        (state.reg[CSR_STATUS / 8] & ~STATUS_RS) | STATUS_RI | STATUS_RS_WAIT;\n  }\n\n  // Writeback rdes0, others are read-only\n  state.reg[CSR_STATUS / 8] =\n      (state.reg[CSR_STATUS / 8] & ~STATUS_RS) | STATUS_RS_CLOSE;\n  do_pci_write(state.rx.cur_addr, descr, 4, 1);\n\n  // move to next descriptor\n  if (rdes1 & TDCTL_ER) // end-of-ring, return to base\n    state.rx.cur_addr = state.reg[CSR_RXLIST / 8];\n  else {\n    if (rdes1 & TDCTL_CH) // explicit chain, use chain address\n      state.rx.cur_addr = rdes3;\n    else\n      // implicit chain\n      state.rx.cur_addr += sizeof(descr) + state.descr_skip;\n  }\n\n  return 1; // indicate processing has occurred\n}\n\n/**\n *  Transmit a packet, if the guest OS has marked a descriptor as containing\n *  data to transmit.\n **/\nint CDEC21143::dec21143_tx() {\n  u32 addr = state.tx.cur_addr;\n\n  u32 bufaddr;\n  unsigned char descr[16];\n  u32 tdes0;\n  u32 tdes1;\n  u32 tdes2;\n  u32 tdes3;\n  int bufsize;\n  int buf1_size;\n  int buf2_size;\n\n  if (state.tx.suspend)\n    return 0;\n\n  do_pci_read(addr, descr, 1, 16);\n\n  tdes0 = descr[0] + (descr[1] << 8) + (descr[2] << 16) + (descr[3] << 24);\n  tdes1 = descr[4] + (descr[5] << 8) + (descr[6] << 16) + (descr[7] << 24);\n  tdes2 = descr[8] + (descr[9] << 8) + (descr[10] << 16) + (descr[11] << 24);\n  tdes3 = descr[12] + (descr[13] << 8) + (descr[14] << 16) + (descr[15] << 24);\n\n  /*  printf(\"{ dec21143_tx: base=0x%08x, tdes0=0x%08x }\\n\", (int)addr,\n   * (int)tdes0);  */\n\n  /*  Only process packets owned by the 21143:  */\n  if (!(tdes0 & TDSTAT_OWN)) {\n    if (state.tx.idling > state.tx.idling_threshold) {\n      state.reg[CSR_STATUS / 8] |= STATUS_TU;\n      state.tx.suspend = true;\n      state.tx.idling = 0;\n    } else\n      state.tx.idling++;\n    return 0;\n  }\n\n  buf1_size = tdes1 & TDCTL_SIZE1;\n  buf2_size = (tdes1 & TDCTL_SIZE2) >> TDCTL_SIZE2_SHIFT;\n  bufaddr = buf1_size ? tdes2 : tdes3;\n  bufsize = buf1_size ? buf1_size : buf2_size;\n\n  // state.reg[CSR_STATUS/8] &= ~STATUS_TS;\n  if (tdes1 & TDCTL_ER) // end-of-ring, return to base\n    state.tx.cur_addr = state.reg[CSR_TXLIST / 8];\n  else {\n    if (tdes1 & TDCTL_CH) // explicit chain, use chain address\n      state.tx.cur_addr = tdes3;\n    else\n      // implicit chain\n      state.tx.cur_addr += (4 * sizeof(uint32_t)) + state.descr_skip;\n  }\n\n  /*\n     printf(\"{ TX (%llx): 0x%08x 0x%08x 0x%x 0x%x: buf %i bytes at 0x%x }\\n\",\n     (long long)addr, tdes0, tdes1, tdes2, tdes3, bufsize, (int)bufaddr);\n   */\n\n  /*  Assume no error:  */\n  tdes0 &= ~(TDSTAT_Tx_UF | TDSTAT_Tx_EC | TDSTAT_Tx_LC | TDSTAT_Tx_NC |\n             TDSTAT_Tx_LO | TDSTAT_Tx_TO | TDSTAT_ES);\n\n  if (tdes1 & TDCTL_Tx_SET) {\n\n    /*\n     *  Setup Packet.\n     *\n     *  TODO. For now, just ignore it, and pretend it worked.\n     */\n\n    //              printf(\"{ TX: setup packet }\\n\");\n    if (bufsize != 192)\n      printf(\"[ dec21143: setup packet len = %i, should be 192! ]\\n\",\n             (int)bufsize);\n    do_pci_read(bufaddr, state.setup_filter, 1, 192);\n    SetupFilter();\n\n    if (tdes1 & TDCTL_Tx_IC)\n      state.reg[CSR_STATUS / 8] |= STATUS_TI;\n\n    /*  New descriptor values, according to the docs:  */\n    tdes0 = 0x7fffffff;\n    tdes1 = 0xffffffff;\n    tdes2 = 0xffffffff;\n    tdes3 = 0xffffffff;\n  } else {\n\n    /*\n     *  Data Packet.\n     */\n\n    //              printf(\"{ TX: data packet: \");\n    if (tdes1 & TDCTL_Tx_FS) {\n\n      /*  First segment. Let's allocate a new buffer:  */\n\n      /*  printf(\"new frame }\\n\");  */\n\n      // CHECK_ALLOCATION(state.tx.cur_buf = (unsigned char *)malloc(bufsize));\n      state.tx.cur_buf_len = 0;\n    } else {\n\n      /*  Not first segment. Increase the length of the current buffer:  */\n\n      /*  printf(\"continuing last frame }\\n\");  */\n      if (state.tx.cur_buf == NULL)\n        printf(\"[ dec21143: WARNING! tx: middle segment, but no first \"\n               \"segment?! ]\\n\");\n\n      // CHECK_REALLOCATION(state.tx.cur_buf, realloc(state.tx.cur_buf,\n      // state.tx.cur_buf_len + bufsize), unsigned char);\n    }\n\n    /*  \"DMA\" data from emulated physical memory into the buf:  */\n    do_pci_read(bufaddr, state.tx.cur_buf + state.tx.cur_buf_len, 1, bufsize);\n\n    state.tx.cur_buf_len += bufsize;\n\n/* only partial frames were written to the pcap filter, because the second\n * buffer was not considered when collecting the ethernet frames in dec21143_tx.\n * It can happen that both buffers to which tdes2 and tdes3 point contain data.\n * When this happens the data of both buffers have to be combined to get a valid\n * ethernet frame and hence IP packet. The patch simply checks if buf2_size is\n * greater 0 and if that's true append the data from the buffer pointed to by\n * tdes3 to the current frame.\n */\n    if ((buf2_size > 0) && (!(tdes1 & TDCTL_CH))) {\n      do_pci_read(tdes3, state.tx.cur_buf + state.tx.cur_buf_len, 1, buf2_size);\n      state.tx.cur_buf_len += buf2_size;\n    }\n\n    /*  Last segment? Then actually transmit it:  */\n    if (tdes1 & TDCTL_Tx_LS) {\n\n      /*  printf(\"{ TX: data frame complete. }\\n\");  */\n\n      // if not in internal loopback mode, transmit packet to wire\n      if (!(state.reg[CSR_OPMODE / 8] & OPMODE_OM_INTLOOP)) {\n\n        // printf(\"pcap send: %d bytes   \\n\", state.tx.cur_buf_len);\n        if (pcap_sendpacket(fp, state.tx.cur_buf, state.tx.cur_buf_len))\n          printf(\"Error sending the packet: %s\\n\", pcap_geterr(fp));\n      }\n\n      // if in internal or external loopback mode, add packet to read queue\n      if (state.reg[CSR_OPMODE / 8] & OPMODE_OM) {\n        bool crc = !(tdes1 & TDCTL_Tx_AC);\n\n        // printf(\"21143: %s packet, AC: %d\\n\", (state.reg[CSR_OPMODE / 8] &\n        // OPMODE_OM_INTLOOP) ? \"IL\" : \"EL\", !crc); printf(\"21143: TX enabled:\n        // %d, RX enabled: %d\\n\", state.reg[CSR_OPMODE /8] & OPMODE_ST,\n        // state.reg[CSR_OPMODE /8] & OPMODE_SR); printf(\"21143: tx(), len=%d,\n        // addr=%08x, mode=%s\\n\", state.tx.cur_buf_len, (int) state.tx.cur_buf,\n        // (state.reg[CSR_OPMODE / 8] & OPMODE_OM_INTLOOP) ? \"IL\" : \"EL\");\n        // printf(\"21143: tx(), data=|\");\n        // unsigned char* aptr = state.tx.cur_buf;\n        // for(int i=0; i<state.tx.cur_buf_len; i++) {\n        //      printf(\"%02x-\",*aptr++);\n        //}\n        // printf(\"|\\n\");\n        rx_queue->add_tail(state.tx.cur_buf, state.tx.cur_buf_len, calc_crc,\n                           crc);\n      }\n\n      // free(state.tx.cur_buf);\n      // state.tx.cur_buf = NULL;\n      state.tx.cur_buf_len = 0;\n\n      /*  Interrupt, if Tx_IC is set:  */\n      if (tdes1 & TDCTL_Tx_IC)\n        state.reg[CSR_STATUS / 8] |= STATUS_TI;\n    }\n\n    /*  We are done with this segment.  */\n    tdes0 &= ~TDSTAT_OWN;\n  }\n\n  /*  Error summary:  */\n  if (tdes0 & (TDSTAT_Tx_UF | TDSTAT_Tx_EC | TDSTAT_Tx_LC | TDSTAT_Tx_NC |\n               TDSTAT_Tx_LO | TDSTAT_Tx_TO))\n    tdes0 |= TDSTAT_ES;\n\n  /*  Descriptor writeback:  */\n  descr[0] = (u8)tdes0;\n  descr[1] = (u8)(tdes0 >> 8);\n  descr[2] = (u8)(tdes0 >> 16);\n  descr[3] = (u8)(tdes0 >> 24);\n  descr[4] = (u8)tdes1;\n  descr[5] = (u8)(tdes1 >> 8);\n  descr[6] = (u8)(tdes1 >> 16);\n  descr[7] = (u8)(tdes1 >> 24);\n  descr[8] = (u8)tdes2;\n  descr[9] = (u8)(tdes2 >> 8);\n  descr[10] = (u8)(tdes2 >> 16);\n  descr[11] = (u8)(tdes2 >> 24);\n  descr[12] = (u8)tdes3;\n  descr[13] = (u8)(tdes3 >> 8);\n  descr[14] = (u8)(tdes3 >> 16);\n  descr[15] = (u8)(tdes3 >> 24);\n\n  do_pci_write(addr, descr, 1, 16);\n\n  return 1;\n}\n\nvoid CDEC21143::SetupFilter() {\n  u8 mac[16][6];\n  char mac_txt[16][20];\n  char filter[1000];\n  int i;\n  int j;\n  int numUnique;\n  int unique[16];\n  bool u;\n#if defined(DEBUG_NIC_FILTER)\n  printf(\"Building a filter...\\n\");\n#endif\n  for (i = 0; i < 16; i++) {\n    mac[i][0] = state.setup_filter[i * 12];\n    mac[i][1] = state.setup_filter[i * 12 + 1];\n    mac[i][2] = state.setup_filter[i * 12 + 4];\n    mac[i][3] = state.setup_filter[i * 12 + 5];\n    mac[i][4] = state.setup_filter[i * 12 + 8];\n    mac[i][5] = state.setup_filter[i * 12 + 9];\n    sprintf(mac_txt[i], \"%02x:%02x:%02x:%02x:%02x:%02x\", mac[i][0], mac[i][1],\n            mac[i][2], mac[i][3], mac[i][4], mac[i][5]);\n#if defined(DEBUG_NIC_FILTER)\n    printf(\"MAC[%d] = %s. \\n\", i, mac_txt[i]);\n#endif\n  }\n\n#if defined(DEBUG_NIC_FILTER)\n  printf(\"Filter mode: \");\n  if (state.reg[CSR_OPMODE / 8] & OPMODE_PR)\n    printf(\"promiscuous.\\n\");\n  else {\n    if (state.reg[CSR_OPMODE / 8] & OPMODE_IF)\n      printf(\"inverse \");\n    if (state.reg[CSR_OPMODE / 8] & OPMODE_HP) {\n      printf(\"hash \");\n      if (state.reg[CSR_OPMODE / 8] & OPMODE_HO)\n        printf(\"only \");\n    } else\n      printf(\"perfect \");\n    printf(\"filtering.\\n\");\n  }\n#endif\n  numUnique = 0;\n  for (i = 0; i < 16; i++) {\n    u = true;\n    for (j = 0; j < numUnique; j++) {\n      if (mac[i][0] == mac[unique[j]][0] && mac[i][1] == mac[unique[j]][1] &&\n          mac[i][2] == mac[unique[j]][2] && mac[i][3] == mac[unique[j]][3] &&\n          mac[i][4] == mac[unique[j]][4] && mac[i][5] == mac[unique[j]][5]) {\n        u = false;\n        break;\n      }\n    }\n\n    if (u) {\n      unique[numUnique] = i;\n      numUnique++;\n    }\n  }\n\n#if defined(DEBUG_NIC_FILTER)\n  for (i = 0; i < numUnique; i++)\n    printf(\"Unique MAC[%d] = %s. \\n\", i, mac_txt[unique[i]]);\n#endif\n  filter[0] = '\\0';\n\n  // strcat(filter,\"ether broadcast\");\n  // There must be at least one unique item; at least the mac of the card\n  strcat(filter, \"ether dst \");\n  strcat(filter, mac_txt[unique[0]]);\n  for (i = 1; i < numUnique; i++) {\n    strcat(filter, \" or ether dst \");\n    strcat(filter, mac_txt[unique[i]]);\n  }\n\n#if defined(DEBUG_NIC_FILTER)\n  printf(\"FILTER = %s.   \\n\", filter);\n#endif\n  if (pcap_compile(fp, &fcode, filter, 1, 0xffffffff) < 0)\n    FAILURE_1(Logic, \"Unable to compile the packet filter (%s)\", filter);\n\n  if (pcap_setfilter(fp, &fcode) < 0)\n    FAILURE(Runtime, \"Error setting the filter.\");\n}\n\n/**\n * Reset the network interface internals to their condition immediately\n * after power-up, including the PCI configuration.\n **/\nvoid CDEC21143::ResetPCI() {\n  CPCIDevice::ResetPCI();\n\n  ResetNIC();\n}\n\n/**\n * Reset the network interface internals to their condition immediately\n * after power-up. This does not affect the PCI configuration.\n *\n * Code for computing the SROM checksum is taken from [T64].\n **/\nvoid CDEC21143::ResetNIC() {\n  int leaf;\n\n  if (state.rx.cur_buf != NULL)\n    free(state.rx.cur_buf);\n\n  //  if (state.tx.cur_buf != NULL)\n  //        free(state.tx.cur_buf);\n  state.rx.cur_buf = /*state.tx.cur_buf = */ NULL;\n\n  memset(state.reg, 0, sizeof(uint32_t) * 32);\n  memset(state.srom.data, 0, sizeof(state.srom.data));\n  memset(state.mii.phy_reg, 0, sizeof(state.mii.phy_reg));\n\n  /*  Register values at reset, according to the manual:  */\n  state.reg[CSR_BUSMODE / 8] = 0xfe000000; /*  csr0   */\n  state.reg[CSR_MIIROM / 8] = 0xfff483ff;  /*  csr9   */\n  state.reg[CSR_SIACONN / 8] = 0xffff0000; /*  csr13  */\n  state.reg[CSR_SIATXRX / 8] = 0xffffffff; /*  csr14  */\n  state.reg[CSR_SIAGEN / 8] = 0x8ff00000;  /*  csr15  */\n\n  state.tx.idling_threshold = 10;\n  state.rx.cur_addr = state.tx.cur_addr = 0;\n\n  /*  Version (= 1) and Chip count (= 1):  */\n  state.srom.data[TULIP_ROM_SROM_FORMAT_VERION] = 1;\n  state.srom.data[TULIP_ROM_CHIP_COUNT] = 1;\n\n  /*  Set the MAC address:  */\n  memcpy(state.srom.data + TULIP_ROM_IEEE_NETWORK_ADDRESS, state.mac, 6);\n\n  leaf = 30;\n  state.srom.data[TULIP_ROM_CHIPn_DEVICE_NUMBER(0)] = 0;\n  state.srom.data[TULIP_ROM_CHIPn_INFO_LEAF_OFFSET(0)] = leaf & 255;\n  state.srom.data[TULIP_ROM_CHIPn_INFO_LEAF_OFFSET(0) + 1] = leaf >> 8;\n\n  state.srom.data[leaf + TULIP_ROM_IL_SELECT_CONN_TYPE] = 0; /*  Not used?  */\n  state.srom.data[leaf + TULIP_ROM_IL_MEDIA_COUNT] = 2;\n  leaf += TULIP_ROM_IL_MEDIAn_BLOCK_BASE;\n\n  state.srom.data[leaf] = 7; /*  descriptor length  */\n  state.srom.data[leaf + 1] = TULIP_ROM_MB_21142_SIA;\n  state.srom.data[leaf + 2] = TULIP_ROM_MB_MEDIA_100TX;\n\n  /*  here comes 4 bytes of GPIO control/data settings  */\n  leaf += state.srom.data[leaf];\n\n  state.srom.data[leaf] = 15; /*  descriptor length  */\n  state.srom.data[leaf + 1] = TULIP_ROM_MB_21142_MII;\n  state.srom.data[leaf + 2] = 0; /*  PHY nr  */\n  state.srom.data[leaf + 3] = 0; /*  len of select sequence  */\n  state.srom.data[leaf + 4] = 0; /*  len of reset sequence  */\n\n  /*  5,6, 7,8, 9,10, 11,12, 13,14 = unused by GXemul  */\n  leaf += state.srom.data[leaf];\n\n  /*  MII PHY initial state:  */\n  state.mii.state = MII_STATE_RESET;\n\n  /*  PHY #0:  */\n  state.mii.phy_reg[MII_BMSR] =\n      BMSR_100TXFDX | BMSR_10TFDX | BMSR_ACOMP | BMSR_ANEG | BMSR_LINK;\n\n  state.tx.suspend = false;\n\n  // compute the CRC for the SROM data.  This code is from the\n  // tu sample driver from HP in if_tu.c, which was apparently\n  // derived from the 21140 Hardware Specification\n  unsigned int POLY = 0x04c11db6;\n  unsigned int FlippedCrc = 0;\n  unsigned int Crc = 0xffffffff;\n  unsigned char i;\n  unsigned char CurrentByte;\n  unsigned char Bit;\n  unsigned char Msb;\n  unsigned char chksm_1;\n  unsigned char chksm_2;\n\n  for (i = 0; i < 126; i++) {\n    CurrentByte = state.srom.data[i];\n\n    for (Bit = 0; Bit < 8; Bit++) {\n      Msb = (Crc >> 31) & 1;\n      Crc <<= 1;\n\n      if (Msb ^ (CurrentByte & 1)) {\n        Crc ^= POLY;\n        Crc |= 1;\n      }\n\n      CurrentByte >>= 1;\n    }\n  }\n\n  for (i = 0; i < 32; i++) {\n    FlippedCrc <<= 1;\n    Bit = Crc & 1;\n    Crc >>= 1;\n    FlippedCrc += Bit;\n  }\n\n  Crc = FlippedCrc ^ 0xffffffff;\n\n  chksm_1 = Crc & 0xff;\n  chksm_2 = Crc >> 8;\n\n  state.srom.data[126] = chksm_1;\n  state.srom.data[127] = chksm_2;\n#if defined(DEBUG_NIC_SROM)\n  printf(\"%%NIC-I-CKSUM: SROM checksum bytes are %02x, %02x\\n\",\n         state.srom.data[126], state.srom.data[127]);\n#endif\n}\n\nstatic u32 nic_magic1 = 0xDEC21143;\nstatic u32 nic_magic2 = 0x21143DEC;\n\n/**\n * Save state to a Virtual Machine State file.\n **/\nint CDEC21143::SaveState(FILE *f) {\n  long ss = sizeof(state);\n  int res;\n\n  if ((res = CPCIDevice::SaveState(f)))\n    return res;\n\n  fwrite(&nic_magic1, sizeof(u32), 1, f);\n  fwrite(&ss, sizeof(long), 1, f);\n  fwrite(&state, sizeof(state), 1, f);\n  fwrite(&nic_magic2, sizeof(u32), 1, f);\n  printf(\"%s: %ld bytes saved.\\n\", devid_string, ss);\n  return 0;\n}\n\n/**\n * Restore state from a Virtual Machine State file.\n **/\nint CDEC21143::RestoreState(FILE *f) {\n  long ss;\n  u32 m1;\n  u32 m2;\n  int res;\n  size_t r;\n\n  if ((res = CPCIDevice::RestoreState(f)))\n    return res;\n\n  r = fread(&m1, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m1 != nic_magic1) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&ss, sizeof(long), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (ss != sizeof(state)) {\n    printf(\"%s: STRUCT SIZE does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&state, sizeof(state), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&m2, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m2 != nic_magic2) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  printf(\"%s: %ld bytes restored.\\n\", devid_string, ss);\n  return 0;\n}\n#endif // defined(HAVE_PCAP)\n"
  },
  {
    "path": "src/DEC21143.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon GXemul, which is Copyright (C) 2004-2007\n * Anders Gavare.  All rights reserved.\n */\n\n#if !defined(INCLUDED_DEC21143_H_)\n#define INCLUDED_DEC21143_H_\n\n#include \"DEC21143_mii.hpp\"\n#include \"DEC21143_tulipreg.hpp\"\n#include \"PCIDevice.hpp\"\n#if defined(WIN32)\n#define HAVE_REMOTE\n#endif\n#include \"Ethernet.hpp\"\n#include <pcap.h>\n\n/**\n * \\brief Emulated DEC 21143 NIC device.\n *\n * Documentation consulted:\n *  - 21143 PCI/Cardbus 10/100Mb/s Ethernet LAN Controller Hardware Reference\n *Manual  [HRM]. (http://download.intel.com/design/network/manuals/27807401.pdf)\n *  - Tru64 Device Driver Kit Version 2 (Ethernet sample = tu driver!) [T64].\n *(http://h30097.www3.hp.com/docs/dev_doc/DOCUMENTATION/HTML/dev_docs_r2.html)\n *  .\n **/\nclass CDEC21143 : public CPCIDevice {\npublic:\n  virtual int SaveState(FILE *f);\n  virtual int RestoreState(FILE *f);\n\n  virtual void check_state();\n  virtual void WriteMem_Bar(int func, int bar, u32 address, int dsize,\n                            u32 data);\n  virtual u32 ReadMem_Bar(int func, int bar, u32 address, int dsize);\n\n  CDEC21143(CConfigurator *confg, class CSystem *c, int pcibus, int pcidev);\n  virtual ~CDEC21143();\n  virtual void ResetPCI();\n  void ResetNIC();\n  void SetupFilter();\n  void receive_process();\n  void run();\n  virtual void init();\n  virtual void start_threads();\n  virtual void stop_threads();\n\nprivate:\n  static int nic_num;\n\n  std::unique_ptr<std::thread> myThread;\n  std::atomic_bool myThreadDead{false};\n  bool StopThread;\n\n  u32 nic_read(u32 address, int dsize);\n  void nic_write(u32 address, int dsize, u32 data);\n  void mii_access(uint32_t oldreg, uint32_t idata);\n  void srom_access(uint32_t oldreg, uint32_t idata);\n\n  int dec21143_rx();\n  int dec21143_tx();\n  void set_tx_state(int tx_state);\n  void set_rx_state(int rx_state);\n\n  CPacketQueue *rx_queue;\n  pcap_t *fp;\n  struct bpf_program fcode;\n  bool calc_crc;\n\n  /// The state structure contains all elements that need to be saved to the\n  /// statefile.\n  struct SNIC_state {\n    bool irq_was_asserted; /**< remember state of IRQ */\n\n    u8 mac[6];            /**< ethernet address */\n    u8 setup_filter[192]; /**< filter for perfect filtering */\n    int descr_skip;       // Descriptor Skip Length [DSL] (in bytes)\n\n    /// SROM emulation\n    struct SNIC_srom {\n      u8 data[1 << (7)];\n      int curbit;\n      int opcode;\n      int opcode_has_started;\n      int addr;\n    } srom;\n\n    /// MII PHY emulation\n    struct SNIC_mii {\n      u16 phy_reg[MII_NPHY * 32];\n      int state;\n      int bit;\n      int opcode;\n      int phyaddr;\n      int regaddr;\n    } mii;\n\n    u32 reg[32]; /**< 21143 registers */\n\n    /// Internal TX state\n    struct SNIC_tx {\n      u32 cur_addr;\n      unsigned char *cur_buf;\n      int cur_buf_len;\n      int idling;\n      int idling_threshold;\n      bool suspend;\n    } tx;\n\n    /// Internal RX state\n    struct SNIC_rx {\n      u32 cur_addr;\n      unsigned char *cur_buf;\n      int cur_buf_len;\n      int cur_offset;\n      eth_packet current;\n    } rx;\n  } state;\n};\n#endif // !defined(INCLUDED_DEC21143_H)\n"
  },
  {
    "path": "src/DEC21143_mii.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This file is based upon NetBsd.\n *\n * Copyright (c) 1997 Manuel Bouyer.  All rights reserved.\n *\n * Modification to match BSD/OS 3.0 MII interface by Jason R. Thorpe,\n * Numerical Aerospace Simulation Facility, NASA Ames Research Center.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. All advertising materials mentioning features or use of this software\n *    must display the following acknowledgement:\n *\tThis product includes software developed by Manuel Bouyer.\n * 4. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#ifndef _DEV_MII_MII_H_\n#define _DEV_MII_MII_H_\n\n/*\n * Registers common to all PHYs.\n */\n#define MII_NPHY 32 /* max # of PHYs per MII */\n\n/*\n * MII commands, used if a device must drive the MII lines\n * manually.\n */\n#define MII_COMMAND_START 0x01\n#define MII_COMMAND_READ 0x02\n#define MII_COMMAND_WRITE 0x01\n#define MII_COMMAND_ACK 0x02\n\n#define MII_BMCR 0x00        /* Basic mode control register (rw) */\n#define BMCR_RESET 0x8000    /* reset */\n#define BMCR_LOOP 0x4000     /* loopback */\n#define BMCR_SPEED0 0x2000   /* speed selection (LSB) */\n#define BMCR_AUTOEN 0x1000   /* autonegotiation enable */\n#define BMCR_PDOWN 0x0800    /* power down */\n#define BMCR_ISO 0x0400      /* isolate */\n#define BMCR_STARTNEG 0x0200 /* restart autonegotiation */\n#define BMCR_FDX 0x0100      /* Set duplex mode */\n#define BMCR_CTEST 0x0080    /* collision test */\n#define BMCR_SPEED1 0x0040   /* speed selection (MSB) */\n\n#define BMCR_S10 0x0000        /* 10 Mb/s */\n#define BMCR_S100 BMCR_SPEED0  /* 100 Mb/s */\n#define BMCR_S1000 BMCR_SPEED1 /* 1000 Mb/s */\n\n#define BMCR_SPEED(x) ((x) & (BMCR_SPEED0 | BMCR_SPEED1))\n#define MII_BMSR 0x01        /* Basic mode status register (ro) */\n#define BMSR_100T4 0x8000    /* 100 base T4 capable */\n#define BMSR_100TXFDX 0x4000 /* 100 base Tx full duplex capable */\n#define BMSR_100TXHDX 0x2000 /* 100 base Tx half duplex capable */\n#define BMSR_10TFDX 0x1000   /* 10 base T full duplex capable */\n#define BMSR_10THDX 0x0800   /* 10 base T half duplex capable */\n#define BMSR_100T2FDX 0x0400 /* 100 base T2 full duplex capable */\n#define BMSR_100T2HDX 0x0200 /* 100 base T2 half duplex capable */\n#define BMSR_EXTSTAT 0x0100  /* Extended status in register 15 */\n#define BMSR_MFPS 0x0040     /* MII Frame Preamble Suppression */\n#define BMSR_ACOMP 0x0020    /* Autonegotiation complete */\n#define BMSR_RFAULT 0x0010   /* Link partner fault */\n#define BMSR_ANEG 0x0008     /* Autonegotiation capable */\n#define BMSR_LINK 0x0004     /* Link status */\n#define BMSR_JABBER 0x0002   /* Jabber detected */\n#define BMSR_EXTCAP 0x0001   /* Extended capability */\n\n/*\n * Note that the EXTSTAT bit indicates that there is extended status\n * info available in register 15, but 802.3 section 22.2.4.3 also\n * states that that all 1000 Mb/s capable PHYs will set this bit to 1.\n */\n#define BMSR_MEDIAMASK                                                         \\\n  (BMSR_100T4 | BMSR_100TXFDX | BMSR_100TXHDX | BMSR_10TFDX | BMSR_10THDX |    \\\n   BMSR_100T2FDX | BMSR_100T2HDX)\n\n/*\n * Convert BMSR media capabilities to ANAR bits for autonegotiation.\n * Note the shift chopps off the BMSR_ANEG bit.\n */\n#define BMSR_MEDIA_TO_ANAR(x) (((x)&BMSR_MEDIAMASK) >> 6)\n#define MII_PHYIDR1 0x02 /* ID register 1 (ro) */\n\n#define MII_PHYIDR2 0x03   /* ID register 2 (ro) */\n#define IDR2_OUILSB 0xfc00 /* OUI LSB */\n#define IDR2_MODEL 0x03f0  /* vendor model */\n#define IDR2_REV 0x000f    /* vendor revision */\n\n#define MII_ANAR 0x04 /* Autonegotiation advertisement (rw) */\n\n/* section 28.2.4.1 and 37.2.6.1 */\n#define ANAR_NP 0x8000    /* Next page (ro) */\n#define ANAR_ACK 0x4000   /* link partner abilities acknowledged (ro) */\n#define ANAR_RF 0x2000    /* remote fault (ro) */\n#define ANAR_FC 0x0400    /* local device supports PAUSE */\n#define ANAR_T4 0x0200    /* local device supports 100bT4 */\n#define ANAR_TX_FD 0x0100 /* local device supports 100bTx FD */\n#define ANAR_TX 0x0080    /* local device supports 100bTx */\n#define ANAR_10_FD 0x0040 /* local device supports 10bT FD */\n#define ANAR_10 0x0020    /* local device supports 10bT */\n#define ANAR_CSMA 0x0001  /* protocol selector CSMA/CD */\n\n#define ANAR_X_FD 0x0020 /* local device supports 1000BASE-X FD */\n#define ANAR_X_HD 0x0040 /* local device supports 1000BASE-X HD */\n#define ANAR_X_PAUSE_NONE (0 << 10)\n#define ANAR_X_PAUSE_SYM (1 << 10)\n#define ANAR_X_PAUSE_ASYM (2 << 10)\n#define ANAR_X_PAUSE_TOWARDS (3 << 10)\n#define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */\n\n/* section 28.2.4.1 and 37.2.6.1 */\n#define ANLPAR_NP 0x8000    /* Next page (ro) */\n#define ANLPAR_ACK 0x4000   /* link partner accepted ACK (ro) */\n#define ANLPAR_RF 0x2000    /* remote fault (ro) */\n#define ANLPAR_FC 0x0400    /* link partner supports PAUSE */\n#define ANLPAR_T4 0x0200    /* link partner supports 100bT4 */\n#define ANLPAR_TX_FD 0x0100 /* link partner supports 100bTx FD */\n#define ANLPAR_TX 0x0080    /* link partner supports 100bTx */\n#define ANLPAR_10_FD 0x0040 /* link partner supports 10bT FD */\n#define ANLPAR_10 0x0020    /* link partner supports 10bT */\n#define ANLPAR_CSMA 0x0001  /* protocol selector CSMA/CD */\n\n#define ANLPAR_X_FD 0x0020 /* local device supports 1000BASE-X FD */\n#define ANLPAR_X_HD 0x0040 /* local device supports 1000BASE-X HD */\n#define ANLPAR_X_PAUSE_MASK (3 << 10)\n#define ANLPAR_X_PAUSE_NONE (0 << 10)\n#define ANLPAR_X_PAUSE_SYM (1 << 10)\n#define ANLPAR_X_PAUSE_ASYM (2 << 10)\n#define ANLPAR_X_PAUSE_TOWARDS (3 << 10)\n#define MII_ANER 0x06 /* Autonegotiation expansion (ro) */\n\n/* section 28.2.4.1 and 37.2.6.1 */\n#define ANER_MLF 0x0010     /* multiple link detection fault */\n#define ANER_LPNP 0x0008    /* link parter next page-able */\n#define ANER_NP 0x0004      /* next page-able */\n#define ANER_PAGE_RX 0x0002 /* Page received */\n#define ANER_LPAN 0x0001    /* link parter autoneg-able */\n\n#define MII_ANNP 0x07 /* Autonegotiation next page */\n\n/* section 28.2.4.1 and 37.2.6.1 */\n#define MII_ANLPRNP 0x08 /* Autonegotiation link partner rx next page */\n\n/* section 32.5.1 and 37.2.6.1 */\n\n/* This is also the 1000baseT control register */\n#define MII_100T2CR 0x09         /* 100base-T2 control register */\n#define GTCR_TEST_MASK 0xe000    /* see 802.3ab ss. 40.6.1.1.2 */\n#define GTCR_MAN_MS 0x1000       /* enable manual master/slave control */\n#define GTCR_ADV_MS 0x0800       /* 1 = adv. master, 0 = adv. slave */\n#define GTCR_PORT_TYPE 0x0400    /* 1 = DCE, 0 = DTE (NIC) */\n#define GTCR_ADV_1000TFDX 0x0200 /* adv. 1000baseT FDX */\n#define GTCR_ADV_1000THDX 0x0100 /* adv. 1000baseT HDX */\n\n/* This is also the 1000baseT status register */\n#define MII_100T2SR 0x0a        /* 100base-T2 status register */\n#define GTSR_MAN_MS_FLT 0x8000  /* master/slave config fault */\n#define GTSR_MS_RES 0x4000      /* result: 1 = master, 0 = slave */\n#define GTSR_LRS 0x2000         /* local rx status, 1 = ok */\n#define GTSR_RRS 0x1000         /* remove rx status, 1 = ok */\n#define GTSR_LP_1000TFDX 0x0800 /* link partner 1000baseT FDX capable */\n#define GTSR_LP_1000THDX 0x0400 /* link partner 1000baseT HDX capable */\n#define GTSR_LP_ASM_DIR 0x0200  /* link partner asym. pause dir. capable */\n#define GTSR_IDLE_ERR 0x00ff    /* IDLE error count */\n\n#define MII_EXTSR 0x0f        /* Extended status register */\n#define EXTSR_1000XFDX 0x8000 /* 1000X full-duplex capable */\n#define EXTSR_1000XHDX 0x4000 /* 1000X half-duplex capable */\n#define EXTSR_1000TFDX 0x2000 /* 1000T full-duplex capable */\n#define EXTSR_1000THDX 0x1000 /* 1000T half-duplex capable */\n\n#define EXTSR_MEDIAMASK                                                        \\\n  (EXTSR_1000XFDX | EXTSR_1000XHDX | EXTSR_1000TFDX | EXTSR_1000THDX)\n#endif /* _DEV_MII_MII_H_ */\n"
  },
  {
    "path": "src/DEC21143_tulipreg.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This file is based upon NetBsd.\n *\n * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.\n * All rights reserved.\n *\n * This code is derived from software contributed to The NetBSD Foundation\n * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,\n * NASA Ames Research Center.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. All advertising materials mentioning features or use of this software\n *    must display the following acknowledgement:\n *\tThis product includes software developed by the NetBSD\n *\tFoundation, Inc. and its contributors.\n * 4. Neither the name of The NetBSD Foundation nor the names of its\n *    contributors may be used to endorse or promote products derived\n *    from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS\n * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS\n * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n\n#ifndef __volatile\n#define __volatile\n#endif\n#ifndef _DEV_IC_TULIPREG_H_\n#define _DEV_IC_TULIPREG_H_\n\n/*\n * Register description for the Digital Semiconductor ``Tulip'' (21x4x)\n * Ethernet controller family.\n */\n\n/*\n * Descriptor Status bits common to transmit and receive.\n */\n#define TDSTAT_OWN 0x80000000 /* Tulip owns descriptor */\n#define TDSTAT_ES 0x00008000  /* Error Summary */\n\n/*\n * Descriptor Status bits for Receive Descriptor.\n */\n#define TDSTAT_Rx_FF 0x40000000  /* Filtering Fail */\n#define TDSTAT_Rx_FL 0x3fff0000  /* Frame Length including CRC */\n#define TDSTAT_Rx_DE 0x00004000  /* Descriptor Error */\n#define TDSTAT_Rx_DT 0x00003000  /* Data Type */\n#define TDSTAT_Rx_RF 0x00000800  /* Runt Frame */\n#define TDSTAT_Rx_MF 0x00000400  /* Multicast Frame */\n#define TDSTAT_Rx_FS 0x00000200  /* First Descriptor */\n#define TDSTAT_Rx_LS 0x00000100  /* Last Descriptor */\n#define TDSTAT_Rx_TL 0x00000080  /* Frame Too Long */\n#define TDSTAT_Rx_CS 0x00000040  /* Collision Seen */\n#define TDSTAT_Rx_RT 0x00000020  /* Frame Type */\n#define TDSTAT_Rx_RW 0x00000010  /* Receive Watchdog */\n#define TDSTAT_Rx_RE 0x00000008  /* Report on MII Error */\n#define TDSTAT_Rx_DB 0x00000004  /* Dribbling Bit */\n#define TDSTAT_Rx_CE 0x00000002  /* CRC Error */\n#define TDSTAT_Rx_ZER 0x00000001 /* Zero (always 0) */\n\n#define TDSTAT_Rx_LENGTH(x) (((x)&TDSTAT_Rx_FL) >> 16)\n#define TDSTAT_Rx_DT_SR 0x00000000 /* Serial Received Frame */\n#define TDSTAT_Rx_DT_IL 0x00001000 /* Internal Loopback Frame */\n#define TDSTAT_Rx_DT_EL 0x00002000 /* External Loopback Frame */\n#define TDSTAT_Rx_DT_r 0x00003000  /* Reserved */\n\n/*\n * Descriptor Status bits for Transmit Descriptor.\n */\n#define TDSTAT_Tx_TO 0x00004000 /* Transmit Jabber Timeout */\n#define TDSTAT_Tx_LO 0x00000800 /* Loss of Carrier */\n#define TDSTAT_Tx_NC 0x00000400 /* No Carrier */\n#define TDSTAT_Tx_LC 0x00000200 /* Late Collision */\n#define TDSTAT_Tx_EC 0x00000100 /* Excessive Collisions */\n#define TDSTAT_Tx_HF 0x00000080 /* Heartbeat Fail */\n#define TDSTAT_Tx_CC 0x00000078 /* Collision Count */\n#define TDSTAT_Tx_LF 0x00000004 /* Link Fail */\n#define TDSTAT_Tx_UF 0x00000002 /* Underflow Error */\n#define TDSTAT_Tx_DE 0x00000001 /* Deferred */\n\n#define TDSTAT_Tx_COLLISIONS(x) (((x)&TDSTAT_Tx_CC) >> 3)\n\n/*\n * Descriptor Control bits common to transmit and receive.\n */\n#define TDCTL_SIZE1 0x000007ff /* Size of buffer 1 */\n#define TDCTL_SIZE1_SHIFT 0\n\n#define TDCTL_SIZE2 0x003ff800 /* Size of buffer 2 */\n#define TDCTL_SIZE2_SHIFT 11\n\n#define TDCTL_ER 0x02000000 /* End of Ring */\n#define TDCTL_CH 0x01000000 /* Second Address Chained */\n\n/*\n * Descriptor Control bits for Transmit Descriptor.\n */\n#define TDCTL_Tx_IC 0x80000000  /* Interrupt on Completion */\n#define TDCTL_Tx_LS 0x40000000  /* Last Segment */\n#define TDCTL_Tx_FS 0x20000000  /* First Segment */\n#define TDCTL_Tx_FT1 0x10000000 /* Filtering Type 1 */\n#define TDCTL_Tx_SET 0x08000000 /* Setup Packet */\n#define TDCTL_Tx_AC 0x04000000  /* Add CRC Disable */\n#define TDCTL_Tx_DPD 0x00800000 /* Disabled Padding */\n#define TDCTL_Tx_FT0 0x00400000 /* Filtering Type 0 */\n\n/*\n * The Tulip filter is programmed by \"transmitting\" a Setup Packet\n * (indicated by TDCTL_Tx_SET).  The filtering type is indicated\n * as follows:\n *\n *\tFT1\tFT0\tDescription\n *\t---\t---\t-----------\n *\t0\t0\tPerfect Filtering: The Tulip interprets the\n *\t\t\tdescriptor buffer as a table of 16 MAC addresses\n *\t\t\tthat the Tulip should receive.\n *\n *\t0\t1\tHash Filtering: The Tulip interprets the\n *\t\t\tdescriptor buffer as a 512-bit hash table\n *\t\t\tplus one perfect address.  If the incoming\n *\t\t\taddress is Multicast, the hash table filters\n *\t\t\tthe address, else the address is filtered by\n *\t\t\tthe perfect address.\n *\n *\t1\t0\tInverse Filtering: Like Perfect Filtering, except\n *\t\t\tthe table is addresses that the Tulip does NOT\n *\t\t\treceive.\n *\n *\t1\t1\tHash-only Filtering: Like Hash Filtering, but\n *\t\t\tphysical addresses are matched by the hash table\n *\t\t\tas well, and not by matching a single perfect\n *\t\t\taddress.\n *\n * A Setup Packet must always be 192 bytes long.  The Tulip can store\n * 16 MAC addresses.  If not all 16 are specified in Perfect Filtering\n * or Inverse Filtering mode,  then unused entries should duplicate\n * one of the valid entries.\n */\n#define TDCTL_Tx_FT_PERFECT 0\n#define TDCTL_Tx_FT_HASH TDCTL_Tx_FT0\n#define TDCTL_Tx_FT_INVERSE TDCTL_Tx_FT1\n#define TDCTL_Tx_FT_HASHONLY (TDCTL_Tx_FT1 | TDCTL_Tx_FT0)\n#define TULIP_SETUP_PACKET_LEN 192\n#define TULIP_MAXADDRS 16\n#define TULIP_MCHASHSIZE 512\n\n/*\n * Maximum size of a Tulip Ethernet Address ROM or SROM.\n */\n#define TULIP_ROM_SIZE(bits) (2 << (bits))\n#define TULIP_MAX_ROM_SIZE 512\n\n/*\n * Format of the standard Tulip SROM information:\n *\n *\tByte offset\tSize\tUsage\n *\t0\t\t18\treserved\n *\t18\t\t1\tSROM Format Version\n *\t19\t\t1\tChip Count\n *\t20\t\t6\tIEEE Network Address\n *\t26\t\t1\tChip 0 Device Number\n *\t27\t\t2\tChip 0 Info Leaf Offset\n *\t29\t\t1\tChip 1 Device Number\n *\t30\t\t2\tChip 1 Info Leaf Offset\n *\t32\t\t1\tChip 2 Device Number\n *\t33\t\t2\tChip 2 Info Leaf Offset\n *\t...\t\t1\tChip n Device Number\n *\t...\t\t2\tChip n Info Leaf Offset\n *\t...\t\t...\t...\n *\tChip Info Leaf Information\n *\t...\n *\t...\n *\t...\n *\t126\t\t2\tCRC32 checksum\n */\n#define TULIP_ROM_SROM_FORMAT_VERION 18 /* B */\n#define TULIP_ROM_CHIP_COUNT 19         /* B */\n#define TULIP_ROM_IEEE_NETWORK_ADDRESS 20\n#define TULIP_ROM_CHIPn_DEVICE_NUMBER(n) (26 + ((n)*3))    /* B */\n#define TULIP_ROM_CHIPn_INFO_LEAF_OFFSET(n) (27 + ((n)*3)) /* W */\n#define TULIP_ROM_CRC32_CHECKSUM 126                       /* W */\n#define TULIP_ROM_CRC32_CHECKSUM1 94                       /* W */\n\n#define TULIP_ROM_IL_SELECT_CONN_TYPE 0 /* W */\n#define TULIP_ROM_IL_MEDIA_COUNT 2      /* B */\n#define TULIP_ROM_IL_MEDIAn_BLOCK_BASE 3\n\n#define SELECT_CONN_TYPE_TP 0x0000\n#define SELECT_CONN_TYPE_BNC 0x0001\n#define SELECT_CONN_TYPE_AUI 0x0002\n#define SELECT_CONN_TYPE_100TX 0x0003\n#define SELECT_CONN_TYPE_100T4 0x0006\n#define SELECT_CONN_TYPE_100FX 0x0007\n#define SELECT_CONN_TYPE MII_10T 0x0009\n#define SELECT_CONN_TYPE_MII_100TX 0x000d\n#define SELECT_CONN_TYPE_MII_100T4 0x000f\n#define SELECT_CONN_TYPE_MII_100FX 0x0010\n#define SELECT_CONN_TYPE_TP_AUTONEG 0x0100\n#define SELECT_CONN_TYPE_TP_FDX 0x0204\n#define SELECT_CONN_TYPE_MII_10T_FDX 0x020a\n#define SELECT_CONN_TYPE_100TX_FDX 0x020e\n#define SELECT_CONN_TYPE_MII_100TX_FDX 0x0211\n#define SELECT_CONN_TYPE_TP_NOLINKPASS 0x0400\n#define SELECT_CONN_TYPE_ASENSE 0x0800\n#define SELECT_CONN_TYPE_ASENSE_POWERUP 0x8800\n#define SELECT_CONN_TYPE_ASENSE_AUTONEG 0x0900\n\n#define TULIP_ROM_MB_MEDIA_CODE 0x3f\n#define TULIP_ROM_MB_MEDIA_TP 0x00\n#define TULIP_ROM_MB_MEDIA_BNC 0x01\n#define TULIP_ROM_MB_MEDIA_AUI 0x02\n#define TULIP_ROM_MB_MEDIA_100TX 0x03\n#define TULIP_ROM_MB_MEDIA_TP_FDX 0x04\n#define TULIP_ROM_MB_MEDIA_100TX_FDX 0x05\n#define TULIP_ROM_MB_MEDIA_100T4 0x06\n#define TULIP_ROM_MB_MEDIA_100FX 0x07\n#define TULIP_ROM_MB_MEDIA_100FX_FDX 0x08\n\n#define TULIP_ROM_MB_EXT 0x40\n\n#define TULIP_ROM_MB_CSR13 1 /* W */\n#define TULIP_ROM_MB_CSR14 3 /* W */\n#define TULIP_ROM_MB_CSR15 5 /* W */\n\n#define TULIP_ROM_MB_SIZE(mc) (((mc)&TULIP_ROM_MB_EXT) ? 7 : 1)\n#define TULIP_ROM_MB_NOINDICATOR 0x8000\n#define TULIP_ROM_MB_DEFAULT 0x4000\n#define TULIP_ROM_MB_POLARITY 0x0080\n#define TULIP_ROM_MB_OPMODE(x) (((x)&0x71) << 18)\n#define TULIP_ROM_MB_BITPOS(x) (1 << (((x)&0x0e) >> 1))\n#define TULIP_ROM_MB_21140_GPR 0   /* 21140[A] GPR block */\n#define TULIP_ROM_MB_21140_MII 1   /* 21140[A] MII block */\n#define TULIP_ROM_MB_21142_SIA 2   /* 2114[23] SIA block */\n#define TULIP_ROM_MB_21142_MII 3   /* 2114[23] MII block */\n#define TULIP_ROM_MB_21143_SYM 4   /* 21143 SYM block */\n#define TULIP_ROM_MB_21143_RESET 5 /* 21143 reset block */\n\n#define TULIP_ROM_GETW(data, off)                                              \\\n  ((uint32_t)(data)[(off)] | (uint32_t)((data)[(off) + 1]) << 8)\n\n/*\n * Tulip control registers.\n */\n#define TULIP_CSR0 0x00\n#define TULIP_CSR1 0x08\n#define TULIP_CSR2 0x10\n#define TULIP_CSR3 0x18\n#define TULIP_CSR4 0x20\n#define TULIP_CSR5 0x28\n#define TULIP_CSR6 0x30\n#define TULIP_CSR7 0x38\n#define TULIP_CSR8 0x40\n#define TULIP_CSR9 0x48\n#define TULIP_CSR10 0x50\n#define TULIP_CSR11 0x58\n#define TULIP_CSR12 0x60\n#define TULIP_CSR13 0x68\n#define TULIP_CSR14 0x70\n#define TULIP_CSR15 0x78\n#define TULIP_CSR16 0x80\n#define TULIP_CSR17 0x88\n#define TULIP_CSR18 0x90\n#define TULIP_CSR19 0x98\n#define TULIP_CSR20 0xa0\n#define TULIP_CSR21 0xa8\n#define TULIP_CSR22 0xb0\n#define TULIP_CSR23 0xb8\n#define TULIP_CSR24 0xc0\n#define TULIP_CSR25 0xc8\n#define TULIP_CSR26 0xd0\n#define TULIP_CSR27 0xd8\n#define TULIP_CSR28 0xe0\n#define TULIP_CSR29 0xe8\n#define TULIP_CSR30 0xf0\n#define TULIP_CSR31 0xf8\n\n#define TULIP_CSR_INDEX(csr) ((csr) >> 3)\n\n/* CSR0 - Bus Mode */\n#define CSR_BUSMODE TULIP_CSR0\n#define BUSMODE_SWR 0x00000001 /* software reset */\n#define BUSMODE_BAR 0x00000002 /* bus arbitration */\n#define BUSMODE_DSL 0x0000007c /* descriptor skip length */\n#define BUSMODE_BLE 0x00000080 /* big endian */\n\n/* programmable burst length */\n#define BUSMODE_PBL_DEFAULT 0x00000000 /*     default value */\n#define BUSMODE_PBL_1LW 0x00000100     /*     1 longword */\n#define BUSMODE_PBL_2LW 0x00000200     /*     2 longwords */\n#define BUSMODE_PBL_4LW 0x00000400     /*     4 longwords */\n#define BUSMODE_PBL_8LW 0x00000800     /*     8 longwords */\n#define BUSMODE_PBL_16LW 0x00001000    /*    16 longwords */\n#define BUSMODE_PBL_32LW 0x00002000    /*    32 longwords */\n\n/* cache alignment */\n#define BUSMODE_CAL_NONE 0x00000000 /*     no alignment */\n#define BUSMODE_CAL_8LW 0x00004000  /*     8 longwords */\n#define BUSMODE_CAL_16LW 0x00008000 /*    16 longwords */\n#define BUSMODE_CAL_32LW 0x0000c000 /*    32 longwords */\n#define BUSMODE_DAS 0x00010000      /* diagnostic address space */\n\n/*   must be zero on most */\n\n/* transmit auto-poll */\n#define BUSMODE_TAP_NONE 0x00000000    /*     no auto-polling */\n#define BUSMODE_TAP_200us 0x00020000   /*   200 uS */\n#define BUSMODE_TAP_800us 0x00040000   /*   400 uS */\n#define BUSMODE_TAP_1_6ms 0x00060000   /*   1.6 mS */\n#define BUSMODE_TAP_12_8us 0x00080000  /*  12.8 uS (21041+) */\n#define BUSMODE_TAP_25_6us 0x000a0000  /*  25.6 uS (21041+) */\n#define BUSMODE_TAP_51_2us 0x000c0000  /*  51.2 uS (21041+) */\n#define BUSMODE_TAP_102_4us 0x000e0000 /* 102.4 uS (21041+) */\n#define BUSMODE_DBO 0x00100000         /* desc-only b/e (21041+) */\n#define BUSMODE_RME 0x00200000         /* rd/mult enab (21140+) */\n#define BUSMODE_RLE 0x00800000         /* rd/line enab (21140+) */\n#define BUSMODE_WLE 0x01000000         /* wt/line enab (21140+) */\n\n/* CSR1 - Transmit Poll Demand */\n#define CSR_TXPOLL TULIP_CSR1\n#define TXPOLL_TPD 0x00000001 /* transmit poll demand */\n\n/* CSR2 - Receive Poll Demand */\n#define CSR_RXPOLL TULIP_CSR2\n#define RXPOLL_RPD 0x00000001 /* receive poll demand */\n\n/* CSR3 - Receive List Base Address */\n#define CSR_RXLIST TULIP_CSR3\n\n/* CSR4 - Transmit List Base Address */\n#define CSR_TXLIST TULIP_CSR4\n\n/* CSR5 - Status */\n#define CSR_STATUS TULIP_CSR5\n#define STATUS_TI 0x00000001     /* transmit interrupt */\n#define STATUS_TPS 0x00000002    /* transmit process stopped */\n#define STATUS_TU 0x00000004     /* transmit buffer unavail */\n#define STATUS_TJT 0x00000008    /* transmit jabber timeout */\n#define STATUS_LNPANC 0x00000010 /* link pass (21041) */\n#define STATUS_UNF 0x00000020    /* transmit underflow */\n#define STATUS_RI 0x00000040     /* receive interrupt */\n#define STATUS_RU 0x00000080     /* receive buffer unavail */\n#define STATUS_RPS 0x00000100    /* receive process stopped */\n#define STATUS_RWT 0x00000200    /* receive watchdog timeout */\n#define STATUS_AT                                                              \\\n  0x00000400 /* SIA AUI/TP pin changed                                         \\\n                      (21040) */\n#define STATUS_ETI                                                             \\\n  0x00000400 /* early transmit interrupt                                       \\\n                      (21142) */\n#define STATUS_FD                                                              \\\n  0x00000800                         /* full duplex short frame                \\\n                                              received (21040) */\n#define STATUS_TM 0x00000800         /* timer expired (21041) */\n#define STATUS_LNF 0x00001000        /* link fail (21040) */\n#define STATUS_SE 0x00002000         /* system error */\n#define STATUS_ER 0x00004000         /* early receive (21041) */\n#define STATUS_AIS 0x00008000        /* abnormal interrupt summary */\n#define STATUS_NIS 0x00010000        /* normal interrupt summary */\n#define STATUS_RS 0x000e0000         /* receive process state */\n#define STATUS_RS_STOPPED 0x00000000 /* Stopped */\n#define STATUS_RS_FETCH                                                        \\\n  0x00020000 /* Running - fetch receive                                        \\\n                      descriptor */\n#define STATUS_RS_CHECK                                                        \\\n  0x00040000                           /* Running - check for end              \\\n                                                of receive */\n#define STATUS_RS_WAIT 0x00060000      /* Running - wait for packet */\n#define STATUS_RS_SUSPENDED 0x00080000 /* Suspended */\n#define STATUS_RS_CLOSE                                                        \\\n  0x000a0000 /* Running - close receive                                        \\\n                      descriptor */\n#define STATUS_RS_FLUSH                                                        \\\n  0x000c0000 /* Running - flush current                                        \\\n                      frame from FIFO */\n#define STATUS_RS_QUEUE                                                        \\\n  0x000e0000                         /* Running - queue current                \\\n                                              frame from FIFO into             \\\n                                              buffer */\n#define STATUS_TS 0x00700000         /* transmit process state */\n#define STATUS_TS_STOPPED 0x00000000 /* Stopped */\n#define STATUS_TS_FETCH                                                        \\\n  0x00100000 /* Running - fetch transmit                                       \\\n                      descriptor */\n#define STATUS_TS_WAIT                                                         \\\n  0x00200000 /* Running - wait for end                                         \\\n                      of transmission */\n#define STATUS_TS_READING                                                      \\\n  0x00300000                           /* Running - read buffer from           \\\n                                                memory and queue into          \\\n                                                FIFO */\n#define STATUS_TS_RESERVED 0x00400000  /* RESERVED */\n#define STATUS_TS_SETUP 0x00500000     /* Running - Setup packet */\n#define STATUS_TS_SUSPENDED 0x00600000 /* Suspended */\n#define STATUS_TS_CLOSE 0x00700000     /* Running - close transmit descriptor */\n#define STATUS_EB 0x03800000           /* error bits */\n#define STATUS_EB_PARITY 0x00000000    /* parity errror */\n#define STATUS_EB_MABT 0x00800000      /* master abort */\n#define STATUS_EB_TABT 0x01000000      /* target abort */\n#define STATUS_GPPI 0x04000000         /* GPIO interrupt (21142) */\n#define STATUS_LC 0x08000000           /* 100baseTX link change (21142) */\n#define STATUS_X3201_PMEIS                                                     \\\n  0x10000000 /* power management event interrupt summary */\n#define STATUS_X3201_SFIS                                                      \\\n  0x80000000 /* second function (Modem) interrupt status */\n\n/* CSR6 - Operation Mode */\n#define CSR_OPMODE TULIP_CSR6\n#define OPMODE_HP 0x00000001         /* hash/perfect mode (ro) */\n#define OPMODE_SR 0x00000002         /* start receive */\n#define OPMODE_HO 0x00000004         /* hash only mode (ro) */\n#define OPMODE_PB 0x00000008         /* pass bad frames */\n#define OPMODE_IF 0x00000010         /* inverse filter mode (ro) */\n#define OPMODE_SB 0x00000020         /* start backoff counter */\n#define OPMODE_PR 0x00000040         /* promiscuous mode */\n#define OPMODE_PM 0x00000080         /* pass all multicast */\n#define OPMODE_FKD 0x00000100        /* flaky oscillator disable */\n#define OPMODE_FD 0x00000200         /* full-duplex mode */\n#define OPMODE_OM 0x00000c00         /* operating mode */\n#define OPMODE_OM_NORMAL 0x00000000  /*     normal mode */\n#define OPMODE_OM_INTLOOP 0x00000400 /*     internal loopback */\n#define OPMODE_OM_EXTLOOP 0x00000800 /*     external loopback */\n#define OPMODE_FC 0x00001000         /* force collision */\n#define OPMODE_ST 0x00002000         /* start transmitter */\n#define OPMODE_TR 0x0000c000         /* threshold control */\n#define OPMODE_TR_72 0x00000000      /*     72 bytes */\n#define OPMODE_TR_96 0x00004000      /*     96 bytes */\n#define OPMODE_TR_128 0x00008000     /*    128 bytes */\n#define OPMODE_TR_160 0x0000c000     /*    160 bytes */\n#define OPMODE_BP 0x00010000         /* backpressure enable */\n#define OPMODE_CA 0x00020000         /* capture effect enable */\n#define OPMODE_PS 0x00040000 /* port select: 1 = MII/SYM, 0 = SRL (21140) */\n#define OPMODE_HBD                                                             \\\n  0x00080000 /* heartbeat disable: set in MII/SYM 100mbps, set according to    \\\n                PHY in MII 10mbps mode (21140) */\n#define OPMODE_SF 0x00200000 /* store and forward mode (21140) */\n#define OPMODE_TTM                                                             \\\n  0x00400000 /* Transmit Threshold Mode: 1 = 10mbps, 0 = 100mbps (21140) */\n#define OPMODE_PCS 0x00800000    /* PCS function (21140) */\n#define OPMODE_SCR 0x01000000    /* scrambler mode (21140) */\n#define OPMODE_MBO 0x02000000    /* must be one (21140) */\n#define OPMODE_IDAMSB 0x04000000 /* ignore dest addr MSB (21142) */\n#define OPMODE_RA 0x40000000     /* receive all (21140) */\n#define OPMODE_SC 0x80000000     /* special capture effect enable (21041+) */\n\n/* Shorthand for media-related OPMODE bits */\n#define OPMODE_MEDIA_BITS                                                      \\\n  (OPMODE_FD | OPMODE_PS | OPMODE_TTM | OPMODE_PCS | OPMODE_SCR)\n\n/* CSR7 - Interrupt Enable */\n#define CSR_INTEN TULIP_CSR7\n\n/* See bits for CSR5 -- Status */\n\n/* CSR8 - Missed Frames */\n#define CSR_MISSED TULIP_CSR8\n#define MISSED_MFC 0x0000ffff /* missed packet count */\n#define MISSED_MFO                                                             \\\n  0x00010000 /* missed packet count                                            \\\n                      overflowed */\n#define MISSED_FOC                                                             \\\n  0x0ffe0000 /* fifo overflow counter                                          \\\n                      (21140) */\n#define MISSED_OCO                                                             \\\n  0x10000000 /* overflow counter overflowed                                    \\\n                      (21140) */\n\n#define MISSED_GETMFC(x) ((x)&MISSED_MFC)\n#define MISSED_GETFOC(x) (((x)&MISSED_FOC) >> 17)\n\n/* CSR9 - MII, SROM, Boot ROM, Ethernet Address ROM register. */\n#define CSR_MIIROM TULIP_CSR9\n#define MIIROM_DATA 0x000000ff   /* byte of data to/from Boot ROM (21041+) */\n#define MIIROM_SROMCS 0x00000001 /* SROM chip select */\n#define MIIROM_SROMSK 0x00000002 /* SROM clock */\n#define MIIROM_SROMDI 0x00000004 /* SROM data in (to) */\n#define MIIROM_SROMDO 0x00000008 /* SROM data out (from) */\n#define MIIROM_REG 0x00000400    /* external register select */\n#define MIIROM_SR 0x00000800     /* SROM select */\n#define MIIROM_BR 0x00001000     /* boot ROM select */\n#define MIIROM_WR 0x00002000     /* write to boot ROM */\n#define MIIROM_RD 0x00004000     /* read from boot ROM */\n#define MIIROM_MOD 0x00008000    /* mode select (ro) (21041) */\n#define MIIROM_MDC 0x00010000    /* MII clock */\n#define MIIROM_MDO 0x00020000    /* MII data out */\n#define MIIROM_MIIDIR                                                          \\\n  0x00040000                  /* MII direction mode                            \\\n                                       1 = PHY in read,                        \\\n                                       0 = PHY in write */\n#define MIIROM_MDI 0x00080000 /* MII data in */\n#define MIIROM_DN 0x80000000  /* data not valid (21040) */\n\n/* SROM opcodes */\n#define TULIP_SROM_OPC_ERASE 0x04\n#define TULIP_SROM_OPC_WRITE 0x05\n#define TULIP_SROM_OPC_READ 0x06\n\n/* CSR10 - Boot ROM address register (21041+). */\n#define CSR_ROMADDR TULIP_CSR10\n#define ROMADDR_MASK 0x000003ff /* boot rom address */\n\n/* CSR11 - General Purpose Timer (21041+). */\n#define CSR_GPT TULIP_CSR11\n#define GPT_VALUE 0x0000ffff /* timer value */\n#define GPT_CON 0x00010000   /* continuous mode */\n\n/* 21143-PD and 21143-TD Interrupt Mitigation bits */\n#define GPT_NRX 0x000e0000   /* number of Rx packets */\n#define GPT_RXT 0x00f00000   /* Rx timer */\n#define GPT_NTX 0x07000000   /* number of Tx packets */\n#define GPT_TXT 0x78000000   /* Tx timer */\n#define GPT_CYCLE 0x80000000 /* cycle size */\n\n/* CSR12 - SIA Status Register. */\n#define CSR_SIASTAT TULIP_CSR12\n#define SIASTAT_PAUI 0x00000001  /* pin AUI/TP indication (21040) */\n#define SIASTAT_MRA 0x00000001   /* MII receive activity (21142) */\n#define SIASTAT_NCR 0x00000002   /* network connection error */\n#define SIASTAT_LS100 0x00000002 /* 100baseT link status 0 == pass (21142) */\n#define SIASTAT_LKF 0x00000004   /* link fail status */\n#define SIASTAT_LS10 0x00000004  /* 10baseT link status 0 == pass (21142) */\n#define SIASTAT_APS 0x00000008   /* auto polarity status */\n#define SIASTAT_DSD 0x00000010   /* PLL self test done */\n#define SIASTAT_DSP 0x00000020   /* PLL self test pass */\n#define SIASTAT_DAZ 0x00000040   /* PLL all zero */\n#define SIASTAT_DAO 0x00000080   /* PLL all one */\n#define SIASTAT_SRA 0x00000100   /* selected port receive activity (21041) */\n#define SIASTAT_ARA 0x00000100   /* AUI receive activity (21142) */\n#define SIASTAT_NRA                                                            \\\n  0x00000200                   /* non-selected port receive activity (21041)   \\\n                                */\n#define SIASTAT_TRA 0x00000200 /* 10base-T receive activity (21142) */\n#define SIASTAT_NSN 0x00000400 /* non-stable NLPs detected (21041) */\n#define SIASTAT_TRF 0x00000800 /* transmit remote fault (21041) */\n#define SIASTAT_ANS 0x00007000 /* autonegotiation state (21041) */\n#define SIASTAT_ANS_DIS 0x00000000       /*     disabled */\n#define SIASTAT_ANS_TXDIS 0x00001000     /*     transmit disabled */\n#define SIASTAT_ANS_START 0x00001000     /*     (MX98715AEC) */\n#define SIASTAT_ANS_ABD 0x00002000       /*     ability detect */\n#define SIASTAT_ANS_ACKD 0x00003000      /*     acknowledge detect */\n#define SIASTAT_ANS_ACKC 0x00004000      /*     complete acknowledge */\n#define SIASTAT_ANS_FLPGOOD 0x00005000   /*     FLP link good */\n#define SIASTAT_ANS_LINKCHECK 0x00006000 /*     link check */\n#define SIASTAT_LPN 0x00008000           /* link partner negotiable (21041) */\n#define SIASTAT_LPC 0xffff0000           /* link partner code word */\n#define SIASTAT_GETLPC(x) (((x)&SIASTAT_LPC) >> 16)\n\n/* CSR13 - SIA Connectivity Register. */\n#define CSR_SIACONN TULIP_CSR13\n#define SIACONN_SRL 0x00000001 /* SIA reset (0 == reset) */\n#define SIACONN_PS 0x00000002  /* pin AUI/TP selection (21040) */\n#define SIACONN_CAC 0x00000004 /* CSR autoconfiguration */\n#define SIACONN_AUI 0x00000008 /* select AUI (0 = TP) */\n#define SIACONN_EDP 0x00000010 /* SIA PLL external input enable (21040) */\n#define SIACONN_ENI 0x00000020 /* encoder input multiplexer (21040) */\n#define SIACONN_SIM                                                            \\\n  0x00000040                   /* serial interface input multiplexer (21040)   \\\n                                */\n#define SIACONN_ASE 0x00000080 /* APLL start enable (21040) */\n#define SIACONN_SEL                                                            \\\n  0x00000f00 /* external port output multiplexer select (21040) */\n#define SIACONN_IE 0x00001000      /* input enable (21040) */\n#define SIACONN_OE1_3 0x00002000   /* output enable 1, 3 (21040) */\n#define SIACONN_OE2_4 0x00004000   /* output enable 2, 4 (21040) */\n#define SIACONN_OE5_6_7 0x00008000 /* output enable 5, 6, 7 (21040) */\n#define SIACONN_SDM                                                            \\\n  0x0000ef00 /* SIA diagnostic mode; always set to this value for normal       \\\n                operation (21041) */\n\n/* CSR14 - SIA Transmit Receive Register. */\n#define CSR_SIATXRX TULIP_CSR14\n#define SIATXRX_ECEN 0x00000001         /* encoder enable */\n#define SIATXRX_LBK 0x00000002          /* loopback enable */\n#define SIATXRX_DREN 0x00000004         /* driver enable */\n#define SIATXRX_LSE 0x00000008          /* link pulse send enable */\n#define SIATXRX_CPEN 0x00000030         /* compensation enable */\n#define SIATXRX_CPEN_DIS0 0x00000000    /*     disabled */\n#define SIATXRX_CPEN_DIS1 0x00000010    /*     disabled */\n#define SIATXRX_CPEN_HIGHPWR 0x00000020 /*     high power */\n#define SIATXRX_CPEN_NORMAL 0x00000030  /*     normal */\n#define SIATXRX_MBO 0x00000040          /* must be one (21041 pass 2) */\n#define SIATXRX_TH 0x00000040           /* 10baseT HDX enable (21142) */\n#define SIATXRX_ANE 0x00000080 /* autonegotiation enable (21041/21142) */\n#define SIATXRX_RSQ 0x00000100 /* receive squelch enable */\n#define SIATXRX_CSQ 0x00000200 /* collision squelch enable */\n#define SIATXRX_CLD 0x00000400 /* collision detect enable */\n#define SIATXRX_SQE 0x00000800 /* signal quality generation enable */\n#define SIATXRX_LTE 0x00001000 /* link test enable */\n#define SIATXRX_APE 0x00002000 /* auto-polarity enable */\n#define SIATXRX_SPP 0x00004000 /* set polarity plus */\n#define SIATXRX_TAS                                                            \\\n  0x00008000 /* 10base-T/AUI autosensing enable (21041/21142) */\n#define SIATXRX_THX 0x00010000 /* 100baseTX-HDX (21142) */\n#define SIATXRX_TXF 0x00020000 /* 100baseTX-FDX (21142) */\n#define SIATXRX_T4 0x00040000  /* 100baseT4 (21142) */\n\n/* CSR15 - SIA General Register. */\n#define CSR_SIAGEN TULIP_CSR15\n#define SIAGEN_JBD 0x00000001  /* jabber disable */\n#define SIAGEN_HUJ 0x00000002  /* host unjab */\n#define SIAGEN_JCK 0x00000004  /* jabber clock */\n#define SIAGEN_ABM 0x00000008  /* BNC select (21041) */\n#define SIAGEN_RWD 0x00000010  /* receive watchdog disable */\n#define SIAGEN_RWR 0x00000020  /* receive watchdog release */\n#define SIAGEN_LE1 0x00000040  /* LED 1 enable (21041) */\n#define SIAGEN_LV1 0x00000080  /* LED 1 value (21041) */\n#define SIAGEN_TSCK 0x00000100 /* test clock */\n#define SIAGEN_FUSQ 0x00000200 /* force unsquelch */\n#define SIAGEN_FLF 0x00000400  /* force link fail */\n#define SIAGEN_LSD 0x00000800  /* LED stretch disable (21041) */\n#define SIAGEN_LEE 0x00000800  /* Link extend enable (21142) */\n#define SIAGEN_DPST 0x00001000 /* PLL self-test start */\n#define SIAGEN_FRL 0x00002000  /* force receiver low */\n#define SIAGEN_LE2 0x00004000  /* LED 2 enable (21041) */\n#define SIAGEN_RMP 0x00004000  /* received magic packet (21143) */\n#define SIAGEN_LV2 0x00008000  /* LED 2 value (21041) */\n#define SIAGEN_HCKR 0x00008000 /* hacker (21143) */\n#define SIAGEN_MD 0x000f0000   /* general purpose mode/data */\n#define SIAGEN_LGS0 0x00100000 /* LED/GEP 0 select */\n#define SIAGEN_LGS1 0x00200000 /* LED/GEP 1 select */\n#define SIAGEN_LGS2 0x00400000 /* LED/GEP 2 select */\n#define SIAGEN_LGS3 0x00800000 /* LED/GEP 3 select */\n#define SIAGEN_GEI0 0x01000000 /* GEP pin 0 intr enable */\n#define SIAGEN_GEI1 0x02000000 /* GEP pin 1 intr enable */\n#define SIAGEN_RME 0x04000000  /* receive match enable */\n#define SIAGEN_CWE 0x08000000  /* control write enable */\n#define SIAGEN_GI0 0x10000000  /* GEP pin 0 interrupt */\n#define SIAGEN_GI1 0x20000000  /* GEP pin 1 interrupt */\n#define SIAGEN_RMI 0x40000000  /* receive match interrupt */\n\n/* CSR12 - General Purpose Port (21140+). */\n#define CSR_GPP TULIP_CSR12\n#define GPP_MD 0x000000ff  /* general purpose mode/data */\n#define GPP_GPC 0x00000100 /* general purpose control */\n\n/*\n * Digital Semiconductor 21142/21143 registers.\n */\n\n/* SIA configuration for 10baseT (from the 21143 manual) */\n#define SIACONN_21142_10BASET 0x00000001\n#define SIATXRX_21142_10BASET 0x00007f3f\n#define SIAGEN_21142_10BASET 0x00000008\n\n/* SIA configuration for 10baseT full-duplex (from the 21143 manual) */\n#define SIACONN_21142_10BASET_FDX 0x00000001\n#define SIATXRX_21142_10BASET_FDX 0x00007f3d\n#define SIAGEN_21142_10BASET_FDX 0x00000008\n\n/* SIA configuration for 10base5 (from the 21143 manual) */\n#define SIACONN_21142_AUI 0x00000009\n#define SIATXRX_21142_AUI 0x00004705\n#define SIAGEN_21142_AUI 0x0000000e\n\n/* SIA configuration for 10base2 (from the 21143 manual) */\n#define SIACONN_21142_BNC 0x00000009\n#define SIATXRX_21142_BNC 0x00004705\n#define SIAGEN_21142_BNC 0x00000006\n#endif /* _DEV_IC_TULIPREG_H_ */\n"
  },
  {
    "path": "src/DMA.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"DMA.hpp\"\n#include \"AliM1543C.hpp\"\n#include \"PCIDevice.hpp\"\n#include \"StdAfx.hpp\"\n#include \"System.hpp\"\n\n#define DEBUG_DMA\n\nCDMA *theDMA = 0;\n\n/**\n * Constructor.\n **/\nCDMA::CDMA(CConfigurator *cfg, CSystem *c) : CSystemComponent(cfg, c) {\n  int i;\n\n  // DMA Setup\n#define LEGACY_IO(id, port, size)                                              \\\n  c->RegisterMemory(this, id, U64(0x00000801fc000000) + port, size)\n  LEGACY_IO(DMA0_IO_CHANNEL, 0x00, 8);\n  LEGACY_IO(DMA0_IO_MAIN, 0x08, 8);\n  LEGACY_IO(DMA_IO_LPAGE, 0x81, 11);\n  LEGACY_IO(DMA1_IO_CHANNEL, 0xc0, 16);\n  LEGACY_IO(DMA1_IO_MAIN, 0xd0, 16);\n  LEGACY_IO(DMA_IO_HPAGE, 0x481, 11);\n  LEGACY_IO(DMA0_IO_EXT, 0x040b, 1);\n  LEGACY_IO(DMA1_IO_EXT, 0x04D6, 1);\n\n  for (i = 0; i < 8; i++) {\n    state.channel[i].c_lobyte = true;\n    state.channel[i].a_lobyte = true;\n  }\n  state.controller[0].mask = 0xff;\n  state.controller[1].mask = 0xff;\n\n  theDMA = this;\n  printf(\"dma: $Id: DMA.cpp,v 1.9 2008/04/29 09:24:52 iamcamiel Exp $\\n\");\n}\n\n/**\n * Destructor.\n **/\nCDMA::~CDMA() {}\nint CDMA::DoClock() { return 0; }\n\nconst char *dma_index_names[] = {\n    \"DMA0_IO_MAIN\",    \"DMA1_IO_MAIN\",    \"DMA_IO_LPAGE\", \"DMA_IO_HPAGE\",\n    \"DMA0_IO_CHANNEL\", \"DMA1_IO_CHANNEL\", \"DMA0_IO_EXT\",  \"DMA1_IO_EXT\"};\n#define DMA_INDEX(n) dma_index_names[n - DMA_IO_BASE]\n\nu64 CDMA::ReadMem(int index, u64 address, int dsize) {\n  u64 ret;\n  u8 data = 0;\n  int num;\n  // printf(\"dma: Readmem %s, %\" PRIx64 \", %x\\n\",DMA_INDEX(index),address, dsize);\n  switch (dsize) {\n  case 32:\n    ret = ReadMem(index, address, 8);\n    ret |= ReadMem(index, address + 1, 8) << 8;\n    ret |= ReadMem(index, address + 2, 8) << 16;\n    ret |= ReadMem(index, address + 3, 8) << 32;\n    return ret;\n\n  case 16:\n    ret = ReadMem(index, address, 8);\n    ret |= ReadMem(index, address + 1, 8) << 8;\n    return ret;\n\n  case 8:\n\n    if (index == DMA1_IO_CHANNEL || index == DMA1_IO_MAIN)\n      address >>= 1;\n\n    switch (index) {\n    case DMA0_IO_CHANNEL:\n    case DMA1_IO_CHANNEL:\n      num = ((address & 0x0e) >> 1) + (index * 4);\n      if (address & 1) {\n        // word count registers\n        data = (state.channel[num].count >>\n                (state.channel[num].c_lobyte ? 8 : 0)) &\n               0xff;\n        state.channel[num].c_lobyte = !state.channel[num].c_lobyte;\n      } else {\n        // base address\n        data = (state.channel[num].current >>\n                (state.channel[num].a_lobyte ? 8 : 0)) &\n               0xff;\n        state.channel[num].a_lobyte = !state.channel[num].a_lobyte;\n      }\n      break;\n\n    case DMA0_IO_MAIN:\n    case DMA1_IO_MAIN:\n      num = ((address & 0x0e) >> 1) + ((index - DMA_IO_BASE) * 4);\n      printf(\"num: %d\\n\", num);\n      for (int i = 0; i < 4; i++)\n        data |= ((state.channel[(num * 4) + i].count ==\n                  state.channel[(num * 4) + 1].current)\n                     ? 1\n                     : 0)\n                << i;\n      data |= (state.controller[num].request & 0x0f) << 4;\n      break;\n\n    default:\n      FAILURE(InvalidArgument, \"dma: ReadMem index out of range\");\n    }\n\n#if defined(DEBUG_DMA)\n    printf(\"dma: read %s,%\" PRIx64 \": %\" PRIx8 \".   \\n\", DMA_INDEX(index),\n           address, data);\n#endif\n  }\n\n  return data;\n}\n\nvoid CDMA::WriteMem(int index, u64 address, int dsize, u64 data) {\n  int num = 0;\n  int channelmap[] = {2, 3, 1, 0xff, 0xff, 0xff, 0, 0xff,\n                      6, 7, 5, 0xff, 0xff, 0xff, 4};\n  switch (dsize) {\n  case 32:\n    WriteMem(index, address + 0, 8, (data >> 0) & 0xff);\n    WriteMem(index, address + 1, 8, (data >> 8) & 0xff);\n    WriteMem(index, address + 2, 8, (data >> 16) & 0xff);\n    WriteMem(index, address + 3, 8, (data >> 24) & 0xff);\n    return;\n\n  case 16:\n    WriteMem(index, address + 0, 8, (data >> 0) & 0xff);\n    WriteMem(index, address + 1, 8, (data >> 8) & 0xff);\n    return;\n\n  case 8:\n    data &= 0xff;\n    if (index == DMA1_IO_CHANNEL || index == DMA1_IO_MAIN)\n      address >>= 1;\n\n#if defined(DEBUG_DMA)\n      // printf(\"dma: write %s, %02x: %02x.   \\n\", DMA_INDEX(index),\n      // (u32)address, data);\n#endif\n    switch (index) {\n    case DMA1_IO_CHANNEL:\n      num = 1;\n    case DMA0_IO_CHANNEL:\n      num = ((address & 0x0e) >> 1) + (num * 4);\n      if (address & 1) {\n        if (state.channel[num].c_lobyte)\n          state.channel[num].count = (state.channel[num].count & 0xff00) | data;\n        else\n          state.channel[num].count =\n              (state.channel[num].count & 0xff) | (data << 8);\n        state.channel[num].c_lobyte = !state.channel[num].c_lobyte;\n#if defined(DEBUG_DMA)\n        printf(\"dma channel %d count: %04x\\n\", num, state.channel[num].count);\n#endif\n      } else {\n        if (state.channel[num].a_lobyte)\n          state.channel[num].base = (state.channel[num].base & 0xff00) | data;\n        else\n          state.channel[num].base =\n              (state.channel[num].base & 0xff) | (data << 8);\n        state.channel[num].a_lobyte = !state.channel[num].a_lobyte;\n#if defined(DEBUG_DMA)\n        printf(\"dma channel %d base: %04x\\n\", num, state.channel[num].count);\n#endif\n      }\n      break;\n\n    case DMA1_IO_MAIN:\n      num = 1;\n    case DMA0_IO_MAIN:\n      switch (address) {\n      case 0: // command\n        printf(\"dma: command register %d written with %\" PRIx64 \"\\n\", num,\n               data);\n        state.controller[num].command = data;\n        break;\n\n      case 1: // request\n        set_request(num, data & 0x03, (data & 0x04) >> 2);\n        break;\n\n      case 2: // single mask\n        printf(\"dma: mask single on %d : %\" PRIx64 \" %s\\n\", num, data & 0x03,\n               data & 0x4 ? \"Masked\" : \"Unmasked\");\n        state.controller[num].mask =\n            (state.controller[num].mask & ~(1 << (data & 0x03))) |\n            ((data & 0x04) >> 2);\n        printf(\"     Mask status: %x\\n\", state.controller[num].mask);\n        do_dma();\n        break;\n\n      case 3: // mode register\n        printf(\"dma: mode register %d for channel %\" PRIx64\n               \" written with %\" PRIx64 \"\\n\",\n               num, (num * 4) + (data & 0x03), data);\n        printf(\"    Mode: %s, Address %s, Autoinit %s, Command: %s\\n\",\n               (data & 0x80 ? (data & 0x40 ? \"Cascade\" : \"Block\")\n                            : (data & 0x40 ? \"Single\" : \"Demand\")),\n               (data & 0x20 ? \"Increment\" : \"Decrement\"),\n               (data & 0x10 ? \"Enable\" : \"Disable\"),\n               (data & 0x08 ? (data & 0x04 ? \"Illegal\" : \"Read\")\n                            : (data & 0x04 ? \"Write\" : \"Verify\")));\n\n        state.channel[(num * 4) + (data & 0x03)].mode = data;\n        break;\n\n      case 4: // clear flipflop(s)\n        printf(\"dma: flipflops cleared for dma %d\\n\", num);\n        for (int i = (num * 4); i < ((num + 1) * 4); i++)\n          state.channel[i].a_lobyte = state.channel[i].c_lobyte = true;\n        break;\n\n      case 5: // master reset\n#if defined(DEBUG_DMA)\n        printf(\"DMA-I-RESET: DMA %d reset.\", index - DMA_IO_BASE);\n#endif\n        for (int i = (num * 4); i < ((num + 1) * 4); i++)\n          state.channel[i].a_lobyte = state.channel[i].c_lobyte = true;\n        state.controller[num].mask = 0xff;\n        break;\n\n      case 6: // master enable\n        state.controller[num].mask = 0x00;\n        do_dma();\n        break;\n\n      case 7: // master mask\n        state.controller[num].mask = data;\n        do_dma();\n        break;\n      }\n      break;\n\n    case DMA_IO_LPAGE:\n    case DMA_IO_HPAGE:\n      if (channelmap[address] == 0xff) {\n        printf(\"dma: unknown page register %\" PRIx64 \"\\n\", address);\n        return;\n      }\n      num = channelmap[address];\n      if (index == DMA_IO_LPAGE)\n        state.channel[num].pagebase =\n            (state.channel[num].pagebase & 0xff00) | data;\n      else\n        state.channel[num].pagebase =\n            (state.channel[num].pagebase & 0xff) | (data << 8);\n\n#if defined(DEBUG_DMA)\n      printf(\"dma channel %d pagebase: %04x\\n\", num,\n             state.channel[num].pagebase);\n#endif\n\n      break;\n\n    case DMA0_IO_EXT:\n    case DMA1_IO_EXT:\n      printf(\"dma: extended mode register %d written: %\" PRIx64 \"\\n\",\n             index - DMA0_IO_EXT, data);\n      break;\n\n    default:\n      FAILURE(InvalidArgument, \"dma: WriteMem index out of range\");\n    }\n\n    return;\n  }\n}\n\nstatic u32 dma_magic1 = 0x65324387;\nstatic u32 dma_magic2 = 0x24092875;\n\n/**\n * Save state to a Virtual Machine State file.\n **/\nint CDMA::SaveState(FILE *f) {\n  long ss = sizeof(state);\n\n  fwrite(&dma_magic1, sizeof(u32), 1, f);\n  fwrite(&ss, sizeof(long), 1, f);\n  fwrite(&state, sizeof(state), 1, f);\n  fwrite(&dma_magic2, sizeof(u32), 1, f);\n  printf(\"dma: %ld bytes saved.\\n\", ss);\n  return 0;\n}\n\n/**\n * Restore state from a Virtual Machine State file.\n **/\nint CDMA::RestoreState(FILE *f) {\n  long ss;\n  u32 m1;\n  u32 m2;\n  size_t r;\n\n  r = fread(&m1, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"dma: unexpected end of file!\\n\");\n    return -1;\n  }\n\n  if (m1 != dma_magic1) {\n    printf(\"dma: MAGIC 1 does not match!\\n\");\n    return -1;\n  }\n\n  r = fread(&ss, sizeof(long), 1, f);\n  if (r != 1) {\n    printf(\"dma: unexpected end of file!\\n\");\n    return -1;\n  }\n\n  if (ss != sizeof(state)) {\n    printf(\"dma: STRUCT SIZE does not match!\\n\");\n    return -1;\n  }\n\n  r = fread(&state, sizeof(state), 1, f);\n  if (r != 1) {\n    printf(\"dma: unexpected end of file!\\n\");\n    return -1;\n  }\n\n  r = fread(&m2, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"dma: unexpected end of file!\\n\");\n    return -1;\n  }\n\n  if (m2 != dma_magic2) {\n    printf(\"dma: MAGIC 1 does not match!\\n\");\n    return -1;\n  }\n\n  printf(\"dma: %ld bytes restored.\\n\", ss);\n  return 0;\n}\n\n/**\n * Set the software request bit for a channel, and initiate DMA\n **/\nvoid CDMA::set_request(int num, int channel, int data) {\n  state.controller[num].request =\n      (state.controller[num].request & ~(1 << (data & 0x03))) |\n      ((data & 0x04) >> 2);\n  state.channel[(num * 4) + (data & 0x03)].current = 0;\n  do_dma();\n}\n\n/**\n * Perform a DMA if one is ready.\n *\n * \\todo I'm not sure what would actually trigger this, so its mostly just a\n * placeholder.\n **/\nvoid CDMA::do_dma() {\n  for (int ctrlr = 0; ctrlr < 2; ctrlr++) {\n    if ((state.controller[ctrlr].command & 0x04) ==\n        0) // controller not disabled.\n    {\n      for (int chnl = 0; chnl < 4; chnl++) {\n        if ((state.controller[ctrlr].mask & (1 << chnl)) ==\n            0) // channel not masked\n        {\n          if (state.controller[ctrlr].request &\n              (1 << chnl)) // channel has request\n          {\n            // Do it!\n          }\n        }\n      }\n    }\n  }\n}\n\n/**\n * This can be called by a device to perform a DMA in one fell swoop.\n **/\n\nvoid CDMA::send_data(int channel, void *data) {\n  if ((state.controller[channel < 4 ? 0 : 1].command & 0x04) == 0) {\n    if ((state.controller[channel < 4 ? 0 : 1].mask & (1 << channel)) == 0) {\n      u64 addr =\n          (state.channel[channel].pagebase << 16) + state.channel[channel].base;\n      int count = get_count(channel);\n\n      printf(\"DMA send_data:  %x @ %16\" PRIx64 \"x\\n  \", count, addr);\n      for (int i = 0; i < count; i++) {\n        printf(\"%02x \", *((char *)data + i) & 0xff);\n        if (i % 16 == 15)\n          printf(\"\\n  \");\n      }\n      printf(\"\\n\");\n\n      // increment\n      theAli->do_pci_write(addr, data, 1, count);\n\n      // set the terminal count bit\n      if (channel < 4)\n        state.controller[0].status |= 1 << channel;\n      else\n        state.controller[1].status |= 1 << channel;\n    } else {\n      printf(\"dma: dma requested by device on channel %d, but it is masked.\\n\",\n             channel);\n    }\n  } else {\n    printf(\"dma: dma requested by device, but controller %d is disabled.\\n\",\n           channel < 4 ? 0 : 1);\n  }\n}\n\nvoid CDMA::recv_data(int channel, void *data) {}\n"
  },
  {
    "path": "src/DMA.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_DMA_H)\n#define INCLUDED_DMA_H\n\n#include \"SystemComponent.hpp\"\n\n/**\n * \\brief Emulated DMA controller.\n **/\n\nclass CDMA : public CSystemComponent {\npublic:\n  CDMA(CConfigurator *cfg, CSystem *c);\n  virtual ~CDMA();\n\n  virtual int DoClock();\n  virtual void WriteMem(int index, u64 address, int dsize, u64 data);\n  virtual u64 ReadMem(int index, u64 address, int dsize);\n  virtual int SaveState(FILE *f);\n  virtual int RestoreState(FILE *f);\n\n  void set_request(int index, int channel, int data);\n  void send_data(int channel, void *data);\n  void recv_data(int channel, void *data);\n  int get_count(int channel) { return state.channel[channel].count; };\n\nprivate:\n  void do_dma();\n\n  /// The state structure contains all elements that need to be saved to the\n  /// statefile.\n  struct SDMA_state {\n    /// DMA channel state\n    struct SDMA_chan {\n      bool a_lobyte; // address lobyte expected\n      bool c_lobyte; // count lobyte expected\n      u16 current;\n      u16 base;\n      u16 pagebase;\n      u16 count;\n      u8 mode;\n    } channel[8];\n\n    /// DMA controller state\n    struct SDMA_ctrl {\n      u8 status;\n      u8 command;\n      u8 request;\n      u8 mask;\n    } controller[2];\n  } state;\n};\n\n#define DMA_IO_BASE 0x1000\n#define DMA0_IO_MAIN DMA_IO_BASE + 0\n#define DMA1_IO_MAIN DMA_IO_BASE + 1\n#define DMA_IO_LPAGE DMA_IO_BASE + 2\n#define DMA_IO_HPAGE DMA_IO_BASE + 3\n#define DMA0_IO_CHANNEL DMA_IO_BASE + 4\n#define DMA1_IO_CHANNEL DMA_IO_BASE + 5\n#define DMA0_IO_EXT DMA_IO_BASE + 6\n#define DMA1_IO_EXT DMA_IO_BASE + 7\n\nextern CDMA *theDMA;\n\n#endif // !defined(INCLUDED_DMA_H)\n"
  },
  {
    "path": "src/DPR.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"DPR.hpp\"\n#include \"AlphaCPU.hpp\"\n#include \"Serial.hpp\"\n#include \"StdAfx.hpp\"\n#include \"System.hpp\"\n#include <time.h>\n\n#define ToBCD(x) (((x) / 10 << 4) | ((x) % 10))\n\nextern CSerial *srl[2];\n\n/**\n * Constructor.\n **/\nCDPR::CDPR(CConfigurator *cfg, CSystem *c) : CSystemComponent(cfg, c) {\n  if (theDPR)\n    FAILURE(Configuration, \"More than one DPR\");\n  theDPR = this;\n\n  c->RegisterMemory(this, 0, U64(0x0000080110000000), 0x100000); // 16KB\n}\n\n/**\n * Initialize the DPR device.\n **/\nvoid CDPR::init() {\n  int i;\n\n  memset(&state, 0, sizeof(state));\n  RestoreStateF();\n\n  for (i = 0; i < cSystem->get_cpu_num(); i++) {\n    state.ram[i * 0x20 + 0x00] = 1;                   // EV6 BIST\n    state.ram[i * 0x20 + 0x01] = (i == 0) ? 0x80 : i; // SROM status\n    state.ram[i * 0x20 + 0x02] = 1;                   // STR status\n    state.ram[i * 0x20 + 0x03] = 1;                   // CSC status\n    state.ram[i * 0x20 + 0x04] = 1;                   // Pchip0 status\n    state.ram[i * 0x20 + 0x05] = 1;                   // Pchip1 status\n    state.ram[i * 0x20 + 0x06] = 1;                   // DIMx status\n    state.ram[i * 0x20 + 0x07] = 1;                   // TIG bus status\n    state.ram[i * 0x20 + 0x08] = 0xdd;                // DPR test started\n    state.ram[i * 0x20 + 0x09] = 1;                   // DPR status\n    state.ram[i * 0x20 + 0x0a] = 0xff;                // CPU speed status\n    state.ram[i * 0x20 + 0x0b] =\n        (cSystem->get_cpu(i)->get_speed() / 1000000) % 256; // speed\n    state.ram[i * 0x20 + 0x0c] =\n        (cSystem->get_cpu(i)->get_speed() / 1000000) / 256; // speed\n\n    // powerup time BCD:\n    time_t now = time(NULL);\n\n    // Check for absolute time override at system level\n    char *faketime = myCfg->get_text_value(\"time\");\n    if (faketime) {\n      struct tm ft;\n      memset(&ft, 0, sizeof(ft));\n      ft.tm_isdst = -1;\n      if (sscanf(faketime, \"%d-%d-%d %d:%d:%d\", &ft.tm_year, &ft.tm_mon,\n                 &ft.tm_mday, &ft.tm_hour, &ft.tm_min, &ft.tm_sec) >= 3) {\n        ft.tm_year -= 1900;\n        ft.tm_mon -= 1;\n        now = mktime(&ft);\n      }\n    }\n\n    struct tm *t = localtime(&now);\n    state.ram[i * 0x20 + 0x10] = ToBCD(t->tm_hour);\n    state.ram[i * 0x20 + 0x11] = ToBCD(t->tm_min);\n    state.ram[i * 0x20 + 0x12] = ToBCD(t->tm_sec);\n    state.ram[i * 0x20 + 0x13] = ToBCD(t->tm_mday);\n    state.ram[i * 0x20 + 0x14] = ToBCD(t->tm_mon + 1);\n    state.ram[i * 0x20 + 0x15] =\n        ToBCD(t->tm_year - 100); // tm_year is based on 1900\n#if defined(DEBUG_DPR)\n    printf(\"%%DPR-I-BOOTDATE: %02x-%02x-%02x, %02x:%02x:%02x\\n\",\n           state.ram[i * 0x20 + 21], state.ram[i * 0x20 + 20],\n           state.ram[i * 0x20 + 19], state.ram[i * 0x20 + 16],\n           state.ram[i * 0x20 + 17], state.ram[i * 0x20 + 18]);\n#endif\n    state.ram[i * 0x20 + 0x16] = 0; // no error\n    state.ram[i * 0x20 + 0x1e] =\n        0x80; // CPU SROM sync moet 0x80 zijn; anders --> cpu0 startup failure\n    state.ram[i * 0x20 + 0x1f] = 8; // cach size in MB\n  }\n\n  state.ram[0xda] = 0xaa; // TIG load\n\n  // DIMM config\n  state.ram[0x80] = 0xf0; // twice-split 8 dimms array 0\n  state.ram[0x81] = 0x01; // 64 MB\n\n  //    state.ram[0x82] = 0xf1; // twice-split 8 dimms array 1\n  //    state.ram[0x83] = 0x01; // 64 MB\n  //    state.ram[0x84] = 0xf2; // twice-split 8 dimms array 2\n  //    state.ram[0x85] = 0x01; // 64 MB\n  //    state.ram[0x86] = 0xf3; // twice-split 8 dimms array 3\n  //    state.ram[0x87] = 0x01; // 64 MB\n  // powerup failure bits\n  state.ram[0x88] = 0;    // each bit is one DIMM on MMB0\n  state.ram[0x89] = 0x00; // MMB1\n  state.ram[0x8a] = 0x00; // MMB2\n  state.ram[0x8b] = 0x00; // MMB3\n\n  // misconfigured DIMM bits\n  state.ram[0x8c] = 0;    // each bit is one DIMM on MMB0\n  state.ram[0x8d] = 0;    // MMB1\n  state.ram[0x8e] = 0;    // MMB2\n  state.ram[0x8f] = 0;    // MMB3\n  state.ram[0x90] = 0xff; // psu / vterm present\n  state.ram[0x91] = 0x00; // psu ok bits\n  state.ram[0x92] = 0x07; // ac inputs valid\n  state.ram[0x93] = 0x25; // cpu 0 temp in C\n  state.ram[0x94] = 0x25; // cpu 1 temp in C\n  state.ram[0x95] = 0x25; // cpu 2 temp in C\n  state.ram[0x96] = 0x25; // cpu 3 temp in C\n  state.ram[0x97] = 0x25; // pci 0 temp in C\n  state.ram[0x98] = 0x25; // pci 1 temp in C\n  state.ram[0x99] = 0x25; // pci 2 temp in C\n  state.ram[0x9a] = 0x8b; // fan 0 speed\n  state.ram[0x9b] = 0x8b; // fan 1 speed\n  state.ram[0x9c] = 0x8b; // fan 2 speed\n  state.ram[0x9d] = 0x8b; // fan 3 speed\n  state.ram[0x9e] = 0x8b; // fan 4 speed\n  state.ram[0x9f] = 0x8b; // fan 5 speed\n\n  // vector 680 info (various faults)\n  for (i = 0xa0; i < 0xaa; i++)\n    state.ram[i] = 0;\n\n  state.ram[0xaa] = 0x00; // fans good\n\n  // RMC read failure DIMM bits\n  state.ram[0xab] = 0;    // each bit is one DIMM on MMB0\n  state.ram[0xac] = 0xff; // MMB1\n  state.ram[0xad] = 0xff; // MMB2\n  state.ram[0xae] = 0xff; // MMB3\n  switch (cSystem->get_cpu_num()) {\n  case 1:\n    state.ram[0xaf] = 0x0e; // all MMB I2C's read + CPU 0\n    break;\n  case 2:\n    state.ram[0xaf] = 0x0c; // all MMB I2C's read + CPU 0\n    break;\n  case 3:\n    state.ram[0xaf] = 0x08; // all MMB I2C's read + CPU 0\n    break;\n  case 4:\n    state.ram[0xaf] = 0x00; // all MMB I2C's read + CPU 0\n    break;\n  }\n\n  state.ram[0xb0] = 0x00; // PCI i2c read\n  state.ram[0xb1] = 0x00; // mainboard i2c read\n  state.ram[0xb2] = 0x00; // psu's and scsi backplanes i2c read\n  state.ram[0xba] = 0xba; // i2c finished\n  state.ram[0xbb] = 0x00; // rmc error\n  state.ram[0xbc] = 0x00; // rmc flash update error status\n\n  // 680 fatal registers\n  state.ram[0xbd] = 0x07; // ac inputs valid\n  state.ram[0xbe] = 0;    // faults\n  state.ram[0xbf] = 0;    // faults\n  state.ram[0xda] = 0xaa; // tig load success\n\n  // Power-supplies\n  state.ram[0xdb] = 0xf4; // PS0 id\n  state.ram[0xdc] = 0x45; // 3.3v current\n  state.ram[0xdd] = 0x51; // 5.0v current\n  state.ram[0xde] = 0x37; // 12v current\n  state.ram[0xdf] = 0x8b; // fan speed\n  state.ram[0xe0] = 0xd6; // ac voltage (230v)\n  state.ram[0xe1] = 0x49; // internal temp. (56 C)\n  state.ram[0xe2] = 0x4b; // inlet temp. (20 C)\n  state.ram[0xe4] = 0xf5; // PS1 id\n  state.ram[0xe5] = 0x45; // 3.3v current\n  state.ram[0xe6] = 0x51; // 5.0v current\n  state.ram[0xe7] = 0x37; // 12v current\n  state.ram[0xe8] = 0x8b; // fan speed\n  state.ram[0xe9] = 0xd6; // ac voltage (230v)\n  state.ram[0xea] = 0x49; // internal temp. (56 C)\n  state.ram[0xeb] = 0x4b; // inlet temp. (20 C)\n  state.ram[0xed] = 0xf6; // PS2 id\n  state.ram[0xee] = 0x45; // 3.3v current\n  state.ram[0xef] = 0x51; // 5.0v current\n  state.ram[0xf0] = 0x37; // 12v current\n  state.ram[0xf1] = 0x8b; // fan speed\n  state.ram[0xf2] = 0xd6; // ac voltage (230v)\n  state.ram[0xf3] = 0x49; // internal temp. (56 C)\n  state.ram[0xf4] = 0x4b; // inlet temp. (20 C)\n\n  // EEROMs\n\n  /*\n     100: MMB0 DIMM 2\n     200: MMB0 DIMM 3\n     300: MMB0 DIMM 4\n     400: MMB0 DIMM 5\n     500: MMB0 DIMM 6\n     600: MMB0 DIMM 7\n     700: MMB0 DIMM 8\n     800: MMB0 DIMM 1\n     900: MMB1 DIMM 2\n     a00: MMB1 DIMM 3\n     b00: MMB1 DIMM 4\n     c00: MMB1 DIMM 5\n     d00: MMB1 DIMM 6\n     e00: MMB1 DIMM 7\n     f00: MMB1 DIMM 8\n     1000: MMB1 DIMM 1\n     1100: MMB2 DIMM 2\n     1200: MMB2 DIMM 3\n     1300: MMB2 DIMM 4\n     1400: MMB2 DIMM 5\n     1500: MMB2 DIMM 6\n     1600: MMB2 DIMM 7\n     1700: MMB2 DIMM 8\n     1800: MMB2 DIMM 1\n     1900: MMB3 DIMM 2\n     1a00: MMB3 DIMM 3\n     1b00: MMB3 DIMM 4\n     1c00: MMB3 DIMM 5\n     1d00: MMB3 DIMM 6\n     1e00: MMB3 DIMM 7\n     1f00: MMB3 DIMM 8\n     2000: MMB3 DIMM 1\n     2100: CPU0\n     2200: CPU1\n     2300: CPU2\n     2400: CPU3\n     2500: MMB0\n     2600: MMB1\n     2700: MMB2\n     2800: MMB3\n     2900: CPB (PCI backplane)\n     2a00: CSB (motherboard)\n     3100: PSU0 cont @ 3d00\n     3200: PSU1 cont @ 3e00\n     3300: PSU2 cont @ 3f00\n     3b00: SCSI0 (backplane)\n     3c00: SCSI1\n\n     2B00:2BFF  RMC Last EV6 Correctable Error\n     ASCII character string that indicates correctable error occurred, type,\n     FRU, and so on. 2C00:2CFF  RMC Last Redundant Failure ASCII character\n     string that indicates redundant failure occurred, type, FRU, and so on.\n     2D00:2DFF  RMC Last System Failure\n     ASCII character string that indicates system failure occurred, type, FRU,\n     and so on. 2E00:2FFF  RMC Uncorrectable machine logout frame (512 bytes)\n   */\n\n  //    3000:3008       SROM Version (ASCII string)\n  state.ram[0x3000] = 'V';\n  state.ram[0x3001] = '2';\n  state.ram[0x3002] = '.';\n  state.ram[0x3003] = '2';\n  state.ram[0x3004] = '2';\n  state.ram[0x3005] = 'G';\n  state.ram[0x3006] = 0;\n  state.ram[0x3007] = 0;\n  state.ram[0x3008] = 0;\n\n  //    3009:300B       RMC Rev Level of RMC first byte is letter Rev [x/t/v]\n  //    second 2 bytes are major/minor.\n  //                            This is the rev level of the RMC on-chip code.\n  state.ram[0x3009] = 'V';\n  state.ram[0x300a] = 0x31;\n  state.ram[0x300b] = 0x30;\n\n  //    300C:300E       RMC Rev Level of RMC first byte is letter Rev [x/t/v]\n  //    second 2 bytes are major/minor.\n  //                            This is the rev level of the RMC flash code.\n  state.ram[0x300c] = 'V';\n  state.ram[0x300d] = 0x31;\n  state.ram[0x300e] = 0x30;\n\n  //    300F:3010 300F RMC Revision Field of the DPR Structure\n  //    3400 SROM Size of Bcache in MB\n  state.ram[0x3400] = 8;\n\n  // 3401 SROM Flash SROM is valid flag; 8 = valid,0 = invalid\n  state.ram[0x3401] = 8;\n\n  // 3402 SROM System's errors determined by SROM\n  state.ram[0x3402] = 0;\n\n  for (i = 0; i < cSystem->get_cpu_num(); i++) {\n    state.ram[0x3418 + 0x10 * i] = 0xff;\n    // 3410:3417 SROM/SRM Jump to address for CPU0\n    // 3418 SROM/SRM Waiting to jump to flag for CPU0\n    // 3419 SROM Shadow of value written to EV6 DC_CTL register.\n    // 341A:341E SROM Shadow of most recent writes to EV6 CBOX \"Write-many\"\n    // chain.\n  }\n\n  // 34A0:34A7 SROM Array 0 to DIMM ID translation\n  //                                                                            Bits<4:0>\n  //            Bits<7:5>\n  //            0 = Exists, No Error                    Bits <2:0> =\n  //            1 = Expected Missing DIMM                       + 1 (1-8)\n  //            2 = Error - Missing DIMM(s)             Bits <4:3> =\n  //            4 = Error - Illegal MMB                 (0-3) DIMM(s)\n  //            6 = Error - Incompatible DIMM(s)\n  //    34A8:34AF SROM Repeat for Array 1 of Array 0 34A0:34A7\n  //    34B0:34B7 SROM Repeat for Array 2 of Array 0 34A0:34A7\n  //    34B8:34CF SROM Repeat for Array 3 of Array 0 34A0:34A7\n  for (i = 0; i < 0x20; i++)\n    state.ram[0x34a0 + i] = i;\n\n  //    34C0:34FF       Used as scratch area for SROM\n  //    3500:35FF       Used as the dedicated buffer in which SRM writes OCP or\n  //    FRU EEROM data.\n  //                            Firmware will write this data, RMC will only\n  //                            read this data.\n  //    3600:36FF 3600 SRM Reserved\n  //    3700:37FF SRM Reserved\n  //    3800:3AFF RMC RMC scratch space\n  printf(\"%s: $Id: DPR.cpp,v 1.23 2008/06/12 07:29:44 iamcamiel Exp $\\n\",\n         devid_string);\n}\n\n/**\n * Destructor.\n **/\nCDPR::~CDPR() {}\nu64 CDPR::ReadMem(int index, u64 address, int dsize) {\n  u64 data = 0;\n  int a = (int)(address >> 6);\n\n  data = state.ram[a];\n\n#if defined(DEBUG_DPR)\n  printf(\"%%DPR-I-READ: Dual-Port RAM read @ 0x%08x: 0x%02x\\n\", a,\n         (u32)(data & 0xff));\n#endif\n  return data;\n}\n\nvoid CDPR::WriteMem(int index, u64 address, int dsize, u64 data) {\n  int i;\n  int a = (int)(address >> 6);\n#if defined(DEBUG_DPR)\n  printf(\"%%DPR-I-WRITE: Dual-Port RAM write 0x%08x 0x%02x:\\n\", a,\n         (u32)(data & 0xff));\n#endif\n\n  // FOR COMMANDS:\n  //\n  // 0xf9:      buffer size\n  // 0xfb:fa    qualifier / address\n  // 0xfc:      completion code (0 = ok, 80 = error, 81 = invalid code, 82 =\n  // invalid qualifier) 0xfd:      rmc command id for response 0xfe: command\n  // code 0xff:      rmc command id for command COMMANDS: 01:        update\n  // EEPROM 02:        update baud rate 03:        write to OCP F0: update RMC\n  // flash\n  state.ram[a] = (char)data;\n  switch (a) {\n  case 0xff:\n\n    // command\n    state.ram[0xfd] = state.ram[0xff];\n    switch (state.ram[0xfe]) {\n    case 1:\n\n      /*\n         100: MMB0 DIMM 2\n         200: MMB0 DIMM 3\n         300: MMB0 DIMM 4\n         400: MMB0 DIMM 5\n         500: MMB0 DIMM 6\n         600: MMB0 DIMM 7\n         700: MMB0 DIMM 8\n         800: MMB0 DIMM 1\n         900: MMB1 DIMM 2\n         a00: MMB1 DIMM 3\n         b00: MMB1 DIMM 4\n         c00: MMB1 DIMM 5\n         d00: MMB1 DIMM 6\n         e00: MMB1 DIMM 7\n         f00: MMB1 DIMM 8\n         1000: MMB1 DIMM 1\n         1100: MMB2 DIMM 2\n         1200: MMB2 DIMM 3\n         1300: MMB2 DIMM 4\n         1400: MMB2 DIMM 5\n         1500: MMB2 DIMM 6\n         1600: MMB2 DIMM 7\n         1700: MMB2 DIMM 8\n         1800: MMB2 DIMM 1\n         1900: MMB3 DIMM 2\n         1a00: MMB3 DIMM 3\n         1b00: MMB3 DIMM 4\n         1c00: MMB3 DIMM 5\n         1d00: MMB3 DIMM 6\n         1e00: MMB3 DIMM 7\n         1f00: MMB3 DIMM 8\n         2000: MMB3 DIMM 1\n         2100: CPU0\n         2200: CPU1\n         2300: CPU2\n         2400: CPU3\n         2500: MMB0\n         2600: MMB1\n         2700: MMB2\n         2800: MMB3\n         2900: CPB (PCI backplane)\n         2a00: CSB (motherboard)\n         3100: PSU0 cont @ 3d00\n         3200: PSU1 cont @ 3e00\n         3300: PSU2 cont @ 3f00\n         3b00: SCSI0 (backplane)\n         3c00: SCSI1 */\n\n      // FRU-Write\n      switch (state.ram[0xfb]) {\n      case 0x21:\n      case 0x22:\n      case 0x23:\n      case 0x24:\n        if ((state.ram[0xfb] - 0x20) > cSystem->get_cpu_num()) {\n          state.ram[0xfc] = 0x80;\n          break;\n        }\n\n      case 1:\n      case 2:\n      case 3:\n      case 4:\n      case 5:\n      case 6:\n      case 7:\n      case 8:\n      case 0x25:\n      case 0x26:\n      case 0x27:\n      case 0x28:\n      case 0x29:\n      case 0x2a:\n      case 0x31:\n      case 0x32:\n      case 0x33:\n      case 0x3b:\n      case 0x3c:\n      case 0x3d:\n      case 0x3e:\n      case 0x3f:\n        for (i = 0; i < state.ram[0xf9] + 1; i++) {\n          state.ram[state.ram[0xfb] * 0x100 + state.ram[0xfa] + i] =\n              state.ram[0x3500 + state.ram[0xfa] + i];\n#if defined(DEBUG_DPR)\n          printf(\"%%DPR-I-FRU: FRU data %02x @ FRU %02x set to %02x\\n\",\n                 state.ram[0xfa] + i, state.ram[0xfb],\n                 state.ram[0x3500 + state.ram[0xfa] + i]);\n#endif\n        }\n\n        state.ram[0xfc] = 0;\n        break;\n\n      default:\n#if defined(DEBUG_DPR)\n        printf(\"%%DPR-I-RMC: RMC Command given: %02x\\r\\n\", state.ram[0xfe]);\n        printf(\"%%DPR-I-RMC: f9:%02x fb-fa:%02x%02x\\r\\n\", state.ram[0xf9],\n               state.ram[0xfb], state.ram[0xfa]);\n#endif\n        state.ram[0xfc] = 0x80;\n      }\n      break;\n\n    case 2:\n      state.ram[0xfc] = 0;\n      break;\n\n    case 3:\n\n      // OCP-Write\n#if defined(DEBUG_DPR)\n      sprintf(trcbuffer,\n              \"%%%%DPR-I-OCP: OCP Text set to \\\"0123456789abcdef\\\"\\r\\n\");\n      memcpy(trcbuffer + 29, &(state.ram[0x3500]), 16);\n\n      //                    srl[0]->write(trcbuffer);\n      printf(trcbuffer);\n#endif\n      state.ram[0xfc] = 0;\n      break;\n\n    case 0xf0:\n      state.ram[0xfc] = 0;\n\n    default:\n#if defined(DEBUG_DPR)\n      printf(\"%%DPR-I-RMC: RMC Command given: %02x\\r\\n\", state.ram[0xfe]);\n      printf(\"%%DPR-I-RMC: f9:%02x fb-fa:%02x%02x\\r\\n\", state.ram[0xf9],\n             state.ram[0xfb], state.ram[0xfa]);\n#endif\n      state.ram[0xfc] = 0x81;\n    }\n    break;\n\n  case 0xfd:\n\n    // end of command\n    state.ram[0xff] = state.ram[0xfd];\n    break;\n\n  case 0x3428:\n    // start cpu 1\n    if (cSystem->get_cpu_num() > 1) {\n      printf(\"*** DPR *** Starting CPU 1 ***\\n\");\n      cSystem->get_cpu(1)->set_pc(0x8001); // should come from dpr...\n      cSystem->get_cpu(1)->stop_waiting();\n    }\n    break;\n\n  case 0x3438:\n    // start cpu 2\n    if (cSystem->get_cpu_num() > 2) {\n      printf(\"*** DPR *** Starting CPU 2 ***\\n\");\n      cSystem->get_cpu(2)->set_pc(0x8001); // should come from dpr...\n      cSystem->get_cpu(2)->stop_waiting();\n    }\n    break;\n\n  case 0x3448:\n    // start cpu 3\n    if (cSystem->get_cpu_num() > 3) {\n      printf(\"*** DPR *** Starting CPU 3 ***\\n\");\n      cSystem->get_cpu(3)->set_pc(0x8001); // should come from dpr...\n      cSystem->get_cpu(3)->stop_waiting();\n    }\n    break;\n  }\n\n  return;\n}\n\n/**\n * Save state to a DPR rom file.\n **/\nvoid CDPR::SaveStateF(char *fn) {\n  FILE *ff;\n  ff = fopen(fn, \"wb\");\n  if (ff) {\n    SaveState(ff);\n    fclose(ff);\n    printf(\"%%DPR-I-SAVEST: DPR state saved to %s\\n\", fn);\n  } else {\n    printf(\"%%DPR-F-NOSAVE: DPR could not be saved to %s\\n\", fn);\n  }\n}\n\n/**\n * Save state to the default DPR rom file.\n **/\nvoid CDPR::SaveStateF() {\n  SaveStateF(myCfg->get_text_value(\"rom.dpr\", \"dpr.rom\"));\n}\n\n/**\n * Restore state from a DPR rom file.\n **/\nvoid CDPR::RestoreStateF(char *fn) {\n  FILE *ff;\n  ff = fopen(fn, \"rb\");\n  if (ff) {\n    RestoreState(ff);\n    fclose(ff);\n    printf(\"%%DPR-I-RESTST: DPR state restored from %s\\n\", fn);\n  } else {\n    printf(\"%%DPR-F-NOREST: DPR could not be restored from %s\\n\", fn);\n  }\n}\n\nstatic u32 dpr_magic1 = 0x18A7B92D;\nstatic u32 dpr_magic2 = 0xD29B7A81;\n\n/**\n * Save state to a Virtual Machine State file.\n **/\nint CDPR::SaveState(FILE *f) {\n  long ss = sizeof(state);\n\n  fwrite(&dpr_magic1, sizeof(u32), 1, f);\n  fwrite(&ss, sizeof(long), 1, f);\n  fwrite(&state, sizeof(state), 1, f);\n  fwrite(&dpr_magic2, sizeof(u32), 1, f);\n  printf(\"%s: %ld bytes saved.\\n\", \"dpr\", ss);\n  return 0;\n}\n\n/**\n * Restore state from a Virtual Machine State file.\n **/\nint CDPR::RestoreState(FILE *f) {\n  long ss;\n  u32 m1;\n  u32 m2;\n  size_t r;\n\n  r = fread(&m1, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", \"dpr\");\n    return -1;\n  }\n\n  if (m1 != dpr_magic1) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", \"dpr\");\n    return -1;\n  }\n\n  r = fread(&ss, sizeof(long), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", \"dpr\");\n    return -1;\n  }\n\n  if (ss != sizeof(state)) {\n    printf(\"%s: STRUCT SIZE does not match!\\n\", \"dpr\");\n    return -1;\n  }\n\n  r = fread(&state, sizeof(state), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", \"dpr\");\n    return -1;\n  }\n\n  r = fread(&m2, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", \"dpr\");\n    return -1;\n  }\n\n  if (m2 != dpr_magic2) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", \"dpr\");\n    return -1;\n  }\n\n  printf(\"%s: %ld bytes restored.\\n\", \"dpr\", ss);\n  return 0;\n}\n\n/**\n * Restore state from the default DPR rom file.\n **/\nvoid CDPR::RestoreStateF() {\n  RestoreStateF(myCfg->get_text_value(\"rom.dpr\", \"dpr.rom\"));\n}\n\nCDPR *theDPR = 0;\n"
  },
  {
    "path": "src/DPR.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_DPR_H)\n#define INCLUDED_DPR_H\n\n#include \"SystemComponent.hpp\"\n\n/**\n * \\brief Emulated dual-port RAM and management controller.\n **/\nclass CDPR : public CSystemComponent {\npublic:\n  CDPR(CConfigurator *cfg, class CSystem *c);\n  virtual ~CDPR();\n  virtual void init();\n  virtual void WriteMem(int index, u64 address, int dsize, u64 data);\n  virtual u64 ReadMem(int index, u64 address, int dsize);\n  virtual int SaveState(FILE *f);\n  virtual int RestoreState(FILE *f);\n  void SaveStateF();\n  void RestoreStateF();\n  void SaveStateF(char *fn);\n  void RestoreStateF(char *fn);\n\nprotected:\n  /// The state structure contains all elements that need to be saved to the\n  /// statefile.\n  struct SDPR_state {\n    u8 ram[16 * 1024];\n  } state;\n};\n\nextern CDPR *theDPR;\n#endif // !defined(INCLUDED_DPR_H_)\n"
  },
  {
    "path": "src/Disk.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"Disk.hpp\"\n#include \"StdAfx.hpp\"\n\n/**\n * \\brief Constructor.\n **/\nCDisk::CDisk(CConfigurator *cfg, CSystem *sys, CDiskController *ctrl,\n             int idebus, int idedev)\n    : CSystemComponent(cfg, sys) {\n  char *a;\n  char *b;\n  char *c;\n  char *d;\n\n  myCfg = cfg;\n  myCtrl = ctrl;\n  myBus = idebus;\n  myDev = idedev;\n  atapi_mode = false;\n\n  a = myCfg->get_myName();\n  b = myCfg->get_myValue();\n  c = myCfg->get_myParent()->get_myName();\n  d = myCfg->get_myParent()->get_myValue();\n\n  free(devid_string); // we override the default to include the controller.\n  CHECK_ALLOCATION(devid_string = (char *)malloc(strlen(a) + strlen(b) +\n                                                 strlen(c) + strlen(d) + 6));\n  sprintf(devid_string, \"%s(%s).%s(%s)\", c, d, a, b);\n\n  serial_number = myCfg->get_text_value(\"serial_num\", \"ES40EM00000\");\n  revision_number = myCfg->get_text_value(\"rev_num\", \"0.0\");\n  read_only = myCfg->get_bool_value(\"read_only\");\n  is_cdrom = myCfg->get_bool_value(\"cdrom\");\n\n  state.block_size = is_cdrom ? 2048 : 512;\n  state.scsi.sense.available = false;\n\n  myCtrl->register_disk(this, myBus, myDev);\n}\n\n/**\n * \\brief Destructor.\n **/\nCDisk::~CDisk(void) {\n  free(devid_string);\n  devid_string = nullptr;\n}\n\n/**\n * \\Calculate the number of cylinders to report.\n **/\nvoid CDisk::calc_cylinders() {\n  cylinders = byte_size / state.block_size / sectors / heads;\n\n  off_t_large chs_size = sectors * cylinders * heads * state.block_size;\n  if (chs_size < byte_size)\n    cylinders++;\n}\n\n/**\n * \\brief Called when this device is selected.\n *\n * Set status fields up to begin a new SCSI command sequence\n * and set the SCSI bus phase to Message Out.\n **/\nvoid CDisk::scsi_select_me(int bus) {\n  state.scsi.msgo.written = 0;\n  state.scsi.msgi.available = 0;\n  state.scsi.msgi.read = 0;\n  state.scsi.cmd.written = 0;\n  state.scsi.dati.available = 0;\n  state.scsi.dati.read = 0;\n  state.scsi.dato.expected = 0;\n  state.scsi.dato.written = 0;\n  state.scsi.stat.available = 0;\n  state.scsi.stat.read = 0;\n  state.scsi.lun_selected = false;\n\n  // state.scsi.disconnect_priv = false;\n  // state.scsi.will_disconnect = false;\n  // state.scsi.disconnected = false;\n  if (atapi_mode)\n    scsi_set_phase(bus, SCSI_PHASE_COMMAND);\n  else\n    scsi_set_phase(bus, SCSI_PHASE_MSG_OUT);\n}\n\nstatic u32 disk_magic1 = 0xD15D15D1;\nstatic u32 disk_magic2 = 0x15D15D5;\n\n/**\n * Save state to a Virtual Machine State file.\n **/\nint CDisk::SaveState(FILE *f) {\n  long ss = sizeof(state);\n\n  fwrite(&disk_magic1, sizeof(u32), 1, f);\n  fwrite(&ss, sizeof(long), 1, f);\n  fwrite(&state, sizeof(state), 1, f);\n  fwrite(&disk_magic2, sizeof(u32), 1, f);\n  printf(\"%s: %d bytes saved.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\n/**\n * Restore state from a Virtual Machine State file.\n **/\nint CDisk::RestoreState(FILE *f) {\n  long ss;\n  u32 m1;\n  u32 m2;\n  size_t r;\n\n  r = fread(&m1, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m1 != disk_magic1) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&ss, sizeof(long), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (ss != sizeof(state)) {\n    printf(\"%s: STRUCT SIZE does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&state, sizeof(state), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&m2, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m2 != disk_magic2) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  // calc_cylinders(); // state.block_size may have changed.\n  determine_layout();\n\n  printf(\"%s: %d bytes restored.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\n/**\n * \\brief Return the number of bytes expected or available.\n *\n * Return the number of bytes we still expect to receive\n * from the initiator, or still have available for the\n * initiator, in the current SCSI phase.\n *\n * For an overview of data transfer during a SCSI bus phase,\n * see SCSIDevice::scsi_xfer_ptr.\n **/\nsize_t CDisk::scsi_expected_xfer_me(int bus) {\n  switch (scsi_get_phase(0)) {\n  case SCSI_PHASE_DATA_OUT:\n    return state.scsi.dato.expected - state.scsi.dato.written;\n\n  case SCSI_PHASE_DATA_IN:\n    return state.scsi.dati.available - state.scsi.dati.read;\n\n  case SCSI_PHASE_COMMAND:\n    return 256 - state.scsi.cmd.written;\n\n  case SCSI_PHASE_STATUS:\n    return state.scsi.stat.available - state.scsi.stat.read;\n\n  case SCSI_PHASE_MSG_OUT:\n    return 256 - state.scsi.msgo.written;\n\n  case SCSI_PHASE_MSG_IN:\n    return state.scsi.msgi.available - state.scsi.msgi.read;\n\n  default:\n    FAILURE_2(IllegalState, \"%s: transfer requested in phase %d\\n\",\n              devid_string, scsi_get_phase(0));\n  }\n}\n\n/**\n * \\brief Return a pointer where the initiator can read or write data.\n *\n * Return a pointer to where the initiator can read or write\n * (the remainder of) our data in the current SCSI phase.\n *\n * For an overview of data transfer during a SCSI bus phase,\n * see SCSIDevice::scsi_xfer_ptr.\n **/\nvoid *CDisk::scsi_xfer_ptr_me(int bus, size_t bytes) {\n  void *res = 0;\n\n  switch (scsi_get_phase(0)) {\n  case SCSI_PHASE_DATA_OUT:\n    res = &(state.scsi.dato.data[state.scsi.dato.written]);\n    state.scsi.dato.written += bytes;\n    break;\n\n  case SCSI_PHASE_DATA_IN:\n    res = &(state.scsi.dati.data[state.scsi.dati.read]);\n    state.scsi.dati.read += bytes;\n    break;\n\n  case SCSI_PHASE_COMMAND:\n    res = &(state.scsi.cmd.data[state.scsi.cmd.written]);\n    state.scsi.cmd.written += bytes;\n    break;\n\n  case SCSI_PHASE_STATUS:\n    res = &(state.scsi.stat.data[state.scsi.stat.read]);\n    state.scsi.stat.read += bytes;\n    break;\n\n  case SCSI_PHASE_MSG_OUT:\n    res = &(state.scsi.msgo.data[state.scsi.msgo.written]);\n    state.scsi.msgo.written += bytes;\n    break;\n\n  case SCSI_PHASE_MSG_IN:\n\n    // if (PT.reselected)\n    //{\n    //  retval = 0x80; // identify\n    //  break;\n    //}\n    // if (PT.disconnected)\n    //{\n    //  if (!PT.dati_ptr)\n    //    retval = 0x04; // disconnect\n    //  else\n    //  {\n    //    if (state.scsi.msgi.read==0)\n    //    {\n    //      retval = 0x02; // save data pointer\n    //      state.scsi.msgi.read=1;\n    //    }\n    //    else if (state.scsi.msgi.read==1)\n    //    {\n    //      retval = 0x04; // disconnect\n    //      state.scsi.msgi.read=0;\n    //    }\n    //  }\n    //  break;\n    //}\n    res = &(state.scsi.msgi.data[state.scsi.msgi.read]);\n    state.scsi.msgi.read += bytes;\n    break;\n\n  default:\n    FAILURE_2(IllegalState, \"%s: transfer requested in phase %d\\n\",\n              devid_string, scsi_get_phase(0));\n  }\n\n  return res;\n}\n\n/**\n * \\brief Process data written or read.\n *\n * Determine what action (if any) should be taken after a\n * transfer, and what the next SCSI bus phase should be.\n *\n * For an overview of data transfer during a SCSI bus phase,\n * see SCSIDevice::scsi_xfer_ptr.\n *\n * \\todo Handle disconnect/reconnect properly.\n **/\nvoid CDisk::scsi_xfer_done_me(int bus) {\n  int res;\n  int newphase = scsi_get_phase(0);\n\n  switch (scsi_get_phase(0)) {\n  case SCSI_PHASE_DATA_OUT:\n    if (state.scsi.dato.written < state.scsi.dato.expected)\n      break;\n\n    res = do_scsi_command();\n    if (res == 2)\n      FAILURE(IllegalState, \"do_command returned 2 after DATA OUT phase\");\n\n    if (state.scsi.dati.available)\n      newphase = SCSI_PHASE_DATA_IN;\n    else\n      newphase = SCSI_PHASE_STATUS;\n    break;\n\n  case SCSI_PHASE_DATA_IN:\n    if (state.scsi.dati.read < state.scsi.dati.available)\n      break;\n\n    newphase = SCSI_PHASE_STATUS;\n    break;\n\n  case SCSI_PHASE_COMMAND:\n    res = do_scsi_command();\n    if (res == 2)\n      newphase = SCSI_PHASE_DATA_OUT;\n    else if (state.scsi.dati.available)\n      newphase = SCSI_PHASE_DATA_IN;\n    else\n      newphase = SCSI_PHASE_STATUS;\n    break;\n\n  case SCSI_PHASE_STATUS:\n    if (state.scsi.stat.read < state.scsi.stat.available)\n      break;\n\n    if (atapi_mode) {\n      scsi_free(0);\n      return;\n    }\n\n    newphase = SCSI_PHASE_MSG_IN;\n    break;\n\n  case SCSI_PHASE_MSG_OUT:\n    newphase = do_scsi_message(); // command\n    break;\n\n  case SCSI_PHASE_MSG_IN:\n\n    // if (state.scsi.reselected)\n    //{\n    //  state.scsi.reselected = false;\n    //  newphase = state.scsi.disconnect_phase;\n    //}\n    // else if (state.scsi.disconnected)\n    //{\n    //  if (!state.scsi.msgi.read)\n    //    newphase = -1;\n    //}\n    if (state.scsi.msgi.read < state.scsi.msgi.available)\n      break;\n\n    if (state.scsi.cmd.written) {\n      scsi_free(0);\n      return;\n    } else\n      newphase = SCSI_PHASE_COMMAND;\n    break;\n\n  default:\n    FAILURE_2(IllegalState, \"%s: transfer requested in phase %d\\n\",\n              devid_string, scsi_get_phase(0));\n  }\n\n  // if data in and can disconnect...\n  // if (state.phase!=7 && newphase==1 && PT.will_disconnect &&\n  // !PT.disconnected)\n  //{\n  //  printf(\"%s: Disconnecting now...\\n\",devid_string);\n  //  PT.disconnected = true;\n  //  PT.disconnect_phase = newphase;\n  //  newphase = 7; // msg in\n  //}\n  if (newphase != scsi_get_phase(0)) {\n\n    //    if (newphase==-1)\n    //    {\n    //      printf(\"%s: Disconnect. Timer started!\\n\",devid_string);\n    //      // disconnect. generate interrupt?\n    //      state.disconnected = 20;\n    //    }\n    scsi_set_phase(0, newphase);\n  }\n\n  // getchar();\n}\n\n// SCSI commands:\n#define SCSICMD_TEST_UNIT_READY 0x00\n#define SCSICMD_REQUEST_SENSE 0x03\n#define SCSICMD_INQUIRY 0x12\n\n#define SCSICMD_READ 0x08\n#define SCSICMD_READ_10 0x28\n#define SCSICMD_READ_12 0xA8\n#define SCSICMD_READ_16 0x88\n#define SCSICMD_READ_32 0x7F\n#define SCSICMD_READ_LONG 0x3E\n#define SCSICMD_READ_CD 0xBE\n\n#define SCSICMD_WRITE 0x0A\n#define SCSICMD_WRITE_10 0x2A\n#define SCSICMD_WRITE_12 0xAA\n#define SCSICMD_WRITE_LONG 0x3F\n\n#define SCSICMD_MODE_SELECT 0x15\n#define SCSICMD_MODE_SENSE 0x1a\n#define SCSICMD_START_STOP_UNIT 0x1b\n#define SCSICMD_PREVENT_ALLOW_REMOVE 0x1e\n#define SCSICMD_MODE_SENSE_10 0x5a\n\n#define SCSICMD_SYNCHRONIZE_CACHE 0x35\n\n//  SCSI block device commands:\n#define SCSIBLOCKCMD_READ_CAPACITY 0x25\n\n//  SCSI CD-ROM commands:\n#define SCSICDROM_READ_SUBCHANNEL 0x42\n#define SCSICDROM_READ_TOC 0x43\n\n// SCSI CD-R/RW commands:\n#define SCSICDRRW_FORMAT 0x04\n#define SCSICDRRW_READ_DISC_INFO 0x51\n#define SCSICDRRW_READ_TRACK_INFO 0x52\n#define SCSICDRRW_RESERVE_TRACK 0x53\n#define SCSICDRRW_SEND_OPC_INFO 0x54\n#define SCSICDRRW_REPAIR_TRACK 0x58\n#define SCSICDRRW_READ_MASTER_CUE 0x59\n#define SCSICDRRW_CLOSE_TRACK 0x5b\n#define SCSICDRRW_READ_BUFFER_CAP 0x5c\n#define SCSICDRRW_SEND_CUE_SHEET 0x5d\n#define SCSICDRRW_BLANK 0xa1\n\n//  SCSI tape commands:\n#define SCSICMD_REWIND 0x01\n#define SCSICMD_READ_BLOCK_LIMITS 0x05\n#define SCSICMD_SPACE 0x11\n\n// SCSI mode pages:\n#define SCSIMP_VENDOR 0x00\n#define SCSIMP_READ_WRITE_ERRREC 0x01\n#define SCSIMP_DISCONNECT_RECONNECT 0x02\n#define SCSIMP_FORMAT_PARAMS 0x03\n#define SCSIMP_RIGID_GEOMETRY 0x04\n#define SCSIMP_FLEX_PARAMS 0x05\n#define SCSIMP_CACHING 0x08\n#define SCSIMP_CDROM_CAP 0x2A\n\n#define SCSI_OK 0\n#define SCSI_ILL_CMD -1   /* illegal command */\n#define SCSI_LBA_RANGE -2 /* LBA out of range */\n#define SCSI_TOO_BIG -3   /* Too big for buffer */\n\nvoid CDisk::do_scsi_error(int errcode) {\n  state.scsi.stat.available = 1;\n  state.scsi.stat.data[0] = 0;\n  state.scsi.stat.read = 0;\n  state.scsi.msgi.available = 1;\n  state.scsi.msgi.data[0] = 0;\n  state.scsi.msgi.read = 0;\n\n  if (errcode == SCSI_OK) {\n#if defined(DEBUG_SCSI)\n    printf(\"%s: Command returns OK status.\\n\", devid_string);\n#endif\n    return;\n  }\n\n  state.scsi.stat.data[0] = 0x02;  // check sense\n  state.scsi.sense.data[0] = 0xf0; // error code\n  state.scsi.sense.data[1] = 0x00; // segment number\n  state.scsi.sense.data[3] = 0x00; // info\n  state.scsi.sense.data[4] = 0x00;\n  state.scsi.sense.data[5] = 0x00;\n  state.scsi.sense.data[6] = 0x00;\n  state.scsi.sense.data[7] = 10;   // additional sense length\n  state.scsi.sense.data[8] = 0x00; // command specific\n  state.scsi.sense.data[9] = 0x00;\n  state.scsi.sense.data[10] = 0x00;\n  state.scsi.sense.data[11] = 0x00;\n  state.scsi.sense.data[14] = 0x00; // FRU code\n  state.scsi.sense.data[15] = 0x00; // sense key specific\n  state.scsi.sense.data[16] = 0x00;\n  state.scsi.sense.data[17] = 0x00;\n  state.scsi.sense.available = 18;\n\n  switch (errcode) {\n  case SCSI_ILL_CMD:\n    state.scsi.sense.data[2] = 0x05;  // illegal request\n    state.scsi.sense.data[12] = 0x20; // invalid command\n    state.scsi.sense.data[13] = 0x00;\n#if defined(DEBUG_SCSI)\n    printf(\"%s: Command returns check sense status (sense: ILLEGAL COMMAND).\\n\",\n           devid_string);\n#endif\n    break;\n\n  case SCSI_LBA_RANGE:\n    state.scsi.sense.data[2] = 0x05;  // illegal request\n    state.scsi.sense.data[12] = 0x21; // LBA out of range\n    state.scsi.sense.data[13] = 0x00;\n#if defined(DEBUG_SCSI)\n    printf(\n        \"%s: Command returns check sense status (sense: LBA OUT OF RANGE).\\n\",\n        devid_string);\n#endif\n    break;\n\n  case SCSI_TOO_BIG:\n    state.scsi.sense.data[2] = 0x05;  // illegal request\n    state.scsi.sense.data[12] = 0x55; // system resource failure\n    state.scsi.sense.data[13] = 0x00;\n#if defined(DEBUG_SCSI)\n    printf(\"%s: Command returns check sense status (sense: SYSTEM RESOURCE \"\n           \"FAILURE).\\n\",\n           devid_string);\n#endif\n  }\n}\n\n/**\n * Basic algorithm taken from libcdio for converting lba to msf\n **/\nstatic u32 lba2msf(off_t_large lba) {\n#define PREGAP_SECTORS 150\n#define CD_FRAMES_PER_SEC 75\n#define CD_MAX_LSN 450150\n\n#define bin2bcd(x) ((x / 10) << 4) | (x % 10)\n  int m;\n\n  int s;\n\n  int f;\n  lba -= PREGAP_SECTORS;\n  if (lba >= -PREGAP_SECTORS) {\n    m = (lba + PREGAP_SECTORS) / (CD_FRAMES_PER_SEC * 60);\n    lba -= m * (CD_FRAMES_PER_SEC * 60);\n    s = (lba + PREGAP_SECTORS) / CD_FRAMES_PER_SEC;\n    lba -= s * CD_FRAMES_PER_SEC;\n    f = lba + PREGAP_SECTORS;\n  } else {\n    m = (lba + CD_MAX_LSN) / (CD_FRAMES_PER_SEC * 60);\n    lba -= m * (CD_FRAMES_PER_SEC * 60);\n    s = (lba + CD_MAX_LSN) / CD_FRAMES_PER_SEC;\n    lba -= s * CD_FRAMES_PER_SEC;\n    f = lba + CD_MAX_LSN;\n  }\n\n  if (m > 99)\n    m = 99;\n\n  // printf(\"m=%d, s=%d, f=%d == m=%x, s=%x, f=%x\\n\",\n  // m,s,f,bin2bcd(m),bin2bcd(s),bin2bcd(f));\n  return bin2bcd(m) << 16 | bin2bcd(s) << 8 | bin2bcd(f);\n}\n\n/**\n * \\brief Handle a SCSI command.\n *\n * Called when a SCSI command has been received. We parse\n * the command, and set up the state for the data in or\n * data out phases.\n *\n * If a data out phase is required, we return the value 2\n * to indicate this. In that case, do_scsi_command will be\n * called again once the data out has been received from\n * the initiator.\n **/\nint CDisk::do_scsi_command() {\n  unsigned int retlen = 0;\n  int q;\n  int pagecode;\n  u32 ofs = 0;\n\n#if defined(DEBUG_SCSI)\n  printf(\"%s: %d-byte command \", devid_string, state.scsi.cmd.written);\n  for (unsigned int x = 0; x < state.scsi.cmd.written; x++)\n    printf(\"%02x \", state.scsi.cmd.data[x]);\n  printf(\"\\n\");\n#endif\n  if (state.scsi.cmd.written < 1)\n    return 0;\n\n  if (state.scsi.cmd.data[1] & 0xe0) {\n#if defined(DEBUG_SCSI)\n    printf(\"%s: LUN selected...\\n\", devid_string);\n#endif\n    state.scsi.lun_selected = true;\n  }\n\n  if (state.scsi.lun_selected && state.scsi.cmd.data[0] != SCSICMD_INQUIRY &&\n      state.scsi.cmd.data[0] != SCSICMD_REQUEST_SENSE) {\n    FAILURE_1(NotImplemented, \"%s: LUN not supported!\\n\", devid_string);\n  }\n\n  switch (state.scsi.cmd.data[0]) {\n  case SCSICMD_TEST_UNIT_READY:\n#if defined(DEBUG_SCSI)\n    printf(\"%s: TEST UNIT READY.\\n\", devid_string);\n#endif\n\n    // unit is always ready...\n    do_scsi_error(SCSI_OK);\n    break;\n\n  case SCSICMD_REQUEST_SENSE:\n#if defined(DEBUG_SCSI)\n    printf(\"%s: REQUEST SENSE.\\n\", devid_string);\n#endif\n    retlen = state.scsi.cmd.data[4];\n\n    //    FAILURE(\"Sense requested\");\n    if (!state.scsi.sense.available) {\n#if defined(DEBUG_SCSI)\n      printf(\"%s: NO SENSE.\\n\", devid_string);\n#endif\n      state.scsi.sense.data[0] = 0xf0; // error code\n      state.scsi.sense.data[1] = 0x00; // segment number\n      state.scsi.sense.data[2] = 0x00; // sense key: no sense\n      state.scsi.sense.data[3] = 0x00; // info\n      state.scsi.sense.data[4] = 0x00;\n      state.scsi.sense.data[5] = 0x00;\n      state.scsi.sense.data[6] = 0x00;\n      state.scsi.sense.data[7] = 10;   // additional sense length\n      state.scsi.sense.data[8] = 0x00; // command specific\n      state.scsi.sense.data[9] = 0x00;\n      state.scsi.sense.data[10] = 0x00;\n      state.scsi.sense.data[11] = 0x00;\n      state.scsi.sense.data[12] =\n          0x00; // additional sense code: no additional sense\n      state.scsi.sense.data[13] = 0x00; // additional qualifier\n      state.scsi.sense.data[14] = 0x00; // FRU code\n      state.scsi.sense.data[15] = 0x00; // sense key specific\n      state.scsi.sense.data[16] = 0x00;\n      state.scsi.sense.data[17] = 0x00;\n      state.scsi.sense.available = 18;\n    }\n\n#if defined(DEBUG_SCSI)\n    printf(\"%s: Returning data: \", devid_string);\n    for (unsigned int x1 = 0; x1 < state.scsi.sense.available; x1++)\n      printf(\"%02x \", state.scsi.sense.data[x1]);\n    printf(\"\\n\");\n#endif\n    state.scsi.dati.read = 0;\n    state.scsi.dati.available = retlen;\n    memcpy(state.scsi.dati.data, state.scsi.sense.data,\n           state.scsi.sense.available);\n    for (unsigned int x2 = state.scsi.sense.available; x2 < retlen; x2++)\n      state.scsi.dati.data[x2] = 0;\n\n    do_scsi_error(SCSI_OK);\n    break;\n\n  case SCSICMD_INQUIRY: {\n#if defined(DEBUG_SCSI)\n    printf(\"%s: INQUIRY.\\n\", devid_string);\n#endif\n    if ((state.scsi.cmd.data[1] & 0x1e) != 0x00) {\n      FAILURE_2(NotImplemented,\n                \"%s: Don't know how to handle INQUIRY with cmd[1]=0x%02x.\\n\",\n                devid_string, state.scsi.cmd.data[1]);\n      break;\n    }\n\n    u8 qual_dev = state.scsi.lun_selected ? 0x7F : (cdrom() ? 0x05 : 0x00);\n\n    retlen = state.scsi.cmd.data[4];\n    state.scsi.dati.data[0] = qual_dev; // device type\n    if (state.scsi.cmd.data[1] & 0x01) {\n\n      // Vital Product Data\n      switch (state.scsi.cmd.data[2]) {\n      case 0x00:\n\n        // Page 0 is basically a list of page codes supported, so if\n        // any others are added, make sure to insert them in the proper\n        // place and increase the page length.\n        state.scsi.dati.data[1] = 0x00; // page code 0\n        state.scsi.dati.data[2] = 0x00; // reserved\n        state.scsi.dati.data[3] = 0x02; // page length\n        state.scsi.dati.data[4] = 0x00; // page 0 is supported.\n        state.scsi.dati.data[5] = 0x80; // page 0x80 is supported.\n        break;\n\n      case 0x80:\n        char serial_number[20];\n        sprintf(serial_number, \"SRL%04x\", scsi_initiator_id[0] * 0x0101);\n\n        // unit serial number page\n        state.scsi.dati.data[1] = 0x80; // page code: 0x80\n        state.scsi.dati.data[2] = 0x00; // reserved\n        state.scsi.dati.data[3] = (u8)strlen(serial_number);\n        memcpy(&state.scsi.dati.data[4], serial_number, strlen(serial_number));\n        break;\n\n      default:\n#if 1\n        FAILURE_1(NotImplemented,\n                  \"Don't know format for vital product data page %02x!!\\n\",\n                  state.scsi.cmd.data[2]);\n#else\n        state.scsi.dati.data[1] = state.scsi.cmd.data[2]; // page code\n        state.scsi.dati.data[2] = 0x00;                   // reserved\n#endif\n      }\n    } else {\n\n      //  Return values:\n      if (retlen < 36) {\n        printf(\"%s: SCSI inquiry len=%i, <36!\\n\", devid_string, retlen);\n        retlen = 36;\n      }\n\n      state.scsi.dati.data[1] = 0;    // not removable;\n      state.scsi.dati.data[2] = 0x02; // ANSI scsi 2\n      state.scsi.dati.data[3] = 0x02; // response format\n      state.scsi.dati.data[4] = 32;   // additional length\n      state.scsi.dati.data[5] = 0;    // reserved\n      state.scsi.dati.data[6] = 0x04; // reserved\n      state.scsi.dati.data[7] = 0x60; // capabilities\n\n      //                        vendor  model           rev.\n      memcpy(&(state.scsi.dati.data[8]), \"DEC     RZ58     (C) DEC2000\", 28);\n\n      //  Some data is different for CD-ROM drives:\n      if (cdrom()) {\n        state.scsi.dati.data[1] = 0x80; //  0x80 = removable\n\n        //                           vendor  model           rev.\n        memcpy(&(state.scsi.dati.data[8]), \"DEC     RRD42   (C) DEC 4.5d\", 28);\n      }\n    }\n\n    state.scsi.dati.read = 0;\n    state.scsi.dati.available = retlen;\n\n#if defined(DEBUG_SCSI)\n    printf(\"%s: Returning data: \", devid_string);\n    for (unsigned int x1 = 0; x1 < 36; x1++)\n      printf(\"%02x \", state.scsi.dati.data[x1]);\n    printf(\"\\n\");\n#endif\n    do_scsi_error(SCSI_OK);\n  } break;\n\n  case SCSICMD_START_STOP_UNIT:\n    // TODO: Implement properly\n    // https://github.com/lenticularis39/axpbox/issues/36\n    do_scsi_error(SCSI_OK);\n    break;\n\n  case SCSICMD_MODE_SENSE:\n  case SCSICMD_MODE_SENSE_10:\n#if defined(DEBUG_SCSI)\n    printf(\"%s: MODE SENSE.\\n\", devid_string);\n#endif\n    {\n      int num_blk_desc = 1;\n\n      if (state.scsi.cmd.data[0] == SCSICMD_MODE_SENSE) {\n        q = 4;\n        retlen = state.scsi.cmd.data[4];\n        state.scsi.dati.data[0] = retlen; // mode data length\n        state.scsi.dati.data[1] =\n            cdrom() ? 0x01 : 0x00;      // medium type (120 mm data for CD-ROM)\n        state.scsi.dati.data[2] = 0x00; // device specific parameter\n        state.scsi.dati.data[3] =\n            8 * num_blk_desc; // block descriptor length: 1 page (?)\n      } else {\n        q = 8;\n        retlen = state.scsi.cmd.data[7] * 256 + state.scsi.cmd.data[8];\n        state.scsi.dati.data[0] = (u8)(retlen >> 8); // mode data length\n        state.scsi.dati.data[1] = (u8)retlen;\n        state.scsi.dati.data[2] =\n            cdrom() ? 0x01 : 0x00;      // medium type (120 mm data for CD-ROM)\n        state.scsi.dati.data[3] = 0x00; // device specific parameter\n        state.scsi.dati.data[4] = 0x00; // reserved\n        state.scsi.dati.data[5] = 0x00; // reserved\n        state.scsi.dati.data[6] = (u8)(\n            (8 * num_blk_desc) >> 8); //  block descriptor length: 1 page (?)\n        state.scsi.dati.data[7] = (u8)(8 * num_blk_desc);\n      }\n\n      if ((state.scsi.cmd.data[2] & 0xc0) > 0x40) {\n        FAILURE_2(NotImplemented, \"%s: mode sense, cmd[2] = 0x%02x.\\n\",\n                  devid_string, state.scsi.cmd.data[2]);\n      }\n\n      bool changeable = ((state.scsi.cmd.data[2] & 0xc0) == 0x40);\n\n      //  Return data:\n      if (retlen > DATI_BUFSZ) {\n        printf(\"%s: read too big (%d)\\n\", devid_string, retlen);\n        do_scsi_error(SCSI_TOO_BIG);\n        break;\n      }\n\n      state.scsi.dati.read = 0;\n      state.scsi.dati.available = retlen; //  Restore size.\n      pagecode = state.scsi.cmd.data[2] & 0x3f;\n\n      // printf(\"[ MODE SENSE pagecode=%i ]\\n\", pagecode);\n      state.scsi.dati.data[q++] = 0x00; //  density code\n      state.scsi.dati.data[q++] =\n          0; //  nr of blocks, high (0 = all remaining blocks)\n      state.scsi.dati.data[q++] = 0;    //  nr of blocks, mid\n      state.scsi.dati.data[q++] = 0;    //  nr of blocks, low\n      state.scsi.dati.data[q++] = 0x00; //  reserved\n      state.scsi.dati.data[q++] = (u8)(get_block_size() >> 16) & 255;\n      state.scsi.dati.data[q++] = (u8)(get_block_size() >> 8) & 255;\n      state.scsi.dati.data[q++] = (u8)(get_block_size() >> 0) & 255;\n\n      for (unsigned int x1 = q; x1 < retlen; x1++)\n        state.scsi.dati.data[x1] = 0;\n\n      do_scsi_error(SCSI_OK);\n\n      //  descriptors, 8 bytes (each)\n      //  page, n bytes (each)\n      switch (pagecode) {\n      case SCSIMP_VENDOR: // vendor specific\n        //  TODO: Nothing here?\n        break;\n\n      case SCSIMP_READ_WRITE_ERRREC: //  read-write error recovery page\n        state.scsi.dati.data[q + 0] = pagecode;\n        state.scsi.dati.data[q + 1] = 10;\n        break;\n\n      case SCSIMP_FORMAT_PARAMS: //  format device page\n        state.scsi.dati.data[q + 0] = pagecode;\n        state.scsi.dati.data[q + 1] = 22;\n        if (!changeable) {\n\n          //  10,11 = sectors per track\n          state.scsi.dati.data[q + 10] = 0;\n          state.scsi.dati.data[q + 11] = (u8)get_sectors();\n\n          //  12,13 = physical sector size\n          state.scsi.dati.data[q + 12] = (u8)(get_block_size() >> 8) & 255;\n          state.scsi.dati.data[q + 13] = (u8)(get_block_size() >> 0) & 255;\n        }\n        break;\n\n      case SCSIMP_RIGID_GEOMETRY: //  rigid disk geometry page\n        state.scsi.dati.data[q + 0] = pagecode;\n        state.scsi.dati.data[q + 1] = 22;\n        if (!changeable) {\n          state.scsi.dati.data[q + 2] = (u8)(get_cylinders() >> 16) & 255;\n          state.scsi.dati.data[q + 3] = (u8)(get_cylinders() >> 8) & 255;\n          state.scsi.dati.data[q + 4] = (u8)get_cylinders() & 255;\n          state.scsi.dati.data[q + 5] = (u8)get_heads();\n\n          // rpms\n          state.scsi.dati.data[q + 20] = (7200 >> 8) & 255;\n          state.scsi.dati.data[q + 21] = 7200 & 255;\n        }\n        break;\n\n      case SCSIMP_FLEX_PARAMS: //  flexible disk page\n        if (cdrom()) {\n          FAILURE_1(NotImplemented,\n                    \"%s: CD-ROM write parameter page not implemented.\\n\",\n                    devid_string);\n        }\n\n        state.scsi.dati.data[q + 0] = pagecode;\n        state.scsi.dati.data[q + 1] = 0x1e; // length\n        if (!changeable) {\n\n          //  2,3 = transfer rate\n          state.scsi.dati.data[q + 2] = ((5000) >> 8) & 255;\n          state.scsi.dati.data[q + 3] = (5000) & 255;\n\n          state.scsi.dati.data[q + 4] = (u8)get_heads();\n          state.scsi.dati.data[q + 5] = (u8)get_sectors();\n\n          //  6,7 = data bytes per sector\n          state.scsi.dati.data[q + 6] = (u8)(get_block_size() >> 8) & 255;\n          state.scsi.dati.data[q + 7] = (u8)(get_block_size() >> 0) & 255;\n\n          state.scsi.dati.data[q + 8] = (u8)(get_cylinders() >> 8) & 255;\n          state.scsi.dati.data[q + 9] = (u8)get_cylinders() & 255;\n\n          // rpms\n          state.scsi.dati.data[q + 28] = (7200 >> 8) & 255;\n          state.scsi.dati.data[q + 29] = 7200 & 255;\n        }\n        break;\n\n      case SCSIMP_CACHING:                      // Caching page\n        state.scsi.dati.data[q + 0] = pagecode; // page code\n        state.scsi.dati.data[q + 1] = 0x12;     // page length\n        if (!changeable) {\n\n          // 2 = IC,ABPF,CAP,DISC,SIZE,WCE,MF,RCD\n          //     |  |    |   |    |    |   |  +- read cache disable (0=no)\n          //     |  |    |   |    |    |   +---- multiplication factor (0=block)\n          //     |  |    |   |    |    +-------- write cache enable (0=no cache)\n          //     |  |    |   |    +------------- use cache segment size (0=no)\n          //     |  |    |   +------------------ prefetch across cyls (1=yes)\n          //     |  |    +---------------------- cache analysis (0=drive)\n          //     |  +--------------------------- abort prefetch (1=abrt on cmd)\n          //     +------------------------------ initiator control (0=drive)\n          state.scsi.dati.data[q + 2] = 0x0a;\n\n          state.scsi.dati.data[q + 3] = 0;    // read/write cache retention\n          state.scsi.dati.data[q + 4] = 0x00; // disable prefetch\n          state.scsi.dati.data[q + 5] = 0x00; // for req's greater than this\n          state.scsi.dati.data[q + 6] = 0;    // minimum prefetch\n          state.scsi.dati.data[q + 7] = 0;\n\n          state.scsi.dati.data[q + 8] = 0; // maximum prefetch\n          state.scsi.dati.data[q + 9] = 0;\n\n          state.scsi.dati.data[q + 10] = 0; // maximum prefetch ceiling\n          state.scsi.dati.data[q + 11] = 0;\n\n          state.scsi.dati.data[q + 12] = 0;\n          state.scsi.dati.data[q + 13] = 0; // # cache segments\n          state.scsi.dati.data[q + 14] = 0; // cache segement size\n          state.scsi.dati.data[q + 15] = 0;\n\n          state.scsi.dati.data[q + 16] = 0; // reserved\n          state.scsi.dati.data[q + 17] = 0; // non-cache segement size\n          state.scsi.dati.data[q + 18] = 0;\n          state.scsi.dati.data[q + 19] = 0;\n        }\n        break;\n\n      case SCSIMP_CDROM_CAP: // CD-ROM capabilities\n        state.scsi.dati.data[q + 0] = pagecode;\n        state.scsi.dati.data[q + 1] = 0x14; // length\n        if (!changeable) {\n          state.scsi.dati.data[q + 2] = 0x03; // read CD-R/CD-RW\n          state.scsi.dati.data[q + 3] = 0x00; // no write\n          state.scsi.dati.data[q + 4] = 0x00; // dvd/audio capabilities\n          state.scsi.dati.data[q + 5] = 0x00; // cd-da capabilities\n          state.scsi.dati.data[q + 6] =\n              state.scsi.locked ? 0x23 : 0x21; // tray-loader\n          state.scsi.dati.data[q + 7] = 0x00;\n          state.scsi.dati.data[q + 8] =\n              (u8)(2800 >> 8); // max read speed in kBps (2.8Mbps = 16x)\n          state.scsi.dati.data[q + 9] = (u8)(2800 >> 0);\n          state.scsi.dati.data[q + 10] =\n              (u8)(0 >> 8); // number of volume levels\n          state.scsi.dati.data[q + 11] = (u8)(0 >> 0);\n          state.scsi.dati.data[q + 12] = (u8)(64 >> 8); // buffer size in KBytes\n          state.scsi.dati.data[q + 13] = (u8)(64 >> 0);\n          state.scsi.dati.data[q + 14] = (u8)(2800 >> 8); // current read speed\n          state.scsi.dati.data[q + 15] = (u8)(2800 >> 0);\n          state.scsi.dati.data[q + 16] = 0;            // reserved\n          state.scsi.dati.data[q + 17] = 0;            // digital output format\n          state.scsi.dati.data[q + 18] = (u8)(0 >> 8); // max write speed\n          state.scsi.dati.data[q + 19] = (u8)(0 >> 0);\n          state.scsi.dati.data[q + 20] = (u8)(0 >> 8); // current write speed\n          state.scsi.dati.data[q + 21] = (u8)(0 >> 0);\n        }\n        break;\n\n      default:\n        FAILURE_2(NotImplemented,\n                  \"%s: MODE_SENSE for page %i is not yet implemented!\\n\",\n                  devid_string, pagecode);\n      }\n\n#if defined(DEBUG_SCSI)\n      printf(\"%s: Returning data: \", devid_string);\n      for (unsigned int x1 = 0; x1 < q + 30; x1++)\n        printf(\"%02x \", state.scsi.dati.data[x1]);\n      printf(\"\\n\");\n#endif\n    }\n    break;\n\n  case SCSICMD_PREVENT_ALLOW_REMOVE:\n    if (state.scsi.cmd.data[4] & 1) {\n      state.scsi.locked = true;\n#if defined(DEBUG_SCSI)\n      printf(\"%s: PREVENT MEDIA REMOVAL.\\n\", devid_string);\n#endif\n    } else {\n      state.scsi.locked = false;\n#if defined(DEBUG_SCSI)\n      printf(\"%s: ALLOW MEDIA REMOVAL.\\n\", devid_string);\n#endif\n    }\n\n    do_scsi_error(SCSI_OK);\n    break;\n\n  case SCSICMD_MODE_SELECT:\n\n    // get data out first...\n    state.scsi.dato.expected = 12;\n    if (state.scsi.dato.written < state.scsi.dato.expected)\n      return 2;\n\n#if defined(DEBUG_SCSI)\n    printf(\"%s: MODE SELECT.\\n\", devid_string);\n    printf(\"Data: \");\n    for (unsigned int x = 0; x < state.scsi.dato.written; x++)\n      printf(\"%02x \", state.scsi.dato.data[x]);\n    printf(\"\\n\");\n#endif\n    if (state.scsi.cmd.written == 6 && state.scsi.dato.written == 12 &&\n        state.scsi.dato.data[0] ==\n            0x00 // data length\n                 //&& state.scsi.dato.data[1] == 0x05 // medium type - ignore\n        && state.scsi.dato.data[2] == 0x00  // dev. specific\n        && state.scsi.dato.data[3] == 0x08  // block descriptor length\n        && state.scsi.dato.data[4] == 0x00  // density code\n        && state.scsi.dato.data[5] == 0x00  // all blocks\n        && state.scsi.dato.data[6] == 0x00  // all blocks\n        && state.scsi.dato.data[7] == 0x00  // all blocks\n        && state.scsi.dato.data[8] == 0x00) // reserved\n    {\n      set_block_size((state.scsi.dato.data[9] << 16) |\n                     (state.scsi.dato.data[10] << 8) |\n                     state.scsi.dato.data[11]);\n#if defined(DEBUG_SCSI)\n      printf(\"%s: Block size set to %d.\\n\", devid_string, get_block_size());\n#endif\n    } else {\n      unsigned int x;\n      printf(\"%s: MODE SELECT ignored.\\nCommand: \", devid_string);\n      for (x = 0; x < state.scsi.cmd.written; x++)\n        printf(\"%02x \", state.scsi.cmd.data[x]);\n      printf(\"\\nData: \");\n      for (x = 0; x < state.scsi.dato.written; x++)\n        printf(\"%02x \", state.scsi.dato.data[x]);\n      printf(\"\\nThis might be an attempt to change our blocksize or something \"\n             \"like that...\\nPlease check the above data, then press enter.\\n>\");\n      getchar();\n    }\n\n    // ignore it...\n    do_scsi_error(SCSI_OK);\n    break;\n\n  case SCSIBLOCKCMD_READ_CAPACITY:\n#if defined(DEBUG_SCSI)\n    printf(\"%s: READ CAPACITY.\\n\", devid_string);\n#endif\n    if (state.scsi.cmd.data[8] & 1) {\n      FAILURE_1(\n          NotImplemented,\n          \"%s: Don't know how to handle READ CAPACITY with PMI bit set.\\n\",\n          devid_string);\n      break;\n    }\n\n    // READ CAPACITY returns the number of the last LBA (n-1);\n    // not the number of LBA's (n)\n    state.scsi.dati.data[0] = (u8)((get_lba_size() - 1) >> 24) & 255;\n    state.scsi.dati.data[1] = (u8)((get_lba_size() - 1) >> 16) & 255;\n    state.scsi.dati.data[2] = (u8)((get_lba_size() - 1) >> 8) & 255;\n    state.scsi.dati.data[3] = (u8)((get_lba_size() - 1) >> 0) & 255;\n\n    state.scsi.dati.data[4] = (u8)(get_block_size() >> 24) & 255;\n    state.scsi.dati.data[5] = (u8)(get_block_size() >> 16) & 255;\n    state.scsi.dati.data[6] = (u8)(get_block_size() >> 8) & 255;\n    state.scsi.dati.data[7] = (u8)(get_block_size() >> 0) & 255;\n\n    state.scsi.dati.read = 0;\n    state.scsi.dati.available = 8;\n\n#if defined(DEBUG_SCSI)\n    printf(\"%s: Returning data: \", devid_string);\n    for (unsigned int x1 = 0; x1 < 8; x1++)\n      printf(\"%02x \", state.scsi.dati.data[x1]);\n    printf(\"\\n\");\n#endif\n    do_scsi_error(SCSI_OK);\n    break;\n\n  case SCSICMD_READ:\n  case SCSICMD_READ_10:\n  case SCSICMD_READ_12:\n  case SCSICMD_READ_CD:\n#if defined(DEBUG_SCSI)\n    printf(\"%s: READ.\\n\", devid_string);\n#endif\n\n    // if (state.scsi.disconnect_priv)\n    //{\n    //  //printf(\"%s: Will disconnect before returning read data.\\n\",\n    //  devid_string); state.scsi.will_disconnect = true;\n    //}\n    if (state.scsi.cmd.data[0] == SCSICMD_READ) {\n\n      //  bits 4..0 of cmd[1], and cmd[2] and cmd[3]\n      //  hold the logical block address.\n      //\n      //  cmd[4] holds the number of logical blocks\n      //  to transfer. (Special case if the value is\n      //  0, actually means 256.)\n      ofs = ((state.scsi.cmd.data[1] & 0x1f) << 16) +\n            (state.scsi.cmd.data[2] << 8) + state.scsi.cmd.data[3];\n      retlen = state.scsi.cmd.data[4];\n      if (retlen == 0)\n        retlen = 256;\n    } else if (state.scsi.cmd.data[0] == SCSICMD_READ_10) {\n\n      //  cmd[2..5] hold the logical block address.\n      //  cmd[7..8] holds the number of logical\n      ofs = (state.scsi.cmd.data[2] << 24) + (state.scsi.cmd.data[3] << 16) +\n            (state.scsi.cmd.data[4] << 8) + state.scsi.cmd.data[5];\n      retlen = (state.scsi.cmd.data[7] << 8) + state.scsi.cmd.data[8];\n    } else if (state.scsi.cmd.data[0] == SCSICMD_READ_12) {\n\n      //  cmd[2..5] hold the logical block address.\n      //  cmd[6..9] holds the number of logical\n      ofs = (state.scsi.cmd.data[2] << 24) + (state.scsi.cmd.data[3] << 16) +\n            (state.scsi.cmd.data[4] << 8) + state.scsi.cmd.data[5];\n      retlen = (state.scsi.cmd.data[6] << 24) + (state.scsi.cmd.data[7] << 16) +\n               (state.scsi.cmd.data[8] << 8) + state.scsi.cmd.data[9];\n    } else if (state.scsi.cmd.data[0] == SCSICMD_READ_CD) {\n      if (state.scsi.cmd.data[9] != 0x10) {\n        FAILURE_2(NotImplemented, \"%s: READ CD issued with data type %02x.\\n\",\n                  devid_string, state.scsi.cmd.data[9]);\n      }\n\n      //  cmd[2..5] hold the logical block address.\n      //  cmd[6..8] holds the number of logical blocks to transfer.\n      ofs = (state.scsi.cmd.data[2] << 24) + (state.scsi.cmd.data[3] << 16) +\n            (state.scsi.cmd.data[4] << 8) + state.scsi.cmd.data[5];\n      retlen = (state.scsi.cmd.data[6] << 16) + (state.scsi.cmd.data[7] << 8) +\n               state.scsi.cmd.data[8];\n    }\n\n    // Within bounds?\n    if ((ofs + retlen) > get_lba_size()) {\n      do_scsi_error(SCSI_LBA_RANGE);\n      break;\n    }\n\n    // Would exceed buffer?\n    if (retlen > DATI_BUFSZ) {\n      printf(\"%s: read too big (%d)\\n\", devid_string, retlen);\n      do_scsi_error(SCSI_TOO_BIG);\n      break;\n    }\n\n    //  Return data:\n    seek_block(ofs);\n    read_blocks(state.scsi.dati.data, retlen);\n    state.scsi.dati.read = 0;\n    state.scsi.dati.available = retlen * get_block_size();\n\n#if defined(DEBUG_SCSI)\n    printf(\"%s: READ  ofs=%d size=%d\\n\", devid_string, ofs, retlen);\n#endif\n    do_scsi_error(SCSI_OK);\n    break;\n\n  case SCSICMD_READ_LONG:\n#if defined(DEBUG_SCSI)\n    printf(\"%s: READ_LONG.\\n\", devid_string);\n#endif\n\n    // The read long command is used to read one block of disk data, including\n    // ECC data. OpenVMS uses read long / write long to do host-based shadowing.\n    // During driver initialization, OpenVMS will check each disk to see if it\n    // supports host-based shadowing, by trying to find the right size for read\n    // long commands. The emulated scsi disk sets the size for read long / write\n    // long commands to 514 bytes (the first value OpenVMS tries).\n    //  cmd[2..5] hold the logical block address.\n    //  cmd[7..8] holds the number of bytes to transfer\n    ofs = (state.scsi.cmd.data[2] << 24) + (state.scsi.cmd.data[3] << 16) +\n          (state.scsi.cmd.data[4] << 8) + state.scsi.cmd.data[5];\n    retlen = (state.scsi.cmd.data[7] << 8) + state.scsi.cmd.data[8];\n\n    state.scsi.stat.available = 1;\n    state.scsi.stat.data[0] = 0;\n    state.scsi.stat.read = 0;\n    state.scsi.msgi.available = 1;\n    state.scsi.msgi.data[0] = 0;\n    state.scsi.msgi.read = 0;\n\n    // If the requested size is not 514 bytes, don't accept it.\n    if (retlen != 514) {\n      do_scsi_error(SCSI_ILL_CMD);\n      break;\n    }\n\n    // Within bounds?\n    if ((ofs + 1) > get_lba_size()) {\n      do_scsi_error(SCSI_LBA_RANGE);\n      break;\n    }\n\n    // Would exceed buffer?\n    if (retlen > DATI_BUFSZ) {\n      printf(\"%s: read too big (%d)\\n\", devid_string, retlen);\n      do_scsi_error(SCSI_TOO_BIG);\n      break;\n    }\n\n    //  Return data:\n    seek_block(ofs);\n    read_blocks(state.scsi.dati.data, 1);\n    for (unsigned int x1 = get_block_size(); x1 < retlen; x1++)\n      state.scsi.dati.data[x1] = 0; // set ECC bytes to 0.\n    state.scsi.dati.read = 0;\n    state.scsi.dati.available = retlen;\n    do_scsi_error(SCSI_OK);\n    break;\n\n  case SCSICMD_WRITE:\n  case SCSICMD_WRITE_10:\n#if defined(DEBUG_SCSI)\n    printf(\"%s: WRITE.\\n\", devid_string);\n#endif\n    if (state.scsi.cmd.data[0] == SCSICMD_WRITE) {\n\n      //  bits 4..0 of cmd[1], and cmd[2] and cmd[3]\n      //  hold the logical block address.\n      //\n      //  cmd[4] holds the number of logical blocks\n      //  to transfer. (Special case if the value is\n      //  0, actually means 256.)\n      ofs = ((state.scsi.cmd.data[1] & 0x1f) << 16) +\n            (state.scsi.cmd.data[2] << 8) + state.scsi.cmd.data[3];\n      retlen = state.scsi.cmd.data[4];\n      if (retlen == 0)\n        retlen = 256;\n    } else {\n\n      //  cmd[2..5] hold the logical block address.\n      //  cmd[7..8] holds the number of logical blocks\n      //  to transfer.\n      ofs = (state.scsi.cmd.data[2] << 24) + (state.scsi.cmd.data[3] << 16) +\n            (state.scsi.cmd.data[4] << 8) + state.scsi.cmd.data[5];\n      retlen = (state.scsi.cmd.data[7] << 8) + state.scsi.cmd.data[8];\n    }\n\n    // Within bounds?\n    if (((ofs + retlen)) > get_lba_size()) {\n      do_scsi_error(SCSI_LBA_RANGE);\n      break;\n    }\n\n    // Would exceed buffer?\n    if (retlen * get_block_size() > DATO_BUFSZ) {\n      printf(\"%s: write too big (%d)\\n\", devid_string,\n             (int)(retlen * get_block_size()));\n      do_scsi_error(SCSI_TOO_BIG);\n      break;\n    }\n\n    state.scsi.dato.expected = retlen * get_block_size();\n\n    if (state.scsi.dato.written < state.scsi.dato.expected)\n      return 2;\n\n    //  Write data\n    seek_block(ofs);\n    write_blocks(state.scsi.dato.data, retlen);\n\n#if defined(DEBUG_SCSI)\n    printf(\"%s: WRITE  ofs=%d size=%d\\n\", devid_string, ofs, retlen);\n#endif\n    do_scsi_error(SCSI_OK);\n    break;\n\n  case SCSICMD_SYNCHRONIZE_CACHE:\n#if defined(DEBUG_SCSI)\n    printf(\"%s: SYNCHRONIZE CACHE.\\n\", devid_string);\n#endif\n    do_scsi_error(SCSI_OK);\n    break;\n\n  case SCSICDROM_READ_TOC: {\n#if defined(DEBUG_SCSI)\n    printf(\"%s: CDROM READ TOC.\\n\", devid_string);\n#endif\n    if (state.scsi.cmd.data[2] & 0x0f) {\n      FAILURE_2(NotImplemented,\n                \"%s: I don't understand READ TOC/PMA/ATIP with format %01x.\\n\",\n                devid_string, state.scsi.cmd.data[2] & 0x0f);\n    }\n\n    if (state.scsi.cmd.data[6] > 1 && state.scsi.cmd.data[6] != 0xAA) {\n      FAILURE_2(InvalidArgument, \"%s: I don't know CD-ROM track 0x%02x.\\n\",\n                devid_string, state.scsi.cmd.data[6]);\n    }\n\n    retlen = state.scsi.cmd.data[7] * 256 + state.scsi.cmd.data[8];\n\n    state.scsi.dati.available = retlen;\n    state.scsi.dati.read = 0;\n\n    int q = 2;\n\n    /*Here's an actual response from a single-track pressed CD to the\n          command  0x43, 00, 00, 00, 00, 00, 00, 00, 0x0c, 0x40, 00, 00\n\n          0000 00 0a 01 01 00 14 01 00 00 00 00 00 00 00 00 00 ................\n          0010 00 43 d6 02 00 81 ff ff 19 00 00 00 00 00 00 00 .C..............\n          0020 01 00 00 00 00 00 00 00 01 00 00 00 01 00 01 00 ................\n          0030 00 00 00 00 00 10 00 00 00 10 00 00 01 00 00 00 ................\n    */\n    state.scsi.dati.data[q++] = 1; // first track\n    state.scsi.dati.data[q++] = 1; // last track\n    if (state.scsi.cmd.data[6] <= 1) {\n      state.scsi.dati.data[q++] = 0;    // reserved\n      state.scsi.dati.data[q++] = 0x14; // adr/control (Q-channel: current\n                                        // position, data track, no copy)\n      state.scsi.dati.data[q++] = 1;    // track number\n      state.scsi.dati.data[q++] = 0;    // reserved\n      if (state.scsi.cmd.data[1] & 0x02) {\n        u32 x = lba2msf(0);\n        state.scsi.dati.data[q++] = 0;\n        state.scsi.dati.data[q++] = (x & 0xff0000) >> 16;\n        state.scsi.dati.data[q++] = (x & 0xff00) >> 8;\n        state.scsi.dati.data[q++] = x & 0xff;\n      } else {\n        state.scsi.dati.data[q++] = 0 >> 24; // lba\n        state.scsi.dati.data[q++] = 0 >> 16;\n        state.scsi.dati.data[q++] = 0 >> 8;\n        state.scsi.dati.data[q++] = 0;\n      }\n    }\n\n    state.scsi.dati.data[q++] = 0; // reserved\n    state.scsi.dati.data[q++] =\n        0x16; // adr/control (Q-channel: current position, data track, copy)\n    state.scsi.dati.data[q++] = 0xAA; // track number\n    state.scsi.dati.data[q++] = 0;    // reserved\n    if (state.scsi.cmd.data[1] & 0x02) {\n      u32 x = lba2msf(get_lba_size());\n      state.scsi.dati.data[q++] = 0;\n      state.scsi.dati.data[q++] = (x & 0xff0000) >> 16;\n      state.scsi.dati.data[q++] = (x & 0xff00) >> 8;\n      state.scsi.dati.data[q++] = x & 0xff;\n    } else {\n      state.scsi.dati.data[q++] = (u8)(get_lba_size() >> 24); // lba\n      state.scsi.dati.data[q++] = (u8)(get_lba_size() >> 16);\n      state.scsi.dati.data[q++] = (u8)(get_lba_size() >> 8);\n      state.scsi.dati.data[q++] = (u8)get_lba_size();\n    }\n\n    state.scsi.dati.data[0] = (u8)(q >> 8);\n    state.scsi.dati.data[1] = (u8)q;\n\n#if defined(DEBUG_SCSI)\n    printf(\"%s: Returning data: \", devid_string);\n    for (unsigned int x1 = 0; x1 < q; x1++)\n      printf(\"%02x \", state.scsi.dati.data[x1]);\n    printf(\"\\n\");\n#endif\n    do_scsi_error(SCSI_OK);\n  } break;\n\n  case SCSICDRRW_FORMAT:\n  case SCSICDRRW_READ_DISC_INFO:\n  case SCSICDRRW_READ_TRACK_INFO:\n  case SCSICDRRW_RESERVE_TRACK:\n  case SCSICDRRW_SEND_OPC_INFO:\n  case SCSICDRRW_REPAIR_TRACK:\n  case SCSICDRRW_READ_MASTER_CUE:\n  case SCSICDRRW_CLOSE_TRACK:\n  case SCSICDRRW_READ_BUFFER_CAP:\n  case SCSICDRRW_SEND_CUE_SHEET:\n  case SCSICDRRW_BLANK:\n\n    // These are CD-R/RW specific commands; we pretend to be a simple\n    // CD-ROM player, so no support for these commands.\n#if defined(DEBUG_SCSI)\n    printf(\"%s: CD-R/RW specific.\\n\", devid_string);\n#endif\n    do_scsi_error(SCSI_ILL_CMD);\n    break;\n\n  default:\n    FAILURE_2(NotImplemented, \"%s: Unknown SCSI command 0x%02x.\\n\",\n              devid_string, state.scsi.cmd.data[0]);\n  }\n\n  return 0;\n}\n\n/**\n * \\brief Handle a (series of) SCSI message(s).\n *\n * Called when one or more SCSI messages have been received.\n * We parse the message(s) and return what the next SCSI bus\n * phase should be.\n **/\nint CDisk::do_scsi_message() {\n  unsigned int msg;\n  unsigned int msglen;\n\n  msg = 0;\n  while (msg < state.scsi.msgo.written) {\n    if (state.scsi.msgo.data[msg] & 0x80) {\n\n      // identify\n#if defined(DEBUG_SCSI)\n      printf(\"%s: MSG: identify\", devid_string);\n#endif\n      if (state.scsi.msgo.data[msg] & 0x40) {\n#if defined(DEBUG_SCSI)\n        printf(\" w/disconnect priv\");\n#endif\n\n        //        state.scsi.disconnect_priv = true;\n      }\n\n      if (state.scsi.msgo.data[msg] & 0x07) {\n\n        // LUN...\n#if defined(DEBUG_SCSI)\n        printf(\" for lun %d%\", state.scsi.msgo.data[msg] & 0x07);\n#endif\n        state.scsi.lun_selected = true;\n      }\n\n#if defined(DEBUG_SCSI)\n      printf(\"\\n\");\n#endif\n      msg++;\n    } else {\n      switch (state.scsi.msgo.data[msg]) {\n      case 0x01:\n#if defined(DEBUG_SCSI)\n        printf(\"%s: MSG: extended: \", devid_string);\n#endif\n        msglen = state.scsi.msgo.data[msg + 1];\n        msg += 2;\n        switch (state.scsi.msgo.data[msg]) {\n        case 0x01: {\n#if defined(DEBUG_SCSI)\n          printf(\"SDTR.\\n\");\n#endif\n          state.scsi.msgi.available = msglen + 2;\n          state.scsi.msgi.data[0] = 0x01;\n          state.scsi.msgi.data[1] = msglen;\n          for (unsigned int x = 0; x < msglen; x++)\n            state.scsi.msgi.data[2 + x] = state.scsi.msgo.data[msg + x];\n        } break;\n\n        case 0x03: {\n#if defined(DEBUG_SCSI)\n          printf(\"WDTR.\\n\");\n#endif\n          state.scsi.msgi.available = msglen + 2;\n          state.scsi.msgi.data[0] = 0x01;\n          state.scsi.msgi.data[1] = msglen;\n          for (unsigned int x = 0; x < msglen; x++)\n            state.scsi.msgi.data[2 + x] = state.scsi.msgo.data[msg + x];\n        } break;\n\n        default:\n          FAILURE_2(NotImplemented,\n                    \"%s: MSG: don't understand extended message %02x.\\n\",\n                    devid_string, state.scsi.msgo.data[msg]);\n        }\n\n        msg += msglen;\n        break;\n\n      default:\n        FAILURE_2(NotImplemented, \"%s: MSG: don't understand message %02x.\\n\",\n                  devid_string, state.scsi.msgo.data[msg]);\n      }\n    }\n  }\n\n  // return next phase\n  if (state.scsi.msgi.available)\n    return SCSI_PHASE_MSG_IN;\n  else\n    return SCSI_PHASE_COMMAND;\n}\n\nstatic int primes_54[54] = {\n    2,   3,   5,   7,   11,  13,  17,  19,  23,  29,  31,  37,  41,  43,\n    47,  53,  59,  61,  67,  71,  73,  79,  83,  89,  97,  101, 103, 107,\n    109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181,\n    191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251};\n\n//  2 3 5 7 11 13\nstatic int pri16[16][6] = {{4, 0, 0, 0, 0, 0},  // 16\n                           {0, 1, 1, 0, 0, 0},  // 15\n                           {1, 0, 0, 1, 0, 0},  // 14\n                           {0, 0, 0, 0, 0, 1},  // 13\n                           {2, 1, 0, 0, 0, 0},  // 12\n                           {0, 0, 0, 0, 1, 0},  // 11\n                           {1, 0, 1, 0, 0, 0},  // 10\n                           {0, 2, 0, 0, 0, 0},  // 9\n                           {3, 0, 0, 0, 0, 0},  // 8\n                           {0, 0, 0, 1, 0, 0},  // 7\n                           {1, 1, 0, 0, 0, 0},  // 6\n                           {0, 0, 1, 0, 0, 0},  // 5\n                           {2, 0, 0, 0, 0, 0},  // 4\n                           {0, 1, 0, 0, 0, 0},  // 3\n                           {1, 0, 0, 0, 0, 0},  // 2\n                           {0, 0, 0, 0, 0, 0}}; // 1\nstatic off_t_large get_primes(off_t_large value, int pri[54]) {\n  int i;\n  for (i = 0; i < 54; i++) {\n    pri[i] = 0;\n    while (!(value % primes_54[i])) {\n      pri[i]++;\n      value /= primes_54[i];\n    }\n  }\n\n  return value;\n}\n\n/**\n * Calculate optimal disk layout...\n **/\n#define MAX_HD 16\n#define MAX_SEC 50\n\nvoid CDisk::determine_layout() {\n  int disk_primes[54];\n  int compare_primes[54];\n\n  long heads_sectors = 0;\n  long c_heads = 0;\n  bool b;\n  int prime;\n\n  get_primes(get_lba_size(), disk_primes);\n\n  for (heads_sectors = MAX_SEC * MAX_HD; heads_sectors > 0; heads_sectors--) {\n    if (get_primes(heads_sectors, compare_primes) > 1)\n      continue;\n\n    for (c_heads = MAX_HD; c_heads > 0; c_heads--) {\n      b = true;\n      for (prime = 0; prime < 6; prime++) {\n        if (pri16[16 - c_heads][prime] > compare_primes[prime]) {\n          b = false;\n          break;\n        }\n      }\n\n      if (b)\n        break;\n    }\n\n    if (heads_sectors / c_heads > MAX_SEC)\n      continue;\n\n    b = true;\n    for (prime = 0; prime < 54; prime++) {\n      if (compare_primes[prime] > disk_primes[prime]) {\n        b = false;\n        break;\n      }\n    }\n\n    if (b)\n      break;\n  }\n\n  heads = c_heads;\n  sectors = heads_sectors / c_heads;\n\n  //  sectors = 32;\n  //  heads = 8;\n  cylinders = get_lba_size() / heads / sectors;\n}\n"
  },
  {
    "path": "src/Disk.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(__DISK_H__)\n#define __DISK_H__\n\n#include \"DiskController.hpp\"\n#include \"SCSIBus.hpp\"\n#include \"SCSIDevice.hpp\"\n\n#define DATO_BUFSZ 256 * 1024\n#define DATI_BUFSZ 256 * 1024\n\n/**\n * \\brief Abstract base class for disks (connects to a CDiskController)\n **/\nclass CDisk : public CSystemComponent, public CSCSIDevice {\npublic:\n  CDisk(CConfigurator *cfg, CSystem *sys, CDiskController *c, int idebus,\n        int idedev);\n  virtual ~CDisk(void);\n  virtual int SaveState(FILE *f);\n  virtual int RestoreState(FILE *f);\n\n  virtual void scsi_select_me(int bus);\n  virtual size_t scsi_expected_xfer_me(int bus);\n  virtual void *scsi_xfer_ptr_me(int bus, size_t bytes);\n  virtual void scsi_xfer_done_me(int bus);\n\n  void set_atapi_mode() { atapi_mode = true; };\n\n  int do_scsi_command();\n  int do_scsi_message();\n  void do_scsi_error(int errcode);\n\n  virtual bool seek_byte(off_t_large byte) = 0;\n  virtual size_t read_bytes(void *dest, size_t bytes) = 0;\n  virtual size_t write_bytes(void *src, size_t bytes) = 0;\n\n  bool seek_block(off_t_large lba) {\n    return seek_byte(lba * state.block_size);\n  };\n  size_t read_blocks(void *dest, size_t blocks) {\n    return read_bytes(dest, blocks * state.block_size) / state.block_size;\n  };\n  size_t write_blocks(void *src, size_t blocks) {\n    return write_bytes(src, blocks * state.block_size) / state.block_size;\n  };\n\n  size_t get_block_size() { return state.block_size; };\n  void set_block_size(size_t bs) {\n    state.block_size = bs;\n    determine_layout(); /*calc_cylinders();*/\n  };\n\n  void determine_layout();\n\n  off_t_large get_lba_size() { return byte_size / state.block_size; };\n  off_t_large get_byte_size() { return byte_size; };\n  off_t_large get_chs_size() { return cylinders * heads * sectors; };\n  off_t_large get_cylinders() { return cylinders; };\n  long get_heads() { return heads; };\n  long get_sectors() { return sectors; };\n\n  char *get_serial() { return serial_number; };\n  char *get_model() { return model_number; };\n  char *get_rev() { return revision_number; };\n\n  bool ro() { return read_only; };\n  bool rw() { return !read_only; };\n  bool cdrom() { return is_cdrom; };\n\n  void calc_cylinders();\n\nprotected:\n  CConfigurator *myCfg;\n  CDiskController *myCtrl;\n  int myBus;\n  int myDev;\n\n  char *serial_number;\n  char *model_number;\n  char *revision_number;\n\n  bool read_only;\n  bool is_cdrom;\n\n  off_t_large byte_size;\n  off_t_large cylinders;\n  long heads;\n  long sectors;\n\n  bool atapi_mode;\n\n  /// The state structure contains all elements that need to be saved to the\n  /// statefile\n  struct SDisk_state {\n    size_t\n        block_size; /**< How many bytes there are in a physical disk block. **/\n    off_t_large byte_pos; /**< Current byte position in the disk. **/\n\n    /// SCSI state for SCSI-connected disks\n    struct SDisk_scsi {\n\n      // State for Message In Phase (disk -> controller)\n      struct SDisk_msgi {\n        u8 data[256];           /**< Data buffer. **/\n        unsigned int available; /**< Number of bytes available to read. **/\n        unsigned int read;      /**< Number of bytes read so far. **/\n      } msgi;\n\n      /// State for Message Out Phase (controller -> disk)\n      struct SDisk_msgo {\n        u8 data[256];         /**< Data buffer. **/\n        unsigned int written; /**< Number of bytes in buffer. **/\n      } msgo;\n\n      bool lun_selected; /**< A LUN has been selected. CDisk doesn't support\n                            LUNs. **/\n\n      /// state for Command phase (controller -> disk)\n      struct SDisk_cmd {\n        u8 data[256];         /**< Data buffer. **/\n        unsigned int written; /**< Number of bytes in buffer. **/\n      } cmd;\n\n      /// State for Data In phase (disk -> controller)\n      struct SDisk_dati {\n        u8 data[DATI_BUFSZ];    /**< Data buffer. **/\n        unsigned int available; /**< Number of bytes available to read. **/\n        unsigned int read;      /**< Number of bytes read so far. **/\n      } dati;\n\n      /// State for Data Out phase (controller -> disk)\n      struct SDisk_dato {\n        u8 data[DATO_BUFSZ];   /**< Data buffer. **/\n        unsigned int expected; /**< Number of bytes the initiator is expected to\n                                  write. **/\n        unsigned int written;  /**< Number of bytes written sofar. **/\n      } dato;\n\n      /// State for Status phase (disk -> controller)\n      struct SDisk_stat {\n        u8 data[256];           /**< Data buffer. **/\n        unsigned int available; /**< Number of bytes available to read. **/\n        unsigned int read;      /**< Number of bytes read so far. **/\n      } stat;\n\n      /// State for request sense\n      struct SDisk_sense {\n        u8 data[256];\n        unsigned int available;\n      } sense;\n\n      bool locked; /**< Media is locked (for CD-ROM type devices). **/\n\n      // bool disconnect_priv;       /**< Initiator has allowed us to\n      // disconnect/reconnect. **/ bool will_disconnect;       /**< We intend to\n      // disconnect. **/ bool disconnected;          /**< We have disconnected.\n      // **/ bool reselected;            /**< We have reselected the initiator.\n      // **/ int disconnect_phase;       /**< After we reconnect, we should go\n      // to this SCSI phase. **/\n    } scsi;\n  } state;\n};\n#endif //! defined(__DISK_H__)\n"
  },
  {
    "path": "src/DiskController.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"DiskController.hpp\"\n#include \"Disk.hpp\"\n#include \"StdAfx.hpp\"\n\nCDiskController::CDiskController(int num_busses, int num_devices) {\n  num_bus = num_busses;\n  num_dev = num_devices;\n\n  disks = (CDisk **)calloc(num_bus * num_dev, sizeof(CDisk *));\n}\n\nCDiskController::~CDiskController(void) { free(disks); }\n\nvoid CDiskController::register_disk(class CDisk *dsk, int bus, int dev) {\n  if (bus >= num_bus)\n    FAILURE(Configuration, \"Can't register disk: bus number out of range\");\n  if (dev >= num_dev)\n    FAILURE(Configuration, \"Can't register disk: device number out of range\");\n\n  disks[bus * num_bus + dev] = dsk;\n}\n\nclass CDisk *CDiskController::get_disk(int bus, int dev) {\n  if (bus >= num_bus)\n    return 0;\n  if (dev >= num_dev)\n    return 0;\n\n  return disks[bus * num_bus + dev];\n}\n"
  },
  {
    "path": "src/DiskController.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(__DISKCONTROLLER_H__)\n#define __DISKCONTROLLER_H__\n\n/**\n * \\brief Abstract base class for disk controllers (uses CDisk's)\n **/\nclass CDiskController {\npublic:\n  CDiskController(int num_busses, int num_devs);\n  ~CDiskController(void);\n\n  virtual void register_disk(class CDisk *dsk, int bus, int dev);\n  class CDisk *get_disk(int bus, int dev);\n\nprivate:\n  int num_bus;\n  int num_dev;\n\n  class CDisk **disks;\n};\n#endif //! defined(__DISKCONTROLLER_H__)\n"
  },
  {
    "path": "src/DiskDevice.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"DiskDevice.hpp\"\n#include \"StdAfx.hpp\"\n\n#if defined(_WIN32)\n#include <WinIoCtl.h>\n#endif\nCDiskDevice::CDiskDevice(CConfigurator *cfg, CSystem *sys, CDiskController *c,\n                         int idebus, int idedev)\n    : CDisk(cfg, sys, c, idebus, idedev) {\n  filename = myCfg->get_text_value(\"device\");\n  if (!filename) {\n    FAILURE_1(Configuration, \"%s: Disk has no device attached!\\n\",\n              devid_string);\n  }\n\n  if (read_only) {\n#if defined(_WIN32)\n    buffer = (char *)malloc(2048);\n    buffer_size = 2048;\n    handle =\n        CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,\n                   FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);\n#else\n    handle = fopen(filename, \"rb\");\n#endif\n  } else {\n#if defined(_WIN32)\n    handle = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,\n                        NULL, OPEN_EXISTING,\n                        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);\n#else\n    handle = fopen(filename, \"rb+\");\n#endif\n  }\n\n#if defined(_WIN32)\n  if (handle == INVALID_HANDLE_VALUE) {\n    FAILURE_3(Runtime, \"%s: Could not open device %s. Error %ld.\", devid_string,\n              filename, GetLastError());\n  }\n\n#else\n  if (!handle) {\n    FAILURE_2(Runtime, \"%s: Could not open device %s.\", devid_string, filename);\n  }\n#endif\n\n  // determine size...\n#if defined(_WIN32)\n  DISK_GEOMETRY x;\n  DWORD bytesret;\n\n  if (!DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &x,\n                       sizeof(x), &bytesret, NULL)) {\n    FAILURE_3(Runtime, \"%s: Could not get drive geometry for %s. Error %ld.\",\n              devid_string, filename, GetLastError());\n  }\n\n  sectors = x.SectorsPerTrack;\n  heads = x.TracksPerCylinder;\n  byte_size = x.Cylinders.QuadPart * x.TracksPerCylinder * x.SectorsPerTrack *\n              x.BytesPerSector;\n  dev_block_size = x.BytesPerSector;\n\n  LARGE_INTEGER a;\n  a.QuadPart = 0;\n  SetFilePointerEx(handle, a, (PLARGE_INTEGER)&state.byte_pos, FILE_BEGIN);\n#else\n  fseek_large(handle, 0, SEEK_END);\n  byte_size = ftell_large(handle);\n  fseek_large(handle, 0, SEEK_SET);\n  state.byte_pos = ftell_large(handle);\n\n  sectors = 32;\n  heads = 8;\n#endif\n\n  // calc_cylinders();\n  determine_layout();\n\n  model_number = myCfg->get_text_value(\"model_number\", filename);\n\n  printf(\"%s: Mounted device %s, %\" PRId64 \" %zd-byte blocks, %\" PRId64 \"/%ld/%ld.\\n\",\n         devid_string, filename, byte_size / state.block_size, state.block_size,\n         cylinders, heads, sectors);\n}\n\nCDiskDevice::~CDiskDevice(void) {\n  printf(\"%s: Closing file.\\n\", devid_string);\n#if defined(_WIN32)\n  if (handle != INVALID_HANDLE_VALUE)\n    CloseHandle(handle);\n#else\n  if (handle)\n    fclose(handle);\n#endif\n}\n\nbool CDiskDevice::seek_byte(off_t_large byte) {\n  if (byte >= byte_size) {\n    FAILURE_1(InvalidArgument, \"%s: Seek beyond end of file!\\n\", devid_string);\n  }\n\n#if defined(_WIN32)\n  state.byte_pos = byte;\n#else\n  fseek_large(handle, byte, SEEK_SET);\n  state.byte_pos = ftell_large(handle);\n#endif\n  return true;\n}\n\nsize_t CDiskDevice::read_bytes(void *dest, size_t bytes) {\n\n  //  printf(\"%s: read %d bytes @ %\" LL\n  //  \"d.\\n\",devid_string,bytes,state.byte_pos);\n#if defined(_WIN32)\n  off_t_large byte_from = (state.byte_pos / dev_block_size) * dev_block_size;\n  off_t_large byte_to =\n      (((state.byte_pos + bytes - 1) / dev_block_size) + 1) * dev_block_size;\n  DWORD byte_len = (DWORD)(byte_to - byte_from);\n  DWORD byte_off = (DWORD)(state.byte_pos - byte_from);\n  LARGE_INTEGER a;\n  DWORD r;\n\n  if (byte_len > buffer_size) {\n    buffer_size = byte_len;\n    CHECK_REALLOCATION(buffer, realloc(buffer, buffer_size), char);\n\n    //    printf(\"%s: buffer enlarged to %d bytes.\\n\",devid_string,buffer_size);\n  }\n\n  a.QuadPart = byte_from;\n  SetFilePointerEx(handle, a, NULL, FILE_BEGIN);\n\n  ReadFile(handle, buffer, byte_len, &r, NULL);\n\n  if (r != (byte_len)) {\n    printf(\"%s: Tried to read %d bytes from pos %ld, but could only read %d bytes!\\n\",\n           devid_string, byte_len, byte_from, r);\n    printf(\"%s: Error %ld.\\n\", devid_string, GetLastError());\n  }\n\n  memcpy(dest, buffer + byte_off, bytes);\n  state.byte_pos += bytes;\n  return bytes;\n#else\n  size_t r;\n  r = fread(dest, 1, bytes, handle);\n  state.byte_pos = ftell_large(handle);\n  return r;\n#endif\n}\n\nsize_t CDiskDevice::write_bytes(void *src, size_t bytes) {\n  if (read_only)\n    return 0;\n\n#if defined(_WIN32)\n  off_t_large byte_from = (state.byte_pos / dev_block_size) * dev_block_size;\n  off_t_large byte_to =\n      (((state.byte_pos + bytes - 1) / dev_block_size) + 1) * dev_block_size;\n  DWORD byte_len = (DWORD)(byte_to - byte_from);\n  DWORD byte_off = (DWORD)(state.byte_pos - byte_from);\n  LARGE_INTEGER a;\n  DWORD r;\n\n  if (byte_len > buffer_size) {\n    buffer_size = byte_len;\n    CHECK_REALLOCATION(buffer, realloc(buffer, buffer_size), char);\n  }\n\n  if (byte_from != state.byte_pos) {\n\n    // we don't write the entire first block, so we read it\n    // from disk first so we don't corrupt the disk\n    a.QuadPart = byte_from;\n    SetFilePointerEx(handle, a, NULL, FILE_BEGIN);\n    ReadFile(handle, buffer, (DWORD)dev_block_size, &r, NULL);\n    if (r != (dev_block_size)) {\n      printf(\"%s: Tried to read %d bytes from pos %ld, but could only read %zd bytes!\\n\",\n             devid_string, dev_block_size, byte_from, r);\n      FAILURE(InvalidArgument, \"Error during device write operation. \"\n                               \"Terminating to avoid disk corruption.\");\n    }\n  }\n\n  if ((byte_to != state.byte_pos + bytes) &&\n      (byte_to - byte_from > dev_block_size)) {\n\n    // we don't write the entire last block, so we read it\n    // from disk first so we don't corrupt the disk\n    a.QuadPart = byte_to - dev_block_size;\n    SetFilePointerEx(handle, a, NULL, FILE_BEGIN);\n    ReadFile(handle, buffer + byte_len - dev_block_size, (DWORD)dev_block_size,\n             &r, NULL);\n    if (r != (dev_block_size)) {\n      printf(\"%s: Tried to read %d bytes from pos %ld, but could only read %zd bytes!\\n\",\n             devid_string, dev_block_size, byte_to - dev_block_size, r);\n      FAILURE(InvalidArgument, \"Error during device write operation. \"\n                               \"Terminating to avoid disk corruption.\");\n    }\n  }\n\n  // add the data we're writing to the buffer\n  memcpy(buffer + byte_off, src, bytes);\n\n  a.QuadPart = byte_from;\n  SetFilePointerEx(handle, a, NULL, FILE_BEGIN);\n\n  // and write the buffer to disk\n  WriteFile(handle, buffer, byte_len, &r, NULL);\n\n  if (r != byte_len) {\n    printf(\"%s: Tried to write %d bytes to pos %ld, but could only write %d bytes!\\n\",\n           devid_string, byte_len, byte_from, r);\n    FAILURE(InvalidArgument, \"Error during device write operation. Terminating \"\n                             \"to avoid disk corruption.\");\n  }\n\n  state.byte_pos += bytes;\n  return bytes;\n#else\n  size_t r;\n  r = fwrite(src, 1, bytes, handle);\n  state.byte_pos = ftell_large(handle);\n  return r;\n#endif\n}\n"
  },
  {
    "path": "src/DiskDevice.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(__DISKDEV_H__)\n#define __DISKDEV_H__\n\n#include \"Disk.hpp\"\n\n/**\n * \\brief Emulated disk that uses a raw device.\n **/\nclass CDiskDevice : public CDisk {\npublic:\n  CDiskDevice(CConfigurator *cfg, CSystem *sys, CDiskController *c, int idebus,\n              int idedev);\n  virtual ~CDiskDevice(void);\n\n  virtual bool seek_byte(off_t_large byte);\n  virtual size_t read_bytes(void *dest, size_t bytes);\n  virtual size_t write_bytes(void *src, size_t bytes);\n\nprotected:\n#if defined(_WIN32)\n  HANDLE handle;\n  char *buffer;\n  size_t buffer_size;\n  size_t dev_block_size;\n#else\n  FILE *handle;\n#endif\n  char *filename;\n};\n#endif //! defined(__DISKFILE_H__)\n"
  },
  {
    "path": "src/DiskFile.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Copyright (C) 2020 Remy van Elst\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"DiskFile.hpp\"\n#include \"StdAfx.hpp\"\n#include <fstream>\n#include <iostream>\n\nCDiskFile::CDiskFile(CConfigurator *cfg, CSystem *sys, CDiskController *c,\n                     int idebus, int idedev)\n    : CDisk(cfg, sys, c, idebus, idedev) {\n\n  /* If the filename exists in the config, use that,\n   * otherwise, use a default filename */\n  filename = myCfg->get_text_value(\"file\");\n  if (!filename) {\n    defaultFilename = std::string(devid_string) + \".default.img\";\n    std::cerr << devid_string\n              << \": Disk has no filename attached! Assuming default: \"\n              << defaultFilename << std::endl;\n    filename = const_cast<char *>(defaultFilename.c_str());\n  }\n\n  /* if the file does not exist, create it. ifs actually checks for\n   * accessibility, not for existence, but for compatibility with\n   * platforms without c++17/boost and std::filesystem::exists, this\n   * is good enough. ifstream.good() returns false if the file does\n   * not exist.*/\n  std::ifstream ifs(filename, std::ios::binary);\n  if (!ifs.good()) {\n    std::cerr << devid_string << \": file does not exist: \" << filename\n              << std::endl;\n\n    /* If the disk file size was not set and the disk file does not exist, do\n     * not create it, but exit */\n    u64 diskFileSize = myCfg->get_num_value(\"autocreate_size\", false, 0);\n    if (!diskFileSize) {\n      FAILURE_1(Runtime, \"%s: file does not exist and no autocreate_size set.\",\n                devid_string);\n    }\n\n    /* Don't create disk file if it's supposed to be a cdrom */\n    if (is_cdrom) {\n      FAILURE_1(Runtime, \"%s: file does not exist and is configured as cdrom.\",\n                devid_string);\n    }\n\n    createDiskFile(filename, diskFileSize);\n  }\n\n  if (!read_only) {\n    /* If the file is not configured as readonly, test if we can\n     * write to it by opening it in append mode. Just using 'out'\n     * would overwrite the contents of the file, which is\n     * unwanted. Issue #29. */\n    checkFileWritable(filename);\n  }\n\n  handle = fopen(filename, read_only ? \"rb\" : \"rb+\");\n\n  // determine size...\n  fseek_large(handle, 0, SEEK_END);\n  byte_size = ftell_large(handle);\n  fseek_large(handle, 0, SEEK_SET);\n  state.byte_pos = ftell_large(handle);\n\n  sectors = 32;\n  heads = 8;\n\n  // calc_cylinders();\n  determine_layout();\n\n  model_number = myCfg->get_text_value(\"model_number\", filename);\n\n  // skip to the filename portion of the path.\n  char *p = model_number;\n#if defined(_WIN32)\n  char x = '\\\\';\n#elif defined(__VMS)\n  char x = ']';\n#else\n  char x = '/';\n#endif\n  while (*p) {\n    if (*p == x)\n      model_number = p + 1;\n    p++;\n  }\n\n  printf(\"%s: Mounted file %s, %\" PRId64 \" %zd-byte blocks, %\" PRId64 \"/%ld/%ld.\\n\",\n         devid_string, filename, byte_size / state.block_size, state.block_size,\n         cylinders, heads, sectors);\n}\n\nvoid CDiskFile::checkFileWritable(const std::string& fileName) const {\n  std::ofstream ofs(fileName, std::ios::app);\n  // is_open for an ofstream checks if the file can be written to\n  bool isWritable = (ofs.is_open() && ofs.good());\n  if (!isWritable) {\n    FAILURE_2(Runtime, \"%s: file %s is not writable\", devid_string, fileName.c_str())\n  }\n  ofs.close();\n}\n\nvoid CDiskFile::createDiskFile(const std::string &fileName, u64 diskFileSize) {\n\n  std::ofstream ofs(fileName, std::ios::binary);\n  if (ofs.is_open() && ofs.good()) {\n    ofs.seekp((diskFileSize)-1);\n    ofs.write(\"\", 1);\n  } else {\n    FAILURE_1(Runtime, \"%s: File does not exist and could not be created\",\n              devid_string);\n  }\n\n  std::cout << devid_string << \" \" << (diskFileSize / 1024 / 1024) << \"MB file \"\n            << filename << \" created\" << std::endl;\n}\n\nCDiskFile::~CDiskFile(void) {\n  printf(\"%s: Closing file.\\n\", devid_string);\n  fclose(handle);\n}\n\nbool CDiskFile::seek_byte(off_t_large byte) {\n  if (byte >= byte_size) {\n    FAILURE_1(InvalidArgument, \"%s: Seek beyond end of file!\\n\", devid_string);\n  }\n\n  fseek_large(handle, byte, SEEK_SET);\n  state.byte_pos = ftell_large(handle);\n\n  return true;\n}\n\nsize_t CDiskFile::read_bytes(void *dest, size_t bytes) {\n  size_t r;\n  r = fread(dest, 1, bytes, handle);\n  state.byte_pos = ftell_large(handle);\n  return r;\n}\n\nsize_t CDiskFile::write_bytes(void *src, size_t bytes) {\n  if (read_only)\n    return 0;\n\n  size_t r;\n  r = fwrite(src, 1, bytes, handle);\n  state.byte_pos = ftell_large(handle);\n  return r;\n}\n"
  },
  {
    "path": "src/DiskFile.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Copyright (C) 2020 Remy van Elst\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(__DISKFILE_H__)\n#define __DISKFILE_H__\n\n#include \"Disk.hpp\"\n\n/**\n * \\brief Emulated disk that uses an image file.\n **/\nclass CDiskFile : public CDisk {\npublic:\n  CDiskFile(CConfigurator *cfg, CSystem *sys, CDiskController *c, int idebus,\n            int idedev);\n  virtual ~CDiskFile(void);\n\n  virtual bool seek_byte(off_t_large byte);\n  virtual size_t read_bytes(void *dest, size_t bytes);\n  virtual size_t write_bytes(void *src, size_t bytes);\n\n  FILE *get_handle() { return handle; };\n\nprotected:\n  FILE *handle;\n  char *filename;\n\n  void createDiskFile(const std::string &filename, u64 diskFileSize);\n  std::string defaultFilename;\n  void checkFileWritable(const std::string& filename) const;\n};\n#endif //! defined(__DISKFILE_H__)\n"
  },
  {
    "path": "src/DiskRam.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"DiskRam.hpp\"\n#include \"StdAfx.hpp\"\n\nCDiskRam::CDiskRam(CConfigurator *cfg, CSystem *sys, CDiskController *c,\n                   int idebus, int idedev)\n    : CDisk(cfg, sys, c, idebus, idedev) {\n  byte_size = myCfg->get_num_value(\"size\", false, 512 * 1024 * 1024);\n\n  CHECK_ALLOCATION(ramdisk = malloc((size_t)byte_size));\n\n  state.byte_pos = 0;\n\n  sectors = 32;\n  heads = 8;\n\n  // calc_cylinders();\n  determine_layout();\n\n  model_number = myCfg->get_text_value(\"model_number\", \"ES40RAMDISK\");\n\n  printf(\"%s: Mounted RAMDISK, %\" PRId64 \" %zd-byte blocks, %\" PRId64 \"/%ld/%ld.\\n\",\n         devid_string, byte_size / state.block_size, state.block_size,\n         cylinders, heads, sectors);\n}\n\nCDiskRam::~CDiskRam(void) {\n  if (ramdisk) {\n    printf(\"%s: RAMDISK freed.\\n\", devid_string);\n    free(ramdisk);\n    ramdisk = 0;\n  }\n}\n\nbool CDiskRam::seek_byte(off_t_large byte) {\n  if (byte >= byte_size) {\n    FAILURE_1(InvalidArgument, \"%s: Seek beyond end of file!\\n\", devid_string);\n  }\n\n  state.byte_pos = byte;\n  return true;\n}\n\nsize_t CDiskRam::read_bytes(void *dest, size_t bytes) {\n  if (state.byte_pos >= byte_size)\n    return 0;\n\n  while (state.byte_pos + bytes >= byte_size)\n    bytes--;\n\n  memcpy(dest, &(((char *)ramdisk)[state.byte_pos]), bytes);\n  state.byte_pos += (unsigned long)bytes;\n  return bytes;\n}\n\nsize_t CDiskRam::write_bytes(void *src, size_t bytes) {\n  if (state.byte_pos >= byte_size)\n    return 0;\n\n  while (state.byte_pos + bytes >= byte_size)\n    bytes--;\n\n  memcpy(&(((char *)ramdisk)[state.byte_pos]), src, bytes);\n  state.byte_pos += (unsigned long)bytes;\n  return bytes;\n}\n"
  },
  {
    "path": "src/DiskRam.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(__DISKRAM_H__)\n#define __DISKRAM_H__\n\n#include \"Disk.hpp\"\n\n/**\n * \\brief Emulated disk that uses RAM.\n **/\nclass CDiskRam : public CDisk {\npublic:\n  CDiskRam(CConfigurator *cfg, CSystem *sys, CDiskController *c, int idebus,\n           int idedev);\n  virtual ~CDiskRam(void);\n\n  virtual bool seek_byte(off_t_large byte);\n  virtual size_t read_bytes(void *dest, size_t bytes);\n  virtual size_t write_bytes(void *src, size_t bytes);\n\nprotected:\n  void *ramdisk;\n};\n#endif //! defined(__DISKFILE_H__)\n"
  },
  {
    "path": "src/Ethernet.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon GXemul, which is Copyright (C) 2004-2007\n * Anders Gavare.  All rights reserved.\n */\n\n#include \"Ethernet.hpp\"\n#include \"telnet.hpp\"\n\n/**\n * \\brief Packet Queue for Ethernet packets.\n **/\nCPacketQueue::CPacketQueue(const char *name, int max) {\n  this->name = name;\n  this->max = max;\n  head = 0;\n  tail = -1;\n  cnt = 0;\n  highwater = 0;\n  dropped = 0;\n  packets = new eth_packet[max];\n}\n\nCPacketQueue::~CPacketQueue() {\n  delete[] packets;\n  printf(\"CPacketQueue(%s): highwater=%d, lost=%d\\n\", name, highwater, dropped);\n}\n\nvoid CPacketQueue::flush() {\n  cnt = 0;\n  head = 0;\n  tail = -1;\n}\n\nstatic const u32 crcTable[256] = {\n    0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,\n    0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,\n    0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,\n    0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,\n    0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,\n    0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,\n    0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,\n    0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,\n    0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,\n    0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,\n    0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,\n    0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,\n    0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,\n    0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,\n    0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,\n    0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,\n    0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,\n    0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,\n    0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,\n    0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,\n    0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,\n    0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,\n    0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,\n    0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,\n    0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,\n    0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,\n    0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,\n    0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,\n    0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,\n    0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,\n    0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,\n    0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,\n    0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,\n    0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,\n    0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,\n    0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,\n    0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,\n    0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,\n    0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,\n    0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,\n    0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,\n    0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,\n    0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D};\n\nstatic u32 eth_crc32(u32 crc, const void *vbuf, int len) {\n  const u32 mask = 0xFFFFFFFF;\n  const unsigned char *buf = (const unsigned char *)vbuf;\n\n  crc ^= mask;\n  while (0 != len--)\n    crc = (crc >> 8) ^ crcTable[(crc ^ (*buf++)) & 0xFF];\n  return (crc ^ mask);\n}\n\nbool CPacketQueue::add_tail(const u8 *packet_data, int packet_len,\n                            bool calc_crc, bool need_crc) {\n  if ((cnt >= max) || (packet_len < 1) || (packet_len > 1514)) {\n    dropped += 1;\n    printf(\"CPacketQueue(%s):add() packet lost! Size = %d\", name, packet_len);\n    printf(\".. dst: %02x-%02x-%02x-%02x-%02x-%02x \", packet_data[0],\n           packet_data[1], packet_data[2], packet_data[3], packet_data[4],\n           packet_data[5]);\n    printf(\".. src: %02x-%02x-%02x-%02x-%02x-%02x \\n\", packet_data[6],\n           packet_data[7], packet_data[8], packet_data[9], packet_data[10],\n           packet_data[11]);\n    return false;\n  }\n\n  tail += 1;\n  if (tail >= max) {\n    tail = 0;\n  }\n\n  eth_packet *next = &packets[tail];\n  next->len = packet_len;\n  next->used = 0;\n  memcpy(next->frame, packet_data, packet_len); // copy packet data\n  if (need_crc) {                               // If packet needs CRC\n    u32 crc = calc_crc ? eth_crc32(0, packet_data, packet_len)\n                       : 0;                     // recalculate crc if needed\n    u32 ncrc = htonl(crc);                      // put crc in network order\n    memcpy(&next->frame[packet_len], &ncrc, 4); // append CRC to packet\n    next->len += 4;                             // increase packet length\n  }\n\n  cnt += 1;\n  if (cnt > highwater) {\n    highwater = cnt;\n  }\n\n  return true;\n}\n\nbool CPacketQueue::get_head(eth_packet &packet) {\n  if (cnt <= 0) {\n    return false;\n  }\n\n  eth_packet *headp = &packets[head];\n  packet.len = headp->len;\n  packet.used = headp->used;\n  memcpy(packet.frame, headp->frame, sizeof(packet.frame));\n  head += 1;\n  if (head >= max) {\n    head = 0;\n  }\n\n  cnt -= 1;\n  return true;\n}\n"
  },
  {
    "path": "src/Ethernet.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon GXemul, which is Copyright (C) 2004-2007\n * Anders Gavare.  All rights reserved.\n */\n\n#if !defined(INCLUDED_ETHERNET_H)\n#define INCLUDED_ETHERNET_H\n\n#include \"StdAfx.hpp\"\n\n#define ETH_MAX_PACKET_RAW 1514\n#define ETH_MAX_PACKET_CRC 1518\n\nstruct eth_frame { // ethernet (wire) frame\n  u8 src[6];       // source address\n  u8 dst[6];       // destination address\n  u8 protocol[2];  // protocol\n  u8 data[1500];   // data: variable 46-1500 bytes\n  u8 crc_fill[4];  // space for max packet crc\n};\n\nstruct eth_packet {             // ethernet packet\n  int len;                      // size of packet\n  int used;                     // bytes used (consumed)\n  u8 frame[ETH_MAX_PACKET_CRC]; // ethernet frame\n};\n\n/**\n * \\brief Packet Queue for Ethernet packets.\n **/\nclass CPacketQueue { // Ethernet Packet Queue\n\n  // private:\npublic:\n  const char *name;    // queue name\n  int max;             // maximum items allowed in queue\n  int head;            // first item in queue\n  int tail;            // last item in queue\n  int cnt;             // current item count\n  int highwater;       // highwater mark (statistics)\n  int dropped;         // packets dropped because queue was full\n  eth_packet *packets; // packet array; dynamically allocated\npublic:\n  inline int count() { return cnt; }\n\n  // get current count\n  inline int lost() { return dropped; }\n\n  // get number of lost packets\n  void flush(); // empties packet queue\n  bool add_tail(const u8 *packet_data, int packet_len, bool calc_crc,\n                bool need_crc);            // adds pcap packet to queue\n  bool get_head(eth_packet &packet);       // get packet at head\n  CPacketQueue(const char *name, int max); // constructor\n  ~CPacketQueue();                         // destructor\n};\n#endif // !defined(INCLUDED_ETHERNET_H)\n"
  },
  {
    "path": "src/Flash.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"Flash.hpp\"\n#include \"AlphaCPU.hpp\"\n#include \"StdAfx.hpp\"\n#include \"System.hpp\"\n\n// These are the modes for our flash-state-machine.\n#define MODE_READ 0\n#define MODE_STEP1 1\n#define MODE_STEP2 2\n#define MODE_AUTOSEL 3\n#define MODE_PROGRAM 4\n#define MODE_ERASE_STEP3 5\n#define MODE_ERASE_STEP4 6\n#define MODE_ERASE_STEP5 7\n#define MODE_CONFIRM_0 8\n#define MODE_CONFIRM_1 9\n\nextern CAlphaCPU *cpu[4];\n\n/**\n * Constructor.\n **/\nCFlash::CFlash(CConfigurator *cfg, CSystem *c) : CSystemComponent(cfg, c) {\n  if (theSROM)\n    FAILURE(Configuration, \"More than one Flash\");\n  theSROM = this;\n  c->RegisterMemory(this, 0, U64(0x0000080100000000), 0x8000000); // 2MB\n  memset(state.Flash, 0xff, 2 * 1024 * 1024);\n  RestoreStateF();\n  state.mode = MODE_READ;\n\n  printf(\"%s: $Id: Flash.cpp,v 1.19 2008/03/24 22:11:50 iamcamiel Exp $\\n\",\n         devid_string);\n}\n\n/**\n * Destructor.\n **/\nCFlash::~CFlash() {}\n\n/**\n * Read a byte from flashmemory.\n * Normally, this returns one byte from flash, however, after some commands\n * sent to the flash-rom, this returns identification or status information.\n **/\nu64 CFlash::ReadMem(int index, u64 address, int dsize) {\n  u64 data = 0;\n  int a = (int)(address >> 6);\n\n  switch (state.mode) {\n  case MODE_AUTOSEL:\n    switch (a) {\n    case 0:\n      data = 1; // manufacturer\n      break;\n    case 1:\n      data = 0xad; // device\n      break;\n    default:\n      data = 0;\n    }\n    break;\n\n  case MODE_CONFIRM_0:\n    data = 0x80;\n    state.mode = MODE_READ;\n    break;\n\n  case MODE_CONFIRM_1:\n    data = 0x80;\n    state.mode = MODE_CONFIRM_0;\n    break;\n\n  default:\n    data = state.Flash[a];\n  }\n\n  return data;\n}\n\n/**\n * Write command or programming data to flash-rom.\n *\n * The state machine for this looks like this:\n * \\code\n *         |\n *         v\n *     MODE_READ <---------------------------+\n *         | write 0x5555:0xaa               |\n *         v                                 |\n *     MODE_STEP1 ---------------------------+\n *         | write 0x2aaa:0x55               |\n *         v                                 |\n *     ==MODE_STEP2= ------------------------+\n * 0x80| 0xa0| 0x90| write 0x5555            |\n *     |     |     v                         |\n *     |     | MODE_AUTOSEL (read device id)-+\n *     |     v                               |\n *     | MODE_PROGRAM                        |\n *     |     | write data byte               |\n *     |     +-------------------------------+\n *     v                                     |\n *  MODE_ERASE_STEP3 ------------------------+\n *     | write 0x5555:0xaa                   |\n *     v                                     |\n *  MODE_ERASE_STEP4 ------------------------+\n *     | write 0x2aaa:0x55                   |\n *     v                                     |\n *  MODE_ERASE_STEP4 ------------------------+\n *   | write 0x30  | write 0x5555:0x10       |\n *   | anywhere    v                         |\n *   v           ERASE ENTIRE FLASH          |\n * ERASE BLOCK     |                         |\n *       |         |                         |\n *       v         v                         |\n *      MODE_CONFIRM1                        |\n *          | read 0x80                      |\n *          v                                |\n *      MODE_CONFIRM2                        |\n *          | read 0x80                      |\n *          +--------------------------------+\n * \\endcode\n **/\nvoid CFlash::WriteMem(int index, u64 address, int dsize, u64 data) {\n  int a = (int)(address >> 6);\n\n  switch (state.mode) {\n  case MODE_READ:\n  case MODE_AUTOSEL:\n    if ((a == 0x5555) && (data == 0xaa)) {\n      state.mode = MODE_STEP1;\n      return;\n    }\n\n    state.mode = MODE_READ;\n    return;\n\n  case MODE_STEP1:\n    if ((a == 0x2aaa) && (data == 0x55)) {\n      state.mode = MODE_STEP2;\n      return;\n    }\n\n    state.mode = MODE_READ;\n    return;\n\n  case MODE_STEP2:\n    if (a != 0x5555) {\n      state.mode = MODE_READ;\n      return;\n    }\n\n    switch (data) {\n    case 0x90:\n      state.mode = MODE_AUTOSEL;\n      return;\n    case 0xa0:\n      state.mode = MODE_PROGRAM;\n      return;\n    case 0x80:\n      state.mode = MODE_ERASE_STEP3;\n      return;\n    }\n\n    state.mode = MODE_READ;\n    return;\n\n  case MODE_ERASE_STEP3:\n    if ((a == 0x5555) && (data == 0xaa)) {\n      state.mode = MODE_ERASE_STEP4;\n      return;\n    }\n\n    state.mode = MODE_READ;\n    return;\n\n  case MODE_ERASE_STEP4:\n    if ((a == 0x2aaa) && (data == 0x55)) {\n      state.mode = MODE_ERASE_STEP5;\n      return;\n    }\n\n    state.mode = MODE_READ;\n    return;\n\n  case MODE_ERASE_STEP5:\n    if ((a == 0x5555) && (data == 0x10)) {\n      memset(state.Flash, 0xff, 1 << 21);\n      state.mode = MODE_CONFIRM_1;\n      return;\n    }\n\n    if (data == 0x30) {\n      memset(&state.Flash[(a >> 16) << 16], 0xff, 1 << 16);\n      state.mode = MODE_CONFIRM_1;\n      return;\n    }\n\n    state.mode = MODE_READ;\n    return;\n  }\n\n  // we must now be in mode program...\n  state.Flash[a] = (u8)data;\n  state.mode = MODE_READ;\n}\n\n/**\n * Save state to a flash rom file.\n **/\nvoid CFlash::SaveStateF(char *fn) {\n  FILE *ff;\n  ff = fopen(fn, \"wb\");\n  if (ff) {\n    SaveState(ff);\n    fclose(ff);\n    printf(\"%%FLS-I-SAVEST: Flash state saved to %s\\n\", fn);\n  } else {\n    printf(\"%%FLS-F-NOSAVE: Flash could not be saved to %s\\n\", fn);\n  }\n}\n\n/**\n * Save state to the default flash rom file.\n **/\nvoid CFlash::SaveStateF() {\n  SaveStateF(myCfg->get_text_value(\"rom.flash\", \"flash.rom\"));\n}\n\n/**\n * Restore state from a flash rom file.\n **/\nvoid CFlash::RestoreStateF(char *fn) {\n  FILE *ff;\n  ff = fopen(fn, \"rb\");\n  if (ff) {\n    RestoreState(ff);\n    fclose(ff);\n    printf(\"%%FLS-I-RESTST: Flash state restored from %s\\n\", fn);\n  } else {\n    printf(\"%%FLS-F-NOREST: Flash could not be restored from %s\\n\", fn);\n  }\n}\n\n/**\n * Restore state from the default flash rom file.\n **/\nvoid CFlash::RestoreStateF() {\n  RestoreStateF(myCfg->get_text_value(\"rom.flash\", \"flash.rom\"));\n}\n\nstatic u32 flash_magic1 = 0xFF3E3FF3;\nstatic u32 flash_magic2 = 0x3FF3E3FF;\n\n/**\n * Save state to a Virtual Machine State file.\n **/\nint CFlash::SaveState(FILE *f) {\n  long ss = sizeof(state);\n  fwrite(&flash_magic1, sizeof(u32), 1, f);\n  fwrite(&ss, sizeof(long), 1, f);\n  fwrite(&state, sizeof(state), 1, f);\n  fwrite(&flash_magic2, sizeof(u32), 1, f);\n  printf(\"flash: %ld bytes saved.\\n\", ss);\n  return 0;\n}\n\n/**\n * Restore state from a Virtual Machine State file.\n **/\nint CFlash::RestoreState(FILE *f) {\n  long ss;\n  u32 m1;\n  u32 m2;\n  size_t r;\n\n  r = fread(&m1, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"flash: unexpected end of file!\\n\");\n    return -1;\n  }\n\n  if (m1 != flash_magic1) {\n    printf(\"flash: MAGIC 1 does not match!\\n\");\n    return -1;\n  }\n\n  r = fread(&ss, sizeof(long), 1, f);\n  if (r != 1) {\n    printf(\"flash: unexpected end of file!\\n\");\n    return -1;\n  }\n\n  if (ss != sizeof(state)) {\n    printf(\"flash: STRUCT SIZE does not match!\\n\");\n    return -1;\n  }\n\n  r = fread(&state, sizeof(state), 1, f);\n  if (r != 1) {\n    printf(\"flash: unexpected end of file!\\n\");\n    return -1;\n  }\n\n  r = fread(&m2, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"flash: unexpected end of file!\\n\");\n    return -1;\n  }\n\n  if (m2 != flash_magic2) {\n    printf(\"flash: MAGIC 1 does not match!\\n\");\n    return -1;\n  }\n\n  printf(\"flash: %ld bytes restored.\\n\", ss);\n  return 0;\n}\n\nCFlash *theSROM = 0;\n"
  },
  {
    "path": "src/Flash.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_FLASH_H)\n#define INCLUDED_FLASH_H\n\n#include \"SystemComponent.hpp\"\n\n/**\n * \\brief Emulated flash memory.\n *\n * Flash memory is only used for storing configuration data (such as SRM console\n *variables), it is not used for firmware.\n **/\nclass CFlash : public CSystemComponent {\npublic:\n  virtual void WriteMem(int index, u64 address, int dsize, u64 data);\n  virtual u64 ReadMem(int index, u64 address, int dsize);\n  CFlash(CConfigurator *cfg, class CSystem *c);\n  virtual ~CFlash();\n  virtual int SaveState(FILE *f);\n  virtual int RestoreState(FILE *f);\n  void SaveStateF();\n  void RestoreStateF();\n  void SaveStateF(char *fn);\n  void RestoreStateF(char *fn);\n\nprotected:\n  /// The state structure contains all elements that need to be saved to the\n  /// statefile.\n  struct SFlash_state {\n    u8 Flash[2 * 1024 * 1024];\n    int mode;\n  } state;\n};\n\nextern CFlash *theSROM;\n#endif // !defined(INCLUDED_FLASH_H)\n"
  },
  {
    "path": "src/FloppyController.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"FloppyController.hpp\"\n#include \"DMA.hpp\"\n#include \"Disk.hpp\"\n#include \"StdAfx.hpp\"\n#include \"System.hpp\"\n\n/**\n * Constructor.\n **/\nCFloppyController::CFloppyController(CConfigurator *cfg, CSystem *c, int id)\n    : CSystemComponent(cfg, c), CDiskController(1, 2) {\n  c->RegisterMemory(this, 1536, U64(0x00000801fc0003f0) - (0x80 * id), 6);\n  c->RegisterMemory(this, 1537, U64(0x00000801fc0003f7) - (0x80 * id), 1);\n\n  state.cmd_parms_ptr = 0;\n  state.cmd_res_ptr = 0;\n  state.status.rqm = 1;\n  state.status.dio = 0;\n\n  printf(\"%s: $Id: FloppyController.cpp,v 1.16 2008/04/29 09:53:30 iamcamiel \"\n         \"Exp $\\n\",\n         devid_string);\n}\n\n/**\n * Destructor.\n **/\nCFloppyController::~CFloppyController() {}\n\nconst char *datarate_name[] = {\"500 Kb/S MFM\", \"300 Kb/S MFM\", \"250 Kb/S MFM\",\n                               \"1 Mb/S MFM\"};\n\nstruct cmdinfo_t {\n  u8 command;\n  u8 parms;\n  u8 returns;\n  const char *name;\n} cmdinfo[] = {\n    {0, 0, 0, NULL},\n    {0, 0, 0, NULL},\n    {2, 9, 7, \"Read Track\"},\n    {3, 3, 0, \"Specify\"},\n    {4, 2, 1, \"Sense Drive Status\"},\n    {5, 9, 7, \"Write Data\"},\n    {6, 9, 7, \"Read Data\"},\n    {7, 2, 0, \"Recalibrate\"},\n    {8, 1, 2, \"Sense Interrupt Status\"},\n    {9, 9, 7, \"Write Deleted Data\"},\n    {10, 2, 7, \"Read ID\"},\n    {11, 0, 0, NULL},\n    {12, 9, 7, \"Read Deleted\"},\n    {13, 6, 7, \"Format Track\"},\n    {14, 1, 10, \"DumpReg\"},\n    {15, 3, 0, \"Seek\"},\n    {16, 1, 1, \"Version\"},\n    {17, 9, 7, \"Scan Equal\"},\n    {18, 2, 0, \"Perpendicular Mode\"},\n    {19, 4, 0, \"Configure\"},\n    {20, 1, 1, \"Lock\"},\n    {21, 0, 0, NULL},\n    {22, 9, 7, \"Verify\"},\n    {23, 0, 0, NULL},\n    {24, 0, 0, NULL},\n    {25, 9, 7, \"Scan Low or Equal\"},\n    {26, 0, 0, NULL},\n    {27, 0, 0, NULL},\n    {28, 0, 0, NULL},\n    {29, 9, 7, \"Scan High or Equal\"},\n    {30, 0, 0, NULL},\n    {31, 0, 0, NULL},\n};\n\nvoid CFloppyController::WriteMem(int index, u64 address, int dsize, u64 data) {\n  if (index == 1537)\n    address += 7;\n\n  // printf(\"FDC: Write port %d, value: %x\\n\", address, data);\n\n  switch (address) {\n  case FDC_REG_STATUS_A:\n  case FDC_REG_STATUS_B:\n    printf(\"FDC: Read only register %\" PRId64 \" written.\\n\", address);\n    break;\n\n  case FDC_REG_DOR:\n    // bit 4 = drive 0 motor, bit 5 = drive 1 motor\n    // bit 3 = dma enable (ps/2 reserved?)\n    // bit 2 = 1: fdc enable (reset), 0: hold at reset\n    // bits 1-0:  drive select 0: a, 1: b, I assume 2 & 3 are reserved.\n\n    state.drive[0].motor = (data & 0x10) >> 4;\n    state.drive[1].motor = (data & 0x20) >> 5;\n    state.dma = (data & 0x08) >> 3;\n    state.drive_select = data & 0x03;\n\n    printf(\"FDC:  motor a: %s, motor b: %s, dma: %s, drive: %s\\n\",\n           state.drive[0].motor ? \"on\" : \"off\",\n           state.drive[1].motor ? \"on\" : \"off\", state.dma ? \"on\" : \"off\",\n           state.drive_select == 0 ? \"A\" : \"B\");\n\n    break;\n\n  case FDC_REG_TAPE:\n    printf(\"FDC: Tape register written with %\" PRIx64 \"\\n\", data);\n    break;\n\n  case FDC_REG_STATUS: // write = data rate selector\n    // bit 7 = software reset (self clearing)\n    // bit 6 = power down\n    // bit 5 = reserved (0)\n    // bit 4-2 = write precomp (000 = default)\n    // bit 1-0 = data rate select\n\n    state.datarate = data & 0x03;\n    state.write_precomp = (data & 0x1c) >> 2;\n    printf(\"FDC: data rate %s, precomp: %d\\n\", datarate_name[state.datarate],\n           state.write_precomp);\n\n    break;\n\n  case FDC_REG_COMMAND:\n    // the excitement happens here.\n    if (state.status.dio) {\n      printf(\"Unrequested data byte to command port.  Throwing away.\\n\");\n      break;\n    } else {\n      state.cmd_parms[state.cmd_parms_ptr++] = data;\n      int cmd = state.cmd_parms[0] & 0x1F;\n      state.cmd_res_max = cmdinfo[cmd].returns;\n      // printf(\"FDC: parm_ptr: %d, parms: %d\\n\", state.cmd_parms_ptr,\n      // cmdinfo[cmd].parms);\n      if (state.cmd_parms_ptr == cmdinfo[cmd].parms) {\n        printf(\"FDC: command %s(\", cmdinfo[cmd].name);\n        for (int i = 1; i < state.cmd_parms_ptr; i++) {\n          printf(\"%x \", state.cmd_parms[i]);\n        }\n        printf(\")\\n\");\n\n        state.cmd_res_max = cmdinfo[cmd].returns;\n        state.cmd_res_ptr = 0;\n        state.status.rqm = 0;\n        switch (cmd) {\n        case 3: // specify\n          // set up some hardware parameters.  We really don't care about\n          // the times (step rate time, head unload time, head load time}, but\n          // we may care about the ND bit (parm byte 3, bit 1)...\n          state.dma = ~(state.cmd_parms[2] & 0x01);\n          break;\n\n        case 6: // read data\n          // args:\n          // 0: bit 7 = MT (multitrack), 6 = MFM, 5 = SK (skip flag)\n          // 1: bit 2 = HDS (head), 1 = DS1, 0 = DS0\n          // 2: C = cyl\n          // 3: H = head address\n          // 4: R = sector\n          // 5: N = sector size, 2 = 512b\n          // 6: EOT = end of track 0x24 = 36 sectors (18 * 2)\n          // 7: GPL = gap length\n          // 8: DTL = sector size (if N = 0)\n          {\n            int count = theDMA->get_count(2);\n            void *buffer = malloc(count + 1);\n            int pos = (state.cmd_parms[2] * state.cmd_parms[6])         // cyls\n                      + (state.cmd_parms[3] * (state.cmd_parms[6] / 2)) // head\n                      + state.cmd_parms[4] - 1; // sector (sectors start at 1)\n            SEL_FDISK->seek_byte(pos * 512);\n            SEL_FDISK->read_bytes(buffer, count);\n\n            printf(\"FDC: read data:  %x @ %x\\n  \", count, pos * 512);\n            for (int i = 0; i < count; i++) {\n              printf(\"%02x \", *((char *)buffer + i) & 0xff);\n              if (i % 16 == 15)\n                printf(\"\\n  \");\n            }\n            printf(\"\\n\");\n\n            theDMA->send_data(2, buffer);\n\n            state.cmd_parms[4]++;\n            if (state.cmd_parms[4] > (state.cmd_parms[6] / 2)) {\n              state.cmd_parms[4] = 1;\n              state.cmd_parms[3]++;\n              if (state.cmd_parms[3] > 1) {\n                state.cmd_parms[3] = 0;\n                state.cmd_parms[2]++;\n              }\n            }\n\n            state.cmd_res[0] = (state.cmd_parms[1] & 0x03) | ST0_SE | ST0_INTR;\n            state.cmd_res[1] = 0;\n            state.cmd_res[2] = 0;\n            state.cmd_res[3] = state.cmd_parms[2];\n            state.cmd_res[4] = state.cmd_parms[3];\n            state.cmd_res[5] = state.cmd_parms[4];\n            state.cmd_res[6] = state.cmd_parms[5];\n            SEL_DRIVE.seeking = 1;\n\n            do_interrupt();\n          }\n          break;\n\n        case 7:                  // recalibrate\n          SEL_DRIVE.seeking = 3; // wait for 3 status reads to finish seek.\n          SEL_DRIVE.cylinder = 0;\n          do_interrupt();\n          break;\n\n        case 8: // sense interrupt status\n          if (!state.interrupt)\n            state.cmd_res[0] = 0x80;\n          else\n            state.cmd_res[0] = 0x00; // ?\n\n          state.cmd_res[1] = SEL_DRIVE.cylinder; // present cylinder number\n          break;\n\n        case 15: // seek\n          // args:\n          // 0: opcode\n          // 1: bit 2 = HDS (head), 1 = DS1, 0 = DS0\n          // 2: NCN = new cylinder number\n          SEL_DRIVE.seeking = 3; // wait 3 status reads to finish seek.\n          SEL_DRIVE.cylinder = state.cmd_parms[2];\n          do_interrupt();\n          break;\n\n        case 18: // perpendicular mode\n          // We really don't care, somehow\n          break;\n\n        case 19: // configure\n          // we're software, we don't care (I think)\n          break;\n\n        default:\n          printf(\"Unhandled floppy command: %d = %s\\n\", cmd, cmdinfo[cmd].name);\n          exit(1);\n        }\n\n        state.status.rqm = 1;\n        if (cmdinfo[cmd].returns > 0) {\n          state.status.dio = 1;\n        }\n        state.cmd_parms_ptr = 0;\n      } else {\n        // printf(\"FDC: command parameter byte %d = %x, expecting %d bytes for\n        // %s\\n\", state.cmd_parms_ptr-1, data, cmdinfo[state.cmd_parms[0] &\n        // 0x1f].parms, cmdinfo[state.cmd_parms[0] &0x1f].name);\n      }\n    }\n\n    break;\n\n  case FDC_REG_DIR:\n    // PC/AT, PS/2\n    //    bits 7-2 = reserved\n    //    bit 0-1 = MFM data rate\n    state.datarate = data & 0x03;\n    printf(\"FDC: data rate %s\\n\", datarate_name[state.datarate]);\n\n    break;\n  }\n}\n\nu64 CFloppyController::ReadMem(int index, u64 address, int dsize) {\n  u64 data = 0;\n\n  if (index == 1537)\n    address += 7;\n\n  switch (address) {\n  case FDC_REG_STATUS_A:\n    // bit 7 = interrupt pending\n    // bit 6 = -DRV2  (second drive installed)\n    // bit 5 = step\n    // bit 4 = -track0\n    // bit 3 = head1 select\n    // bit 2 = -index\n    // bit 1 = -write protect\n    // bit 0 = +direction\n\n    break;\n\n  case FDC_REG_STATUS_B:\n    // bit 7-6 reserved (1)\n    // bit 5 = drive select\n    // bit 4 = write data\n    // bit 3 = read data\n    // bit 2 = write enable\n    // bit 1 = motor 1 enable\n    // bit 0 = motor 0 enable\n\n    break;\n\n  case FDC_REG_DOR:\n  case FDC_REG_TAPE:\n    printf(\"FDC: Write only register %\" PRId64 \" read.\", address);\n    break;\n\n  case FDC_REG_STATUS:\n    data = get_status();\n    break;\n\n  case FDC_REG_COMMAND:\n    // The data comes back from here.\n    data = state.cmd_res[state.cmd_res_ptr++];\n    if (state.cmd_res_ptr >= state.cmd_res_max) {\n      state.status.rqm = 1;\n      state.status.dio = 0;\n    }\n\n    break;\n\n  case FDC_REG_DIR:\n    // PS/2 mode:\n    //    bit 7 = diskette change\n    //    bits 6-3 = 1\n    //    bit 2 = datarate select 1\n    //    bit 1 = datarate select 0\n    //    bit 0 = high density select\n\n    break;\n  }\n\n  printf(\"FDC: Read register %\" PRId64 \", value: %\" PRIx64 \"\\n\", address, data);\n\n  return data;\n}\n\nstatic u32 fdc_magic1 = 0x0fdc0fdc;\nstatic u32 fdc_magic2 = 0xfdc0fdc0;\n\nint CFloppyController::SaveState(FILE *f) {\n  long ss = sizeof(state);\n\n  fwrite(&fdc_magic1, sizeof(u32), 1, f);\n  fwrite(&ss, sizeof(long), 1, f);\n  fwrite(&state, sizeof(state), 1, f);\n  fwrite(&fdc_magic2, sizeof(u32), 1, f);\n  printf(\"fdc: %ld bytes saved.\\n\", ss);\n  return 0;\n}\n\nint CFloppyController::RestoreState(FILE *f) {\n  long ss;\n  u32 m1;\n  u32 m2;\n  size_t r;\n\n  r = fread(&m1, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"fdc: unexpected end of file!\\n\");\n    return -1;\n  }\n\n  if (m1 != fdc_magic1) {\n    printf(\"fdc: MAGIC 1 does not match!\\n\");\n    return -1;\n  }\n\n  r = fread(&ss, sizeof(long), 1, f);\n  if (r != 1) {\n    printf(\"fdc: unexpected end of file!\\n\");\n    return -1;\n  }\n\n  if (ss != sizeof(state)) {\n    printf(\"fdc: STRUCT SIZE does not match!\\n\");\n    return -1;\n  }\n\n  r = fread(&state, sizeof(state), 1, f);\n  if (r != 1) {\n    printf(\"fdc: unexpected end of file!\\n\");\n    return -1;\n  }\n\n  r = fread(&m2, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"fdc: unexpected end of file!\\n\");\n    return -1;\n  }\n\n  if (m2 != fdc_magic2) {\n    printf(\"fdc: MAGIC 1 does not match!\\n\");\n    return -1;\n  }\n\n  printf(\"fdc: %ld bytes restored.\\n\", ss);\n  return 0;\n}\n\nvoid CFloppyController::do_interrupt() {\n  // *shrug* I'll figure this out later.\n  state.interrupt = true;\n}\n\nu8 CFloppyController::get_status() {\n  // bit 7 = RQM data register is ready (0: no access is permitted)\n  // bit 6 = 1: transfer from controller to system, 0: sys to controller\n  // bit 5 = non dma mode\n  // bit 4 = diskette controller is busy\n  // bit 3-2 reserved\n  // bit 1 = drive 1 is busy (seeking)\n  // bit 0 = drive 0 is busy (seeking)\n\n  for (int i = 0; i < 2; i++) {\n    if (state.drive[i].seeking > 0)\n      state.drive[i].seeking--;\n    if (state.drive[i].seeking == 0)\n      state.status.seeking[i] = false;\n    else\n      state.status.seeking[i] = true;\n  }\n\n  // we mark the controller busy if a disk is seeking or\n  // if there is data waiting to be sent by the controller.\n  if (state.status.seeking[0] || state.status.seeking[1] ||\n      (state.status.dio && state.status.rqm))\n    state.status.busy = true;\n  else\n    state.status.busy = false;\n\n  printf(\"FDC Status: %s, %s, %s, %s, %s, %s\\n\",\n         state.status.rqm ? \"Data Register Ready\" : \"No Access\",\n         state.status.dio ? \"C->S\" : \"S->C\",\n         state.status.nondma ? \"No DMA\" : \"DMA\",\n         state.status.busy ? \"BUSY\" : \"not busy\",\n         state.status.seeking[0] ? \"Disk 1 Seeking\" : \"Disk 1 Idle\",\n         state.status.seeking[1] ? \"Disk 0 Seeking\" : \"Disk 0 Idle\");\n\n  u8 data =\n      (state.status.rqm ? 0x80 : 0x00) | (state.status.dio ? 0x40 : 0x00) |\n      (state.status.nondma ? 0x20 : 0x00) | (state.status.busy ? 0x10 : 0x00) |\n      (state.status.seeking[1] ? 0x02 : 0x00) |\n      (state.status.seeking[0] ? 0x01 : 0x00);\n  return data;\n}\n"
  },
  {
    "path": "src/FloppyController.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_FLOPPYCONTROLLER_H)\n#define INCLUDED_FLOPPYCONTROLLER_H\n\n#include \"DMA.hpp\"\n#include \"DiskController.hpp\"\n#include \"SystemComponent.hpp\"\n\n/**\n * \\brief Emulated floppy-drive controller.\n **/\nclass CFloppyController : public CSystemComponent, public CDiskController {\npublic:\n  virtual u64 ReadMem(int index, u64 address, int dsize);\n  virtual void WriteMem(int index, u64 address, int dsize, u64 data);\n  CFloppyController(class CConfigurator *cfg, class CSystem *c, int id);\n  virtual ~CFloppyController();\n  virtual int RestoreState(FILE *f);\n  virtual int SaveState(FILE *f);\n\nprivate:\n  void do_interrupt();\n  u8 get_status();\n\n  struct {\n    struct {\n      int seeking;\n      int cylinder;\n      bool motor;\n    } drive[2];\n\n    u8 write_precomp;\n    u8 drive_select;\n    bool dma;\n    u8 datarate;\n\n    struct {\n      bool rqm;\n      bool dio;\n      bool nondma;\n      bool busy;\n      bool seeking[2];\n    } status;\n\n    int busy;\n    u8 cmd_parms[16];\n    u8 cmd_parms_ptr;\n    u8 cmd_res[16];\n    u8 cmd_res_ptr;\n    u8 cmd_res_max;\n\n    bool interrupt;\n\n  } state;\n};\n\n#define FDC_REG_STATUS_A 0\n#define FDC_REG_STATUS_B 1\n#define FDC_REG_DOR 2\n#define FDC_REG_TAPE 3\n#define FDC_REG_STATUS 4\n#define FDC_REG_COMMAND 5\n#define FDC_REG_DIR 7\n\n#define SEL_DRIVE state.drive[state.drive_select]\n#define SEL_FDISK get_disk(0, state.drive_select)\n#define DRIVE(i) state.drive[i]\n#define FDISK(i) get_disk(0, i)\n\n//\n// These defines were stolen from the Linux 1.0 fdreg.h file :)\n//\n/* Bits of FD_ST0 */\n#define ST0_DS 0x03   /* drive select mask */\n#define ST0_HA 0x04   /* Head (Address) */\n#define ST0_NR 0x08   /* Not Ready */\n#define ST0_ECE 0x10  /* Equipment chech error */\n#define ST0_SE 0x20   /* Seek end */\n#define ST0_INTR 0xC0 /* Interrupt code mask */\n\n/* Bits of FD_ST1 */\n#define ST1_MAM 0x01 /* Missing Address Mark */\n#define ST1_WP 0x02  /* Write Protect */\n#define ST1_ND 0x04  /* No Data - unreadable */\n#define ST1_OR 0x10  /* OverRun */\n#define ST1_CRC 0x20 /* CRC error in data or addr */\n#define ST1_EOC 0x80 /* End Of Cylinder */\n\n/* Bits of FD_ST2 */\n#define ST2_MAM 0x01 /* Missing Addess Mark (again) */\n#define ST2_BC 0x02  /* Bad Cylinder */\n#define ST2_SNS 0x04 /* Scan Not Satisfied */\n#define ST2_SEH 0x08 /* Scan Equal Hit */\n#define ST2_WC 0x10  /* Wrong Cylinder */\n#define ST2_CRC 0x20 /* CRC error in data field */\n#define ST2_CM 0x40  /* Control Mark = deleted */\n\n/* Bits of FD_ST3 */\n#define ST3_HA 0x04 /* Head (Address) */\n#define ST3_TZ 0x10 /* Track Zero signal (1=track 0) */\n#define ST3_WP 0x40 /* Write Protect */\n\n#endif // !defined(INCLUDED_FLOPPYCONTROLLER_H)\n"
  },
  {
    "path": "src/FreeTextQuestion.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"Question.hpp\"\n\n/**\n * Question class that allows free-format text input.\n **/\nclass FreeTextQuestion : public Question {\npublic:\n  /**\n   * Define a list of options to show following the question,\n   * to show the user what values are acceptable.\n   **/\n  void setOptions(string options) { mOptions = options; }\n\n  /**\n   * Ask the question, and return the answer.\n   **/\n  virtual string ask() {\n    for (;;) {\n      cout << mQuestion;\n\n      /* If there is an options list, display it after the\n       * question enclosed in ().\n       */\n      if (mOptions != \"\")\n        cout << \" (\" << mOptions << \")\";\n\n      /* If there is a default value, display it after the\n       * question enclosed in [].\n       */\n      if (mDefault != \"\")\n        cout << \" [\" << mDefault << \"]\";\n\n      cout << \": \";\n\n      /* Get the answer.\n       */\n      getline(cin, mAnswer);\n\n      /* If the question is answered with '?', display the\n       * explanation, then ask again.\n       */\n      if (mAnswer == \"?\") {\n        explain();\n        continue;\n      }\n\n      /* If the question is answered with <return>, set the\n       * answer to the default answer.\n       */\n      if (mAnswer == \"\")\n        mAnswer = mDefault;\n\n      /* Return the answer.\n       */\n      return mAnswer;\n    }\n  }\n\nprotected:\n  /** List of options to show after the question. */\n  string mOptions;\n};\n"
  },
  {
    "path": "src/Keyboard.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"Keyboard.hpp\"\n#include \"AliM1543C.hpp\"\n#include \"StdAfx.hpp\"\n#include \"System.hpp\"\n#include <math.h>\n\n#include \"gui/keymap.hpp\"\n#include \"gui/scancodes.hpp\"\n\n/**\n * Constructor.\n **/\nCKeyboard::CKeyboard(CConfigurator *cfg, CSystem *c)\n    : CSystemComponent(cfg, c) {\n  if (theKeyboard != 0)\n    FAILURE(Configuration, \"More than one Keyboard controller\");\n  theKeyboard = this;\n}\n\n/**\n * Initialize the Keyboard device.\n **/\nvoid CKeyboard::init() {\n  int i;\n\n  cSystem->RegisterMemory(this, 0, U64(0x00000801fc000060), 1);\n  cSystem->RegisterMemory(this, 1, U64(0x00000801fc000064), 1);\n\n  resetinternals(1);\n\n  state.kbd_internal_buffer.led_status = 0;\n  state.kbd_internal_buffer.scanning_enabled = 1;\n\n  state.mouse_internal_buffer.num_elements = 0;\n  for (i = 0; i < BX_MOUSE_BUFF_SIZE; i++)\n    state.mouse_internal_buffer.buffer[i] = 0;\n  state.mouse_internal_buffer.head = 0;\n\n  state.status.pare = 0;\n  state.status.tim = 0;\n  state.status.auxb = 0;\n  state.status.keyl = 1;\n  state.status.c_d = 1;\n  state.status.sysf = 0;\n  state.status.inpb = 0;\n  state.status.outb = 0;\n\n  state.kbd_clock_enabled = 1;\n  state.aux_clock_enabled = 0;\n  state.allow_irq1 = 1;\n  state.allow_irq12 = 1;\n  state.kbd_output_buffer = 0;\n  state.aux_output_buffer = 0;\n  state.last_comm = 0;\n  state.expecting_port60h = 0;\n  state.irq1_requested = 0;\n  state.irq12_requested = 0;\n  state.expecting_mouse_parameter = 0;\n  state.bat_in_progress = 0;\n  state.scancodes_translate = 1;\n\n  state.timer_pending = 0;\n\n  // Mouse initialization stuff\n  state.mouse.captured = myCfg->get_bool_value(\"mouse.enabled\", true);\n  state.mouse.sample_rate = 100;   // reports per second\n  state.mouse.resolution_cpmm = 4; // 4 counts per millimeter\n  state.mouse.scaling = 1;         /* 1:1 (default) */\n  state.mouse.mode = MOUSE_MODE_RESET;\n  state.mouse.enable = 0;\n  state.mouse.delayed_dx = 0;\n  state.mouse.delayed_dy = 0;\n  state.mouse.delayed_dz = 0;\n  state.mouse.im_request = 0; // wheel mouse mode request\n  state.mouse.im_mode = 0;    // wheel mouse mode\n  for (i = 0; i < BX_KBD_CONTROLLER_QSIZE; i++)\n    state.kbd_controller_Q[i] = 0;\n  state.kbd_controller_Qsize = 0;\n  state.kbd_controller_Qsource = 0;\n\n  printf(\"kbc: $Id: Keyboard.cpp,v 1.10 2008/05/31 15:47:09 iamcamiel Exp $\\n\");\n}\n\nvoid CKeyboard::start_threads() {\n  if (!myThread) {\n    printf(\" kbd\");\n    StopThread = false;\n    myThread = std::make_unique<std::thread>([this](){ this->run(); });\n  }\n}\n\nvoid CKeyboard::stop_threads() {\n  StopThread = true;\n  if (myThread) {\n    printf(\" kbd\");\n    myThread->join();\n    myThread = nullptr;\n  }\n}\n\n/**\n * Destructor.\n **/\nCKeyboard::~CKeyboard() { stop_threads(); }\n\nu64 CKeyboard::ReadMem(int index, u64 address, int dsize) {\n  switch (index) {\n  case 0:\n    return read_60();\n    break;\n  case 1:\n    return read_64();\n    break;\n  default:\n    FAILURE(InvalidArgument, \"kbc: ReadMem index out of range\");\n  }\n}\n\nvoid CKeyboard::WriteMem(int index, u64 address, int dsize, u64 data) {\n  switch (index) {\n  case 0:\n    write_60((u8)data);\n    break;\n  case 1:\n    write_64((u8)data);\n    break;\n  default:\n    FAILURE(InvalidArgument, \"kbc: ReadMem index out of range\");\n  }\n}\n\n/**\n * Enqueue scancode for a keypress or key-release. Used by the GUI\n *implementation to send keypresses to the keyboard controller.\n **/\nvoid CKeyboard::gen_scancode(u32 key) {\n  unsigned char *scancode;\n  u8 i;\n\n#if defined(DEBUG_KBD)\n  printf(\"gen_scancode(): %s %s  \\n\", bx_keymap->getBXKeyName(key),\n         (key >> 31) ? \"released\" : \"pressed\");\n  if (!state.scancodes_translate)\n    BX_DEBUG((\"keyboard: gen_scancode with scancode_translate cleared\"));\n#endif\n\n  // Ignore scancode if keyboard clock is driven low\n  if (state.kbd_clock_enabled == 0)\n    return;\n\n  // Ignore scancode if scanning is disabled\n  if (state.kbd_internal_buffer.scanning_enabled == 0)\n    return;\n\n  // Source: http://www.win.tue.nl/~aeb/linux/kbd/scancodes-10.html\n  //\n  // Three scancode sets\n  //\n  // The usual PC keyboards are capable of producing three sets\n  // of scancodes. Writing 0xf0 followed by 1, 2 or 3 to port\n  // 0x60 will put the keyboard in scancode mode 1, 2 or 3.\n  // Writing 0xf0 followed by 0 queries the mode, resulting in\n  // a scancode byte 43, 41 or 3f from the keyboard.\n  //\n  // Set 1 contains the values that the XT keyboard (with only\n  // one set of scancodes) produced, with extensions for new\n  // keys. Someone decided that another numbering was more\n  // logical and invented scancode Set 2. However, it was\n  // realized that new scancodes would break old programs, so\n  // the keyboard output was fed to a 8042 microprocessor on\n  // the motherboard that could translate Set 2 back into Set\n  // 1. Indeed a smart construction. This is the default today.\n  // Finally there is the PS/2 version, Set 3, more regular,\n  // but used by almost nobody.\n  //\n  // Sets 2 and 3 are designed to be translated by the 8042.\n  // Set 1 should not be translated.\n  //\n  // Make and Break Codes\n  //\n  // The key press / key release is coded as follows:\n  //\n  // For Set 1, if the make code of a key is c, the break\n  // code will be c+0x80. If the make code is e0 c, the\n  // break code will be e0 c+0x80. The Pause key has make\n  // code e1 1d 45 e1 9d c5 and does not generate a break code.\n  //\n  // For Set 2, if the make code of a key is c, the break code\n  // will be f0 c. If the make code is e0 c, the break code\n  // will be e0 f0 c. The Pause key has the 8-byte make code\n  // e1 14 77 e1 f0 14 f0 77.\n  //\n  // For Set 3, by default most keys do not generate a break\n  // code - only CapsLock, LShift, RShift, LCtrl and LAlt do.\n  // However, by default all non-traditional keys do generate\n  // a break code - thus, LWin, RWin, Menu do, and for example\n  // on the Microsoft Internet keyboard, so do Back, Forward,\n  // Stop, Mail, Search, Favorites, Web/Home, MyComputer,\n  // Calculator, Sleep. On my BTC keyboard, also the Macro key\n  // does.\n  //\n  // In Scancode Mode 3 it is possible to enable or disable\n  // key repeat and the production of break codes either on a\n  // key-by-key basis or for all keys at once. And just like\n  // for Set 2, key release is indicated by a f0 prefix in\n  // those cases where it is indicated. There is nothing\n  // special with the Pause key in scancode mode 3.\n  if (key & BX_KEY_RELEASED)\n    scancode =\n        (unsigned char *)scancodes[(key & 0xFF)][state.current_scancodes_set]\n            .brek;\n  else\n    scancode =\n        (unsigned char *)scancodes[(key & 0xFF)][state.current_scancodes_set]\n            .make;\n\n  // Translation\n  //\n  // The 8042 microprocessor translates the incoming byte stream\n  // produced by the keyboard, and turns an f0 prefix into an OR\n  // with 80 for the next byte.\n  //\n  // Unless told not to translate, the keyboard controller translates\n  // keyboard scancodes into the scancodes it returns to the CPU using\n  // the following table (in hex):\n  //\n  // +----+-------------------------------------------------+\n  // |    | 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f |\n  // +----+-------------------------------------------------+\n  // | 00 | ff 43 41 3f 3d 3b 3c 58 64 44 42 40 3e 0f 29 59 |\n  // | 10 |     65 38 2a 70 1d 10 02 5a 66 71 2c 1f 1e 11 03 5b |\n  // | 20 |     67 2e 2d 20 12 05 04 5c 68 39 2f 21 14 13 06 5d |\n  // | 30 |     69 31 30 23 22 15 07 5e 6a 72 32 24 16 08 09 5f |\n  // | 40 |     6b 33 25 17 18 0b 0a 60 6c 34 35 26 27 19 0c 61 |\n  // | 50 |     6d 73 28 74 1a 0d 62 6e 3a 36 1c 1b 75 2b 63 76 |\n  // | 60 |     55 56 77 78 79 7a 0e 7b 7c 4f 7d 4b 47 7e 7f 6f |\n  // | 70 |     52 53 50 4c 4d 48 01 45 57 4e 51 4a 37 49 46 54 |\n  // | 80 |     80 81 82 41 54 85 86 87 88 89 8a 8b 8c 8d 8e 8f |\n  // | 90 |     90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f |\n  // | a0 |     a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af |\n  // | b0 |     b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf |\n  // | c0 |     c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf |\n  // | d0 |     d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df |\n  // | e0 |     e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef |\n  // | f0 |     -  f1 f2 f3     f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff |\n  // +----+-------------------------------------------------+\n  if (state.scancodes_translate) {\n\n    // Translate before send\n    u8 escaped = 0x00;\n\n    for (i = 0; i < strlen((const char *)scancode); i++) {\n      if (scancode[i] == 0xF0) {\n        escaped = 0x80;\n      } else {\n#if defined(DEBUG_KBD)\n        printf(\"gen_scancode(): writing translated %02x   \\n\",\n               translation8042[scancode[i]] | escaped);\n#endif\n        enQ(translation8042[scancode[i]] | escaped);\n        escaped = 0x00;\n      }\n    }\n  } else {\n\n    // Send raw data\n    for (i = 0; i < strlen((const char *)scancode); i++) {\n#if defined(DEBUG_KBD)\n      printf(\"gen_scancode(): writing raw %02x   \\n\", scancode[i]);\n#endif\n      enQ(scancode[i]);\n    }\n  }\n}\n\n/**\n * Reset keyboard internals.\n **/\nvoid CKeyboard::resetinternals(bool powerup) {\n  state.kbd_internal_buffer.num_elements = 0;\n  for (int i = 0; i < BX_KBD_ELEMENTS; i++)\n    state.kbd_internal_buffer.buffer[i] = 0;\n  state.kbd_internal_buffer.head = 0;\n\n  state.kbd_internal_buffer.expecting_typematic = 0;\n  state.kbd_internal_buffer.expecting_make_break = 0;\n\n  // Default scancode set is mf2 (translation is controlled by the 8042)\n  state.expecting_scancodes_set = 0;\n\n  // state.current_scancodes_set = 1;\n  state.current_scancodes_set = 2;\n\n  // state.scancodes_translate = 1;\n  if (powerup) {\n    state.kbd_internal_buffer.expecting_led_write = 0;\n    state.kbd_internal_buffer.delay = 1;          // 500 mS\n    state.kbd_internal_buffer.repeat_rate = 0x0b; // 10.9 chars/sec\n  }\n}\n\n/**\n * Enqueue a byte (scancode) into the keyboard buffer.\n **/\nvoid CKeyboard::enQ(u8 scancode) {\n  int tail;\n\n#if defined(DEBUG_KBD)\n  printf(\"enQ(0x%02x)\", (unsigned)scancode);\n#endif\n  if (state.kbd_internal_buffer.num_elements >= BX_KBD_ELEMENTS) {\n    printf(\"internal keyboard buffer full, ignoring scancode.(%02x)  \\n\",\n           (unsigned)scancode);\n    return;\n  }\n\n  /* enqueue scancode in multibyte internal keyboard buffer */\n#if defined(DEBUG_KBD)\n  BX_DEBUG(\n      (\"enQ: putting scancode 0x%02x in internal buffer\", (unsigned)scancode));\n#endif\n  tail = (state.kbd_internal_buffer.head +\n          state.kbd_internal_buffer.num_elements) %\n         BX_KBD_ELEMENTS;\n  state.kbd_internal_buffer.buffer[tail] = scancode;\n  state.kbd_internal_buffer.num_elements++;\n\n  if (!state.status.outb && state.kbd_clock_enabled) {\n    state.timer_pending = 1;\n    return;\n  }\n}\n\n/**\n * Read a byte from keyboard port 60.\n **/\nu8 CKeyboard::read_60() {\n  u8 val;\n\n  /* output buffer */\n  if (state.status.auxb) { /* mouse byte available */\n    val = state.aux_output_buffer;\n    state.aux_output_buffer = 0;\n    state.status.outb = 0;\n    state.status.auxb = 0;\n    state.irq12_requested = 0;\n\n    if (state.kbd_controller_Qsize) {\n      unsigned i;\n      state.aux_output_buffer = state.kbd_controller_Q[0];\n      state.status.outb = 1;\n      state.status.auxb = 1;\n      if (state.allow_irq12)\n        state.irq12_requested = 1;\n      for (i = 0; i < state.kbd_controller_Qsize - 1; i++) {\n\n        // move Q elements towards head of queue by one\n        state.kbd_controller_Q[i] = state.kbd_controller_Q[i + 1];\n      }\n\n      state.kbd_controller_Qsize--;\n    }\n\n    // DEV_pic_lower_irq(12);\n    state.timer_pending = 1;\n    execute();\n#if defined(DEBUG_KBD)\n    BX_DEBUG((\"[mouse] read from 0x60 returns 0x%02x\", val));\n#endif\n    return val;\n  } else if (state.status.outb) { /* kbd byte available */\n    val = state.kbd_output_buffer;\n    state.status.outb = 0;\n    state.status.auxb = 0;\n    state.irq1_requested = 0;\n    state.bat_in_progress = 0;\n\n    if (state.kbd_controller_Qsize) {\n      unsigned i;\n      state.aux_output_buffer = state.kbd_controller_Q[0];\n      state.status.outb = 1;\n      state.status.auxb = 1;\n      if (state.allow_irq1)\n        state.irq1_requested = 1;\n      for (i = 0; i < state.kbd_controller_Qsize - 1; i++) {\n\n        // move Q elements towards head of queue by one\n        state.kbd_controller_Q[i] = state.kbd_controller_Q[i + 1];\n      }\n\n#if defined(DEBUG_KBD)\n      BX_DEBUG((\"s.controller_Qsize: %02X\", state.kbd_controller_Qsize));\n#endif\n      state.kbd_controller_Qsize--;\n    }\n\n    //      DEV_pic_lower_irq(1);\n    state.timer_pending = 1;\n    execute();\n#if defined(DEBUG_KBD)\n    BX_DEBUG((\"READ(60) = %02x\", (unsigned)val));\n#endif\n    return val;\n  } else {\n#if defined(DEBUG_KBD)\n    BX_DEBUG((\"num_elements = %d\", state.kbd_internal_buffer.num_elements));\n    BX_DEBUG((\"read from port 60h with outb empty\"));\n    BX_DEBUG((\"READ(60) = %02x\", state.kbd_output_buffer));\n#endif\n    return state.kbd_output_buffer;\n  }\n}\n\n/**\n * Read a byte from keyboard port 64\n *\n * The keyboard controller status register\n *\n * The keyboard controller has an 8-bit status register. It can be inspected by\n *the CPU by reading port 0x64. (Typically, it has the value 0x14: keyboard not\n *locked, self-test completed.)\n *\n * \\code\n * +------+-----+------+------+-----+------+------+------+\n * | PARE |\tTIM | AUXB | KEYL | C/D | SYSF | INPB | OUTB |\n * +------+-----+------+------+-----+------+------+------+\n * \\endcode\n *\n * Bit 7: Parity error\n *    0: OK.\n *    1: Parity error with last byte.\n *\n * Bit 6: Timeout\n *    0: OK.\n *    1: General timeout.\n *\n * Bit 5: Auxiliary output buffer full\n *    Bit 0 tells whether a read from port 0x60 will be valid. If it is valid,\n *this bit 5 tells what data will be read from port 0x60. 0: Keyboard data. 1:\n *Mouse data.\n *\n * Bit 4: Keyboard lock\n *    0: Locked.\n *    1: Not locked.\n *\n * Bit 3: Command/Data\n *    0: Last write to input buffer was data (written via port 0x60).\n *    1: Last write to input buffer was a command (written via port 0x64). (This\n *bit is also referred to as Address Line A2.)\n *\n * Bit 2: System flag\n *    Set to 0 after power on reset. Set to 1 after successful completion of the\n *keyboard controller self-test (Basic Assurance Test, BAT). Can also be set by\n *command (see below).\n *\n * Bit 1: Input buffer status\n *    0: Input buffer empty, can be written.\n *    1: Input buffer full, don't write yet.\n *\n * Bit 0: Output buffer status\n *    0: Output buffer empty, don't read yet.\n *    1: Output buffer full, can be read. (Bit 5 tells whether the available\n *data is from keyboard or mouse.) This bit is cleared when port 0x60 is read.\n **/\nu8 CKeyboard::read_64() {\n  u8 val;\n\n  /* status register */\n  val = (state.status.pare << 7) | (state.status.tim << 6) |\n        (state.status.auxb << 5) | (state.status.keyl << 4) |\n        (state.status.c_d << 3) | (state.status.sysf << 2) |\n        (state.status.inpb << 1) | (state.status.outb << 0);\n  state.status.tim = 0;\n#if defined(DEBUG_KBD)\n  BX_DEBUG((\"read from 0x64 returns 0x%02x\", val));\n#endif\n  return val;\n}\n\n/**\n * Write a byte to keyboard port 60.\n **/\nvoid CKeyboard::write_60(u8 value) {\n#if defined(DEBUG_KBD)\n  printf(\"kbd: port 60 write: %02x.   \\n\", value);\n#endif\n\n  // data byte written last to 0x60\n  state.status.c_d = 0;\n\n  // if expecting data byte from command last sent to port 64h\n  if (state.expecting_port60h) {\n    state.expecting_port60h = 0;\n#if defined(DEBUG_KBD)\n    if (state.status.inpb)\n      printf(\"write to port 60h, not ready for write   \\n\");\n#endif\n    switch (state.last_comm) {\n    case 0x60: // write command byte\n    {\n\n      // The keyboard controller is provided with some RAM, for example\n      // 32 bytes, that can be accessed by the CPU. The most important\n      // part of this RAM is byte 0, the Controller Command Byte (CCB).\n      // It can be read/written by writing 0x20/0x60 to port 0x64 and\n      // then reading/writing a data byte from/to port 0x60.\n      //\n      // This byte has the following layout.\n      //\n      // +---+-------+----+----+---+------+-----+-----+\n      // | 0 | XLATE | ME | KE | 0 | SYSF | MIE | KIE |\n      // +---+-------+----+----+---+------+-----+-----+\n      //\n      // Bit 6: Translate\n      //    0: No translation.\n      //    1: Translate keyboard scancodes, using the translation table\n      //       given above. MCA type 2 controllers cannot set this bit\n      //       to 1. In this case scan code conversion is set using\n      //       keyboard command 0xf0 to port 0x60.\n      //\n      // Bit 5: Mouse enable\n      //    0: Enable mouse.\n      //    1: Disable mouse by driving the clock line low.\n      //\n      // Bit 4: Keyboard enable\n      //    0: Enable keyboard.\n      //    1: Disable keyboard by driving the clock line low.\n      //\n      // Bit 2: System flag\n      //    This bit is shown in bit 2 of the status register. A\n      //    \"cold reboot\" is one with this bit set to zero. A\n      //    \"warm reboot\" is one with this bit set to one (BAT\n      //    already completed). This will influence the tests and\n      //    initializations done by the POST.\n      //\n      // Bit 1: Mouse interrupt enable\n      //    0: Do not use mouse interrupts.\n      //    1: Send interrupt request IRQ12 when the mouse output\n      //       buffer is full.\n      //\n      // Bit 0: Keyboard interrupt enable\n      //    0: Do not use keyboard interrupts.\n      //    1: Send interrupt request IRQ1 when the keyboard output\n      //       buffer is full.\n      //\n      //    When no interrupts are used, the CPU has to poll bits 0\n      //    (and 5) of the status register.\n      bool scan_convert;\n\n      // The keyboard controller is provided with some RAM, for example\n      bool disable_keyboard;\n\n      // The keyboard controller is provided with some RAM, for example\n      bool disable_aux;\n\n      scan_convert = (value >> 6) & 0x01;\n      disable_aux = (value >> 5) & 0x01;\n      disable_keyboard = (value >> 4) & 0x01;\n      state.status.sysf = (value >> 2) & 0x01;\n      state.allow_irq1 = (value >> 0) & 0x01;\n      state.allow_irq12 = (value >> 1) & 0x01;\n      set_kbd_clock_enable(!disable_keyboard);\n      set_aux_clock_enable(!disable_aux);\n      if (state.allow_irq12 && state.status.auxb)\n        state.irq12_requested = 1;\n      else if (state.allow_irq1 && state.status.outb)\n        state.irq1_requested = 1;\n\n#if defined(DEBUG_KBD)\n      BX_DEBUG((\" allow_irq12 set to %u\", (unsigned)state.allow_irq12));\n      if (!scan_convert)\n        BX_INFO((\"keyboard: scan convert turned off\"));\n#endif\n\n      // (mch) NT needs this\n      state.scancodes_translate = scan_convert;\n    } break;\n\n    case 0xd1: // write output port\n#if defined(DEBUG_KBD)\n      BX_DEBUG((\"write output port with value %02xh\", (unsigned)value));\n#endif\n      break;\n\n    case 0xd4: // Write to mouse\n      // I don't think this enables the AUX clock\n      // set_aux_clock_enable(1); // enable aux clock line\n      ctrl_to_mouse(value);\n\n      // ??? should I reset to previous value of aux enable?\n      break;\n\n    case 0xd3: // write mouse output buffer\n      // Queue in mouse output buffer\n      controller_enQ(value, 1);\n      break;\n\n    case 0xd2:\n\n      // Queue in keyboard output buffer\n      controller_enQ(value, 0);\n      break;\n\n    default:\n      printf(\"=== unsupported write to port 60h(lastcomm=%02x): %02x   \\n\",\n             (unsigned)state.last_comm, (unsigned)value);\n    }\n  } else {\n\n    // data byte written last to 0x60\n    state.status.c_d = 0;\n    state.expecting_port60h = 0;\n\n    /* pass byte to keyboard */\n\n    /* ??? should conditionally pass to mouse device here ??? */\n    if (state.kbd_clock_enabled == 0)\n      set_kbd_clock_enable(1);\n    ctrl_to_kbd(value);\n  }\n\n  execute();\n}\n\n/**\n * Write a byte to keyboard port 64.\n **/\nvoid CKeyboard::write_64(u8 value) {\n#if defined(DEBUG_KBD)\n  printf(\"kbd: port 64 write: %02x.   \\n\", value);\n#endif\n\n  static int kbd_initialized = 0;\n  u8 command_byte;\n\n  // command byte written last to 0x64\n  state.status.c_d = 1;\n  state.last_comm = value;\n\n  // most commands NOT expecting port60 write next\n  state.expecting_port60h = 0;\n\n  switch (value) {\n  case 0x20: // get keyboard command byte\n#if defined(DEBUG_KBD)\n    BX_DEBUG((\"get keyboard command byte\"));\n#endif\n\n    // controller output buffer must be empty\n    if (state.status.outb) {\n#if defined(DEBUG_KBD)\n      BX_ERROR((\"kbd: OUTB set and command 0x%02x encountered\", value));\n#endif\n      break;\n    }\n\n    command_byte = (state.scancodes_translate << 6) |\n                   ((!state.aux_clock_enabled) << 5) |\n                   ((!state.kbd_clock_enabled) << 4) | (0 << 3) |\n                   (state.status.sysf << 2) | (state.allow_irq12 << 1) |\n                   (state.allow_irq1 << 0);\n    controller_enQ(command_byte, 0);\n    break;\n\n  case 0x60: // write command byte\n#if defined(DEBUG_KBD)\n    printf(\"kbd_ctrl: command 60: write command byte.   \\n\");\n#endif\n\n    // following byte written to port 60h is command byte\n    state.expecting_port60h = 1;\n    break;\n\n  case 0xa0:\n#if defined(DEBUG_KBD)\n    printf(\"kbd_ctrl: command a0: BIOS name (not supported).   \\n\");\n#endif\n    break;\n\n  case 0xa1:\n#if defined(DEBUG_KBD)\n    printf(\"kbd_ctrl: command a0: BIOS version (not supported).   \\n\");\n#endif\n    break;\n\n  case 0xa7: // disable the aux device\n    set_aux_clock_enable(0);\n#if defined(DEBUG_KBD)\n    printf(\"kbd_ctrl: command a7: aux i/f disable.   \\n\");\n#endif\n    break;\n\n  case 0xa8: // enable the aux device\n    set_aux_clock_enable(1);\n#if defined(DEBUG_KBD)\n    printf(\"kbd_ctrl: command a7: aux i/f enable.   \\n\");\n#endif\n    break;\n\n  case 0xa9: // Test Mouse Port\n             // controller output buffer must be empty\n#if defined(DEBUG_KBD)\n    printf(\"kbd_ctrl: command a9: aux i/f test.   \\n\");\n#endif\n    if (state.status.outb) {\n      printf(\"kbd: OUTB set and command 0x%02x encountered\", value);\n      break;\n    }\n\n    controller_enQ(0x00, 0); // no errors detected\n    break;\n\n  case 0xaa: // motherboard controller self test\n#if defined(DEBUG_KBD)\n    printf(\"kbd_ctrl: command aa: self test.   \\n\");\n#endif\n    if (kbd_initialized == 0) {\n      state.kbd_controller_Qsize = 0;\n      state.status.outb = 0;\n      kbd_initialized = 1;\n    }\n\n    // controller output buffer must be empty\n    if (state.status.outb) {\n      printf(\"kbd: OUTB set and command 0x%02x encountered\", value);\n\n      // break;\n      // drain the queue?\n      state.kbd_internal_buffer.head = 0;\n      state.kbd_internal_buffer.num_elements = 0;\n      state.status.outb = 0;\n    }\n\n    state.status.sysf = 1;   // self test complete\n    controller_enQ(0x55, 0); // controller OK\n    break;\n\n  case 0xab: // Interface Test\n#if defined(DEBUG_KBD)\n    printf(\"kbd_ctrl: command ab: kbd i/f test.   \\n\");\n#endif\n\n    // controller output buffer must be empty\n    if (state.status.outb) {\n      printf(\"kbd: OUTB set and command 0x%02x encountered\", value);\n      break;\n    }\n\n    controller_enQ(0x00, 0);\n    break;\n\n  case 0xad: // disable keyboard\n    set_kbd_clock_enable(0);\n#if defined(DEBUG_KBD)\n    printf(\"kbd_ctrl: command ad: kbd i/f disable.   \\n\");\n#endif\n    break;\n\n  case 0xae: // enable keyboard\n    set_kbd_clock_enable(1);\n#if defined(DEBUG_KBD)\n    printf(\"kbd_ctrl: command ae: kbd i/f enable.   \\n\");\n#endif\n    break;\n\n  case 0xaf: // get controller version\n#if defined(DEBUG_KBD)\n    printf(\"kbd_ctrl: command af: controller version (not supported).   \\n\");\n#endif\n    break;\n\n  case 0xc0: // read input port\n#if defined(DEBUG_KBD)\n    printf(\"kbd_ctrl: command c0: read input port.   \\n\");\n#endif\n\n    // controller output buffer must be empty\n    if (state.status.outb) {\n      BX_PANIC((\"kbd: OUTB set and command 0x%02x encountered\", value));\n      break;\n    }\n\n    // keyboard not inhibited\n    controller_enQ(0x80, 0);\n    break;\n\n  case 0xd0: // read output port: next byte read from port 60h\n#if defined(DEBUG_KBD)\n    printf(\"kbd_ctrl: command d0: read output port. (partial)   \\n\");\n#endif\n\n    // controller output buffer must be empty\n    if (state.status.outb) {\n      BX_PANIC((\"kbd: OUTB set and command 0x%02x encountered\", value));\n      break;\n    }\n\n    controller_enQ((state.irq12_requested << 5) | (state.irq1_requested << 4) |\n                       //              (BX_GET_ENABLE_A20() << 1) |\n                       0x01,\n                   0);\n    break;\n\n  case 0xd1: // write output port: next byte written to port 60h\n#if defined(DEBUG_KBD)\n    printf(\"kbd_ctrl: command d1: write output port.   \\n\");\n#endif\n\n    // following byte to port 60h written to output port\n    state.expecting_port60h = 1;\n    break;\n\n  case 0xd3: // write mouse output buffer\n#if defined(DEBUG_KBD)\n    printf(\"kbd_ctrl: command d3: write aux output buffer.   \\n\");\n#endif\n\n    // following byte to port 60h written to output port as mouse write.\n    state.expecting_port60h = 1;\n    break;\n\n  case 0xd4: // write to mouse\n#if defined(DEBUG_KBD)\n    printf(\"kbd_ctrl: command d4: write to aux.   \\n\");\n#endif\n\n    // following byte written to port 60h\n    state.expecting_port60h = 1;\n    break;\n\n  case 0xd2: // write keyboard output buffer\n#if defined(DEBUG_KBD)\n    printf(\"kbd_ctrl: command d2: write kbd output buffer.   \\n\");\n#endif\n    state.expecting_port60h = 1;\n    break;\n\n  case 0xc1: // Continuous Input Port Poll, Low\n  case 0xc2: // Continuous Input Port Poll, High\n  case 0xe0: // Read Test Inputs\n    BX_PANIC((\"io write 0x64: command = %02xh\", (unsigned)value));\n    break;\n\n  default:\n    if (value == 0xff || (value >= 0xf0 && value <= 0xfd)) {\n\n      /* useless pulse output bit commands ??? */\n#if defined(DEBUG_KBD)\n      BX_DEBUG((\"io write to port 64h, useless command %02x\", (unsigned)value));\n#endif\n      return;\n    }\n\n    BX_ERROR((\"unsupported io write to keyboard port 64, value = %x\",\n              (unsigned)value));\n    break;\n  }\n\n  execute();\n}\n\n/**\n * Enqueue a byte into one of the keyboard controller's output buffers.\n **/\nvoid CKeyboard::controller_enQ(u8 data, unsigned source) {\n\n  // source is 0 for keyboard, 1 for mouse\n#if defined(DEBUG_KBD)\n  BX_DEBUG((\"controller_enQ(%02x) source=%02x\", (unsigned)data, source));\n#endif\n\n  // see if we need to Q this byte from the controller\n  // remember this includes mouse bytes.\n  if (state.status.outb) {\n    if (state.kbd_controller_Qsize >= BX_KBD_CONTROLLER_QSIZE)\n      FAILURE(Runtime, \"controller_enq(): controller_Q full!\");\n    state.kbd_controller_Q[state.kbd_controller_Qsize++] = data;\n    state.kbd_controller_Qsource = source;\n    return;\n  }\n\n  // the Q is empty\n  if (source == 0) { // keyboard\n    state.kbd_output_buffer = data;\n    state.status.outb = 1;\n    state.status.auxb = 0;\n    state.status.inpb = 0;\n    if (state.allow_irq1)\n      state.irq1_requested = 1;\n  } else { // mouse\n    state.aux_output_buffer = data;\n    state.status.outb = 1;\n    state.status.auxb = 1;\n    state.status.inpb = 0;\n    if (state.allow_irq12)\n      state.irq12_requested = 1;\n  }\n}\n\n/**\n * Enable or disable the keyboard clock.\n **/\nvoid CKeyboard::set_kbd_clock_enable(u8 value) {\n  bool prev_kbd_clock_enabled;\n\n  if (value == 0) {\n    state.kbd_clock_enabled = 0;\n  } else {\n\n    /* is another byte waiting to be sent from the keyboard ? */\n    prev_kbd_clock_enabled = state.kbd_clock_enabled;\n    state.kbd_clock_enabled = 1;\n\n    if (prev_kbd_clock_enabled == 0 && state.status.outb == 0)\n      state.timer_pending = 1;\n  }\n}\n\n/**\n * Enable or disable the mouse clock.\n **/\nvoid CKeyboard::set_aux_clock_enable(u8 value) {\n  bool prev_aux_clock_enabled;\n\n#if defined(DEBUG_KBD)\n  BX_DEBUG((\"set_aux_clock_enable(%u)\", (unsigned)value));\n#endif\n  if (value == 0) {\n    state.aux_clock_enabled = 0;\n  } else {\n\n    /* is another byte waiting to be sent from the keyboard ? */\n    prev_aux_clock_enabled = state.aux_clock_enabled;\n    state.aux_clock_enabled = 1;\n    if (prev_aux_clock_enabled == 0 && state.status.outb == 0)\n      state.timer_pending = 1;\n  }\n}\n\n/**\n * Send a byte from controller to keyboard\n **/\nvoid CKeyboard::ctrl_to_kbd(u8 value) {\n#if defined(DEBUG_KBD)\n  BX_DEBUG((\"controller passed byte %02xh to keyboard\", value));\n#endif\n  if (state.kbd_internal_buffer.expecting_make_break) {\n    state.kbd_internal_buffer.expecting_make_break = 0;\n#if defined(DEBUG_KBD)\n    printf(\"setting key %x to make/break mode (unused)   \\n\", value);\n#endif\n    enQ(0xFA); // send ACK\n    return;\n  }\n\n  if (state.kbd_internal_buffer.expecting_typematic) {\n    state.kbd_internal_buffer.expecting_typematic = 0;\n    state.kbd_internal_buffer.delay = (value >> 5) & 0x03;\n#if defined(DEBUG_KBD)\n    switch (state.kbd_internal_buffer.delay) {\n    case 0:\n      BX_INFO((\"setting delay to 250 mS (unused)\"));\n      break;\n    case 1:\n      BX_INFO((\"setting delay to 500 mS (unused)\"));\n      break;\n    case 2:\n      BX_INFO((\"setting delay to 750 mS (unused)\"));\n      break;\n    case 3:\n      BX_INFO((\"setting delay to 1000 mS (unused)\"));\n      break;\n    }\n#endif\n    state.kbd_internal_buffer.repeat_rate = value & 0x1f;\n#if defined(DEBUG_KBD)\n    double cps =\n        1 /\n        ((double)(8 + (value & 0x07)) *\n         (double)exp(log((double)2) * (double)((value >> 3) & 0x03)) * 0.00417);\n    BX_INFO((\"setting repeat rate to %.1f cps (unused)\", cps));\n#endif\n    enQ(0xFA); // send ACK\n    return;\n  }\n\n  if (state.kbd_internal_buffer.expecting_led_write) {\n    state.kbd_internal_buffer.expecting_led_write = 0;\n    state.kbd_internal_buffer.led_status = value;\n#if defined(DEBUG_KBD)\n    BX_DEBUG((\"LED status set to %02x\",\n              (unsigned)state.kbd_internal_buffer.led_status));\n#endif\n    enQ(0xFA); // send ACK %%%\n    return;\n  }\n\n  if (state.expecting_scancodes_set) {\n    state.expecting_scancodes_set = 0;\n    if (value != 0) {\n      if (value < 4) {\n        state.current_scancodes_set = (value - 1);\n#if defined(DEBUG_KBD)\n        BX_INFO((\"Switched to scancode set %d\",\n                 (unsigned)state.current_scancodes_set + 1));\n#endif\n        enQ(0xFA);\n      } else {\n        BX_ERROR((\"Received scancodes set out of range: %d\", value));\n        enQ(0xFF); // send ERROR\n      }\n    } else {\n\n      // Send ACK (SF patch #1159626)\n      enQ(0xFA);\n\n      // Send current scancodes set to port 0x60\n      if (state.scancodes_translate)\n        enQ(translation8042[1 + state.current_scancodes_set]);\n      else\n        enQ(1 + state.current_scancodes_set);\n    }\n\n    return;\n  }\n\n  switch (value) {\n\n  //    case 0x00: // ??? ignore and let OS timeout with no response\n  //#if defined(DEBUG_KBD)\n  //      printf(\"kbd: command 00: ignored.   \\n\");\n  //#endif\n  //      enQ(0xFA); // send ACK %%%\n  //      break;\n  //\n  //    case 0x05: // ???\n  //#if defined(DEBUG_KBD)\n  //      printf(\"kbd: command 05:  unknown.   \\n\");\n  //#endif\n  //      // (mch) trying to get this to work...\n  //      state.status.sysf = 1;\n  //      enQ_imm(0xfe);\n  //      break;\n  case 0xed: // LED Write\n    state.kbd_internal_buffer.expecting_led_write = 1;\n#if defined(DEBUG_KBD)\n    printf(\"kbd: Expecting led write info.   \\n\");\n#endif\n    enQ_imm(0xFA); // send ACK %%%\n    break;\n\n  case 0xee: // echo\n#if defined(DEBUG_KBD)\n    printf(\"kbd: command ee: echo.   \\n\");\n#endif\n    enQ(0xEE); // return same byte (EEh) as echo diagnostic\n    break;\n\n  case 0xf0: // Select alternate scan code set\n    state.expecting_scancodes_set = 1;\n#if defined(DEBUG_KBD)\n    printf(\"kbd: Expecting scancode set info.   \\n\");\n#endif\n    enQ(0xFA); // send ACK\n    break;\n\n  case 0xf2: // identify keyboard\n#if defined(DEBUG_KBD)\n    printf(\"kbd: command f2: identify keyboard.   \\n\");\n#endif\n\n    //  Keyboard IDs\n    //\n    // Keyboards do report an ID as a reply to the command f2. An MF2 AT\n    // keyboard reports ID ab 83. Translation turns this into ab 41.\n    enQ(0xFA);\n    enQ(0xAB);\n\n    if (state.scancodes_translate)\n      enQ(0x41);\n    else\n      enQ(0x83);\n    break;\n\n  case 0xf3: // typematic info\n    state.kbd_internal_buffer.expecting_typematic = 1;\n#if defined(DEBUG_KBD)\n    printf(\"kbd: Expecting typematic info.   \\n\");\n#endif\n    enQ(0xFA); // send ACK\n    break;\n\n  case 0xf4: // enable keyboard\n    state.kbd_internal_buffer.scanning_enabled = 1;\n#if defined(DEBUG_KBD)\n    printf(\"kbd: command f4: enable keyboard.   \\n\");\n#endif\n    enQ(0xFA); // send ACK\n    break;\n\n  case 0xf5: // reset keyboard to power-up settings and disable scanning\n    resetinternals(1);\n    enQ(0xFA); // send ACK\n    state.kbd_internal_buffer.scanning_enabled = 0;\n#if defined(DEBUG_KBD)\n    printf(\"kbd: command f5: reset and disable keyboard.   \\n\");\n#endif\n    break;\n\n  case 0xf6: // reset keyboard to power-up settings and enable scanning\n    resetinternals(1);\n    enQ(0xFA); // send ACK\n    state.kbd_internal_buffer.scanning_enabled = 1;\n#if defined(DEBUG_KBD)\n    printf(\"kbd: command f6: reset and enable keyboard.   \\n\");\n#endif\n    break;\n\n  case 0xfc: // PS/2 Set Key Type to Make/Break\n    state.kbd_internal_buffer.expecting_make_break = 1;\n#if defined(DEBUG_KBD)\n    printf(\"kbd: Expecting make/break info.   \\n\");\n#endif\n    enQ(0xFA); /* send ACK */\n    break;\n\n  case 0xfe: // resend. aiiee.\n    printf(\"kbd: resend command received.   \\n\");\n    break;\n\n  case 0xff: // reset: internal keyboard reset and afterwards the BAT\n#if defined(DEBUG_KBD)\n    printf(\"kbd: command ff: reset keyboard w/BAT.   \\n\");\n#endif\n    resetinternals(1);\n    enQ(0xFA); // send ACK\n    state.bat_in_progress = 1;\n    enQ(0xAA); // BAT test passed\n    break;\n\n  // case 0xd3:\n  //  enQ(0xfa);\n  //  break;\n  case 0xf7: // PS/2 Set All Keys To Typematic\n  case 0xf8: // PS/2 Set All Keys to Make/Break\n  case 0xf9: // PS/2 PS/2 Set All Keys to Make\n  case 0xfa: // PS/2 Set All Keys to Typematic Make/Break\n  case 0xfb: // PS/2 Set Key Type to Typematic\n  case 0xfd: // PS/2 Set Key Type to Make\n    printf(\"kbd: unhandled command: %02x, ACKing     \\n\", value);\n    enQ(0xFA);\n    break;\n\n  default:\n    printf(\"kbd: command %02x: not recognized!   \\n\", value);\n    enQ(0xFE); /* send NACK */\n    break;\n  }\n}\n\n/**\n * enqueue scancode in multibyte internal keyboard buffer\n **/\nvoid CKeyboard::enQ_imm(u8 val) {\n  int tail;\n\n  if (state.kbd_internal_buffer.num_elements >= BX_KBD_ELEMENTS) {\n    BX_PANIC((\"internal keyboard buffer full (imm)\"));\n    return;\n  }\n\n  tail = (state.kbd_internal_buffer.head +\n          state.kbd_internal_buffer.num_elements) %\n         BX_KBD_ELEMENTS;\n\n  state.kbd_output_buffer = val;\n  state.status.outb = 1;\n\n  if (state.allow_irq1)\n    state.irq1_requested = 1;\n}\n\n/**\n * Send a byte from controller to mouse\n **/\nvoid CKeyboard::ctrl_to_mouse(u8 value) {\n#if defined(DEBUG_KBD)\n  BX_DEBUG((\"MOUSE: ctrl_to_mouse(%02xh)\", (unsigned)value));\n  BX_DEBUG((\"  enable = %u\", (unsigned)state.mouse.enable));\n  BX_DEBUG((\"  allow_irq12 = %u\", (unsigned)state.allow_irq12));\n  BX_DEBUG((\"  aux_clock_enabled = %u\", (unsigned)state.aux_clock_enabled));\n#endif\n\n  // an ACK (0xFA) is always the first response to any valid input\n  // received from the system other than Set-Wrap-Mode & Resend-Command\n  if (state.expecting_mouse_parameter) {\n    state.expecting_mouse_parameter = 0;\n    switch (state.last_mouse_command) {\n    case 0xf3: // Set Mouse Sample Rate\n      state.mouse.sample_rate = value;\n#if defined(DEBUG_KBD)\n      BX_DEBUG((\"[mouse] Sampling rate set: %d Hz\", value));\n#endif\n      if ((value == 200) && (!state.mouse.im_request)) {\n        state.mouse.im_request = 1;\n      } else if ((value == 100) && (state.mouse.im_request == 1)) {\n        state.mouse.im_request = 2;\n      } else if ((value == 80) && (state.mouse.im_request == 2)) {\n#if defined(DEBUG_KBD)\n        BX_INFO((\"wheel mouse mode enabled\"));\n#endif\n        state.mouse.im_mode = 1;\n        state.mouse.im_request = 0;\n      } else {\n        state.mouse.im_request = 0;\n      }\n\n      controller_enQ(0xFA, 1); // ack\n      break;\n\n    case 0xe8: // Set Mouse Resolution\n      switch (value) {\n      case 0:\n        state.mouse.resolution_cpmm = 1;\n        break;\n      case 1:\n        state.mouse.resolution_cpmm = 2;\n        break;\n      case 2:\n        state.mouse.resolution_cpmm = 4;\n        break;\n      case 3:\n        state.mouse.resolution_cpmm = 8;\n        break;\n      default:\n        BX_PANIC((\"[mouse] Unknown resolution %d\", value));\n        break;\n      }\n\n#if defined(DEBUG_KBD)\n      BX_DEBUG((\"[mouse] Resolution set to %d counts per mm\",\n                state.mouse.resolution_cpmm));\n#endif\n      controller_enQ(0xFA, 1); // ack\n      break;\n\n    default:\n      BX_PANIC((\"MOUSE: unknown last command (%02xh)\",\n                (unsigned)state.last_mouse_command));\n    }\n  } else {\n    state.expecting_mouse_parameter = 0;\n    state.last_mouse_command = value;\n\n    // test for wrap mode first\n    if (state.mouse.mode == MOUSE_MODE_WRAP) {\n\n      // if not a reset command or reset wrap mode\n      // then just echo the byte.\n      if ((value != 0xff) && (value != 0xec)) {\n\n        //        if (bx_dbg.mouse)\n#if defined(DEBUG_KBD)\n        BX_INFO((\"[mouse] wrap mode: Ignoring command %0X02.\", value));\n#endif\n        controller_enQ(value, 1);\n\n        // bail out\n        return;\n      }\n    }\n\n    switch (value) {\n    case 0xe6:                 // Set Mouse Scaling to 1:1\n      controller_enQ(0xFA, 1); // ACK\n      state.mouse.scaling = 2;\n#if defined(DEBUG_KBD)\n      BX_DEBUG((\"[mouse] Scaling set to 1:1\"));\n#endif\n      break;\n\n    case 0xe7:                 // Set Mouse Scaling to 2:1\n      controller_enQ(0xFA, 1); // ACK\n      state.mouse.scaling = 2;\n#if defined(DEBUG_KBD)\n      BX_DEBUG((\"[mouse] Scaling set to 2:1\"));\n#endif\n      break;\n\n    case 0xe8:                 // Set Mouse Resolution\n      controller_enQ(0xFA, 1); // ACK\n      state.expecting_mouse_parameter = 1;\n      break;\n\n    case 0xea: // Set Stream Mode\n               //        if (bx_dbg.mouse)\n#if defined(DEBUG_KBD)\n      BX_INFO((\"[mouse] Mouse stream mode on.\"));\n#endif\n      state.mouse.mode = MOUSE_MODE_STREAM;\n      controller_enQ(0xFA, 1); // ACK\n      break;\n\n    case 0xec: // Reset Wrap Mode\n      // unless we are in wrap mode ignore the command\n      if (state.mouse.mode == MOUSE_MODE_WRAP) {\n\n        //          if (bx_dbg.mouse)\n#if defined(DEBUG_KBD)\n        BX_INFO((\"[mouse] Mouse wrap mode off.\"));\n#endif\n\n        // restore previous mode except disable stream mode reporting.\n        // ### TODO disabling reporting in stream mode\n        state.mouse.mode = state.mouse.saved_mode;\n        controller_enQ(0xFA, 1); // ACK\n      }\n      break;\n\n    case 0xee: // Set Wrap Mode\n               // ### TODO flush output queue.\n               // ### TODO disable interrupts if in stream mode.\n               //        if (bx_dbg.mouse)\n#if defined(DEBUG_KBD)\n      BX_INFO((\"[mouse] Mouse wrap mode on.\"));\n#endif\n      state.mouse.saved_mode = state.mouse.mode;\n      state.mouse.mode = MOUSE_MODE_WRAP;\n      controller_enQ(0xFA, 1); // ACK\n      break;\n\n    case 0xf0: // Set Remote Mode (polling mode, i.e. not stream mode.)\n               //        if (bx_dbg.mouse)\n#if defined(DEBUG_KBD)\n      BX_INFO((\"[mouse] Mouse remote mode on.\"));\n#endif\n\n      // ### TODO should we flush/discard/ignore any already queued packets?\n      state.mouse.mode = MOUSE_MODE_REMOTE;\n      controller_enQ(0xFA, 1); // ACK\n      break;\n\n    case 0xf2:                 // Read Device Type\n      controller_enQ(0xFA, 1); // ACK\n      if (state.mouse.im_mode)\n        controller_enQ(0x03, 1); // Device ID (wheel z-mouse)\n      else\n        controller_enQ(0x00, 1); // Device ID (standard)\n#if defined(DEBUG_KBD)\n      BX_DEBUG((\"[mouse] Read mouse ID\"));\n#endif\n      break;\n\n    case 0xf3: // Set Mouse Sample Rate (sample rate written to port 60h)\n      controller_enQ(0xFA, 1); // ACK\n      state.expecting_mouse_parameter = 1;\n      break;\n\n    case 0xf4: // Enable (in stream mode)\n      state.mouse.enable = 1;\n      controller_enQ(0xFA, 1); // ACK\n#if defined(DEBUG_KBD)\n      BX_DEBUG((\"[mouse] Mouse enabled (stream mode)\"));\n#endif\n      break;\n\n    case 0xf5: // Disable (in stream mode)\n      state.mouse.enable = 0;\n      controller_enQ(0xFA, 1); // ACK\n#if defined(DEBUG_KBD)\n      BX_DEBUG((\"[mouse] Mouse disabled (stream mode)\"));\n#endif\n      break;\n\n    case 0xf6:                         // Set Defaults\n      state.mouse.sample_rate = 100;   /* reports per second (default) */\n      state.mouse.resolution_cpmm = 4; /* 4 counts per millimeter (default) */\n      state.mouse.scaling = 1;         /* 1:1 (default) */\n      state.mouse.enable = 0;\n      state.mouse.mode = MOUSE_MODE_STREAM;\n      controller_enQ(0xFA, 1); // ACK\n#if defined(DEBUG_KBD)\n      BX_DEBUG((\"[mouse] Set Defaults\"));\n#endif\n      break;\n\n    case 0xff:                         // Reset\n      state.mouse.sample_rate = 100;   /* reports per second (default) */\n      state.mouse.resolution_cpmm = 4; /* 4 counts per millimeter (default) */\n      state.mouse.scaling = 1;         /* 1:1 (default) */\n      state.mouse.mode = MOUSE_MODE_RESET;\n      state.mouse.enable = 0;\n#if defined(DEBUG_KBD)\n      if (state.mouse.im_mode)\n        BX_INFO((\"wheel mouse mode disabled\"));\n#endif\n      state.mouse.im_mode = 0;\n      controller_enQ(0xFA, 1); // ACK\n      controller_enQ(0xAA, 1); // completion code\n      controller_enQ(0x00, 1); // ID code (standard after reset)\n#if defined(DEBUG_KBD)\n      BX_DEBUG((\"[mouse] Mouse reset\"));\n#endif\n      break;\n\n    case 0xe9: // Get mouse information\n      // should we ack here? (mch): Yes\n      controller_enQ(0xFA, 1);                              // ACK\n      controller_enQ(state.mouse.get_status_byte(), 1);     // status\n      controller_enQ(state.mouse.get_resolution_byte(), 1); // resolution\n      controller_enQ(state.mouse.sample_rate, 1);           // sample rate\n#if defined(DEBUG_KBD)\n      BX_DEBUG((\"[mouse] Get mouse information\"));\n#endif\n      break;\n\n    case 0xeb:                 // Read Data (send a packet when in Remote Mode)\n      controller_enQ(0xFA, 1); // ACK\n\n      // perhaps we should be adding some movement here.\n      mouse_enQ_packet(((state.mouse.button_status & 0x0f) | 0x08), 0x00, 0x00,\n                       0x00); // bit3 of first byte always set\n\n      // assumed we really aren't in polling mode, a rather odd assumption.\n#if defined(DEBUG_KBD)\n      BX_ERROR((\"[mouse] Warning: Read Data command partially supported.\"));\n#endif\n      break;\n\n    case 0xbb: // OS/2 Warp 3 uses this command\n#if defined(DEBUG_KBD)\n      BX_ERROR((\"[mouse] ignoring 0xbb command\"));\n#endif\n      break;\n\n    default:\n      BX_ERROR((\"[mouse] ctrl_to_mouse(): got value of 0x%02x\", value));\n      controller_enQ(0xFE, 1); /* send NACK */\n    }\n  }\n}\n\n/**\n * Put a (3/4 byte) mouse packet into the mouse buffer.\n **/\nbool CKeyboard::mouse_enQ_packet(u8 b1, u8 b2, u8 b3, u8 b4) {\n  int bytes = 3;\n  if (state.mouse.im_mode)\n    bytes = 4;\n\n  if ((state.mouse_internal_buffer.num_elements + bytes) >=\n      BX_MOUSE_BUFF_SIZE) {\n    return (0); /* buffer doesn't have the space */\n  }\n\n  mouse_enQ(b1);\n  mouse_enQ(b2);\n  mouse_enQ(b3);\n  if (state.mouse.im_mode)\n    mouse_enQ(b4);\n\n  return (1);\n}\n\n/**\n * Put a byte into the mouse buffer.\n **/\nvoid CKeyboard::mouse_enQ(u8 mouse_data) {\n  int tail;\n\n#if defined(DEBUG_KBD)\n  BX_DEBUG((\"mouse_enQ(%02x)\", (unsigned)mouse_data));\n#endif\n  if (state.mouse_internal_buffer.num_elements >= BX_MOUSE_BUFF_SIZE) {\n    BX_ERROR((\"[mouse] internal mouse buffer full, ignoring mouse data.(%02x)\",\n              (unsigned)mouse_data));\n    return;\n  }\n\n  /* enqueue mouse data in multibyte internal mouse buffer */\n  tail = (state.mouse_internal_buffer.head +\n          state.mouse_internal_buffer.num_elements) %\n         BX_MOUSE_BUFF_SIZE;\n  state.mouse_internal_buffer.buffer[tail] = mouse_data;\n  state.mouse_internal_buffer.num_elements++;\n\n  if (!state.status.outb && state.aux_clock_enabled) {\n    state.timer_pending = 1;\n    return;\n  }\n}\n\n/**\n * Determine what IRQ's need to be asserted.\n **/\nunsigned CKeyboard::periodic() {\n  u8 retval;\n\n  retval = (state.irq1_requested << 0) | (state.irq12_requested << 1);\n  state.irq1_requested = 0;\n  state.irq12_requested = 0;\n\n  if (state.timer_pending == 0) {\n    return (retval);\n  }\n\n  if (1 >= state.timer_pending) {\n    state.timer_pending = 0;\n  } else {\n    state.timer_pending--;\n    return (retval);\n  }\n\n  if (state.status.outb) {\n    return (retval);\n  }\n\n  /* nothing in outb, look for possible data xfer from keyboard or mouse */\n  if (state.kbd_internal_buffer.num_elements &&\n      (state.kbd_clock_enabled || state.bat_in_progress)) {\n#if defined(DEBUG_KBD)\n    BX_DEBUG((\"service_keyboard: key in internal buffer waiting\"));\n#endif\n    state.kbd_output_buffer =\n        state.kbd_internal_buffer.buffer[state.kbd_internal_buffer.head];\n    state.status.outb = 1;\n\n    // commented out since this would override the current state of the\n    // mouse buffer flag - no bug seen - just seems wrong (das)\n    //    state.auxb = 0;\n    state.kbd_internal_buffer.head =\n        (state.kbd_internal_buffer.head + 1) % BX_KBD_ELEMENTS;\n    state.kbd_internal_buffer.num_elements--;\n    if (state.allow_irq1)\n      state.irq1_requested = 1;\n  } else {\n    create_mouse_packet(0);\n    if (state.aux_clock_enabled && state.mouse_internal_buffer.num_elements) {\n#if defined(DEBUG_KBD)\n      BX_DEBUG(\n          (\"service_keyboard: key(from mouse) in internal buffer waiting\"));\n#endif\n      state.aux_output_buffer =\n          state.mouse_internal_buffer.buffer[state.mouse_internal_buffer.head];\n\n      state.status.outb = 1;\n      state.status.auxb = 1;\n      state.mouse_internal_buffer.head =\n          (state.mouse_internal_buffer.head + 1) % BX_MOUSE_BUFF_SIZE;\n      state.mouse_internal_buffer.num_elements--;\n      if (state.allow_irq12)\n        state.irq12_requested = 1;\n    }\n\n#if defined(DEBUG_KBD)\n    else {\n      BX_DEBUG((\"service_keyboard(): no keys waiting\"));\n    }\n#endif\n  }\n\n  return (retval);\n}\n\n/**\n * Create a mouse packet and send it to the controller if needed.\n **/\nvoid CKeyboard::create_mouse_packet(bool force_enq) {\n  u8 b1;\n\n  u8 b2;\n\n  u8 b3;\n\n  u8 b4;\n\n  if (state.mouse_internal_buffer.num_elements && !force_enq)\n    return;\n\n  s16 delta_x = state.mouse.delayed_dx;\n  s16 delta_y = state.mouse.delayed_dy;\n  u8 button_state = state.mouse.button_status | 0x08;\n\n  if (!force_enq && !delta_x && !delta_y) {\n    return;\n  }\n\n  if (delta_x > 254)\n    delta_x = 254;\n  if (delta_x < -254)\n    delta_x = -254;\n  if (delta_y > 254)\n    delta_y = 254;\n  if (delta_y < -254)\n    delta_y = -254;\n\n  b1 = (button_state & 0x0f) | 0x08; // bit3 always set\n  if ((delta_x >= 0) && (delta_x <= 255)) {\n    b2 = (u8)delta_x;\n    state.mouse.delayed_dx -= delta_x;\n  } else if (delta_x > 255) {\n    b2 = (u8)0xff;\n    state.mouse.delayed_dx -= 255;\n  } else if (delta_x >= -256) {\n    b2 = (u8)delta_x;\n    b1 |= 0x10;\n    state.mouse.delayed_dx -= delta_x;\n  } else {\n    b2 = (u8)0x00;\n    b1 |= 0x10;\n    state.mouse.delayed_dx += 256;\n  }\n\n  if ((delta_y >= 0) && (delta_y <= 255)) {\n    b3 = (u8)delta_y;\n    state.mouse.delayed_dy -= delta_y;\n  } else if (delta_y > 255) {\n    b3 = (u8)0xff;\n    state.mouse.delayed_dy -= 255;\n  } else if (delta_y >= -256) {\n    b3 = (u8)delta_y;\n    b1 |= 0x20;\n    state.mouse.delayed_dy -= delta_y;\n  } else {\n    b3 = (u8)0x00;\n    b1 |= 0x20;\n    state.mouse.delayed_dy += 256;\n  }\n\n  b4 = (u8)-state.mouse.delayed_dz;\n\n  mouse_enQ_packet(b1, b2, b3, b4);\n}\n\n/**\n * Keyboard clock. Handle events on a clocked basis.\n *\n * Do the following:\n *  - Let the GUI (if available) handle any pending events.\n *  - Check if interrupts need to be asserted.\n *  - Assert interrupts as needed.\n *  .\n **/\nvoid CKeyboard::execute() {\n  unsigned retval;\n\n  /* -- moved to VGA card --\n    if(bx_gui)\n    {\n      bx_gui->lock();\n      bx_gui->handle_events();\n      bx_gui->unlock();\n    }\n  */\n  retval = periodic();\n\n  if (retval & 0x01)\n    theAli->pic_interrupt(0, 1);\n  if (retval & 0x02)\n    theAli->pic_interrupt(1, 4);\n}\n\n/**\n * Check if threads are still running.\n **/\nvoid CKeyboard::check_state() {\n  if (myThreadDead.load())\n    FAILURE(Thread, \"KBD thread has died\");\n}\n\n/**\n * Thread entry point.\n **/\nvoid CKeyboard::run() {\n  try {\n    for (;;) {\n      if (StopThread)\n        return;\n      execute();\n      std::this_thread::sleep_for(std::chrono::milliseconds(20));\n    }\n  }\n\n  catch (CException &e) {\n    printf(\"Exception in kbd thread: %s.\\n\", e.displayText().c_str());\n    myThreadDead.store(true);\n    // Let the thread die...\n  }\n}\n\nstatic u32 kb_magic1 = 0x65481687;\nstatic u32 kb_magic2 = 0x24895375;\n\n/**\n * Save state to a Virtual Machine State file.\n **/\nint CKeyboard::SaveState(FILE *f) {\n  long ss = sizeof(state);\n\n  fwrite(&kb_magic1, sizeof(u32), 1, f);\n  fwrite(&ss, sizeof(long), 1, f);\n  fwrite(&state, sizeof(state), 1, f);\n  fwrite(&kb_magic2, sizeof(u32), 1, f);\n  printf(\"kbc: %d bytes saved.\\n\", (int)ss);\n  return 0;\n}\n\n/**\n * Restore state from a Virtual Machine State file.\n **/\nint CKeyboard::RestoreState(FILE *f) {\n  long ss;\n  u32 m1;\n  u32 m2;\n  size_t r;\n\n  r = fread(&m1, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"kbc: unexpected end of file!\\n\");\n    return -1;\n  }\n\n  if (m1 != kb_magic1) {\n    printf(\"kbc: MAGIC 1 does not match!\\n\");\n    return -1;\n  }\n\n  r = fread(&ss, sizeof(long), 1, f);\n  if (r != 1) {\n    printf(\"kbc: unexpected end of file!\\n\");\n    return -1;\n  }\n\n  if (ss != sizeof(state)) {\n    printf(\"kbc: STRUCT SIZE does not match!\\n\");\n    return -1;\n  }\n\n  r = fread(&state, sizeof(state), 1, f);\n  if (r != 1) {\n    printf(\"kbc: unexpected end of file!\\n\");\n    return -1;\n  }\n\n  r = fread(&m2, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"kbc: unexpected end of file!\\n\");\n    return -1;\n  }\n\n  if (m2 != kb_magic2) {\n    printf(\"kbc: MAGIC 1 does not match!\\n\");\n    return -1;\n  }\n\n  printf(\"kbc: %d bytes restored.\\n\", (int)ss);\n  return 0;\n}\n\nCKeyboard *theKeyboard = 0;\n"
  },
  {
    "path": "src/Keyboard.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_KEYBOARD_H)\n#define INCLUDED_KEYBOARD_H\n\n#include \"SystemComponent.hpp\"\n#include \"gui/gui.hpp\"\n\n#define BX_KBD_ELEMENTS 16\n#define BX_MOUSE_BUFF_SIZE 48\n\n#define MOUSE_MODE_RESET 10\n#define MOUSE_MODE_STREAM 11\n#define MOUSE_MODE_REMOTE 12\n#define MOUSE_MODE_WRAP 13\n\n/**\n * \\brief Emulated keyboard controller, keyboard and mouse.\n **/\nclass CKeyboard : public CSystemComponent {\npublic:\n  CKeyboard(CConfigurator *cfg, CSystem *c);\n  virtual ~CKeyboard();\n\n  virtual void check_state();\n  virtual void WriteMem(int index, u64 address, int dsize, u64 data);\n  virtual u64 ReadMem(int index, u64 address, int dsize);\n  virtual int SaveState(FILE *f);\n  virtual int RestoreState(FILE *f);\n  void run();\n  void execute();\n\n  void gen_scancode(u32 key);\n\n  virtual void init();\n  virtual void start_threads();\n  virtual void stop_threads();\n\nprivate:\n  std::unique_ptr<std::thread> myThread;\n  std::atomic_bool myThreadDead{false};\n  bool StopThread;\n\n  u8 read_60();\n  void write_60(u8 data);\n  u8 read_64();\n  void write_64(u8 data);\n  void resetinternals(bool powerup);\n  void enQ(u8 scancode);\n  void controller_enQ(u8 data, unsigned source);\n  void set_kbd_clock_enable(u8 value);\n  void set_aux_clock_enable(u8 value);\n  void ctrl_to_kbd(u8 value);\n  void enQ_imm(u8 val);\n  void ctrl_to_mouse(u8 value);\n  bool mouse_enQ_packet(u8 b1, u8 b2, u8 b3, u8 b4);\n  void mouse_enQ(u8 mouse_data);\n  unsigned periodic();\n\n  //  void kbd_clock();\n  void create_mouse_packet(bool force_enq);\n\n  /// The state structure contains all elements that need to be saved to the\n  /// statefile.\n  struct SKb_state {\n\n    /// status bits matching the status port\n    struct SAli_kbdc_status {\n      bool pare; /**< Bit7, 1= parity error from keyboard/mouse - ignored. */\n      bool tim;  /**< Bit6, 1= timeout from keyboard - ignored. */\n      bool auxb; /**< Bit5, 1= mouse data waiting for CPU to read. */\n      bool keyl; /**< Bit4, 1= keyswitch in lock position - ignored. */\n      bool c_d;  /**< Bit3, 1=command to port 64h, 0=data to port 60h. */\n      bool sysf; /**< Bit2 */\n      bool inpb; /**< Bit1 */\n      bool outb; /**< Bit0, 1= keyboard data or mouse data ready for CPU. Check\n                    aux to see which. */\n    } status;\n\n    /* internal to our version of the keyboard controller */\n    bool kbd_clock_enabled;\n    bool aux_clock_enabled;\n    bool allow_irq1;\n    bool allow_irq12;\n    u8 kbd_output_buffer;\n    u8 aux_output_buffer;\n    u8 last_comm;\n    u8 expecting_port60h;\n    u8 expecting_mouse_parameter;\n    u8 last_mouse_command;\n    u32 timer_pending;\n    bool irq1_requested;\n    bool irq12_requested;\n    bool scancodes_translate;\n    bool expecting_scancodes_set;\n    u8 current_scancodes_set;\n    bool bat_in_progress;\n\n    /// mouse status\n    struct SAli_mouse {\n      bool captured; // host mouse capture enabled\n\n      //      u8   type;\n      u8 sample_rate;\n      u8 resolution_cpmm; // resolution in counts per mm\n      u8 scaling;\n      u8 mode;\n      u8 saved_mode; // the mode prior to entering wrap mode\n      bool enable;\n\n      u8 get_status_byte() {\n\n        // top bit is 0 , bit 6 is 1 if remote mode.\n        u8 ret = (u8)((mode == MOUSE_MODE_REMOTE) ? 0x40 : 0);\n        ret |= (enable << 5);\n        ret |= (scaling == 1) ? 0 : (1 << 4);\n        ret |= ((button_status & 0x1) << 2);\n        ret |= ((button_status & 0x2) << 0);\n        return ret;\n      }\n\n      u8 get_resolution_byte() {\n        u8 ret = 0;\n\n        switch (resolution_cpmm) {\n        case 1:\n          ret = 0;\n          break;\n        case 2:\n          ret = 1;\n          break;\n        case 4:\n          ret = 2;\n          break;\n        case 8:\n          ret = 3;\n          break;\n        default:\n          FAILURE(NotImplemented, \"mouse: invalid resolution_cpmm\");\n        };\n        return ret;\n      }\n\n      u8 button_status;\n      s16 delayed_dx;\n      s16 delayed_dy;\n      s16 delayed_dz;\n      u8 im_request;\n      bool im_mode;\n    } mouse;\n\n    /// internal keyboard buffer\n    struct SAli_kbdib {\n      int num_elements;\n      u8 buffer[BX_KBD_ELEMENTS];\n      int head;\n      bool expecting_typematic;\n      bool expecting_led_write;\n      bool expecting_make_break;\n      u8 delay;\n      u8 repeat_rate;\n      u8 led_status;\n      bool scanning_enabled;\n    } kbd_internal_buffer;\n\n    /// internal mouse buffer\n    struct SAli_mib {\n      int num_elements;\n      u8 buffer[BX_MOUSE_BUFF_SIZE];\n      int head;\n    } mouse_internal_buffer;\n\n#define BX_KBD_CONTROLLER_QSIZE 5\n    u8 kbd_controller_Q[BX_KBD_CONTROLLER_QSIZE];\n    unsigned kbd_controller_Qsize;\n    unsigned kbd_controller_Qsource; /**< 0=keyboard, 1=mouse */\n  } state;\n};\n\nextern CKeyboard *theKeyboard;\n#endif // !defined(INCLUDED_KEYBOARD_H)\n"
  },
  {
    "path": "src/Main.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Copyright (C) 2020 Remy van Elst\n * Website: https://github.com/lenticularis39/axpbox\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"config.hpp\"\n#include <cstring>\n#include <iostream>\n\nint main_sim(int argc, char *argv[]);\nint main_cfg(int argc, char *argv[]);\n\nint main(int argc, char **argv) {\n  if (argc <= 1 || (strcmp(argv[1], \"run\") && strcmp(argv[1], \"configure\"))) {\n    std::cerr << \"AXPBox Alpha Emulator\";\n#ifdef PACKAGE_GITSHA\n    std::cerr << \" (commit \" << std::string(PACKAGE_GITSHA) << \")\";\n#endif\n    std::cerr << std::endl;\n    std::cerr << \"Usage: \" << argv[0] << \" run|configure <options>\" << std::endl;\n    return 0;\n  }\n\n  if (strcmp(argv[1], \"run\") == 0) {\n    return main_sim(argc - 1, ++argv);\n  }\n\n  if (strcmp(argv[1], \"configure\") == 0) {\n    return main_cfg(argc - 1, ++argv);\n  }\n}\n"
  },
  {
    "path": "src/MultipleChoiceQuestion.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n/**\n * Class defining a possible answer to a multiple\n * choice question.\n **/\nclass Answer {\npublic:\n  /**\n   * Constructor.\n   *\n   * Defines the answer, value and explanation of\n   * this answer.\n   **/\n  Answer(string answer, string value, string explanation) {\n    mAnswer = answer;\n    mValue = value;\n    mExplanation = explanation;\n  }\n\n  /**\n   * Equality operator. Matches on Answer.\n   **/\n  bool operator==(string x) { return (mAnswer == x); }\n  /**\n   * Get the answer.\n   **/\n  string getAnswer() { return mAnswer; }\n\n  /**\n   * Get the value.\n   **/\n  string getValue() { return mValue; }\n\n  /**\n   * Get the explanation.\n   **/\n  string getExplanation() { return mExplanation; }\n\nprotected:\n  /** Answer as it should be entered by the user. */\n  string mAnswer;\n\n  /** Value as it is output to the config file. */\n  string mValue;\n\n  /** Explanation shown when '?' is given as an answer. */\n  string mExplanation;\n};\n\n/**\n * Vector containing all possible answers to a multiple\n * choice question.\n **/\ntypedef vector<Answer> AnswerSet;\n\n/**\n * Question class implementing a multiple choice question.\n **/\nclass MultipleChoiceQuestion : public FreeTextQuestion {\npublic:\n  /**\n   * Add an answer to the set of allowed answers.\n   **/\n  void addAnswer(string answer, string value, string explanation) {\n    mAnswerSet.push_back(Answer(answer, value, explanation));\n  }\n\n  /**\n   * Explain the question.\n   **/\n  virtual void explain() {\n    AnswerSet::iterator itAnswers;\n\n    /* Explain the quistion as usual.\n     */\n    FreeTextQuestion::explain();\n\n    /* Explain the allowed answers.\n     */\n    cout << \"POSSIBLE VALUES:\\n\";\n\n    /* Iterate through the answer set.\n     */\n    for (itAnswers = mAnswerSet.begin(); itAnswers != mAnswerSet.end();\n         itAnswers++) {\n      /* Print the answer and its explanation.\n       */\n      cout << itAnswers->getAnswer() << \"\\t\\t\" << itAnswers->getExplanation()\n           << \"\\n\";\n    }\n    cout << \"\\n\";\n  }\n\n  /**\n   * Get the number of answers in the answer set.\n   **/\n  size_t countAnswers() { return mAnswerSet.size(); }\n\n  /**\n   * Ask the question.\n   **/\n  virtual string ask() {\n    AnswerSet::iterator itAnswers;\n    string options;\n\n    /* Iterate through the answer set to create the\n     * options list.\n     */\n\n    for (itAnswers = mAnswerSet.begin(); itAnswers != mAnswerSet.end();\n         itAnswers++) {\n      if (options != \"\")\n        options += \",\";\n      options += itAnswers->getAnswer();\n    }\n\n    /* Set the options list.\n     */\n    setOptions(options);\n\n    /* Keep repeating the question until a valid\n     * answer is received.\n     */\n    for (;;) {\n      /* Ask the question as a FreeTextQuestion. This\n       * takes care of the explanation and default\n       * value handling.\n       */\n      FreeTextQuestion::ask();\n\n      /* Try to find the answer received in the answer\n       * set.\n       */\n      itAnswers = find(mAnswerSet.begin(), mAnswerSet.end(), mAnswer);\n\n      /* Has a matching answer be found?\n       */\n      if (itAnswers != mAnswerSet.end()) {\n        /* Get the value for the received answer.\n         */\n        string value = itAnswers->getValue();\n        haveChosen(mAnswer);\n        mAnswer = value;\n\n        /* Return the value.\n         */\n        return mAnswer;\n      }\n\n      /* No valid, matching answer received.\n       */\n      cout << \"\\nPlease enter a valid value, or '?' for help.\\n\\n\";\n    }\n  };\n\n  /**\n   * Remove one answer from the answer set.\n   **/\n  void dropChoice(string choice) {\n    AnswerSet::iterator itAnswers;\n\n    /* Try to find the answer in the answer set.\n     */\n    itAnswers = find(mAnswerSet.begin(), mAnswerSet.end(), mAnswer);\n\n    /* Has a matching answer be found?\n     */\n    if (itAnswers != mAnswerSet.end()) {\n      /* Delete the answer from the list.\n       */\n      mAnswerSet.erase(itAnswers);\n    }\n  }\n\n  /**\n   * Override this to do something special with\n   * the answer received.\n   **/\n  virtual void haveChosen(string choice) {}\n\n  /**\n   * Return the first possible answer.\n   **/\n  string getFirstChoice() { return mAnswerSet.begin()->getAnswer(); }\n\nprotected:\n  /** Set containing all allowed answers. */\n  AnswerSet mAnswerSet;\n};\n"
  },
  {
    "path": "src/NumberQuestion.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n/**\n * Convert an integer to a string.\n **/\ninline string i2s(int x) {\n  ostringstream o;\n  o << x;\n  return o.str();\n}\n\n/**\n * Convert a string to an integer.\n *\n * Throws a CLogicException when the input is not numeric.\n **/\ninline int s2i(const string x) {\n  istringstream i(x);\n  int x1;\n  char c;\n  if (!(i >> x1) || i.get(c))\n    FAILURE(Logic, \"invalid conversion\");\n  ;\n  return x1;\n}\n\n/**\n * Question class that accepts a numeric answer within\n * a defined range.\n **/\nclass NumberQuestion : public FreeTextQuestion {\npublic:\n  /**\n   * Define the allowable range for the answer.\n   **/\n  void setRange(int low, int high) {\n    mLow = low;\n    mHigh = high;\n  }\n\n  /**\n   * Convert the answer to a number.\n   **/\n  int getNum() { return s2i(mAnswer); }\n\n  /**\n   * Ask the question and return the answer.\n   **/\n  virtual string ask() {\n    /* Set the options list to (low-high).\n     */\n    setOptions(i2s(mLow) + \"-\" + i2s(mHigh));\n\n    /* Keep repeating the question until a valid\n     * answer is received.\n     */\n    for (;;) {\n      int value;\n\n      /* Ask the question as a FreeTextQuestion. This\n       * takes care of the explanation and default\n       * value handling.\n       */\n      FreeTextQuestion::ask();\n\n      try {\n        /* Convert the answer to an integer.\n         */\n        value = s2i(mAnswer);\n\n        /* If the answer is within the allowed range,\n         * return it.\n         */\n        if (value >= mLow && value <= mHigh)\n          return mAnswer;\n\n        /* The answer is out of range.\n         */\n        cout << \"\\nPlease enter a value that is within the indicated range, or \"\n                \"'?' for help.\\n\\n\";\n      } catch (CLogicException) {\n        /* The answer is not a number.\n         */\n        cout << \"\\nPlease enter an integer value.\\n\\n\";\n      }\n    }\n  }\n\nprotected:\n  /** Low limit of the allowed range. */\n  int mLow;\n  /** High limit of the allowed range. */\n  int mHigh;\n};\n"
  },
  {
    "path": "src/PCIDevice.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"PCIDevice.hpp\"\n#include \"StdAfx.hpp\"\n#include \"System.hpp\"\n\nstatic size_t pci_dma_chunk_limit(u64 phys_addr, size_t remaining) {\n  const size_t dma_page = 8192;\n  size_t page_remaining = dma_page - (size_t)(phys_addr & (dma_page - 1));\n  return (remaining < page_remaining) ? remaining : page_remaining;\n}\n\nCPCIDevice::CPCIDevice(CConfigurator *cfg, CSystem *c, int pcibus, int pcidev)\n    : CSystemComponent(cfg, c) {\n  int i;\n\n  int j;\n\n  for (i = 0; i < 8; i++) {\n    device_at[i] = false;\n    for (j = 0; j < 8; j++)\n      pci_range_is_io[i][j] = false;\n  }\n\n  for (i = 0; i < MAX_DEV_RANGES; i++)\n    dev_range_is_io[i] = false;\n\n  myPCIBus = pcibus;\n  myPCIDev = pcidev;\n}\n\nCPCIDevice::~CPCIDevice(void) {}\n\nvoid CPCIDevice::add_function(int func, u32 data[64], u32 mask[64]) {\n  memcpy(std_config_data[func], data, 64 * sizeof(u32));\n  memcpy(std_config_mask[func], mask, 64 * sizeof(u32));\n#if defined(ES40_BIG_ENDIAN)\n  int i;\n  for (i = 0; i < 64; i++) {\n    std_config_data[func][i] = endian_32(std_config_data[func][i]);\n    std_config_mask[func][i] = endian_32(std_config_mask[func][i]);\n  }\n#endif\n  device_at[func] = true;\n}\n\nvoid CPCIDevice::add_legacy_io(int id, u32 base, u32 length) {\n  dev_range_is_io[id] = true;\n  cSystem->RegisterMemory(this, id,\n                          U64(0x00000801fc000000) +\n                              (U64(0x0000000200000000) * myPCIBus) + base,\n                          length);\n}\n\nvoid CPCIDevice::add_legacy_mem(int id, u32 base, u32 length) {\n  dev_range_is_io[id] = false;\n  cSystem->RegisterMemory(this, id,\n                          U64(0x0000080000000000) +\n                              (U64(0x0000000200000000) * myPCIBus) + base,\n                          length);\n}\n\nu32 CPCIDevice::config_read(int func, u32 address, int dsize) {\n  u8 *x;\n\n  u32 data = 0;\n\n  x = (u8 *)pci_state.config_data[func];\n  x += address;\n\n  switch (dsize) {\n  case 8:\n    data = endian_8(*x);\n    break;\n  case 16:\n    data = endian_16(*((u16 *)x));\n    break;\n  case 32:\n    data = endian_32(*((u32 *)x));\n    break;\n  }\n\n  data = config_read_custom(func, address, dsize, data);\n\n  //  printf(\"%s(%s).%d config read  %d bytes @ %x = %x\\n\",myCfg->get_myName(),\n  //  myCfg->get_myValue(), func,dsize/8,address, data);\n  return data;\n}\n\nvoid CPCIDevice::config_write(int func, u32 address, int dsize, u32 data) {\n\n  //  printf(\"%s(%s).%d config write %d bytes @ %x = %x\\n\",myCfg->get_myName(),\n  //  myCfg->get_myValue(), func,dsize/8,address, data);\n  u8 *x;\n  u8 *y;\n\n  u32 mask = 0;\n  u32 old_data = 0;\n  u32 new_data = 0;\n\n  x = (u8 *)pci_state.config_data[func];\n  x += address;\n  y = (u8 *)pci_state.config_mask[func];\n  y += address;\n\n#if defined(DEBUG_PCI)\n  if (address == 0x3c && (data & 0xff) != 0xff)\n    printf(\"%s.%d PCI Interrupt set to %02x.\\n\", devid_string, func,\n           data & 0xff);\n#endif\n  switch (dsize) {\n  case 8:\n    data = endian_8(data);\n    old_data = (*x) & 0xff;\n    mask = (*y) & 0xff;\n    new_data = (old_data & ~mask) | (data & mask);\n    *x = (u8)new_data;\n    break;\n\n  case 16:\n    data = endian_16(data);\n    old_data = (*((u16 *)x)) & 0xffff;\n    mask = (*((u16 *)y)) & 0xffff;\n    new_data = (old_data & ~mask) | (data & mask);\n    *((u16 *)x) = (u16)new_data;\n    break;\n\n  case 32:\n    data = endian_32(data);\n    old_data = (*((u32 *)x));\n    mask = (*((u32 *)y));\n    new_data = (old_data & ~mask) | (data & mask);\n    *((u32 *)x) = new_data;\n    break;\n  }\n\n  if (dsize == 32 && ((data & mask) != mask) && ((data & mask) != 0)) {\n    switch (address) {\n    case 0x10:\n    case 0x14:\n    case 0x18:\n    case 0x1c:\n    case 0x20:\n    case 0x24:\n      register_bar(func, (address - 0x10) / 4, endian_32(new_data),\n                   endian_32(mask));\n      break;\n\n    case 0x30:\n      register_bar(func, 6, endian_32(new_data), endian_32(mask));\n      break;\n    }\n  }\n\n  config_write_custom(func, address, dsize, old_data, new_data, data);\n}\n\nvoid CPCIDevice::register_bar(int func, int bar, u32 data, u32 mask) {\n  u32 length = ((~mask) | 1) + 1;\n\n  if ((data & 1) && bar != 6) {\n\n    // io space\n    pci_range_is_io[func][bar] = true;\n\n    cSystem->RegisterMemory(this, PCI_RANGE_BASE + (func * 8) + bar,\n                            U64(0x00000801fc000000) +\n                                (U64(0x0000000200000000) * myPCIBus) +\n                                (data & ~0x3),\n                            length);\n#if defined(DEBUG_PCI)\n    printf(\"%s(%s).%d PCI BAR %d set to IO  % \" PRIx64 \", len %x.\\n\",\n           myCfg->get_myName(), myCfg->get_myValue(), func, bar, t, length);\n#endif\n  } else if ((data & 1) || bar != 6) {\n\n    // io space\n    pci_range_is_io[func][bar] = true;\n\n    cSystem->RegisterMemory(this, PCI_RANGE_BASE + (func * 8) + bar,\n                            U64(0x0000080000000000) +\n                                (U64(0x0000000200000000) * myPCIBus) +\n                                (data & ~0xf),\n                            length);\n#if defined(DEBUG_PCI)\n    printf(\"%s(%s).%d PCI BAR %d set to MEM % \" PRIx64 \", len %x.\\n\",\n           myCfg->get_myName(), myCfg->get_myValue(), func, bar, t, length);\n#endif\n  } else {\n\n    // disabled...\n#if defined(DEBUG_PCI)\n    printf(\"%s(%s).%d PCI BAR %d should be disabled...\\n\", myCfg->get_myName(),\n           myCfg->get_myValue(), func, bar);\n#endif\n  }\n}\n\nvoid CPCIDevice::ResetPCI() {\n  int i;\n\n  for (i = 0; i < 8; i++) {\n    if (device_at[i]) {\n      cSystem->RegisterMemory(this, PCI_RANGE_BASE + (i * 8) + 7,\n                              U64(0x00000801fe000000) +\n                                  (U64(0x0000000200000000) * myPCIBus) +\n                                  (U64(0x0000000000000800) * myPCIDev) +\n                                  (U64(0x0000000000000100) * i),\n                              0x100);\n      memcpy(pci_state.config_data[i], std_config_data[i], 64 * sizeof(u32));\n      memcpy(pci_state.config_mask[i], std_config_mask[i], 64 * sizeof(u32));\n\n      config_write(i, 0x10, 32, endian_32(pci_state.config_data[i][4]));\n      config_write(i, 0x14, 32, endian_32(pci_state.config_data[i][5]));\n      config_write(i, 0x18, 32, endian_32(pci_state.config_data[i][6]));\n      config_write(i, 0x1c, 32, endian_32(pci_state.config_data[i][7]));\n      config_write(i, 0x20, 32, endian_32(pci_state.config_data[i][8]));\n      config_write(i, 0x24, 32, endian_32(pci_state.config_data[i][9]));\n      config_write(i, 0x30, 32, endian_32(pci_state.config_data[i][12]));\n    }\n  }\n}\n\nu64 CPCIDevice::ReadMem(int index, u64 address, int dsize) {\n  int func;\n  int bar;\n\n  if (dsize == 64)\n    return ReadMem(index, address, 32) |\n           (((u64)ReadMem(index, address + 4, 32)) << 32);\n\n  if (dsize != 8 && dsize != 16 && dsize != 32) {\n    FAILURE_5(InvalidArgument,\n              \"ReadMem: %s(%s) Unsupported dsize %d. (%d, %\" PRIx64 \")\\n\",\n              myCfg->get_myName(), myCfg->get_myValue(), dsize, index, address);\n  }\n\n  if (index < PCI_RANGE_BASE) {\n    if (dev_range_is_io[index] &&\n        !(pci_state.config_data[0][1] & endian_32(1))) {\n      printf(\"%s(%s) Legacy IO access with IO disabled from PCI config.\\n\",\n             myCfg->get_myName(), myCfg->get_myValue());\n      return 0;\n    }\n\n    if (!dev_range_is_io[index] &&\n        !(pci_state.config_data[0][1] & endian_32(2))) {\n      printf(\n          \"%s(%s) Legacy memory access with memory disabled from PCI config.\\n\",\n          myCfg->get_myName(), myCfg->get_myValue());\n      return 0;\n    }\n\n    //    printf(\"%s(%s) Calling ReadMem_Legacy(%d).\\n\",myCfg->get_myName(),\n    //    myCfg->get_myValue(), index);\n    return ReadMem_Legacy(index, (u32)address, dsize);\n  }\n\n  index -= PCI_RANGE_BASE;\n\n  bar = index & 7;\n  func = (index / 8) & 7;\n\n  if (bar == 7)\n    return config_read(func, (u32)address, dsize);\n\n  if (pci_range_is_io[func][bar] &&\n      !(pci_state.config_data[func][1] & endian_32(1))) {\n    printf(\"%s(%s).%d PCI IO access with IO disabled from PCI config.\\n\",\n           myCfg->get_myName(), myCfg->get_myValue(), func);\n    return 0;\n  }\n\n  if (!pci_range_is_io[func][bar] &&\n      !(pci_state.config_data[func][1] & endian_32(2))) {\n    printf(\n        \"%s(%s).%d PCI memory access with memory disabled from PCI config.\\n\",\n        myCfg->get_myName(), myCfg->get_myValue(), func);\n    return 0;\n  }\n\n  //  printf(\"%s(%s).%d Calling ReadMem_Bar(%d,%d).\\n\",myCfg->get_myName(),\n  //  myCfg->get_myValue(), func,func,bar);\n  return ReadMem_Bar(func, bar, (u32)address, dsize);\n}\n\nvoid CPCIDevice::WriteMem(int index, u64 address, int dsize, u64 data) {\n  int func;\n  int bar;\n\n  if (dsize == 64) {\n    WriteMem(index, address, 32, data & U64(0xffffffff));\n    WriteMem(index, address + 4, 32, (data >> 32) & U64(0xffffffff));\n    return;\n  }\n\n  if (dsize != 8 && dsize != 16 && dsize != 32) {\n    FAILURE_6(\n        InvalidArgument,\n        \"WriteMem: %s(%s) Unsupported dsize %d. (%d,%\" PRIx64 \",%\" PRIx64 \")\\n\",\n        myCfg->get_myName(), myCfg->get_myValue(), dsize, index, address, data);\n  }\n\n  if (index < PCI_RANGE_BASE) {\n    if (dev_range_is_io[index] &&\n        !(pci_state.config_data[0][1] & endian_32(1))) {\n      printf(\"%s(%s) Legacy IO access with IO disabled from PCI config.\\n\",\n             myCfg->get_myName(), myCfg->get_myValue());\n      return;\n    }\n\n    if (!dev_range_is_io[index] &&\n        !(pci_state.config_data[0][1] & endian_32(2))) {\n      printf(\n          \"%s(%s) Legacy memory access with memory disabled from PCI config.\\n\",\n          myCfg->get_myName(), myCfg->get_myValue());\n      return;\n    }\n\n    WriteMem_Legacy(index, (u32)address, dsize, (u32)data);\n    return;\n  }\n\n  index -= PCI_RANGE_BASE;\n\n  bar = index & 7;\n  func = (index / 8) & 7;\n\n  if (bar == 7) {\n    config_write(func, (u32)address, dsize, (u32)data);\n    return;\n  }\n\n  if (pci_range_is_io[func][bar] &&\n      !(pci_state.config_data[func][1] & endian_32(1))) {\n    printf(\"%s(%s).%d PCI IO access with IO disabled from PCI config.\\n\",\n           myCfg->get_myName(), myCfg->get_myValue(), func);\n    return;\n  }\n\n  if (!pci_range_is_io[func][bar] &&\n      !(pci_state.config_data[func][1] & endian_32(2))) {\n    printf(\n        \"%s(%s).%d PCI memory access with memory disabled from PCI config.\\n\",\n        myCfg->get_myName(), myCfg->get_myValue(), func);\n    return;\n  }\n\n  WriteMem_Bar(func, bar, (u32)address, dsize, (u32)data);\n}\n\nbool CPCIDevice::do_pci_interrupt(int func, bool asserted) {\n  if ((endian_32(pci_state.config_data[func][0x0f]) & 0xff) != 0xff) {\n    cSystem->interrupt(endian_32(pci_state.config_data[func][0x0f]) & 0xff,\n                       asserted);\n    return true;\n  } else\n    return false;\n}\n\nstatic u32 pci_magic1 = 0xC1095A78;\nstatic u32 pci_magic2 = 0x87A5901C;\n\n/**\n * Save state to a Virtual Machine State file.\n **/\nint CPCIDevice::SaveState(FILE *f) {\n  long ss = sizeof(pci_state);\n\n  fwrite(&pci_magic1, sizeof(u32), 1, f);\n  fwrite(&ss, sizeof(long), 1, f);\n  fwrite(&pci_state, sizeof(pci_state), 1, f);\n  fwrite(&pci_magic2, sizeof(u32), 1, f);\n  printf(\"%s: %d PCI bytes saved.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\n/**\n * Restore state from a Virtual Machine State file.\n **/\nint CPCIDevice::RestoreState(FILE *f) {\n  long ss;\n  u32 m1;\n  u32 m2;\n  size_t r;\n\n  r = fread(&m1, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m1 != pci_magic1) {\n    printf(\"%s: PCI MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&ss, sizeof(long), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (ss != sizeof(pci_state)) {\n    printf(\"%s: PCI STRUCT SIZE does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&pci_state, sizeof(pci_state), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&m2, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m2 != pci_magic2) {\n    printf(\"%s: PCI MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  printf(\"%s: %d PCI bytes restored.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\nu32 CPCIDevice::ReadMem_Legacy(int index, u32 address, int dsize) {\n  FAILURE_2(NotImplemented, \"%s(%s) No Legacy read handler installed\",\n            myCfg->get_myName(), myCfg->get_myValue());\n}\n\nvoid CPCIDevice::WriteMem_Legacy(int index, u32 address, int dsize, u32 data) {\n  FAILURE_2(NotImplemented, \"%s(%s) No Legacy write handler installed\",\n            myCfg->get_myName(), myCfg->get_myValue());\n}\n\nu32 CPCIDevice::ReadMem_Bar(int func, int bar, u32 address, int dsize) {\n  FAILURE_3(NotImplemented, \"%s(%s).%d No BAR read handler installed\",\n            myCfg->get_myName(), myCfg->get_myValue(), func);\n}\n\nvoid CPCIDevice::WriteMem_Bar(int func, int bar, u32 address, int dsize,\n                              u32 data) {\n  FAILURE_3(NotImplemented, \"%s(%s).%d No BAR write handler installed\",\n            myCfg->get_myName(), myCfg->get_myValue(), func);\n}\n\n/**\n * \\brief Read data from the PCI bus.\n *\n * Called by the PCI-device to read data off the PCI bus. address is the\n * 32-bit address put on the PCI bus. element_count elements of element_size\n * bytes each will be read in an endian-aware manner.\n **/\nvoid CPCIDevice::do_pci_read(u32 address, void *dest, size_t element_size,\n                             size_t element_count) {\n  size_t el;\n  char *dst = (char *)dest;\n\n  if (element_count == 0)\n    return;\n\n  // get the 64-bit system wide address\n  u64 phys_addr = cSystem->PCI_Phys(myPCIBus, address);\n\n  // if there is only one element to read, this is a simple ReadMem operation.\n  if (element_count == 1) {\n    switch (element_size) {\n    case 1:\n      *(u8 *)dest = (u8)cSystem->ReadMem(phys_addr, 8, this);\n      break;\n\n    case 2:\n      *(u16 *)dest = (u16)cSystem->ReadMem(phys_addr, 16, this);\n      break;\n\n    case 4:\n      *(u32 *)dest = (u32)cSystem->ReadMem(phys_addr, 32, this);\n      break;\n\n    default:\n      FAILURE(InvalidArgument, \"Strange element size\");\n    }\n\n    return;\n  }\n\n#if defined(ES40_BIG_ENDIAN)\n\n  // if this is a big-endian host machine, the memcpy method is only valid\n  // if we're transferring bytes. Otherwise, endian-conversions need to be done.\n  if (element_size == 1) {\n#endif\n    size_t remaining = element_size * element_count;\n    u32 cur_address = address;\n\n    while (remaining != 0) {\n      u64 cur_phys = cSystem->PCI_Phys(myPCIBus, cur_address);\n      size_t chunk = pci_dma_chunk_limit(cur_phys, remaining);\n\n      // get a pointer to system memory if the address is inside main memory\n      char *memptr = cSystem->PtrToMem(cur_phys);\n\n      // Copy only within a single translated DMA page. Scatter-gather DMA does\n      // not guarantee that adjacent PCI bus addresses map to contiguous host\n      // physical memory beyond the current page.\n      if (memptr) {\n        memcpy(dst, memptr, chunk);\n      } else {\n        for (el = 0; el < chunk; el++)\n          dst[el] = (u8)cSystem->ReadMem(cur_phys + el, 8, this);\n      }\n\n      dst += chunk;\n      cur_address += (u32)chunk;\n      remaining -= chunk;\n    }\n    return;\n\n#if defined(ES40_BIG_ENDIAN)\n  }\n#endif\n\n  // outside main memory, or inside main memory with endian-conversion\n  // required we need to do the transfer element-by-element.\n  switch (element_size) {\n  case 1:\n    for (el = 0; el < element_count; el++) {\n      *(u8 *)dst = (u8)cSystem->ReadMem(phys_addr, 8, this);\n      dst++;\n      phys_addr++;\n    }\n    break;\n\n  case 2: {\n    *(u16 *)dst = endian_16((u16)cSystem->ReadMem(phys_addr, 16, this));\n    dst += 2;\n    phys_addr += 2;\n  } break;\n\n  case 4: {\n    *(u32 *)dst = endian_32((u32)cSystem->ReadMem(phys_addr, 32, this));\n    dst += 4;\n    phys_addr += 4;\n  } break;\n\n  default:\n    FAILURE(InvalidArgument, \"Strange element size\");\n  }\n}\n\n/**\n * \\brief Write data to the PCI bus.\n *\n * Called by the PCI-device to write data to the PCI bus. address is the\n * 32-bit address put on the PCI bus. element_count elements of element_size\n * bytes each will be written in an endian-aware manner.\n **/\nvoid CPCIDevice::do_pci_write(u32 address, void *source, size_t element_size,\n                              size_t element_count) {\n  size_t el;\n  char *src = (char *)source;\n\n  if (element_count == 0)\n    return;\n\n  // get the 64-bit system wide address\n  u64 phys_addr = cSystem->PCI_Phys(myPCIBus, address);\n\n  // if there is only one element to read, this is a simple ReadMem operation.\n  if (element_count == 1) {\n    switch (element_size) {\n    case 1:\n      cSystem->WriteMem(phys_addr, 8, *(u8 *)source, this);\n      break;\n    case 2:\n      cSystem->WriteMem(phys_addr, 16, *(u16 *)source, this);\n      break;\n    case 4:\n      cSystem->WriteMem(phys_addr, 32, *(u32 *)source, this);\n      break;\n    default:\n      FAILURE(InvalidArgument, \"Strange element size\");\n    }\n\n    return;\n  }\n\n#if defined(ES40_BIG_ENDIAN)\n\n  // if this is a big-endian host machine, the memcpy method is only valid\n  // if we're transferring bytes. Otherwise, endian-conversions need to be done.\n  if (element_size == 1) {\n#endif\n    size_t remaining = element_size * element_count;\n    u32 cur_address = address;\n\n    while (remaining != 0) {\n      u64 cur_phys = cSystem->PCI_Phys(myPCIBus, cur_address);\n      size_t chunk = pci_dma_chunk_limit(cur_phys, remaining);\n\n      // get a pointer to system memory if the address is inside main memory\n      char *memptr = cSystem->PtrToMem(cur_phys);\n\n      if (memptr) {\n        memcpy(memptr, src, chunk);\n      } else {\n        for (el = 0; el < chunk; el++)\n          cSystem->WriteMem(cur_phys + el, 8, (u8)src[el], this);\n      }\n\n      src += chunk;\n      cur_address += (u32)chunk;\n      remaining -= chunk;\n    }\n    return;\n\n#if defined(ES40_BIG_ENDIAN)\n  }\n#endif\n\n  // outside main memory, or inside main memory with endian-conversion\n  // required we need to do the transfer element-by-element.\n  switch (element_size) {\n  case 1:\n    for (el = 0; el < element_count; el++) {\n      cSystem->WriteMem(phys_addr, 8, *(u8 *)src, this);\n      src++;\n      phys_addr++;\n    }\n    break;\n\n  case 2: {\n    cSystem->WriteMem(phys_addr, 16, endian_16(*(u16 *)src), this);\n    src += 2;\n    phys_addr += 2;\n  } break;\n\n  case 4: {\n    cSystem->WriteMem(phys_addr, 32, endian_32(*(u32 *)src), this);\n    src += 4;\n    phys_addr += 4;\n  } break;\n\n  default:\n    FAILURE(InvalidArgument, \"Strange element size\");\n  }\n}\n"
  },
  {
    "path": "src/PCIDevice.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(__PCIDEVICE_H__)\n#define __PCIDEVICE_H__\n\n#define MAX_DEV_RANGES 50\n\n#define PCI_RANGE_BASE 0x0800\n\n#include \"SystemComponent.hpp\"\n\n/**\n * \\brief Abstract base class for devices on the PCI-bus.\n **/\nclass CPCIDevice : public CSystemComponent {\npublic:\n  CPCIDevice(class CConfigurator *cfg, class CSystem *c, int pcibus,\n             int pcidev);\n  ~CPCIDevice(void);\n  virtual int SaveState(FILE *f);\n  virtual int RestoreState(FILE *f);\n  virtual void ResetPCI();\n  virtual u64 ReadMem(int index, u64 address, int dsize);\n  virtual void WriteMem(int index, u64 address, int dsize, u64 data);\n\n  virtual u32 ReadMem_Legacy(int index, u32 address, int dsize);\n  virtual void WriteMem_Legacy(int index, u32 address, int dsize, u32 data);\n\n  virtual u32 ReadMem_Bar(int func, int bar, u32 address, int dsize);\n  virtual void WriteMem_Bar(int func, int bar, u32 address, int dsize,\n                            u32 data);\n\n  u32 config_read(int func, u32 address, int dsize);\n  void config_write(int func, u32 address, int dsize, u32 data);\n\n  virtual u32 config_read_custom(int func, u32 address, int dsize, u32 data) {\n    return data;\n  };\n  virtual void config_write_custom(int func, u32 address, int dsize,\n                                   u32 old_data, u32 new_data, u32 data){};\n  void register_bar(int func, int bar, u32 data, u32 mask);\n\n  void do_pci_read(u32 address, void *dest, size_t element_size,\n                   size_t element_count);\n  void do_pci_write(u32 address, void *source, size_t element_size,\n                    size_t element_count);\n\nprotected:\n  bool do_pci_interrupt(int func, bool asserted);\n  void add_function(int func, u32 data[64], u32 mask[64]);\n  void add_legacy_io(int id, u32 base, u32 length);\n  void add_legacy_mem(int id, u32 base, u32 length);\n\n  int myPCIBus;\n  int myPCIDev;\n\n  u32 std_config_data[8][64];\n  u32 std_config_mask[8][64];\n  bool device_at[8];\n\n  bool dev_range_is_io[MAX_DEV_RANGES];\n  bool pci_range_is_io[8][8];\n\n  /// The PCI state structure contains all elements that need to be saved to the\n  /// statefile.\n  struct SPCI_state {\n    u32 config_data[8][64];\n    u32 config_mask[8][64];\n  } pci_state;\n};\n#endif //! defined(__PCIDEVICE_H__)\n"
  },
  {
    "path": "src/Port80.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"Port80.hpp\"\n#include \"StdAfx.hpp\"\n#include \"System.hpp\"\n\n/**\n * Constructor.\n **/\nCPort80::CPort80(CConfigurator *cfg, CSystem *c) : CSystemComponent(cfg, c) {\n  c->RegisterMemory(this, 0, U64(0x00000801fc000080), 1);\n  state.p80 = 0;\n}\n\n/**\n * Destructor.\n **/\nCPort80::~CPort80() {}\n\n/**\n * Read from port 80.\n * Returns the value last written to port 80.\n **/\nu64 CPort80::ReadMem(int index, u64 address, int dsize) { return state.p80; }\n\n/**\n * Write to port 80.\n **/\nvoid CPort80::WriteMem(int index, u64 address, int dsize, u64 data) {\n  state.p80 = (u8)data;\n}\n\nstatic u32 p80_magic1 = 0x80FFAA80;\nstatic u32 p80_magic2 = 0xAA8080FF;\n\n/**\n * Save state to a Virtual Machine State file.\n **/\nint CPort80::SaveState(FILE *f) {\n  long ss = sizeof(state);\n\n  fwrite(&p80_magic1, sizeof(u32), 1, f);\n  fwrite(&ss, sizeof(long), 1, f);\n  fwrite(&state, sizeof(state), 1, f);\n  fwrite(&p80_magic2, sizeof(u32), 1, f);\n  printf(\"%s: %ld bytes saved.\\n\", devid_string, ss);\n  return 0;\n}\n\n/**\n * Restore state from a Virtual Machine State file.\n **/\nint CPort80::RestoreState(FILE *f) {\n  long ss;\n  u32 m1;\n  u32 m2;\n  size_t r;\n\n  r = fread(&m1, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m1 != p80_magic1) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&ss, sizeof(long), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (ss != sizeof(state)) {\n    printf(\"%s: STRUCT SIZE does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&state, sizeof(state), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&m2, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m2 != p80_magic2) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  printf(\"%s: %ld bytes restored.\\n\", devid_string, ss);\n  return 0;\n}\n"
  },
  {
    "path": "src/Port80.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_PORT80_H)\n#define INCLUDED_PORT80_H\n\n#include \"SystemComponent.hpp\"\n\n/**\n * \\brief Emulated port 80.\n *\n * Port 80 is a port without a real function, that is used to slow things down.\n * Since our emulator is slow enough already ;-) this port has no function at\n * all, but it needs to be there to avoid error messages about non-existing\n * hardware.\n **/\nclass CPort80 : public CSystemComponent {\npublic:\n  CPort80(CConfigurator *cfg, class CSystem *c);\n  virtual ~CPort80();\n  virtual u64 ReadMem(int index, u64 address, int dsize);\n  virtual void WriteMem(int index, u64 address, int dsize, u64 data);\n  virtual int SaveState(FILE *f);\n  virtual int RestoreState(FILE *f);\n\nprotected:\n  /// The state structure contains all elements that need to be saved to the\n  /// statefile.\n  struct SPort80_state {\n    u8 p80; /**< Last value written.*/\n  } state;\n};\n#endif // !defined(INCLUDED_PORT80_H)\n"
  },
  {
    "path": "src/Question.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_QUESTION_H)\n#define INCLUDED_QUESTION_H\n\n/**\n * Abstract Question base class.\n **/\nclass Question {\npublic:\n  /**\n   * Return the answer previously given.\n   **/\n  string getAnswer() { return mAnswer; }\n\n  /**\n   * Set the answer.\n   **/\n  void setAnswer(string answer) { mAnswer = answer; }\n\n  /**\n   * Define an explanation for the question, that will be shown when\n   * the question is answered with '?'.\n   **/\n  void setExplanation(string explanation) { mExplanation = explanation; }\n\n  /**\n   * Define the question to ask.\n   **/\n  void setQuestion(string question) { mQuestion = question; }\n\n  /**\n   * Define a default value to use when the question is answered\n   * with a <return>.\n   **/\n  void setDefault(string defval) { mDefault = defval; }\n\n  /**\n   * Ask the question, and return the value given.\n   **/\n  virtual string ask() = 0;\n\n  /**\n   * Display the explanation.\n   **/\n  virtual void explain() {\n    cout << \"\\nEXPLANATION:\\n\" << mExplanation << \"\\n\\n\";\n  }\n\nprotected:\n  /** The stored answer. */\n  string mAnswer;\n\n  /** An explanation for the question. */\n  string mExplanation;\n\n  /** The question to ask. */\n  string mQuestion;\n\n  /** Default value. */\n  string mDefault;\n};\n\n#endif // !defined(INCLUDED_QUESTION_H)\n"
  },
  {
    "path": "src/S3Trio64.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"S3Trio64.hpp\"\n#include \"AliM1543C.hpp\"\n#include \"StdAfx.hpp\"\n#include \"System.hpp\"\n#include \"gui/gui.hpp\"\n\nstatic unsigned old_iHeight = 0, old_iWidth = 0, old_MSL = 0;\n\nstatic const u8 ccdat[16][4] = {\n    {0x00, 0x00, 0x00, 0x00}, {0xff, 0x00, 0x00, 0x00},\n    {0x00, 0xff, 0x00, 0x00}, {0xff, 0xff, 0x00, 0x00},\n    {0x00, 0x00, 0xff, 0x00}, {0xff, 0x00, 0xff, 0x00},\n    {0x00, 0xff, 0xff, 0x00}, {0xff, 0xff, 0xff, 0x00},\n    {0x00, 0x00, 0x00, 0xff}, {0xff, 0x00, 0x00, 0xff},\n    {0x00, 0xff, 0x00, 0xff}, {0xff, 0xff, 0x00, 0xff},\n    {0x00, 0x00, 0xff, 0xff}, {0xff, 0x00, 0xff, 0xff},\n    {0x00, 0xff, 0xff, 0xff}, {0xff, 0xff, 0xff, 0xff},\n};\n\n/**\n * Set a specific tile's updated variable.\n *\n * Only reference the array if the tile numbers are within the bounds\n * of the array.  If out of bounds, do nothing.\n **/\n#define SET_TILE_UPDATED(xtile, ytile, value)                                  \\\n  do {                                                                         \\\n    if (((xtile) < BX_NUM_X_TILES) && ((ytile) < BX_NUM_Y_TILES))              \\\n      state.vga_tile_updated[(xtile)][(ytile)] = value;                        \\\n  } while (0)\n\n/**\n * Get a specific tile's updated variable.\n *\n * Only reference the array if the tile numbers are within the bounds\n * of the array.  If out of bounds, return 0.\n **/\n#define GET_TILE_UPDATED(xtile, ytile)                                         \\\n  ((((xtile) < BX_NUM_X_TILES) && ((ytile) < BX_NUM_Y_TILES))                  \\\n       ? state.vga_tile_updated[(xtile)][(ytile)]                              \\\n       : 0)\n\n/**\n * Thread entry point.\n *\n * The thread first initializes the GUI, and then starts looping the\n * following actions until interrupted (by StopThread being set to true)\n *   - Handle any GUI events (mouse moves, keypresses)\n *   - Update the GUI to match the screen buffer\n *   - Flush the updated GUI content to the screen\n *   .\n **/\nvoid CS3Trio64::run() {\n  try {\n    // initialize the GUI (and let it know our tilesize)\n    bx_gui->init(state.x_tilesize, state.y_tilesize);\n    for (;;) {\n      // Terminate thread if StopThread is set to true\n      if (StopThread)\n        return;\n      // Handle GUI events (100 times per second)\n      for (int i = 0; i < 10; i++) {\n        bx_gui->lock();\n        bx_gui->handle_events();\n        bx_gui->unlock();\n        std::this_thread::sleep_for(std::chrono::milliseconds(10));\n      }\n      // Update the screen (10 times per second)\n      bx_gui->lock();\n      update();\n      bx_gui->flush();\n      bx_gui->unlock();\n    }\n  }\n\n  catch (CException &e) {\n    printf(\"Exception in S3 thread: %s.\\n\", e.displayText().c_str());\n    myThreadDead.store(true);\n    // Let the thread die...\n  }\n}\n\n/** Size of ROM image */\nstatic unsigned int rom_max;\n\n/** ROM image */\nstatic u8 option_rom[65536];\n\n/** PCI Configuration Space data block */\nstatic u32 s3_cfg_data[64] = {\n    /*00*/ 0x88115333, // CFID: vendor + device\n    /*04*/ 0x011f0000, // CFCS: command + status\n    /*08*/ 0x03000002, // CFRV: class + revision\n    /*0c*/ 0x00000000, // CFLT: latency timer + cache line size\n    /*10*/ 0xf8000000, // BAR0: FB\n    /*14*/ 0x00000000, // BAR1:\n    /*18*/ 0x00000000, // BAR2:\n    /*1c*/ 0x00000000, // BAR3:\n    /*20*/ 0x00000000, // BAR4:\n    /*24*/ 0x00000000, // BAR5:\n    /*28*/ 0x00000000, // CCIC: CardBus\n    /*2c*/ 0x00000000, // CSID: subsystem + vendor\n    /*30*/ 0x00000000, // BAR6: expansion rom base\n    /*34*/ 0x00000000, // CCAP: capabilities pointer\n    /*38*/ 0x00000000,\n    /*3c*/ 0x281401ff, // CFIT: interrupt configuration\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0};\n\n/** PCI Configuration Space mask block */\nstatic u32 s3_cfg_mask[64] = {\n    /*00*/ 0x00000000, // CFID: vendor + device\n    /*04*/ 0x0000ffff, // CFCS: command + status\n    /*08*/ 0x00000000, // CFRV: class + revision\n    /*0c*/ 0x0000ffff, // CFLT: latency timer + cache line size\n    /*10*/ 0xfc000000, // BAR0: FB\n    /*14*/ 0x00000000, // BAR1:\n    /*18*/ 0x00000000, // BAR2:\n    /*1c*/ 0x00000000, // BAR3:\n    /*20*/ 0x00000000, // BAR4:\n    /*24*/ 0x00000000, // BAR5:\n    /*28*/ 0x00000000, // CCIC: CardBus\n    /*2c*/ 0x00000000, // CSID: subsystem + vendor\n    /*30*/ 0x00000000, // BAR6: expansion rom base\n    /*34*/ 0x00000000, // CCAP: capabilities pointer\n    /*38*/ 0x00000000,\n    /*3c*/ 0x000000ff, // CFIT: interrupt configuration\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0};\n\n/**\n * Constructor.\n *\n * Don't do anything, the real initialization is done by init()\n **/\nCS3Trio64::CS3Trio64(CConfigurator *cfg, CSystem *c, int pcibus, int pcidev)\n    : CVGA(cfg, c, pcibus, pcidev) {}\n\n/**\n * Initialize the S3 device.\n **/\nvoid CS3Trio64::init() {\n  // Register PCI device\n  add_function(0, s3_cfg_data, s3_cfg_mask);\n\n  // Initialize all state variables to 0\n  memset((void *)&state, 0, sizeof(state));\n\n  // Register VGA I/O ports at 3b4, 3b5, 3ba, 3c0..cf, 3d4, 3d5, 3da\n  add_legacy_io(1, 0x3b4, 2);\n  add_legacy_io(3, 0x3ba, 2);\n  add_legacy_io(2, 0x3c0, 16);\n  add_legacy_io(8, 0x3d4, 2);\n  add_legacy_io(9, 0x3da, 1);\n\n  /* The VGA BIOS we use sends text messages to port 0x500.\n     We listen for these messages at port 500. */\n  add_legacy_io(7, 0x500, 1);\n  bios_message_size = 0;\n  bios_message[0] = '\\0';\n\n  // Legacy video address space: A0000 -> bffff\n  add_legacy_mem(4, 0xa0000, 128 * 1024);\n\n  // Reset the base PCI device\n  ResetPCI();\n\n  /* The configuration file variable \"rom\" should point to a VGA BIOS\n     image. If not, try \"vgabios.bin\". */\n  FILE *rom = fopen(myCfg->get_text_value(\"rom\", \"vgabios.bin\"), \"rb\");\n  if (!rom) {\n    FAILURE_1(FileNotFound, \"s3 rom file %s not found\",\n              myCfg->get_text_value(\"rom\", \"vgabios.bin\"));\n  }\n\n  rom_max = (unsigned)fread(option_rom, 1, 65536, rom);\n  fclose(rom);\n\n  // Option ROM address space: C0000\n  add_legacy_mem(5, 0xc0000, rom_max);\n\n  state.vga_enabled = 1;\n  state.misc_output.color_emulation = 1;\n  state.misc_output.enable_ram = 1;\n  state.misc_output.horiz_sync_pol = 1;\n  state.misc_output.vert_sync_pol = 1;\n\n  state.attribute_ctrl.mode_ctrl.enable_line_graphics = 1;\n\n  state.line_offset = 80;\n  state.line_compare = 1023;\n  state.vertical_display_end = 399;\n\n  state.attribute_ctrl.video_enabled = 1;\n  state.attribute_ctrl.color_plane_enable = 0x0f;\n\n  state.pel.dac_state = 0x01;\n  state.pel.mask = 0xff;\n\n  state.graphics_ctrl.memory_mapping = 2; // monochrome text mode\n\n  state.sequencer.reset1 = 1;\n  state.sequencer.reset2 = 1;\n  state.sequencer.extended_mem = 1; // display mem greater than 64K\n  state.sequencer.odd_even = 1;     // use sequential addressing mode\n\n  state.memsize = 0x40000;\n  state.memory = new u8[state.memsize];\n  memset(state.memory, 0, state.memsize);\n\n  state.last_bpp = 8;\n\n  state.CRTC.reg[0x09] = 16;\n  state.graphics_ctrl.memory_mapping = 3; // color text mode\n  state.vga_mem_updated = 1;\n\n  printf(\"%s: $Id: S3Trio64.cpp,v 1.20 2008/05/31 15:47:10 iamcamiel Exp $\\n\",\n         devid_string);\n}\n\n/**\n * Create and start thread.\n **/\nvoid CS3Trio64::start_threads() {\n  if (!myThread) {\n    printf(\" s3\");\n    StopThread = false;\n    myThread = std::make_unique<std::thread>([this](){ this->run(); });\n  }\n}\n\n/**\n * Stop and destroy thread.\n **/\nvoid CS3Trio64::stop_threads() {\n  // Signal the thread to stop\n  StopThread = true;\n  if (myThread) {\n    printf(\" s3\");\n    // Wait for the thread to end execution\n    myThread->join();\n    // And delete the Thread object\n    myThread = nullptr;\n  }\n}\n\n/**\n * Destructor.\n **/\nCS3Trio64::~CS3Trio64() { stop_threads(); }\n\n/**\n * Read from one of the Legacy (fixed-address) memory ranges.\n **/\nu32 CS3Trio64::ReadMem_Legacy(int index, u32 address, int dsize) {\n  u32 data = 0;\n  switch (index) {\n  // IO Port 0x3b4\n  case 1:\n    data = io_read(address + 0x3b4, dsize);\n    break;\n\n  // IO Port 0x3c0..0x3cf\n  case 2:\n    data = io_read(address + 0x3c0, dsize);\n    break;\n\n  // IO Port 0x3ba\n  case 3:\n    data = io_read(address + 0x3ba, dsize);\n    break;\n\n  // VGA Memory\n  case 4:\n    data = legacy_read(address, dsize);\n    break;\n\n  // ROM\n  case 5:\n    data = rom_read(address, dsize);\n    break;\n\n  // IO Port 0x3d4\n  case 8:\n    data = io_read(address + 0x3d4, dsize);\n    break;\n\n  // IO Port 0x3da\n  case 9:\n    data = io_read(address + 0x3da, dsize);\n    break;\n  }\n\n  return data;\n}\n\n/**\n * Write to one of the Legacy (fixed-address) memory ranges.\n **/\nvoid CS3Trio64::WriteMem_Legacy(int index, u32 address, int dsize, u32 data) {\n  switch (index) {\n  // IO Port 0x3b4\n  case 1:\n    io_write(address + 0x3b4, dsize, data);\n    return;\n\n  // IO Port 0x3c0..0x3cf\n  case 2:\n    io_write(address + 0x3c0, dsize, data);\n    return;\n\n  // IO Port 0x3ba\n  case 3:\n    io_write(address + 0x3ba, dsize, data);\n    return;\n\n  // VGA Memory\n  case 4:\n    legacy_write(address, dsize, data);\n    return;\n\n  // BIOS Message IO Port (0x500)\n  case 7:\n    bios_message[bios_message_size++] = (char)data & 0xff;\n    if (((data & 0xff) == 0x0a) || ((data & 0xff) == 0x0d)) {\n      if (bios_message_size > 1) {\n        bios_message[bios_message_size - 1] = '\\0';\n        printf(\"s3: %s\\n\", bios_message);\n      }\n\n      bios_message_size = 0;\n    }\n\n    return;\n\n  // IO Port 0x3d4\n  case 8:\n    io_write(address + 0x3d4, dsize, data);\n    return;\n\n  // IO Port 0x3da\n  case 9:\n    io_write(address + 0x3da, dsize, data);\n    return;\n  }\n}\n\n/**\n * Read from one of the PCI BAR (configurable address) memory ranges.\n **/\nu32 CS3Trio64::ReadMem_Bar(int func, int bar, u32 address, int dsize) {\n  switch (bar) {\n  // PCI memory range\n  case 0:\n    return mem_read(address, dsize);\n  }\n\n  return 0;\n}\n\n/**\n * Write to one of the PCI BAR (configurable address) memory ranges.\n **/\nvoid CS3Trio64::WriteMem_Bar(int func, int bar, u32 address, int dsize,\n                             u32 data) {\n  switch (bar) {\n  // PCI Memory range\n  case 0:\n    mem_write(address, dsize, data);\n    return;\n  }\n}\n\n/**\n * Check if threads are still running.\n **/\nvoid CS3Trio64::check_state() {\n  if (myThreadDead.load())\n    FAILURE(Thread, \"S3 thread has died\");\n}\n\nstatic u32 s3_magic1 = 0x53338811;\nstatic u32 s3_magic2 = 0x88115333;\n\n/**\n * Save state to a Virtual Machine State file.\n **/\nint CS3Trio64::SaveState(FILE *f) {\n  long ss = sizeof(state);\n  int res;\n\n  if ((res = CPCIDevice::SaveState(f)))\n    return res;\n\n  fwrite(&s3_magic1, sizeof(u32), 1, f);\n  fwrite(&ss, sizeof(long), 1, f);\n  fwrite(&state, sizeof(state), 1, f);\n  fwrite(&s3_magic2, sizeof(u32), 1, f);\n  printf(\"%s: %d bytes saved.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\n/**\n * Restore state from a Virtual Machine State file.\n **/\nint CS3Trio64::RestoreState(FILE *f) {\n  long ss;\n  u32 m1;\n  u32 m2;\n  int res;\n  size_t r;\n\n  if ((res = CPCIDevice::RestoreState(f)))\n    return res;\n\n  r = fread(&m1, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m1 != s3_magic1) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&ss, sizeof(long), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (ss != sizeof(state)) {\n    printf(\"%s: STRUCT SIZE does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&state, sizeof(state), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&m2, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m2 != s3_magic2) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  printf(\"%s: %d bytes restored.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\n/**\n * Read from Framebuffer.\n *\n * Not functional.\n **/\nu32 CS3Trio64::mem_read(u32 address, int dsize) {\n  u32 data = 0;\n\n  // printf(\"S3 mem read: %\" PRIx64 \", %d, %\" PRIx64 \"   \\n\", address, dsize, data);\n  return data;\n}\n\n/**\n * Write to Framebuffer.\n *\n * Not functional.\n **/\nvoid CS3Trio64::mem_write(u32 address, int dsize, u32 data) {\n\n  // printf(\"S3 mem write: %\" PRIx64 \", %d, %\" PRIx64 \"   \\n\", address, dsize, data);\n  switch (dsize) {\n  case 8:\n  case 16:\n  case 32:\n    break;\n  }\n}\n\n/**\n * Read from Legacy VGA Memory\n *\n * Calls vga_mem_read to read the data 1 byte at a time.\n **/\nu32 CS3Trio64::legacy_read(u32 address, int dsize) {\n  u32 data = 0;\n  switch (dsize) {\n  case 32:\n    data |= (u64)vga_mem_read((u32)address + 0xA0003) << 24;\n    data |= (u64)vga_mem_read((u32)address + 0xA0002) << 16;\n\n  case 16:\n    data |= (u64)vga_mem_read((u32)address + 0xA0001) << 8;\n\n  case 8:\n    data |= (u64)vga_mem_read((u32)address + 0xA0000);\n  }\n\n  //  //printf(\"S3 legacy read: %\" PRIx64 \", %d, %\" PRIx64 \"   \\n\", address, dsize,\n  //  data);\n  return data;\n}\n\n/**\n * Write to Legacy VGA Memory\n *\n * Calls vga_mem_write to write the data 1 byte at a time.\n **/\nvoid CS3Trio64::legacy_write(u32 address, int dsize, u32 data) {\n\n  //  //printf(\"S3 legacy write: %\" PRIx64 \", %d, %\" PRIx64 \"   \\n\", address, dsize,\n  //  data);\n  switch (dsize) {\n  case 32:\n    vga_mem_write((u32)address + 0xA0002, (u8)(data >> 16));\n    vga_mem_write((u32)address + 0xA0003, (u8)(data >> 24));\n\n  case 16:\n    vga_mem_write((u32)address + 0xA0001, (u8)(data >> 8));\n\n  case 8:\n    vga_mem_write((u32)address + 0xA0000, (u8)(data));\n  }\n}\n\n/**\n * Read from Option ROM\n */\nu32 CS3Trio64::rom_read(u32 address, int dsize) {\n  u32 data = 0x00;\n  u8 *x = (u8 *)option_rom;\n  if (address <= rom_max) {\n    x += address;\n    switch (dsize) {\n    case 8:\n      data = (u32)endian_8((*((u8 *)x)) & 0xff);\n      break;\n    case 16:\n      data = (u32)endian_16((*((u16 *)x)) & 0xffff);\n      break;\n    case 32:\n      data = (u32)endian_32((*((u32 *)x)) & 0xffffffff);\n      break;\n    }\n\n    // printf(\"S3 rom read: %\" PRIx64 \", %d, %\" PRIx64 \"\\n\", address, dsize,data);\n  } else {\n\n    // printf(\"S3 (BAD) rom read: %\" PRIx64 \", %d, %\" PRIx64 \"\\n\", address,\n    // dsize,data);\n  }\n\n  return data;\n}\n\n/**\n * Read from I/O Port\n */\nu32 CS3Trio64::io_read(u32 address, int dsize) {\n  u32 data = 0;\n  if (dsize != 8)\n    FAILURE(InvalidArgument, \"Unsupported dsize\");\n\n  switch (address) {\n  case 0x3c0:\n    data = read_b_3c0();\n    break;\n\n  case 0x3c1:\n    data = read_b_3c1();\n    break;\n\n  case 0x3c2:\n    data = read_b_3c2();\n    break;\n\n  case 0x3c3:\n    data = read_b_3c3();\n    break;\n\n  case 0x3c4:\n    data = read_b_3c4();\n    break;\n\n  case 0x3c5:\n    data = read_b_3c5();\n    break;\n\n  case 0x3c9:\n    data = read_b_3c9();\n    break;\n\n  case 0x3ca:\n    data = read_b_3ca();\n    break;\n\n  case 0x3cc:\n    data = read_b_3cc();\n    break;\n\n  case 0x3cf:\n    data = read_b_3cf();\n    break;\n\n  case 0x3b4:\n  case 0x3d4:\n    data = read_b_3d4();\n    break;\n\n  case 0x3b5:\n  case 0x3d5:\n    data = read_b_3d5();\n    break;\n\n  case 0x3ba:\n  case 0x3da:\n    data = read_b_3da();\n    break;\n\n  default:\n    FAILURE_1(NotImplemented, \"Unhandled port %x read\", address);\n  }\n\n  // printf(\"S3 io read: %\" PRIx64 \", %d, %\" PRIx64 \"   \\n\", address, dsize, data);\n  return data;\n}\n\n/**\n * Write to I/O Port\n *\n * Calls io_write_b to write the data 1 byte at a time.\n */\nvoid CS3Trio64::io_write(u32 address, int dsize, u32 data) {\n\n  //  printf(\"S3 io write: %\" PRIx64 \", %d, %\" PRIx64 \"   \\n\", address+VGA_BASE,\n  //  dsize, data);\n  switch (dsize) {\n  case 8:\n    io_write_b(address, (u8)data);\n    break;\n\n  case 16:\n    io_write_b(address, (u8)data);\n    io_write_b(address + 1, (u8)(data >> 8));\n    break;\n\n  default:\n    FAILURE(InvalidArgument, \"Weird IO size\");\n  }\n}\n\n/**\n * Write one byte to a VGA I/O port.\n **/\nvoid CS3Trio64::io_write_b(u32 address, u8 data) {\n  switch (address) {\n  case 0x3c0:\n    write_b_3c0(data);\n    break;\n\n  case 0x3c2:\n    write_b_3c2(data);\n    break;\n\n  case 0x3c4:\n    write_b_3c4(data);\n    break;\n\n  case 0x3c5:\n    write_b_3c5(data);\n    break;\n\n  case 0x3c6:\n    write_b_3c6(data);\n    break;\n\n  case 0x3c7:\n    write_b_3c7(data);\n    break;\n\n  case 0x3c8:\n    write_b_3c8(data);\n    break;\n\n  case 0x3c9:\n    write_b_3c9(data);\n    break;\n\n  case 0x3ce:\n    write_b_3ce(data);\n    break;\n\n  case 0x3cf:\n    write_b_3cf(data);\n    break;\n\n  case 0x3b4:\n  case 0x3d4:\n    write_b_3d4(data);\n    break;\n\n  case 0x3b5:\n  case 0x3d5:\n    write_b_3d5(data);\n    break;\n\n  default:\n    FAILURE_1(NotImplemented, \"Unhandled port %x write\", address);\n  }\n}\n\n/**\n * Write to the attribute controller I/O port (0x3c0)\n *\n * The attribute controller registers are used to select the 16 color\n * and 64 color palettes used for EGA/CGA compatibility.\n *\n * The attribute registers are accessed in an indexed fashion.\n * The address register is read and written via port 3C0h.\n * The data register is written to port 3C0h and read from port 3C1h.\n * The index and the data are written to the same port, one after\n * another. A flip-flop inside the card keeps track of whether the\n * next write will be handled is an index or data. Because there is\n * no standard method of determining the state of this flip-flop, the\n * ability to reset the flip-flop such that the next write will be\n * handled as an index is provided. This is accomplished by reading\n * the Input Status #1 Register (normally port 3DAh) (the data\n * received is not important.)\n *\n * Attribute registers:\n *   - Palette Index registers (index 0x00 - 0x0f)\n *   - Attribute Mode Control register (index 0x10)\n *   - Overscan Color register (index 0x11)\n *   - Color Plane Enable register (index 0x12)\n *   - Horizontal Pixel Panning register (index 0x13)\n *   - Color Select register (index 0x14)\n *   .\n *\n * \\code\n * Attribute Address Register(3C0h)\n * +---+-+---------+\n * |   |5|4 3 2 1 0|\n * +---+-+---------+\n *      ^     ^\n *      |     +-- 0..4: Attribute Address: This field specifies the index\n *      |               value of the attribute register to be read or written\n *      +----------- 5: Palette Address Source: This bit is set to 0 to load\n *                      color values to the registers in the internal palette.\n *                      It is set to 1 for normal operation of the attribute\n *                      controller.\n *\n * Palette Index Registers (index 0x00 - 0x0f)\n * +---+-----------+\n * |   |5 4 3 2 1 0|\n * +---+-----------+\n *           ^\n *           +--- 0..5: Internal Palette Index: These 6-bit registers allow a\n *                      dynamic mapping between the text attribute or graphic\n *                      color input value and the display color on the CRT\n *                      screen. These internal palette values are sent off-chip\n *                      to the video DAC, where they serve as addresses into\n *                      the DAC registers.\n *\n * Attribute Mode Control Register (index 0x10)\n * +-+-+-+-+-+-+-+-+\n * |7|6|5| |3|2|1|0|\n * +-+-+-+-+-+-+-+-+\n *  ^ ^ ^   ^ ^ ^ ^\n *  | | |   | | | +- 0: ATGE - Attribute Controller Graphics Enable:\n *  | | |   | | |         0: Disables the graphics mode of operation.\n *  | | |   | | |         1: Selects the graphics mode of operation.\n *  | | |   | | +--- 1: MONO - Monochrome Emulation: This bit is present and\n *  | | |   | |         programmable in all of the hardware but it apparently\n *  | | |   | |         does nothing.\n *  | | |   | +----- 2: LGE - Line Graphics Enable: This field is used in 9\n *  | | |   |           bit wide character modes to provide continuity for the\n *  | | |   |           horizontal line characters in the range C0h-DFh:\n *  | | |   |             0: the 9th column is replicated from the 8th column.\n *  | | |   |             1: the 9th column is set to the background.\n *  | | |   +------- 3: BLINK - Blink Enable:\n *  | | |                 0: Bit 7 of the attribute selects the background\n *  | | |                    intensity (allows 16 colors for background).\n *  | | |                 1: Bit 7 of the attribute enables blinking.\n *  | | +----------- 5: PPM -- Pixel Panning Mode: Allows the upper half of\n *  | |                 the screen to pan independently of the lower screen.\n *  | |                   0: nothing special occurs during a successful line\n *  | |                      compare (see the Line Compare field.)\n *  | |                   1: upon a successful line compare, the bottom portion\n *  | |                      of the screen is displayed as if the Pixel Shift\n *  | |                      Count and Byte Panning fields are set to 0.\n *  | +------------- 6: 8BIT -- 8-bit Color Enable:\n *  |                     1: The video data is sampled so that eight bits are\n *  |                        available to select a color in the 256-color mode.\n *  |                     0: All other modes.\n *  +--------------- 7: P54S -- Palette Bits 5-4 Select: Selects the source for\n *                      the P5 and P4 video bits that act as inputs to the video\n *                      DAC.\n *                        0: P5 and P4 are the outputs of the Internal Palette\n *                           registers.\n *                        1: P5 and P4 are bits 1 and 0 of the Color Select\n *                           register.\n *\n * Overscan Color Register (index 0x11)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n *         +----- 0..7: Overscan Palette Index: Selects a color from one of the\n *                      DAC registers for the border.\n *\n * Color Plane Enable Register (index 0x12)\n * +-------+-------+\n * |       |3 2 1 0|\n * +-------+-------+\n *             ^\n *             +- 0..3: Color Plane Enable: Setting a bit to 1 enables the\n *                      corresponding display-memory color plane.\n *\n * Horizontal Pixel Panning Register (index 0x13)\n * +-------+-------+\n * |       |3 2 1 0|\n * +-------+-------+\n *             ^\n *             +- 0..3: Pixel Shift Count: These bits select the number of pels\n *                      that the video data is shifted to the left.\n *\n * Color Select Register (index 0x14)\n * +-------+---+---+\n * |       |3 2|1 0|\n * +-------+---+---+\n *           ^   ^\n *           |   +- 0..1: Color Select 5-4: These bits can be used in place of\n *           |            the P4 and P5 bits from the Internal Palette registers\n *           |            to form the  8-bit digital color value to the video\n *DAC. |            Selecting these bits is done in the Attribute Mode | Control\n *register (index 0x10).\n *           +----- 2..3: Color Select 7-6: In modes other than mode 0x13\n *                        (256-color VGA), these are the two most-significant\n *bits of the 8-bit digital color value to the video DAC. \\endcode\n **/\nvoid CS3Trio64::write_b_3c0(u8 value) {\n  // Variables to save old state (to detect transitions)\n  bool prev_video_enabled;\n  bool prev_line_graphics;\n  bool prev_int_pal_size;\n\n  /* The flip-flop determines whether the write goes to the index-register\n     (address) or the data-register. */\n  if (state.attribute_ctrl.flip_flop == 0) {\n    // Write goes to the index-register.\n\n    /* The index register also has a bit that controls whether video\n       output is enabled or not.\n       We check this bit, and compare it to it's previous state, to\n       determine whether we need to perform an enable or disable\n       transition. */\n    prev_video_enabled = state.attribute_ctrl.video_enabled;\n    state.attribute_ctrl.video_enabled = (value >> 5) & 0x01;\n#if defined(DEBUG_VGA)\n    printf(\"io write 3c0: video_enabled = %u   \\n\",\n           (unsigned)state.attribute_ctrl.video_enabled);\n#endif\n    if (state.attribute_ctrl.video_enabled == 0) {\n      if (prev_video_enabled) {\n#if defined(DEBUG_VGA)\n        printf(\"found disable transition   \\n\");\n#endif\n        // Video output has been disabled. Clear the screen.\n        bx_gui->lock();\n        bx_gui->clear_screen();\n        bx_gui->unlock();\n      }\n    } else if (!prev_video_enabled) {\n#if defined(DEBUG_VGA)\n      printf(\"found enable transition   \\n\");\n#endif\n      // Video output has been enabled. Draw the screen.\n      redraw_area(0, 0, old_iWidth, old_iHeight);\n    }\n\n    // Determine what register should be addressed.\n    value &= 0x1f; /* address = bits 0..4 */\n    state.attribute_ctrl.address = value;\n\n    /* Registers 0x00..0x0f are palette selection registers.\n       Write a debugging message for all other registers. */\n#if defined(DEBUG_VGA)\n    if (value > 0x0f)\n      printf(\"io write 3c0: address mode reg=%u   \\n\", (unsigned)value);\n#endif\n  } else {\n    // Write should go to the data-register.\n\n    // Registers 0x00..0x0f are palette selection registers.\n    if (state.attribute_ctrl.address <= 0x0f) {\n      // Update palette selection only of there is a change.\n      if (value !=\n          state.attribute_ctrl.palette_reg[state.attribute_ctrl.address]) {\n        // Update the palette selection.\n        state.attribute_ctrl.palette_reg[state.attribute_ctrl.address] = value;\n        // Requires redrawing the screen.\n        redraw_area(0, 0, old_iWidth, old_iHeight);\n      }\n    } else {\n      switch (state.attribute_ctrl.address) {\n      // Mode control register\n      case 0x10:\n        prev_line_graphics =\n            state.attribute_ctrl.mode_ctrl.enable_line_graphics;\n        prev_int_pal_size =\n            state.attribute_ctrl.mode_ctrl.internal_palette_size;\n        state.attribute_ctrl.mode_ctrl.graphics_alpha = (value >> 0) & 0x01;\n        state.attribute_ctrl.mode_ctrl.display_type = (value >> 1) & 0x01;\n        state.attribute_ctrl.mode_ctrl.enable_line_graphics =\n            (value >> 2) & 0x01;\n        state.attribute_ctrl.mode_ctrl.blink_intensity = (value >> 3) & 0x01;\n        state.attribute_ctrl.mode_ctrl.pixel_panning_compat =\n            (value >> 5) & 0x01;\n        state.attribute_ctrl.mode_ctrl.pixel_clock_select = (value >> 6) & 0x01;\n        state.attribute_ctrl.mode_ctrl.internal_palette_size =\n            (value >> 7) & 0x01;\n        if (((value >> 2) & 0x01) != prev_line_graphics) {\n          bx_gui->lock();\n          bx_gui->set_text_charmap(\n              &state.memory[0x20000 + state.charmap_address]);\n          bx_gui->unlock();\n          state.vga_mem_updated = 1;\n        }\n\n        if (((value >> 7) & 0x01) != prev_int_pal_size) {\n          redraw_area(0, 0, old_iWidth, old_iHeight);\n        }\n\n#if defined(DEBUG_VGA)\n        printf(\"io write 3c0: mode control: %02x h   \\n\", (unsigned)value);\n#endif\n        break;\n\n      // Overscan Color Register\n      case 0x11:\n        /* We don't do anything with this. Our display doesn't\n           show the overscan part of the normal monitor. */\n        state.attribute_ctrl.overscan_color = (value & 0x3f);\n#if defined(DEBUG_VGA)\n        printf(\"io write 3c0: overscan color = %02x   \\n\", (unsigned)value);\n#endif\n        break;\n\n      // Color Plane Enable Register\n      case 0x12:\n        state.attribute_ctrl.color_plane_enable = (value & 0x0f);\n        redraw_area(0, 0, old_iWidth, old_iHeight);\n#if defined(DEBUG_VGA)\n        printf(\"io write 3c0: color plane enable = %02x   \\n\", (unsigned)value);\n#endif\n        break;\n\n      // Horizontal Pixel Panning Register\n      case 0x13:\n        state.attribute_ctrl.horiz_pel_panning = (value & 0x0f);\n        redraw_area(0, 0, old_iWidth, old_iHeight);\n#if defined(DEBUG_VGA)\n        printf(\"io write 3c0: horiz pel panning = %02x   \\n\", (unsigned)value);\n#endif\n        break;\n\n      // Color Select Register\n      case 0x14:\n        state.attribute_ctrl.color_select = (value & 0x0f);\n        redraw_area(0, 0, old_iWidth, old_iHeight);\n#if defined(DEBUG_VGA)\n        printf(\"io write 3c0: color select = %02x   \\n\",\n               (unsigned)state.attribute_ctrl.color_select);\n#endif\n        break;\n\n      default:\n        FAILURE_1(NotImplemented, \"io write 3c0: data-write mode %02x h\",\n                  (unsigned)state.attribute_ctrl.address);\n      }\n    }\n  }\n\n  // Flip the flip-flop\n  state.attribute_ctrl.flip_flop = !state.attribute_ctrl.flip_flop;\n}\n\n/**\n * Write to the VGA Miscellaneous Output Register (0x3c2)\n *\n * \\code\n * +-+-+-+-+---+-+-+\n * |7|6|5| |3 2|1|0|\n * +-+-+-+-+---+-+-+\n *  ^ ^ ^    ^  ^ ^\n *  | | |    |  | +- 0: I/OAS -- Input/Output Address Select: Selects the CRT\n *  | | |    |  |       controller addresses.\n *  | | |    |  |         0: Compatibility with monochrome adapter\n *  | | |    |  |            (0x3b4,0x3b5,0x03ba)\n *  | | |    |  |         1: Compatibility with color graphics adapter (CGA)\n *  | | |    |  |            (0x3d4,0x3d5,0x03da)\n *  | | |    |  +--- 1: RAM Enable: Controls access from the system:\n *  | | |    |            0: Disables access to the display buffer\n *  | | |    |            1: Enables access to the display buffer\n *  | | |    +--- 2..3: Clock Select: Controls the selection of the dot clocks\n *  | | |               used in driving the display timing:\n *  | | |                 00: Select 25 Mhz clock (320/640 pixel wide modes)\n *  | | |                 01: Select 28 Mhz clock (360/720 pixel wide modes)\n *  | | |                 10: Undefined (possible external clock)\n *  | | |                 11: Undefined (possible external clock)\n *  | | +----------- 5: Odd/Even Page Select: Selects the upper/lower 64K page\n *  | |                 of memory when the system is in an even/odd mode.\n *  | |                   0: Selects the low page.\n *  | |                   1: Selects the high page.\n *  | +------------- 6: Horizontal Sync Polarity\n *  |                     0: Positive sync pulse.\n *  |                     1: Negative sync pulse.\n *  +--------------- 7: Vertical Sync Polarity\n *                        0: Positive sync pulse.\n *                        1: Negative sync pulse.\n * \\endcode\n **/\nvoid CS3Trio64::write_b_3c2(u8 value) {\n  state.misc_output.color_emulation = (value >> 0) & 0x01;\n  state.misc_output.enable_ram = (value >> 1) & 0x01;\n  state.misc_output.clock_select = (value >> 2) & 0x03;\n  state.misc_output.select_high_bank = (value >> 5) & 0x01;\n  state.misc_output.horiz_sync_pol = (value >> 6) & 0x01;\n  state.misc_output.vert_sync_pol = (value >> 7) & 0x01;\n#if defined(DEBUG_VGA)\n  printf(\"io write 3c2:   \\n\");\n  printf(\"  color_emulation = %u   \\n\",\n         (unsigned)state.misc_output.color_emulation);\n  printf(\"  enable_ram = %u   \\n\", (unsigned)state.misc_output.enable_ram);\n  printf(\"  clock_select = %u   \\n\", (unsigned)state.misc_output.clock_select);\n  printf(\"  select_high_bank = %u   \\n\",\n         (unsigned)state.misc_output.select_high_bank);\n  printf(\"  horiz_sync_pol = %u   \\n\",\n         (unsigned)state.misc_output.horiz_sync_pol);\n  printf(\"  vert_sync_pol = %u   \\n\",\n         (unsigned)state.misc_output.vert_sync_pol);\n#endif\n}\n\n/**\n * Write to the VGA sequencer index register (0x3c4)\n *\n * The Sequencer registers control how video data is sent to the DAC.\n *\n * The Sequencer registers are accessed in an indexed fashion. By writing a byte\n * to the Sequencer Index Register (0x3c4) equal to the index of the particular\n * sub-register you wish to access, one can address the data pointed to by that\n * index by reading and writing the Sequencer Data Register (0x3c5).\n *\n * Sequencer registers:\n *   - Reset register (index 0x00)\n *   - Clocking Mode register (index 0x01)\n *   - Map Mask register (index 0x02)\n *   - Character Map Select register (index 0x03)\n *   - Memory Mode register (index 0x04)\n *   .\n *\n * \\code\n * Reset register (index 0x00)\n * +-----------+-+-+\n * |           |1|0|\n * +-----------+-+-+\n *              ^ ^\n *              | +- 0: Asynchronous Reset:\n *              |         0: Commands the sequencer to asynchronously clear and\n *              |            halt. Resetting the sequencer with this bit can\n *              |            cause loss of video data.\n *              |         1: Allows the sequencer to function normally.\n *              +--- 1: Sychnronous Reset:\n *                        0: Commands the sequencer to synchronously clear and\n *                           halt.\n *                        1: Allows the sequencer to function normally.\n * Bits 1 and 0 must be 1 to allow the sequencer to operate.\n * To prevent the loss of data, bit 1 must be set to 0 during the active display\n * interval before changing the clock selection. The clock is changed through\n *the Clocking Mode register or the Miscellaneous Output register.\n *\n * Clocking Mode register (index 0x01)\n * +---+-+-+-+-+-+-+\n * |   |5|4|3|2| |0|\n * +---+-+-+-+-+-+-+\n *      ^ ^ ^ ^   ^\n *      | | | |   +- 0: 9/8 Dot Mode: Selects whether a character is 8 or 9 dots\n *      | | | |         wide. This can be used to select between 720 and 640\n *      | | | |         pixel modes (or 360 and 320) and also is used to provide\n *      | | | |         9 bit wide character fonts in text mode:\n *      | | | |           0: Selects 9 dots per character.\n *      | | | |           1: Selects 8 dots per character.\n *      | | | +----- 2: Shift/Load Rate:\n *      | | |             0: Video serializers are loaded every character clock.\n *      | | |             1: Video serializers are loaded every other character\n *      | | |                clock, which is useful when 16 bits are fetched per\n *      | | |                cycle and chained together in the shift registers.\n *      | | +------- 3: Dot Clock Rate:\n *      | |               0: Selects the normal dot clocks derived from the\n *      | |                  sequencer master clock input.\n *      | |               1: The master clock will be divided by 2 to generate\n *      | |                  the dot clock. All other timings are affected\n *      | |                  because they are derived from the dot clock. The\n *dot | |                  clock divided by 2 is used for 320 and 360 horizontal\n *      | |                  PEL modes.\n *      | +--------- 4: Shift Four Enable:\n *      |                 0: Video serializers are loaded every character clock.\n *      |                 1: Video serializers are loaded every fourth character\n *      |                    clock, which is useful when 32 bits are fetched per\n *      |                    cycle and chained together in the shift registers.\n *      +----------- 5: Screen Disable:\n *                        0: Display enabled.\n *                        1: Display blanked. Maximum memory bandwidth assigned\n *to the system.\n *\n * Map Mask register (index 0x02)\n * +-------+-------+\n * |       |3 2 1 0|\n * +-------+-------+\n *             ^\n *             +- 0..3: Memory Plane Write Enable: If a bit is set, then write\n *                      operations will modify the respective plane of display\n *                      memory. If a bit is not set then write operations will\n *not affect the respective plane of display memory.\n *\n * Character Map Select register (index 0x03)\n * +---+-+-+---+---+\n * |   |5|4|3 2|1 0|\n * +---+-+-+---+---+\n *      ^ ^  ^   ^\n *      | +--|---+- 0..1,4: Character Set B Select: This field is used to select\n *the |    |              font that is used in text mode when bit 3 of the\n *attribute |    |              byte for a character is set to 0. (*)\n *      +----+----- 2..3,5: Character Set A Select: This field is used to select\n *the font that is used in text mode when bit 3 of the attribute byte for a\n *character is set to 1. (*)\n *\n * (*) Note that this field is not contiguous in order to provide EGA\n *compatibility. The font selected resides in plane 2 of display memory at the\n *address specified by this field, as follows:\n * +------+---------------+\n * |  val | font at       |\n * +------+---------------+\n * | 000b | 0000h - 1FFFh |\n * | 001b | 4000h - 5FFFh |\n * | 010b | 8000h - 9FFFh |\n * | 011b | C000h - DFFFh |\n * | 100b | 2000h - 3FFFh |\n * | 101b | 6000h - 7FFFh |\n * | 110b | A000h - BFFFh |\n * | 111b | E000h - FFFFh |\n * +------+---------------+\n *\n * Memory Mode register (index 0x04)\n * +-------+-+-+-+-+\n * |       |3|2|1| |\n * +-------+-+-+-+-+\n *          ^ ^ ^\n *          | | +--- 1: Extended Memory:\n *          | |           0: 64 KB of video memory enabled\n *          | |           1: 256 KB of video memory enabled. This bit must be\n *set to 1 to | |              enable the character map selection described for\n *the | |              previous register. | +----- 2: Odd/Even Host Memory Write\n *Adressing Disable: |             0: Even system addresses access maps 0 and 2,\n *while odd system |                addresses access maps 1 and 3. | 1: System\n *addresses sequentially access data within a bit map, |                and the\n *maps are accessed according to the value in the Map |                Mask\n *register (index 0x02).\n *          +------- 3: Chain 4 Enable: This bit controls the map selected\n *during system read operations. 0: Enables system addresses to sequentially\n *access data within a bit map by using the Map Mask register. 1: Causes the two\n *low-order bits to select the map accessed as shown below:\n *                           +----+----+--------------+\n *                           | A0 | A1 | Map Selected |\n *                           +----+----+--------------+\n *                           |  0 |  0 | 0            |\n *                           |  0 |  1 | 1            |\n *                           |  1 |  0 | 2            |\n *                           |  1 |  1 | 3            |\n *                           +----+----+--------------+\n * \\endcode\n **/\nvoid CS3Trio64::write_b_3c4(u8 value) { state.sequencer.index = value; }\n\n/**\n * Write to the VGA sequencer data register (0x3c5)\n *\n * For a description of the Sequencer registers, see CCirrus::write_b_3c4\n **/\nvoid CS3Trio64::write_b_3c5(u8 value) {\n  unsigned i;\n  u8 charmap1;\n  u8 charmap2;\n\n  switch (state.sequencer.index) {\n  // Sequencer: reset register\n  case 0:\n#if defined(DEBUG_VGA)\n    printf(\"write 0x3c5: sequencer reset: value=0x%02x   \\n\", (unsigned)value);\n#endif\n    if (state.sequencer.reset1 && ((value & 0x01) == 0)) {\n      state.sequencer.char_map_select = 0;\n      state.charmap_address = 0;\n      bx_gui->lock();\n      bx_gui->set_text_charmap(&state.memory[0x20000 + state.charmap_address]);\n      bx_gui->unlock();\n      state.vga_mem_updated = 1;\n    }\n\n    state.sequencer.reset1 = (value >> 0) & 0x01;\n    state.sequencer.reset2 = (value >> 1) & 0x01;\n    break;\n\n  // Sequencer: clocking mode register\n  case 1:\n#if defined(DEBUG_VGA)\n    printf(\"io write 3c5=%02x: clocking mode reg: ignoring   \\n\",\n           (unsigned)value);\n#endif\n    state.sequencer.reg1 = value & 0x3f;\n    state.x_dotclockdiv2 = ((value & 0x08) > 0);\n    break;\n\n  // Sequencer: map mask register\n  case 2:\n    state.sequencer.map_mask = (value & 0x0f);\n    for (i = 0; i < 4; i++)\n      state.sequencer.map_mask_bit[i] = (value >> i) & 0x01;\n    break;\n\n  // Sequencer: character map select register\n  case 3:\n    state.sequencer.char_map_select = value;\n    charmap1 = value & 0x13;\n    if (charmap1 > 3)\n      charmap1 = (charmap1 & 3) + 4;\n    charmap2 = (value & 0x2C) >> 2;\n    if (charmap2 > 3)\n      charmap2 = (charmap2 & 3) + 4;\n    if (state.CRTC.reg[0x09] > 0) {\n      state.charmap_address = (charmap1 << 13);\n      bx_gui->lock();\n      bx_gui->set_text_charmap(&state.memory[0x20000 + state.charmap_address]);\n      bx_gui->unlock();\n      state.vga_mem_updated = 1;\n    }\n\n    if (charmap2 != charmap1)\n      printf(\"char map select: #2=%d (unused)   \\n\", charmap2);\n    break;\n\n  // Sequencer: memory mode register\n  case 4:\n    state.sequencer.extended_mem = (value >> 1) & 0x01;\n    state.sequencer.odd_even = (value >> 2) & 0x01;\n    state.sequencer.chain_four = (value >> 3) & 0x01;\n\n#if defined(DEBUG_VGA)\n    printf(\"io write 3c5: index 4:   \\n\");\n    printf(\"  extended_mem %u   \\n\", (unsigned)state.sequencer.extended_mem);\n    printf(\"  odd_even %u   \\n\", (unsigned)state.sequencer.odd_even);\n    printf(\"  chain_four %u   \\n\", (unsigned)state.sequencer.chain_four);\n#endif\n    break;\n\n  default:\n    FAILURE_1(NotImplemented, \"io write 3c5: index %u unhandled\",\n              (unsigned)state.sequencer.index);\n  }\n}\n\n/**\n * Write to VGA DAC Pixel Mask register (0x3c6)\n *\n * The pixel inputs (R, G and B) are anded with this value. Set to FFh\n * for normal operation.\n **/\nvoid CS3Trio64::write_b_3c6(u8 value) {\n  state.pel.mask = value;\n#if defined(DEBUG_VGA)\n  if (state.pel.mask != 0xff)\n    printf(\"io write 3c6: PEL mask=0x%02x != 0xFF   \\n\", value);\n#endif\n\n  // state.pel.mask should be and'd with final value before\n  // indexing into color register state.pel.data[]\n}\n\n/**\n * Write VGA DAC Address Read Mode register (0x3c7)\n *\n * The Color Registers in the standard VGA provide a mapping between the\n * palette of between 2 and 256 colors to a larger 18-bit color space.\n * This capability allows for efficient use of video memory while\n * providing greater flexibility in color choice. The standard VGA has\n * 256 palette entries containing six bits each of red, green, and blue\n * values. The palette RAM is accessed via a pair of address registers\n * and a data register.\n *\n * To write a palette entry, output the palette entry's index value to\n * the DAC Address Write Mode Register (0x3c8) then perform 3 writes to\n * the DAC Data Register (0x3c9), loading the red, green, then blue\n * values into the palette RAM. The internal write address automatically\n * advances allowing the next value's RGB values to be loaded without\n * having to reprogram the DAC Address Write Mode Register. This allows\n * the entire palette to be loaded in one write operation.\n *\n * To read a palette entry, output the palette entry's index to the DAC\n * Address Read Mode Register (0x3c7). Then perform 3 reads from the DAC\n * Data Register (0x3c9), loading the red, green, then blue values from\n * palette RAM. The internal read address automatically advances\n * allowing the next RGB values to be read without having to reprogram\n * the DAC Address Read Mode Register.\n *\n * The data values are 6-bits each.\n **/\nvoid CS3Trio64::write_b_3c7(u8 value) {\n  state.pel.read_data_register = value;\n  state.pel.read_data_cycle = 0;\n  state.pel.dac_state = 0x03;\n}\n\n/**\n * Write VGA DAC Address Write Mode register (0x3c8)\n *\n * For a description of DAC registers see CCirrus::write_b_3c7\n **/\nvoid CS3Trio64::write_b_3c8(u8 value) {\n  state.pel.write_data_register = value;\n  state.pel.write_data_cycle = 0;\n  state.pel.dac_state = 0x00;\n}\n\n/**\n * Write VGA DAC Data register (0x3c9)\n *\n * For a description of DAC registers see CCirrus::write_b_3c7\n **/\nvoid CS3Trio64::write_b_3c9(u8 value) {\n  switch (state.pel.write_data_cycle) {\n  case 0:\n    state.pel.data[state.pel.write_data_register].red = value;\n    break;\n\n  case 1:\n    state.pel.data[state.pel.write_data_register].green = value;\n    break;\n\n  case 2: {\n    state.pel.data[state.pel.write_data_register].blue = value;\n    // Palette write complete. Check if value has changed\n    bx_gui->lock();\n    bool changed = bx_gui->palette_change(\n        state.pel.write_data_register,\n        state.pel.data[state.pel.write_data_register].red << 2,\n        state.pel.data[state.pel.write_data_register].green << 2,\n        state.pel.data[state.pel.write_data_register].blue << 2);\n    bx_gui->unlock();\n    // If palette value has changed, redraw the screen.\n    if (changed)\n      redraw_area(0, 0, old_iWidth, old_iHeight);\n  } break;\n  }\n\n  // Move on to next RGB component\n  state.pel.write_data_cycle++;\n\n  // palette entry complete, move on to next one\n  if (state.pel.write_data_cycle >= 3) {\n\n    // BX_INFO((\"state.pel.data[%u] {r=%u, g=%u, b=%u}\",\n    //  (unsigned) state.pel.write_data_register,\n    //  (unsigned) state.pel.data[state.pel.write_data_register].red,\n    //  (unsigned) state.pel.data[state.pel.write_data_register].green,\n    //  (unsigned) state.pel.data[state.pel.write_data_register].blue);\n    state.pel.write_data_cycle = 0;\n    state.pel.write_data_register++;\n  }\n}\n\n/**\n * Write to VGA Graphics Controller Index Register (0x3ce)\n *\n * The Graphics Controller registers control how the system accesses video RAM.\n *\n * The Graphics registers are accessed in an indexed fashion. By writing a byte\n * to the Graphics Index Register (0x3ce) equal to the index of the particular\n * sub-register you wish to access, one can address the data pointed to by that\n * index by reading and writing the Graphics Data Register (0x3cf).\n *\n * Graphics registers:\n *   - Set/Reset register (index 0x00)\n *   - Enable Set/Reset register (index 0x01)\n *   - Color Compare register (index 0x02)\n *   - Data Rotate register (index 0x03)\n *   - Read Map Select register (index 0x04)\n *   - Graphics Mode register (index 0x05)\n *   - Miscellaneous Graphics register (index 0x06)\n *   - Color Don't Care register (index 0x07)\n *   - Bit Mask register (index 0x08)\n *   .\n *\n * \\code\n * Set/Reset register (index 0x00)\n * +-------+-------+\n * |       |3 2 1 0|\n * +-------+-------+\n *             ^\n *             +- 0..3: Set/Reset: Bits 3-0 of this field represent planes 3-0\n *of the VGA display memory. This field is used by Write Mode 0 and Write Mode 3\n *(See the Write Mode field.) In Write Mode 0, if the corresponding bit in the\n *Enable Set/Reset field is set, and in Write Mode 3 regardless of the Enable\n *                      Set/Reset field, the value of the bit in this field is\n *                      expanded to 8 bits and substituted for the data of the\n *                      respective plane and passed to the next stage in the\n *                      graphics pipeline, which for Write Mode 0 is the Logical\n *                      Operation unit and for Write Mode 3 is the Bit Mask\n *unit.\n *\n * Enable Set/Reset Register (index 0x01)\n * +-------+-------+\n * |       |3 2 1 0|\n * +-------+-------+\n *             ^\n *             +- 0..3: Enable Set/Reset: Bits 3-0 of this field represent\n *planes 3-0 of the VGA display memory. This field is used in Write Mode 0 (See\n *the Write Mode field) to select whether data for each plane is derived from\n *host data or from expansion of the respective bit in the Set/Reset field.\n *\n * Color Compare Register (index 0x02)\n * +-------+-------+\n * |       |3 2 1 0|\n * +-------+-------+\n *             ^\n *             +- 0..3: Color Compare: Bits 3-0 of this field represent planes\n *3-0 of the VGA display memory. This field holds a reference color that is used\n *by Read Mode 1 (See the Read Mode field.) Read Mode 1 returns the result of\n *the comparison between this value and a location of display memory, modified\n *by the Color Don't Care field.\n *\n * Data Rotate Register (index 0x03)\n * +-----+---+-----+\n * |     |4 3|2 1 0|\n * +-----+---+-----+\n *         ^    ^\n *         |    +- 0..2: Rotate Count:\n *         |             This field is used in Write Mode 0 and Write Mode 3\n *(See |             the Write Mode field.) In these modes, the host data is |\n *rotated to the right by the value specified by the value of |             this\n *field. A rotation operation consists of moving bits |             7-1 right\n *one position to bits 6-0, simultaneously |             wrapping bit 0 around\n *to bit 7, and is repeated the number |             of times specified by this\n *field.\n *         +------ 3..4: Logical Operation:\n *                       This field is used in Write Mode 0 and Write Mode 2\n *(See the Write Mode field.) The logical operation stage of the graphics\n *pipeline is 32 bits wide (1 byte * 4 planes) and performs the operations on\n *its inputs from the previous stage in the graphics pipeline and the latch\n *register. The latch register remains unchanged and the result is passed on to\n *the next stage in the pipeline. The results based on the value of this field\n *are: 00: Result is input from previous stage unmodified. 01: Result is input\n *from previous stage logical ANDed with latch register. 10: Result is input\n *from previous stage logical ORed with latch register. 11: Result is input from\n *previous stage logical XORed with latch register.\n *\n * Read Map Select register (index 0x04)\n * +-----------+---+\n * |           |1 0|\n * +-----------+---+\n *               ^\n *               +- 0..1: Read Map Select: The value of this field is used in\n *Read Mode 0 (see the Read Mode field) to specify the display memory plane to\n *transfer data from. Due to the arrangement of video memory, this field must be\n *modified four times to read one or more pixels values in the planar video\n *modes.\n *\n * Graphics Mode Register (index 0x05)\n * +-+-+-+-+-+-+---+\n * | |6|5|4|3| |1 0|\n * +-+-+-+-+-+-+---+\n *    ^ ^ ^ ^    ^\n *    | | | |    +- 0..1: Write Mode\n *    | | | |             This field selects between four write modes, simply\n *known | | | |             as Write Modes 0-3, based upon the value of this\n *field: | | | |               00: Write Mode 0: In this mode, the host data is\n *first | | | |                   rotated as per the Rotate Count field, then\n *the | | | |                   Enable Set/Reset mechanism selects data from\n *this or | | | |                   the Set/Reset field. Then the selected\n *Logical | | | |                   Operation is performed on the resulting data\n *and the | | | |                   data in the latch register. Then the Bit\n *Mask field | | | |                   is used to select which bits come from\n *the resulting | | | |                   data and which come from the latch\n *register. Finally, | | | |                   only the bit planes enabled by\n *the Memory Plane Write | | | |                   Enable field are written to\n *memory. | | | |               01: Write Mode 1: In this mode, data is\n *transferred directly | | | |                   from the 32 bit latch register\n *to display memory, | | | |                   affected only by the Memory Plane\n *Write Enable field. | | | |                   The host data is not used in\n *this mode. | | | |               10: Write Mode 2: In this mode, the bits 3-0\n *of the host | | | |                   data are replicated across all 8 bits of\n *their | | | |                   respective planes. Then the selected Logical\n *Operation | | | |                   is performed on the resulting data and the\n *data in the | | | |                   latch register. Then the Bit Mask field\n *is used to | | | |                   select which bits come from the resulting\n *data and which | | | |                   come from the latch register.\n *Finally, only the bit | | | |                   planes enabled by the Memory\n *Plane Write Enable field | | | |                   are written to memory. | |\n *| |               11: Write Mode 3: In this mode, the data in the Set/Reset |\n *| | |                   field is used as if the Enable Set/Reset field were\n *set | | | |                   to 1111b. Then the host data is first rotated as\n *per the | | | |                   Rotate Count field, then logical ANDed with\n *the value of | | | |                   the Bit Mask field. The resulting value\n *is used on the | | | |                   data obtained from the Set/Reset\n *field in the same way | | | |                   that the Bit Mask field would\n *ordinarily be used. to | | | |                   select which bits come from\n *the expansion of the | | | |                   Set/Reset field and which come\n *from the latch register. | | | |                   Finally, only the bit\n *planes enabled by the Memory Plane | | | |                   Write Enable\n *field are written to memory. | | | +--------- 3: Read Mode: | | | This field\n *selects between two read modes, simply known as Read | | |               Mode\n *0, and Read Mode 1, based upon the value of this field: | | | 0: Read Mode 0:\n *In this mode, a byte from one of the four | | |                    planes is\n *returned on read operations. The plane from | | |                    which the\n *data is returned is determined by the value of | | |                    the\n *Read Map Select field. | | |                 1: Read Mode 1: In this mode, a\n *comparison is made between | | |                    display memory and a\n *reference color defined by the Color | | |                    Compare field.\n *Bit planes not set in the Color Don't Care | | |                    field then\n *the corresponding color plane is not considered | | |                    in\n *the comparison. Each bit in the returned result | | | represents one\n *comparison between the reference color, with | | |                    the bit\n *being set if the comparison is true. | | +----------- 4: Host Odd/Even Memory\n *Read Addressing Enable: | |                   0: Selects the standard\n *addressing mode. | |                   1: Selects the odd/even addressing mode\n *used by the IBM CGA | |                      Adapter. | | Normally, the value\n *here follows the value of Memory Mode | |                 register bit 2 in\n *the sequencer.\" | +------------- 5: Shift Register Interleave Mode: | 1:\n *Directs the shift registers in the graphics controller to | format the serial\n *data stream with even-numbered bits from |                        both maps on\n *even-numbered maps, and odd-numbered bits from |                        both\n *maps on the odd-numbered maps. This bit is used for | modes 4 and 5.\n *    +--------------- 6: 256-Color Shift Mode:\n *                          0: Allows bit 5 to control the loading of the shift\n *registers. 1: Causes the shift registers to be loaded in a manner that\n *                             supports the 256-color mode.\n *\n * Miscellaneous Graphics register (index 0x06)\n * +-------+---+-+-+\n * |       |3 2|1|0|\n * +-------+---+-+-+\n *           ^  ^ ^\n *           |  | +- 0: Alphanumeric Mode Disable:\n *           |  |       This bit controls alphanumeric mode addressing.\n *           |  |         0: Text mode.\n *           |  |         1: Graphics modes, disables character generator\n *latches. |  +--- 1: Chain Odd/Even Enable |            1: Directs the system\n *address bit, A0, to be replaced by a |               higher-order bit. The odd\n *map is then selected when A0 is 1, |               and the even map when A0 is\n *0.\n *           +--- 2..3: Memory Map Select\n *                      This field specifies the range of host memory addresses\n *that is decoded by the VGA hardware and mapped into display memory accesses.\n *The values of this field and their corresponding host memory ranges are: 00:\n *A0000h-BFFFFh (128K region) 01: A0000h-AFFFFh (64K region) 10: B0000h-B7FFFh\n *(32K region) 11: B8000h-BFFFFh (32K region)\n *\n * Color Don't Care register (index 0x07)\n * +-------+-------+\n * |       |3 2 1 0|\n * +-------+-------+\n *             ^\n *             +- 0..3: Color Don't Care: Bits 3-0 of this field represent\n *planes 3-0 of the VGA display memory. This field selects the planes that are\n *used in the comparisons made by Read Mode 1 (See the Read Mode field.) Read\n *Mode 1 returns the result of the comparison between the value of the Color\n *                      Compare field and a location of display memory. If a bit\n *                      in this field is set, then the corresponding display\n *                      plane is considered in the comparison. If it is not set,\n *                      then that plane is ignored for the results of the\n *                      comparison.\n *\n * Bit Mask register (index 0x08)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n *         +----- 0..7: Bit Mask: This field is used in Write Modes 0, 2, and 3\n *                      (See the Write Mode field.) It it is applied to one byte\n *                      of data in all four display planes. If a bit is set,\n *                      then the value of corresponding bit from the previous\n *                      stage in the graphics pipeline is selected; otherwise\n *                      the value of the corresponding bit in the latch register\n *                      is used instead. In Write Mode 3, the incoming data\n *byte, after being rotated is logical ANDed with this byte and the resulting\n *value is used in the same way this field would normally be used by itself.\n * \\endcode\n **/\nvoid CS3Trio64::write_b_3ce(u8 value) {\n#if defined(DEBUG_VGA)\n  if (value > 0x08) /* ??? */\n    printf(\"io write: 3ce: value > 8   \\n\");\n#endif\n  state.graphics_ctrl.index = value;\n}\n\n/**\n * Write to VGA Graphics Controller Data Register (0x3cf)\n *\n * For a description of the Graphics registers, see CCirrus::write_b_3ce\n **/\nvoid CS3Trio64::write_b_3cf(u8 value) {\n  u8 prev_memory_mapping;\n  bool prev_graphics_alpha;\n  bool prev_chain_odd_even;\n\n  /* Graphics Controller Registers 00..08 */\n  switch (state.graphics_ctrl.index) {\n  case 0: /* Set/Reset */\n    state.graphics_ctrl.set_reset = value & 0x0f;\n    break;\n\n  case 1: /* Enable Set/Reset */\n    state.graphics_ctrl.enable_set_reset = value & 0x0f;\n    break;\n\n  case 2: /* Color Compare */\n    state.graphics_ctrl.color_compare = value & 0x0f;\n    break;\n\n  case 3: /* Data Rotate */\n    state.graphics_ctrl.data_rotate = value & 0x07;\n\n    /* ??? is this bits 3..4 or 4..5 */\n    state.graphics_ctrl.raster_op = (value >> 3) & 0x03; /* ??? */\n    break;\n\n  case 4: /* Read Map Select */\n    state.graphics_ctrl.read_map_select = value & 0x03;\n#if defined(DEBUG_VGA)\n    printf(\"io write to 03cf = %02x (RMS)   \\n\", (unsigned)value);\n#endif\n    break;\n\n  case 5: /* Mode */\n    state.graphics_ctrl.write_mode = value & 0x03;\n    state.graphics_ctrl.read_mode = (value >> 3) & 0x01;\n    state.graphics_ctrl.odd_even = (value >> 4) & 0x01;\n    state.graphics_ctrl.shift_reg = (value >> 5) & 0x03;\n\n#if defined(DEBUG_VGA)\n    if (state.graphics_ctrl.odd_even)\n      printf(\"io write: 3cf: reg 05: value = %02xh   \\n\", (unsigned)value);\n    if (state.graphics_ctrl.shift_reg)\n      printf(\"io write: 3cf: reg 05: value = %02xh   \\n\", (unsigned)value);\n#endif\n    break;\n\n  case 6: /* Miscellaneous */\n    prev_graphics_alpha = state.graphics_ctrl.graphics_alpha;\n    prev_chain_odd_even = state.graphics_ctrl.chain_odd_even;\n    prev_memory_mapping = state.graphics_ctrl.memory_mapping;\n\n    state.graphics_ctrl.graphics_alpha = value & 0x01;\n    state.graphics_ctrl.chain_odd_even = (value >> 1) & 0x01;\n    state.graphics_ctrl.memory_mapping = (value >> 2) & 0x03;\n#if defined(DEBUG_VGA)\n    printf(\"memory_mapping set to %u   \\n\",\n           (unsigned)state.graphics_ctrl.memory_mapping);\n    printf(\"graphics mode set to %u   \\n\",\n           (unsigned)state.graphics_ctrl.graphics_alpha);\n    printf(\"odd_even mode set to %u   \\n\",\n           (unsigned)state.graphics_ctrl.odd_even);\n    printf(\"io write: 3cf: reg 06: value = %02xh   \\n\", (unsigned)value);\n#endif\n    if (prev_memory_mapping != state.graphics_ctrl.memory_mapping) {\n      redraw_area(0, 0, old_iWidth, old_iHeight);\n    }\n\n    if (prev_graphics_alpha != state.graphics_ctrl.graphics_alpha) {\n      redraw_area(0, 0, old_iWidth, old_iHeight);\n      old_iHeight = 0;\n    }\n    break;\n\n  case 7: /* Color Don't Care */\n    state.graphics_ctrl.color_dont_care = value & 0x0f;\n    break;\n\n  case 8: /* Bit Mask */\n    state.graphics_ctrl.bitmask = value;\n    break;\n\n  default:\n\n    /* ??? */\n    FAILURE_1(NotImplemented, \"io write: 3cf: index %u unhandled\",\n              (unsigned)state.graphics_ctrl.index);\n  }\n}\n\n/**\n * Write to VGA CRTC Index Register (0x3b4 or 0x3d4)\n *\n * The VGA CRTC Registers control how the video is output to the display.\n *\n * The CRTC registers are accessed in an indexed fashion. By writing a byte\n * to the CRTC Index Register (0x3d4) equal to the index of the particular\n * sub-register you wish to access, one can address the data pointed to by that\n * index by reading and writing the CRTC Data Register (0x3d5).\n *\n * CRTC registers:\n *   - Horizontal Total Register (index 0x00)\n *   - End Horizontal Display Register (index 0x01)\n *   - Start Horizontal Blanking Register (index 0x02)\n *   - End Horizontal Blanking Register (index 0x03)\n *   - Start Horizontal Retrace Register (index 0x04)\n *   - End Horizontal Retrace Register (index 0x05)\n *   - Vertical Total Register (index 0x06)\n *   - Overflow Register (index 0x07)\n *   - Preset Row Scan Register (index 0x08)\n *   - Maximum Scan Line Register (index 0x09)\n *   - Cursor Start Register (index 0x0a)\n *   - Cursor End Register (index 0x0b)\n *   - Start Address High Register (index 0x0c)\n *   - Start Address Low Register (index 0x0d)\n *   - Cursor Location High Register (index 0x0e)\n *   - Cursor Location Low Register (index 0x0f)\n *   - Vertical Retrace Start Register (index 0x10)\n *   - Vertical Retrace End Register (index 0x11)\n *   - Vertical Display End Register (index 0x12)\n *   - Offset Register (index 0x13)\n *   - Underline Location Register (index 0x14)\n *   - Start Vertical Blanking Register (index 0x15)\n *   - End Vertical Blanking (index 0x16)\n *   - CRTC Mode Control Register (index 0x17)\n *   - Line Compare Register (index 0x18)\n *   .\n *\n * \\code\n * Horizontal Total register (index 0x00)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Horizontal Total:\n * This field is used to specify the number of character clocks per scan line.\n * This field, along with the dot rate selected, controls the horizontal\n * refresh rate of the VGA by specifying the amount of time one scan line\n * takes.  This field is not programmed with the actual number of character\n * clocks, however. Due to timing factors of the VGA hardware (which, for\n * compatibility purposes has been emulated by VGA compatible chipsets), the\n * actual horizontal total is 5 character clocks more than the value stored in\n * this field, thus one needs to subtract 5 from the actual horizontal total\n * value desired before programming it into this register.\n *\n * End Horizontal Display register (index 0x01)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: End Horizontal Display:\n * This field is used to control the point that the sequencer stops outputting\n * pixel values from display memory, and sequences the pixel value specified by\n * the Overscan Palette Index field for the remainder of the scan line. The\n * overscan begins the character clock after the the value programmed into this\n * field. This register should be programmed with the number of character\n * clocks in the active display - 1. Note that the active display may be\n * affected by the Display Enable Skew field.\n *\n * Start Horizontal Blanking register (index 0x02)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Start Horizontal Blanking:\n * This field is used to specify the character clock at which the horizontal\n * blanking period begins.  During the horizontal blanking period, the VGA\n * hardware forces the DAC into a blanking state, where all of the intensities\n * output are at minimum value, no matter what color information the attribute\n * controller is sending to the DAC.  This field works in conjunction with the\n * End Horizontal Blanking field to specify the horizontal blanking period.\n * Note that the horizontal blanking can be programmed to appear anywhere within\n * the scan line, as well as being programmed to a value greater than the\n * Horizontal Total field preventing the horizontal blanking from occurring at\n * all.\n *\n * End Horizontal Blanking register (index 0x03)\n * +-+---+---------+\n * |7|6 5|4 3 2 1 0|\n * +-+---+---------+\n *  ^  ^      ^\n *  |  |      +-- 0..4: End Horizontal Blanking:\n *  |  |                Contains bits 4-0 of the End Horizontal Blanking field\n *  |  |                which specifies the end of the horizontal blanking\n *  |  |                period.  Bit 5 is located in bit 7 of the End Horizontal\n *  |  |                Retrace register (index 0x05). After the period has\n *  |  |                begun as specified by the Start Horizontal Blanking\n *  |  |                field, the 6-bit value of this field is compared against\n *  |  |                the lower 6 bits of the character clock. When a match\n *  |  |                occurs, the horizontal blanking signal is disabled. This\n *  |  |                provides from 1 to 64 character clocks although some\n *  |  |                implementations may match in the character clock\n *  |  |                specified by the Start Horizontal Blanking field, in\n *which |  |                case the range is 0 to 63.  Note that if blanking\n *extends |  |                past the end of the scan line, it will end on the\n *first |  |                match of this field on the next scan line. |\n *+--------- 5..6: Display Enable Skew: |                   This field affects\n *the timings of the display enable |                   circuitry in the VGA.\n *The value of this field is the number |                   of character clocks\n *that the display enable \"signal\" is |                   delayed. In all known\n *VGA cards, this field is always |                   programmed to 0.\n *Programming it to non-zero values results |                   in the overscan\n *being displayed over the number of |                   characters programmed\n *into this field at the beginning of |                   the scan line, as well\n *as the end of the active display |                   being shifted the number\n *of characters programmed into this |                   field. The characters\n *that extend past the normal end of the |                   active display can\n *be garbled in certain circumstances that |                   is dependent on\n *the particular VGA implementation. According |                   to\n *documentation from IBM, \"This skew control is needed to | provide sufficient\n *time for the CRT controller to read a |                   character and\n *attribute code from the video buffer, to gain |                   access to\n *the character generator, and go through the |                   Horizontal PEL\n *Panning register in the attribute controller. |                   Each access\n *requires the 'display enable' signal to be |                   skewed one\n *character clock so that the video output is |                   synchronized\n *with the horizontal and vertical retrace |                   signals.\" as well\n *as \"Note: Character skew is not adjustable |                   on the Type 2\n *video and the bits are ignored; however, |                   programs should\n *set these bits for the appropriate skew to |                   maintain\n *compatibility.\"  This may be required for some early |                   IBM\n *VGA implementations or may be simply an unused \"feature\" | carried over along\n *with its register description from the IBM |                   EGA\n *implementations that require the use of this field.\n *  +--------------- 7: Enable Vertical Retrace Access:\n *                      This field was used in the IBM EGA to provide access to\n *the light pen input values as the light pen registers were mapped over CRTC\n *indexes 10h-11h. The VGA lacks capability for light pen input, thus this field\n *is normally forced to 1 (although always writing it as 1 might be a good idea\n *for compatibility), which in the EGA would enable access to the vertical\n *retrace fields instead of the light pen fields.\n *\n * Start Horizontal Retrace register (index 0x04)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Start Horizontal Retrace:\n * This field specifies the character clock at which the VGA begins sending the\n * horizontal synchronization pulse to the display which signals the monitor to\n *retrace back to the left side of the screen. The end of this pulse is\n *controlled by the End Horizontal Retrace field. This pulse may appear anywhere\n *in the scan line, as well as set to a position beyond the Horizontal Total\n *field which effectively disables the horizontal synchronization pulse.\n *\n * End Horizontal Retrace register (index 0x05)\n * +-+---+---------+\n * |7|6 5|4 3 2 1 0|\n * +-+---+---------+\n *  ^  ^      ^\n *  |  |      +-- 0..4: End Horizontal Retrace:\n *  |  |                This field specifies the end of the horizontal retrace\n *period, |  |                which begins at the character clock specified in\n *the Start |  |                Horizontal Retrace field.  The horizontal\n *retrace signal is |  |                enabled until the lower 5 bits of the\n *character counter match |  |                the 5 bits of this field.  This\n *provides for a horizontal |  |                retrace period from 1 to 32\n *character clocks.  Note that some |  |                implementations may\n *match immediately instead of 32 clocks |  |                away, making the\n *effective range 0 to 31 character clocks. |  +--------- 5..6: Horizontal\n *Retrace Skew: |                   This field delays the start of the\n *horizontal retrace period |                   by the number of character\n *clocks equal to the value of this |                   field.  From\n *observation, this field is programmed to 0, with |                   the\n *exception of the 40 column text modes where this field is | set to 1.  The VGA\n *hardware simply acts as if this value is |                   added to the\n *Start Horizontal Retrace field. According to IBM | documentation, \"For certain\n *modes, the 'horizontal retrace' |                   signal takes up the entire\n *blanking interval. Some internal |                   timings are generated by\n *the falling edge of the 'horizontal |                   retrace' signal. To\n *ensure that the signals are latched |                   properly, the\n *'retrace' signal is started before the end of |                   the 'display\n *enable' signal and then skewed several character |                   clock\n *times to provide the proper screen centering.\" This does | not appear to be\n *the case, leading me to believe this is yet |                   another\n *holdout from the IBM EGA implementations that do |                   require\n *the use of this field.\n *  +--------------- 7: End Horizontal Blanking (bit 5):\n *                      This contains bit 5 of the End Horizontal Blanking field\n *in the End Horizontal Blanking register (index 0x03).\n *\n * Vertical Total register (index 0x06)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Vertical Total\n * This contains the lower 8 bits of the Vertical Total field. Bits 9-8 of this\n *field are located in the Overflow Register (index 0x07). This field determines\n *the number of scanlines in the active display and thus the length of each\n *vertical retrace. This field contains the value of the scanline counter at the\n *beginning of the last scanline in the vertical period.\n *\n * Overflow register (index 0x07)\n * +-+-+-+-+-+-+-+-+\n * |7|6|5|4|3|2|1|0|\n * +-+-+-+-+-+-+-+-+\n *  ^ ^ ^ ^ ^ ^ ^ ^\n *  | | +-|-|-|-|-+- 0,5: Bit 8,9 of Vertical Total (index 0x06)\n *  | +---|-|-|-+--- 1,6: Bit 8,9 of Vertical Display End (index 0x12)\n *  +-----|-|-+----- 2,7: Bit 8,9 of Vertical Retrace Start (index 0x10)\n *        | +--------- 3: Bit 8 of Start Vertical Blanking (index 0x15)\n *        +----------- 4: Bit 8 of Line Compare (index 0x18)\n *\n * Preset Row Scan register (index 0x08)\n * +-+---+---------+\n * | |6 5|4 3 2 1 0|\n * +-+---+---------+\n *     ^      ^\n *     |      +-- 0..4: Preset Row Scan:\n *     |                This field is used when using text mode or any mode with\n *a non-zero |                Maximum Scan Line field (index 0x09) to provide\n *for more precise |                vertical scrolling than the Start Address\n *Register provides. The |                value of this field specifies how many\n *scan lines to scroll the |                display upwards. Valid values range\n *from 0 to the value of the |                Maximum Scan Line field. Invalid\n *values may cause undesired effects |                and seem to be dependent\n *upon the particular VGA implementation.\n *     +--------- 5..6: Byte Panning:\n *                      The value of this field is added to the Start Address\n *Register when calculating the display memory address for the upper left hand\n *pixel or character of the screen. This allows for a maximum shift of 15, 31,\n *or 35 pixels without having to reprogram the Start Address Register.\n *\n * Maximum Scan Line register (index 0x09)\n * +-+-+-+---------+\n * |7|6|5|4 3 2 1 0|\n * +-+-+-+---------+\n *  ^ ^ ^     ^\n *  | | |     +-- 0..4: Maximum Scan Line:\n *  | | |               In text modes, this field is programmed with the\n *character height - 1 | | |               (scan line numbers are zero based.)\n *In graphics modes, a non-zero | | |               value in this field will\n *cause each scan line to be repeated by the | | |               value of this\n *field + 1. | | +----------- 5: Bit 9 of Start Vertical Blanking (index 0x15)\n *  | +------------- 6: Bit 9 of Line Compare (index 0x18)\n *  +--------------- 7: Scan Doubling:\n *                      When this bit is set to 1, 200-scan-line video data is\n *converted to 400-scan-line output. To do this, the clock in the row scan\n *counter is divided by 2, which allows the 200-line modes to be displayed as\n *400 lines on the display (this is called double scanning; each line is\n *                      displayed twice). When this bit is set to 0, the clock\n *to the row scan counter is equal to the horizontal scan rate.\n *\n * Cursor Start Register (index 0x0a)\n * +---+-+---------+\n * |   |5|4 3 2 1 0|\n * +---+-+---------+\n *      ^     ^\n *      |     +-- 0..4: Cursor Scan Line Start:\n *      |               This field controls the appearance of the text-mode\n *cursor by |               specifying the scan line location within a character\n *cell at which |               the cursor should begin, with the top-most scan\n *line in a character |               cell being 0 and the bottom being with the\n *value of the Maximum Scan |               Line field.\n *      +------------5: Cursor Disable:\n *                      This field controls whether or not the text-mode cursor\n *is displayed: 0: Cursor Enabled. 1: Cursor Disabled.\n *\n * Cursor End Register (index 0x0b)\n * +-+---+---------+\n * | |6 5|4 3 2 1 0|\n * +-+---+---------+\n *     ^      ^\n *     |      +-- 0..4: Cursor Scan Line End:\n *     |                This field controls the appearance of the text-mode\n *cursor by |                specifying the scan line location within a\n *character cell at which |                the cursor should end, with the\n *top-most scan line in a character |                cell being 0 and the bottom\n *being with the value of the Maximum Scan |                Line field. If this\n *field is less than the Cursor Scan Line Start |                field, the\n *cursor is not drawn. Some graphics adapters, such as the |                IBM\n *EGA display a split-block cursor instead.\n *     +------------ 5: Cursor Skew:\n *                      This field was necessary in the EGA to synchronize the\n *cursor with internal timing. In the VGA it basically is added to the cursor\n *                      location. In some cases when this value is non-zero and\n *the cursor is near the left or right edge of the screen, the cursor will not\n *appear at all, or a second cursor above and to the left of the actual one may\n *                      appear. This behavior may not be the same on all VGA\n *compatible adapter cards.\n *\n * Start Address High register (index 0x0c)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Bits 8..15 of the Start Address.\n * Bits 0..7 are in the Start Address Low register (index 0x0d). The Start\n *Address field specifies the display memory address of the upper left pixel or\n *character of the screen. Because the standard VGA has a maximum of 256K of\n *memory, and memory is accessed 32 bits at a time, this 16-bit field is\n *sufficient to allow the screen to start at any memory address. Normally this\n *field is programmed to 0h, except when using virtual resolutions, paging,\n * and/or split-screen operation. Note that the VGA display will wrap around in\n *display memory if the starting address is too high. (This may or may not be\n *desirable, depending on your intentions.)\n *\n * Start Address Low register (index 0x0d)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Bits 0..7 of the Start Address. See Start Address High register (index\n *0x0c)\n *\n * Cursor Location High register (index 0x0e)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Bits 8..15 of the Cursor Location.\n * Bits 0..7 are in the Cursor Location Low register (index 0x0d). When the VGA\n *hardware is displaying text mode and the text-mode cursor is enabled, the\n *hardware compares the address of the character currently being displayed with\n *sum of value of this field and the sum of the Cursor Skew field. If the values\n *equal then the scan lines in that character specified by the Cursor Scan Line\n *Start field and the Cursor Scan Line End field are replaced with the\n * foreground color.\n *\n * Cursor Location Low register (index 0x0f)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Bits 0..7 of the Cursor Location. See Cursor Location High register\n *(index 0x0f)\n *\n * Vertical Retrace Start register (index 0x10)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Bits 0..7 of Vertical Retrace Start\n * Bits 8 and 9 are in the Overflow Register (index 0x07). This field controls\n *the start of the vertical retrace pulse which signals the display to move up\n *to the beginning of the active display. This field contains the value of the\n *vertical scanline counter at the beginning of the first scanline where the\n *vertical retrace signal is asserted.\n *\n * Vertical Retrace End register (index 0x11)\n * +-+-+---+-------+\n * |7|6|5|4|3 2 1 0|\n * +-+-+---+-------+\n *  ^ ^ ^ ^   ^\n *  | | | |   +-- 0..3: Vertical Retrace End:\n *  | | | |             This field determines the end of the vertical retrace\n *pulse, and thus its | | | |             length. This field contains the lower\n *four bits of the vertical scanline | | | |             counter at the\n *beginning of the scanline immediately after the last | | | | scanline where\n *the vertical retrace signal is asserted. | | | +--------- 4: End Vertical\n *Interrupt | | +----------- 5: Enable Vertical Interrupt | +------------- 6:\n *Memory Refresh Bandwidth: |                   Nearly all video chipsets\n *include a few registers that control memory, bus, |                   or other\n *timings not directly related to the output of the video card. Most | VGA/SVGA\n *implementations ignore the value of this field; however, in the | least, IBM\n *VGA adapters do utilize it and thus for compatibility with these | chipsets\n *this field should be programmed. This register is used in the IBM | VGA\n *hardware to control the number of DRAM refresh cycles per scan line. | The\n *three refresh cycles per scanline is appropriate for the IBM VGA | horizontal\n *frequency of approximately 31.5 kHz. For horizontal frequencies | greater than\n *this, this setting will work as the DRAM will be refreshed more | often.\n *However, refreshing not often enough for the DRAM can cause memory | loss.\n *Thus at some point slower than 31.5 kHz the five refresh cycle setting |\n *should be used. At which particular point this should occur, would require |\n *better knowledge of the IBM VGA's schematics than I have available. |\n *According to IBM documentation, \"Selecting five refresh cycles allows use of\n *  |                   the VGA chip with 15.75 kHz displays.\" which isn't\n *really enough to go by |                   unless the mode you are defining\n *has a 15.75 kHz horizontal frequency.\n *  +--------------- 7: CRTC Registers Protect Enable:\n *                      This field is used to protect the video timing registers\n *from being changed by programs written for earlier graphics chipsets that\n *attempt to program these registers with values unsuitable for VGA timings.\n *When this field is set to 1, the CRTC register indexes 00h-07h ignore write\n *access, with the exception of bit 4 of the Overflow Register, which holds bit\n *8 of the Line Compare field.\n *\n * Vertical Display End register (index 0x12)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Bits 0..7 of Vertical Display End\n * Bits 8 and 9 are in the Overflow Register (index 0x07). This field contains\n *the value of the vertical scanline counter at the beggining of the scanline\n *immediately after the last scanline of active display.\n *\n * Offset register (index 0x13)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Offset:\n * This field specifies the address difference between consecutive scan lines or\n *two lines of characters. Beginning with the second scan line, the starting\n *scan line is increased by twice the value of this register multiplied by the\n *current memory address size (byte = 1, word = 2, double-word = 4) each line.\n *For text modes the following equation is used: Offset = Width / (\n *MemoryAddressSize * 2 ) and in graphics mode, the following equation is used:\n *       Offset = Width / ( PixelsPerAddress * MemoryAddressSize * 2 )\n * where Width is the width in pixels of the screen. This register can be\n *modified to provide for a virtual resolution, in which case Width is the width\n *is the width in pixels of the virtual screen. PixelsPerAddress is the number\n *of pixels stored in one display memory address, and MemoryAddressSize is the\n *current memory addressing size.\n *\n * Underline Location register (index 0x14)\n * +-+-+-+---------+\n * | |6|5|4 3 2 1 0|\n * +-+-+-+---------+\n *    ^ ^     ^\n *    | |     +-- 0..4: Underline Location\n *    | |               These bits specify the horizontal scan line of a\n *character row on which an | |               underline occurs. The value\n *programmed is the scan line desired minus 1. | +----------- 5: Divide Memory\n *Address Clock by 4: |                   1: The memory-address counter is\n *clocked with the character clock divided |                      by 4, which is\n *used when doubleword addresses are used.\n *    +------------- 6: Double-Word Addressing:\n *                        1: Memory addresses are doubleword addresses. See the\n *description of the word/byte mode bit (bit 6) in the CRT Mode Control Register\n *(index 0x17)\n *\n * Start Vertical Blanking register (index 0x15)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Bits 0..7 of Start Vertical Blanking\n * Bit 8 is in the Overflow Register (index 0x07), and bit 9 is in the Maximum\n *Scan Line register (index 0x09). This field determines when the vertical\n *blanking period begins, and contains the value of the vertical scanline\n *counter at the beginning of the first vertical scanline of blanking.\n *\n * End Vertical Blanking register (index 0x16)\n * +-+-------------+\n * | |6 5 4 3 2 1 0|\n * +-+-------------+\n *          ^\n *          +---- 0..6: End Vertical Blanking:\n *                      This field determines when the vertical blanking period\n *ends, and contains the value of the vertical scanline counter at the beginning\n *of the vertical scanline immediately after the last scanline of blanking.\n *\n * CRTC Mode Control Register (index 0x17)\n * +-+-+-+-+-+-+-+-+\n * |7|6|5| |3|2|1|0|\n * +-+-+-+-+-+-+-+-+\n *  ^ ^ ^   ^ ^ ^ ^\n *  | | |   | | | +- 0: Map Display Address 13:\n *  | | |   | | |       This bit selects the source of bit 13 of the output\n *multiplexer: | | |   | | |         0: Bit 0 of the row scan counter is the\n *source. | | |   | | |         1: Bit 13 of the address counter is the source.\n *  | | |   | | |       The CRT controller used on the IBM Color/Graphics\n *Adapter was capable of | | |   | | |       using 128 horizontal scan-line\n *addresses. For the VGA to obtain 640-by-200 | | |   | | |       graphics\n *resolution, the CRT controller is programmed for 100 horizontal | | |   | | |\n *scan lines with two scan-line addresses per character row. Row scan address |\n *| |   | | |       bit 0 becomes the most-significant address bit to the\n *display buffer. | | |   | | |       Successive scan lines of the display image\n *are displaced in 8KB of memory. | | |   | | |       This bit allows\n *compatibility with the graphics modes of earlier adapters. | | |   | | +--- 1:\n *Map Display Address 14: | | |   | |         This bit selects the source of bit\n *14 of the output multiplexer: | | |   | |           0: Bit 1 of the row scan\n *counter is the source. | | |   | |           1: Bit 14 of the address counter\n *is the source. | | |   | +----- 2: Divide Scan Line clock by 2: | | |   | This\n *bit selects the clock that controls the vertical timing counter: | | |   | 0:\n *The horizontal retrace clock. | | |   |             1: The horizontal retrace\n *clock divided by 2. | | |   |           Dividing the clock effectively doubles\n *the vertical resolution of the CRT | | |   |           controller. The\n *vertical counter has a maximum resolution of 1024 scan lines | | |   | because\n *the vertical total value is 10-bits wide. If the vertical counter is | | |   |\n *clocked with the horizontal retrace divided by 2, the vertical resolution is\n *  | | |   |           doubled to 2048 scan lines.\"\n *  | | |   +------- 3: Divide Memory Address clock by 2:\n *  | | |               This bit selects the clock that controlls the address\n *counter: | | |                 0: The character clock. | | | 1: The character\n *clock divided by 2. | | |               This bit is used to create either a\n *byte or word refresh address for the | | |               display buffer. | |\n *+----------- 5: Address Wrap Select: | |                 This bit selects the\n *memory-address bit, bit MA 13 or MA 15, that appears on | | the output pin MA\n *0, in the word address mode. If the VGA is not in the word | | address mode,\n *bit 0 from the address counter appears on the output pin, MA 0. | | 0: Selects\n *MA 13. Used in applications where only 64KB of video memory is | | present. |\n *|                   1: Selects MA 15. In odd/even mode, this bit should be set\n *to 1 because | |                      256KB of video memory is installed on\n *the system board. | |                 This function maintains compatibility\n *with the IBM Color/Graphics Monitor | |                 Adapter. |\n *+------------- 6: Word/Byte Mode Select: |                     0: Selects the\n *word address mode. The word mode shifts the memory-address | counter bits to\n *the left by one bit; the most-significant bit of the | counter appears on the\n *least-significant bit of the memory address |                        outputs.\n *  |                     1: Selects the byte address mode.\n *  |                   The doubleword bit in the Underline Location register\n *(index 0x14) also |                   controls the addressing. When the\n *doubleword bit is 0, the word/byte bit |                   selects the mode.\n *When the doubleword bit is set to 1, the addressing is | shifted by two bits.\n *  +--------------- 7: Sync Enable:\n *                        0: Disables the horizontal and vertical retrace\n *signals and forces them to an inactive level. 1: Enables the horizontal and\n *vertical retrace signals. This bit does not reset any other registers or\n *signal outputs.\n *\n * Line Compare register (index 0x18)\n * +---------------+\n * |7 6 5 4 3 2 1 0|\n * +---------------+\n *         ^\n * 0..7: Bits 0..7 of Line Compare\n * Bit 8 is in the Overflow Register (index 0x07), and bit 9 is in the Maximum\n *Scan Line register (index 0x09). The Line Compare field specifies the scan\n *line at which a horizontal division can occur, providing for split-screen\n *operation. If no horizontal division is required, this field should be set to\n *3FFh. When the scan line counter reaches the value in the Line Compare field,\n *the current scan line address is reset to 0 and the Preset Row Scan is\n *presumed to be 0. If the Pixel Panning Mode field is set to 1 then the Pixel\n *Shift Count and Byte Panning fields are reset to 0 for the remainder of the\n *display cycle. \\endcode\n **/\nvoid CS3Trio64::write_b_3d4(u8 value) {\n  state.CRTC.address = value & 0x7f;\n#if defined(DEBUG_VGA)\n  if (state.CRTC.address > 0x18)\n    printf(\"write: invalid CRTC register 0x%02x selected\",\n           (unsigned)state.CRTC.address);\n#endif\n}\n\n/**\n * Write to VGA CRTC Data Register (0x3b5 or 0x3d5)\n *\n * For a description of CRTC Registers, see CCirrus::write_b_3d4.\n **/\nvoid CS3Trio64::write_b_3d5(u8 value) {\n\n  /* CRTC Registers */\n  if (state.CRTC.address > 0x18) {\n#if defined(DEBUG_VGA)\n    printf(\"write: invalid CRTC register 0x%02x ignored\",\n           (unsigned)state.CRTC.address);\n#endif\n    return;\n  }\n\n  if (state.CRTC.write_protect && (state.CRTC.address < 0x08)) {\n    if (state.CRTC.address == 0x07) {\n      state.CRTC.reg[state.CRTC.address] &= ~0x10;\n      state.CRTC.reg[state.CRTC.address] |= (value & 0x10);\n      state.line_compare &= 0x2ff;\n      if (state.CRTC.reg[0x07] & 0x10)\n        state.line_compare |= 0x100;\n      redraw_area(0, 0, old_iWidth, old_iHeight);\n      return;\n    } else {\n      return;\n    }\n  }\n\n  if (value != state.CRTC.reg[state.CRTC.address]) {\n    state.CRTC.reg[state.CRTC.address] = value;\n    switch (state.CRTC.address) {\n    case 0x07:\n      state.vertical_display_end &= 0xff;\n      if (state.CRTC.reg[0x07] & 0x02)\n        state.vertical_display_end |= 0x100;\n      if (state.CRTC.reg[0x07] & 0x40)\n        state.vertical_display_end |= 0x200;\n      state.line_compare &= 0x2ff;\n      if (state.CRTC.reg[0x07] & 0x10)\n        state.line_compare |= 0x100;\n      redraw_area(0, 0, old_iWidth, old_iHeight);\n      break;\n\n    case 0x08:\n\n      // Vertical pel panning change\n      redraw_area(0, 0, old_iWidth, old_iHeight);\n      break;\n\n    case 0x09:\n      state.y_doublescan = ((value & 0x9f) > 0);\n      state.line_compare &= 0x1ff;\n      if (state.CRTC.reg[0x09] & 0x40)\n        state.line_compare |= 0x200;\n      redraw_area(0, 0, old_iWidth, old_iHeight);\n      break;\n\n    case 0x0A:\n    case 0x0B:\n    case 0x0E:\n    case 0x0F:\n\n      // Cursor size / location change\n      state.vga_mem_updated = 1;\n      break;\n\n    case 0x0C:\n    case 0x0D:\n\n      // Start address change\n      if (state.graphics_ctrl.graphics_alpha) {\n        redraw_area(0, 0, old_iWidth, old_iHeight);\n      } else {\n        state.vga_mem_updated = 1;\n      }\n      break;\n\n    case 0x12:\n      state.vertical_display_end &= 0x300;\n      state.vertical_display_end |= state.CRTC.reg[0x12];\n      break;\n\n    case 0x13:\n    case 0x14:\n    case 0x17:\n\n      // Line offset change\n      state.line_offset = state.CRTC.reg[0x13] << 1;\n      if (state.CRTC.reg[0x14] & 0x40)\n        state.line_offset <<= 2;\n      else if ((state.CRTC.reg[0x17] & 0x40) == 0)\n        state.line_offset <<= 1;\n      redraw_area(0, 0, old_iWidth, old_iHeight);\n      break;\n\n    case 0x18:\n      state.line_compare &= 0x300;\n      state.line_compare |= state.CRTC.reg[0x18];\n      redraw_area(0, 0, old_iWidth, old_iHeight);\n      break;\n    }\n  }\n}\n\n/**\n * Read from the attribute controller index register (0x3c0)\n *\n * For a description of the attribute controller registers, see\n *CCirrus::write_b_3c0.\n **/\nu8 CS3Trio64::read_b_3c0() {\n  if (state.attribute_ctrl.flip_flop == 0) {\n\n    // BX_INFO((\"io read: 0x3c0: flip_flop = 0\"));\n    return (state.attribute_ctrl.video_enabled << 5) |\n           state.attribute_ctrl.address;\n  } else {\n    FAILURE(NotImplemented, \"io read: 0x3c0: flip_flop != 0\");\n  }\n}\n\n/**\n * Read from the attribute controller data register (0x3c1)\n *\n * For a description of the attribute controller registers, see\n *CCirrus::write_b_3c0.\n **/\nu8 CS3Trio64::read_b_3c1() {\n  u8 retval;\n  switch (state.attribute_ctrl.address) {\n  case 0x00:\n  case 0x01:\n  case 0x02:\n  case 0x03:\n  case 0x04:\n  case 0x05:\n  case 0x06:\n  case 0x07:\n  case 0x08:\n  case 0x09:\n  case 0x0a:\n  case 0x0b:\n  case 0x0c:\n  case 0x0d:\n  case 0x0e:\n  case 0x0f:\n    retval = state.attribute_ctrl.palette_reg[state.attribute_ctrl.address];\n    return (retval);\n    break;\n\n  case 0x10: /* mode control register */\n    retval = (state.attribute_ctrl.mode_ctrl.graphics_alpha << 0) |\n             (state.attribute_ctrl.mode_ctrl.display_type << 1) |\n             (state.attribute_ctrl.mode_ctrl.enable_line_graphics << 2) |\n             (state.attribute_ctrl.mode_ctrl.blink_intensity << 3) |\n             (state.attribute_ctrl.mode_ctrl.pixel_panning_compat << 5) |\n             (state.attribute_ctrl.mode_ctrl.pixel_clock_select << 6) |\n             (state.attribute_ctrl.mode_ctrl.internal_palette_size << 7);\n    return (retval);\n    break;\n\n  case 0x11: /* overscan color register */\n    return (state.attribute_ctrl.overscan_color);\n    break;\n\n  case 0x12: /* color plane enable */\n    return (state.attribute_ctrl.color_plane_enable);\n    break;\n\n  case 0x13: /* horizontal PEL panning register */\n    return (state.attribute_ctrl.horiz_pel_panning);\n    break;\n\n  case 0x14: /* color select register */\n    return (state.attribute_ctrl.color_select);\n    break;\n\n  default:\n    FAILURE_1(NotImplemented, \"io read: 0x3c1: unknown register 0x%02x\",\n              (unsigned)state.attribute_ctrl.address);\n  }\n}\n\n/**\n * Read from the VGA Input Status register (0x3c2)\n *\n * \\code\n * +-----+-+-------+\n * |     |4|       |\n * +-----+-+-------+\n *        ^\n *        +--------- 4: Switch Sense:\n *                      Returns the status of the four sense switches as\n *selected by the Clock Select field of the Miscellaneous Output Register (See\n *                      CCirrus::write_b_3c2)\n * \\endcode\n **/\nu8 CS3Trio64::read_b_3c2() {\n  return 0; // input status register\n}\n\n/**\n * Read from the VGA Enable register (0x3c3)\n *\n * (Not sure where this comes from; doesn't seem to be in the VGA specs.)\n **/\nu8 CS3Trio64::read_b_3c3() { return state.vga_enabled; }\n\n/**\n * Read from the VGA sequencer index register (0x3c4)\n *\n * For a description of the Sequencer registers, see CCirrus::write_b_3c4\n **/\nu8 CS3Trio64::read_b_3c4() { return state.sequencer.index; }\n\n/**\n * Read from the VGA sequencer data register (0x3c5)\n *\n * For a description of the Sequencer registers, see CCirrus::write_b_3c4\n **/\nu8 CS3Trio64::read_b_3c5() {\n  switch (state.sequencer.index) {\n  case 0: /* sequencer: reset */\n#if defined(DEBUG_VGA)\n    BX_DEBUG((\"io read 0x3c5: sequencer reset\"));\n#endif\n    return (state.sequencer.reset1 ? 1 : 0) | (state.sequencer.reset2 ? 2 : 0);\n    break;\n\n  case 1: /* sequencer: clocking mode */\n#if defined(DEBUG_VGA)\n    BX_DEBUG((\"io read 0x3c5: sequencer clocking mode\"));\n#endif\n    return state.sequencer.reg1;\n    break;\n\n  case 2: /* sequencer: map mask register */\n    return state.sequencer.map_mask;\n    break;\n\n  case 3: /* sequencer: character map select register */\n    return state.sequencer.char_map_select;\n    break;\n\n  case 4: /* sequencer: memory mode register */\n    return (state.sequencer.extended_mem << 1) |\n           (state.sequencer.odd_even << 2) | (state.sequencer.chain_four << 3);\n    break;\n\n  default:\n    FAILURE_1(NotImplemented, \"io read 0x3c5: index %u unhandled\",\n              (unsigned)state.sequencer.index);\n  }\n}\n\n/**\n * Read from VGA DAC Data register (0x3c9)\n *\n * For a description of DAC registers see CCirrus::write_b_3c7\n **/\nu8 CS3Trio64::read_b_3c9() {\n  u8 retval;\n  if (state.pel.dac_state == 0x03) {\n    switch (state.pel.read_data_cycle) {\n    case 0:\n      retval = state.pel.data[state.pel.read_data_register].red;\n      break;\n    case 1:\n      retval = state.pel.data[state.pel.read_data_register].green;\n      break;\n    case 2:\n      retval = state.pel.data[state.pel.read_data_register].blue;\n      break;\n    default:\n      retval = 0; // keep compiler happy\n    }\n\n    state.pel.read_data_cycle++;\n    if (state.pel.read_data_cycle >= 3) {\n      state.pel.read_data_cycle = 0;\n      state.pel.read_data_register++;\n    }\n  } else {\n    retval = 0x3f;\n  }\n\n  return retval;\n}\n\n/**\n * Read from the VGA Feature Control register (index 0x3ca)\n *\n * \\code\n * +-----------+-+-+\n * |           |1|0|\n * +-----------+-+-+\n *              ^ ^\n *              | +- 0: Feature Control 0 (reserved)\n *              +--- 1: Feature Control 1 (reserved)\n * \\endcode\n **/\nu8 CS3Trio64::read_b_3ca() { return 0; }\n\n/**\n * Write to the VGA Miscellaneous Output Register (0x3cc)\n *\n * For a description of the Miscellaneous Output register, see\n *CCirrus::write_b_3c2\n **/\nu8 CS3Trio64::read_b_3cc() {\n\n  /* Miscellaneous Output / Graphics 1 Position ??? */\n  return ((state.misc_output.color_emulation & 0x01) << 0) |\n         ((state.misc_output.enable_ram & 0x01) << 1) |\n         ((state.misc_output.clock_select & 0x03) << 2) |\n         ((state.misc_output.select_high_bank & 0x01) << 5) |\n         ((state.misc_output.horiz_sync_pol & 0x01) << 6) |\n         ((state.misc_output.vert_sync_pol & 0x01) << 7);\n}\n\n/**\n * Read from VGA Graphics Controller Data Register (0x3cf)\n *\n * For a description of the Graphics registers, see CCirrus::write_b_3ce\n **/\nu8 CS3Trio64::read_b_3cf() {\n  u8 retval;\n  switch (state.graphics_ctrl.index) {\n  case 0: /* Set/Reset */\n    return (state.graphics_ctrl.set_reset);\n    break;\n\n  case 1: /* Enable Set/Reset */\n    return (state.graphics_ctrl.enable_set_reset);\n    break;\n\n  case 2: /* Color Compare */\n    return (state.graphics_ctrl.color_compare);\n    break;\n\n  case 3: /* Data Rotate */\n    retval = ((state.graphics_ctrl.raster_op & 0x03) << 3) |\n             ((state.graphics_ctrl.data_rotate & 0x07) << 0);\n    return (retval);\n    break;\n\n  case 4: /* Read Map Select */\n    return (state.graphics_ctrl.read_map_select);\n    break;\n\n  case 5: /* Mode */\n    retval = ((state.graphics_ctrl.shift_reg & 0x03) << 5) |\n             ((state.graphics_ctrl.odd_even & 0x01) << 4) |\n             ((state.graphics_ctrl.read_mode & 0x01) << 3) |\n             ((state.graphics_ctrl.write_mode & 0x03) << 0);\n\n#if defined(DEBUG_VGA)\n    if (state.graphics_ctrl.odd_even || state.graphics_ctrl.shift_reg)\n      BX_DEBUG((\"io read 0x3cf: reg 05 = 0x%02x\", (unsigned)retval));\n#endif\n    return (retval);\n    break;\n\n  case 6: /* Miscellaneous */\n    return ((state.graphics_ctrl.memory_mapping & 0x03) << 2) |\n           ((state.graphics_ctrl.odd_even & 0x01) << 1) |\n           ((state.graphics_ctrl.graphics_alpha & 0x01) << 0);\n    break;\n\n  case 7: /* Color Don't Care */\n    return (state.graphics_ctrl.color_dont_care);\n    break;\n\n  case 8: /* Bit Mask */\n    return (state.graphics_ctrl.bitmask);\n    break;\n\n  default:\n    FAILURE_1(NotImplemented, \"io read: 0x3cf: index %u unhandled\",\n              (unsigned)state.graphics_ctrl.index);\n  }\n}\n\n/**\n * Read from VGA CRTC Index Register (0x3b5 or 0x3d5)\n *\n * For a description of CRTC Registers, see CCirrus::write_b_3d4.\n **/\nu8 CS3Trio64::read_b_3d4() { return state.CRTC.address; }\n\n/**\n * Read from VGA CRTC Data Register (0x3b5 or 0x3d5)\n *\n * For a description of CRTC Registers, see CCirrus::write_b_3d4.\n **/\nu8 CS3Trio64::read_b_3d5() {\n  if (state.CRTC.address > 0x18) {\n    FAILURE_1(NotImplemented, \"io read: invalid CRTC register 0x%02x   \\n\",\n              (unsigned)state.CRTC.address);\n  }\n\n  return state.CRTC.reg[state.CRTC.address];\n}\n\n/**\n * Read from the VGA Input Status 1 register (0x3ba or 0x3da)\n *\n * \\code\n * +-------+-+---+-+\n * |       |3|   |0|\n * +-------+-+---+-+\n *          ^     ^\n *          |     +- 0: Display Disabled:\n *          |             1: Indicates a horizontal or vertical retrace\n *interval. This |                bit is the real-time status of the inverted\n *'display |                enable' signal. Programs have used this status bit\n *to |                restrict screen updates to the inactive display intervals\n *          |                in order to reduce screen flicker. The video\n *subsystem is |                designed to eliminate this software requirement;\n *screen |                updates may be made at any time without screen\n *degradation.\n *          +------- 1: Vertical Retrace:\n *                        1: Indicates that the display is in a vertical retrace\n *interval. This bit can be programmed, through the Vertical Retrace End\n *                           register, to generate an interrupt at the start of\n *the vertical retrace. \\endcode\n **/\nu8 CS3Trio64::read_b_3da() {\n\n  /* Input Status 1 (color emulation modes) */\n  u8 retval = 0;\n\n  // bit3: Vertical Retrace\n  //       0 = display is in the display mode\n  //       1 = display is in the vertical retrace mode\n  // bit0: Display Enable\n  //       0 = display is in the display mode\n  //       1 = display is not in the display mode; either the\n  //           horizontal or vertical retrace period is active\n  // using 72 Hz vertical frequency\n\n  /*** TO DO ??? ***\n       usec = bx_pc_system.time_usec();\n       switch ( ( state.misc_output.vert_sync_pol << 1) |\n     state.misc_output.horiz_sync_pol )\n       {\n         case 0: vertres = 200; break;\n         case 1: vertres = 400; break;\n         case 2: vertres = 350; break;\n         default: vertres = 480; break;\n       }\n       if ((usec % 13888) < 70) {\n         vert_retrace = 1;\n       }\n       if ((usec % (13888 / vertres)) == 0) {\n         horiz_retrace = 1;\n       }\n\n       if (horiz_retrace || vert_retrace)\n         retval = 0x01;\n       if (vert_retrace)\n         retval |= 0x08;\n\n       *** TO DO ??? ***/\n\n  /* reading this port resets the flip-flop to address mode */\n  state.attribute_ctrl.flip_flop = 0;\n  return retval;\n}\n\nu8 CS3Trio64::get_actl_palette_idx(u8 index) {\n  return state.attribute_ctrl.palette_reg[index];\n}\n\nvoid CS3Trio64::redraw_area(unsigned x0, unsigned y0, unsigned width,\n                            unsigned height) {\n  unsigned xti;\n\n  unsigned yti;\n\n  unsigned xt0;\n\n  unsigned xt1;\n\n  unsigned yt0;\n\n  unsigned yt1;\n\n  unsigned xmax;\n\n  unsigned ymax;\n\n  if ((width == 0) || (height == 0)) {\n    return;\n  }\n\n  state.vga_mem_updated = 1;\n\n  if (state.graphics_ctrl.graphics_alpha) {\n\n    // graphics mode\n    xmax = old_iWidth;\n    ymax = old_iHeight;\n    xt0 = x0 / X_TILESIZE;\n    yt0 = y0 / Y_TILESIZE;\n    if (x0 < xmax) {\n      xt1 = (x0 + width - 1) / X_TILESIZE;\n    } else {\n      xt1 = (xmax - 1) / X_TILESIZE;\n    }\n\n    if (y0 < ymax) {\n      yt1 = (y0 + height - 1) / Y_TILESIZE;\n    } else {\n      yt1 = (ymax - 1) / Y_TILESIZE;\n    }\n\n    for (yti = yt0; yti <= yt1; yti++) {\n      for (xti = xt0; xti <= xt1; xti++) {\n        SET_TILE_UPDATED(xti, yti, 1);\n      }\n    }\n  } else {\n\n    // text mode\n    memset(state.text_snapshot, 0, sizeof(state.text_snapshot));\n  }\n}\n\nvoid CS3Trio64::update(void) {\n  unsigned iHeight;\n\n  unsigned iWidth;\n\n  /* no screen update necessary */\n  if (state.vga_mem_updated == 0)\n    return;\n\n  /* skip screen update when vga/video is disabled or the sequencer is in reset\n   * mode */\n  if (!state.vga_enabled || !state.attribute_ctrl.video_enabled ||\n      !state.sequencer.reset2 || !state.sequencer.reset1)\n    return;\n\n  // fields that effect the way video memory is serialized into screen output:\n  // GRAPHICS CONTROLLER:\n  //   state.graphics_ctrl.shift_reg:\n  //     0: output data in standard VGA format or CGA-compatible 640x200 2 color\n  //        graphics mode (mode 6)\n  //     1: output data in CGA-compatible 320x200 4 color graphics mode\n  //        (modes 4 & 5)\n  //     2: output data 8 bits at a time from the 4 bit planes\n  //        (mode 13 and variants like modeX)\n  // if (state.vga_mem_updated==0 || state.attribute_ctrl.video_enabled == 0)\n  if (state.graphics_ctrl.graphics_alpha) {\n    u8 color;\n    unsigned bit_no;\n    unsigned r;\n    unsigned c;\n    unsigned x;\n    unsigned y;\n    unsigned long byte_offset;\n    unsigned long start_addr;\n    unsigned xc;\n    unsigned yc;\n    unsigned xti;\n    unsigned yti;\n\n    start_addr = (state.CRTC.reg[0x0c] << 8) | state.CRTC.reg[0x0d];\n\n    // BX_DEBUG((\"update: shiftreg=%u, chain4=%u, mapping=%u\",\n    //  (unsigned) state.graphics_ctrl.shift_reg,\n    //  (unsigned) state.sequencer.chain_four,\n    //  (unsigned) state.graphics_ctrl.memory_mapping);\n    determine_screen_dimensions(&iHeight, &iWidth);\n    if ((iWidth != old_iWidth) || (iHeight != old_iHeight) ||\n        (state.last_bpp > 8)) {\n      bx_gui->dimension_update(iWidth, iHeight);\n      old_iWidth = iWidth;\n      old_iHeight = iHeight;\n      state.last_bpp = 8;\n    }\n\n    switch (state.graphics_ctrl.shift_reg) {\n    case 0:\n      u8 attribute, palette_reg_val, DAC_regno;\n\n      unsigned long line_compare;\n      u8 *plane0;\n      u8 *plane1;\n      u8 *plane2;\n      u8 *plane3;\n\n      if (state.graphics_ctrl.memory_mapping == 3) { // CGA 640x200x2\n        for (yc = 0, yti = 0; yc < iHeight; yc += Y_TILESIZE, yti++) {\n          for (xc = 0, xti = 0; xc < iWidth; xc += X_TILESIZE, xti++) {\n            if (GET_TILE_UPDATED(xti, yti)) {\n              for (r = 0; r < Y_TILESIZE; r++) {\n                y = yc + r;\n                if (state.y_doublescan)\n                  y >>= 1;\n                for (c = 0; c < X_TILESIZE; c++) {\n                  x = xc + c;\n\n                  /* 0 or 0x2000 */\n                  byte_offset = start_addr + ((y & 1) << 13);\n\n                  /* to the start of the line */\n                  byte_offset += (320 / 4) * (y / 2);\n\n                  /* to the byte start */\n                  byte_offset += (x / 8);\n\n                  bit_no = 7 - (x % 8);\n                  palette_reg_val =\n                      (((state.memory[byte_offset]) >> bit_no) & 1);\n                  DAC_regno = state.attribute_ctrl.palette_reg[palette_reg_val];\n                  state.tile[r * X_TILESIZE + c] = DAC_regno;\n                }\n              }\n\n              SET_TILE_UPDATED(xti, yti, 0);\n              bx_gui->graphics_tile_update(state.tile, xc, yc);\n            }\n          }\n        }\n      } else { // output data in serial fashion with each display plane\n        // output on its associated serial output.  Standard EGA/VGA format\n        plane0 = &state.memory[0 << 16];\n        plane1 = &state.memory[1 << 16];\n        plane2 = &state.memory[2 << 16];\n        plane3 = &state.memory[3 << 16];\n        line_compare = state.line_compare;\n        if (state.y_doublescan)\n          line_compare >>= 1;\n\n        for (yc = 0, yti = 0; yc < iHeight; yc += Y_TILESIZE, yti++) {\n          for (xc = 0, xti = 0; xc < iWidth; xc += X_TILESIZE, xti++) {\n            if (GET_TILE_UPDATED(xti, yti)) {\n              for (r = 0; r < Y_TILESIZE; r++) {\n                y = yc + r;\n                if (state.y_doublescan)\n                  y >>= 1;\n                for (c = 0; c < X_TILESIZE; c++) {\n                  x = xc + c;\n                  if (state.x_dotclockdiv2)\n                    x >>= 1;\n                  bit_no = 7 - (x % 8);\n                  if (y > line_compare) {\n                    byte_offset =\n                        x / 8 + ((y - line_compare - 1) * state.line_offset);\n                  } else {\n                    byte_offset = start_addr + x / 8 + (y * state.line_offset);\n                  }\n\n                  attribute = (((plane0[byte_offset] >> bit_no) & 0x01) << 0) |\n                              (((plane1[byte_offset] >> bit_no) & 0x01) << 1) |\n                              (((plane2[byte_offset] >> bit_no) & 0x01) << 2) |\n                              (((plane3[byte_offset] >> bit_no) & 0x01) << 3);\n\n                  attribute &= state.attribute_ctrl.color_plane_enable;\n\n                  // undocumented feature ???: colors 0..7 high intensity,\n                  // colors 8..15 blinking using low/high intensity. Blinking is\n                  // not implemented yet.\n                  if (state.attribute_ctrl.mode_ctrl.blink_intensity)\n                    attribute ^= 0x08;\n                  palette_reg_val = state.attribute_ctrl.palette_reg[attribute];\n                  if (state.attribute_ctrl.mode_ctrl.internal_palette_size) {\n\n                    // use 4 lower bits from palette register\n                    // use 4 higher bits from color select register\n                    // 16 banks of 16-color registers\n                    DAC_regno = (palette_reg_val & 0x0f) |\n                                (state.attribute_ctrl.color_select << 4);\n                  } else {\n\n                    // use 6 lower bits from palette register\n                    // use 2 higher bits from color select register\n                    // 4 banks of 64-color registers\n                    DAC_regno =\n                        (palette_reg_val & 0x3f) |\n                        ((state.attribute_ctrl.color_select & 0x0c) << 4);\n                  }\n\n                  // DAC_regno &= video DAC mask register ???\n                  state.tile[r * X_TILESIZE + c] = DAC_regno;\n                }\n              }\n\n              SET_TILE_UPDATED(xti, yti, 0);\n              bx_gui->graphics_tile_update(state.tile, xc, yc);\n            }\n          }\n        }\n      }\n      break; // case 0\n\n    case 1: // output the data in a CGA-compatible 320x200 4 color graphics\n      // mode.  (modes 4 & 5)\n\n      /* CGA 320x200x4 start */\n      for (yc = 0, yti = 0; yc < iHeight; yc += Y_TILESIZE, yti++) {\n        for (xc = 0, xti = 0; xc < iWidth; xc += X_TILESIZE, xti++) {\n          if (GET_TILE_UPDATED(xti, yti)) {\n            for (r = 0; r < Y_TILESIZE; r++) {\n              y = yc + r;\n              if (state.y_doublescan)\n                y >>= 1;\n              for (c = 0; c < X_TILESIZE; c++) {\n                x = xc + c;\n                if (state.x_dotclockdiv2)\n                  x >>= 1;\n\n                /* 0 or 0x2000 */\n                byte_offset = start_addr + ((y & 1) << 13);\n\n                /* to the start of the line */\n                byte_offset += (320 / 4) * (y / 2);\n\n                /* to the byte start */\n                byte_offset += (x / 4);\n\n                attribute = 6 - 2 * (x % 4);\n                palette_reg_val = (state.memory[byte_offset]) >> attribute;\n                palette_reg_val &= 3;\n                DAC_regno = state.attribute_ctrl.palette_reg[palette_reg_val];\n                state.tile[r * X_TILESIZE + c] = DAC_regno;\n              }\n            }\n\n            SET_TILE_UPDATED(xti, yti, 0);\n            bx_gui->graphics_tile_update(state.tile, xc, yc);\n          }\n        }\n      }\n\n      /* CGA 320x200x4 end */\n      break; // case 1\n\n    case 2: // output the data eight bits at a time from the 4 bit plane\n\n    // (format for VGA mode 13 hex)\n    case 3: // FIXME: is this really the same ???\n      if (state.sequencer.chain_four) {\n        unsigned long pixely;\n\n        unsigned long pixelx;\n\n        unsigned long plane;\n\n        if (state.misc_output.select_high_bank != 1) {\n          FAILURE(NotImplemented, \"update: select_high_bank != 1   \\n\");\n        }\n\n        for (yc = 0, yti = 0; yc < iHeight; yc += Y_TILESIZE, yti++) {\n          for (xc = 0, xti = 0; xc < iWidth; xc += X_TILESIZE, xti++) {\n            if (GET_TILE_UPDATED(xti, yti)) {\n              for (r = 0; r < Y_TILESIZE; r++) {\n                pixely = yc + r;\n                if (state.y_doublescan)\n                  pixely >>= 1;\n                for (c = 0; c < X_TILESIZE; c++) {\n                  pixelx = (xc + c) >> 1;\n                  plane = (pixelx % 4);\n                  byte_offset = start_addr + (plane * 65536) +\n                                (pixely * state.line_offset) + (pixelx & ~0x03);\n                  color = state.memory[byte_offset];\n                  state.tile[r * X_TILESIZE + c] = color;\n                }\n              }\n\n              SET_TILE_UPDATED(xti, yti, 0);\n              bx_gui->graphics_tile_update(state.tile, xc, yc);\n            }\n          }\n        }\n      } else { // chain_four == 0, modeX\n        unsigned long pixely;\n\n        // chain_four == 0, modeX\n        unsigned long pixelx;\n\n        // chain_four == 0, modeX\n        unsigned long plane;\n\n        for (yc = 0, yti = 0; yc < iHeight; yc += Y_TILESIZE, yti++) {\n          for (xc = 0, xti = 0; xc < iWidth; xc += X_TILESIZE, xti++) {\n            if (GET_TILE_UPDATED(xti, yti)) {\n              for (r = 0; r < Y_TILESIZE; r++) {\n                pixely = yc + r;\n                if (state.y_doublescan)\n                  pixely >>= 1;\n                for (c = 0; c < X_TILESIZE; c++) {\n                  pixelx = (xc + c) >> 1;\n                  plane = (pixelx % 4);\n                  byte_offset = (plane * 65536) + (pixely * state.line_offset) +\n                                (pixelx >> 2);\n                  color = state.memory[start_addr + byte_offset];\n                  state.tile[r * X_TILESIZE + c] = color;\n                }\n              }\n\n              SET_TILE_UPDATED(xti, yti, 0);\n              bx_gui->graphics_tile_update(state.tile, xc, yc);\n            }\n          }\n        }\n      }\n      break; // case 2\n\n    default:\n      FAILURE_1(NotImplemented, \"update: shift_reg == %u   \\n\",\n                (unsigned)state.graphics_ctrl.shift_reg);\n    }\n\n    state.vga_mem_updated = 0;\n    return;\n  } else { // text mode\n    unsigned long start_address;\n    unsigned long cursor_address;\n    unsigned long cursor_x;\n    unsigned long cursor_y;\n    bx_vga_tminfo_t tm_info;\n    unsigned VDE;\n    unsigned MSL;\n    unsigned cols;\n    unsigned rows;\n    unsigned cWidth;\n\n    tm_info.start_address =\n        2 * ((state.CRTC.reg[12] << 8) + state.CRTC.reg[13]);\n    tm_info.cs_start = state.CRTC.reg[0x0a] & 0x3f;\n    tm_info.cs_end = state.CRTC.reg[0x0b] & 0x1f;\n    tm_info.line_offset = state.CRTC.reg[0x13] << 2;\n    tm_info.line_compare = state.line_compare;\n    tm_info.h_panning = state.attribute_ctrl.horiz_pel_panning & 0x0f;\n    tm_info.v_panning = state.CRTC.reg[0x08] & 0x1f;\n    tm_info.line_graphics = state.attribute_ctrl.mode_ctrl.enable_line_graphics;\n    tm_info.split_hpanning =\n        state.attribute_ctrl.mode_ctrl.pixel_panning_compat;\n    if ((state.sequencer.reg1 & 0x01) == 0) {\n      if (tm_info.h_panning >= 8)\n        tm_info.h_panning = 0;\n      else\n        tm_info.h_panning++;\n    } else {\n      tm_info.h_panning &= 0x07;\n    }\n\n    // Verticle Display End: find out how many lines are displayed\n    VDE = state.vertical_display_end;\n\n    // Maximum Scan Line: height of character cell\n    MSL = state.CRTC.reg[0x09] & 0x1f;\n    if (MSL == 0) {\n#if defined(DEBUG_VGA)\n      BX_ERROR((\"character height = 1, skipping text update\"));\n#endif\n      return;\n    }\n\n    cols = state.CRTC.reg[1] + 1;\n    if ((MSL == 1) && (VDE == 399)) {\n\n      // emulated CGA graphics mode 160x100x16 colors\n      MSL = 3;\n    }\n\n    rows = (VDE + 1) / (MSL + 1);\n    if (rows > BX_MAX_TEXT_LINES) {\n      BX_PANIC((\"text rows>%d: %d\", BX_MAX_TEXT_LINES, rows));\n      return;\n    }\n\n    cWidth = ((state.sequencer.reg1 & 0x01) == 1) ? 8 : 9;\n    iWidth = cWidth * cols;\n    iHeight = VDE + 1;\n    if ((iWidth != old_iWidth) || (iHeight != old_iHeight) ||\n        (MSL != old_MSL) || (state.last_bpp > 8)) {\n      bx_gui->dimension_update(iWidth, iHeight, MSL + 1, cWidth);\n      old_iWidth = iWidth;\n      old_iHeight = iHeight;\n      old_MSL = MSL;\n      state.last_bpp = 8;\n    }\n\n    // pass old text snapshot & new VGA memory contents\n    start_address = 2 * ((state.CRTC.reg[12] << 8) + state.CRTC.reg[13]);\n    cursor_address = 2 * ((state.CRTC.reg[0x0e] << 8) + state.CRTC.reg[0x0f]);\n    if (cursor_address < start_address) {\n      cursor_x = 0xffff;\n      cursor_y = 0xffff;\n    } else {\n      cursor_x = ((cursor_address - start_address) / 2) % (iWidth / cWidth);\n      cursor_y = ((cursor_address - start_address) / 2) / (iWidth / cWidth);\n    }\n\n    bx_gui->text_update(state.text_snapshot, &state.memory[start_address],\n                        cursor_x, cursor_y, tm_info, rows);\n\n    // screen updated, copy new VGA memory contents into text snapshot\n    memcpy(state.text_snapshot, &state.memory[start_address], 2 * cols * rows);\n    state.vga_mem_updated = 0;\n  }\n}\n\nvoid CS3Trio64::determine_screen_dimensions(unsigned *piHeight,\n                                            unsigned *piWidth) {\n  int ai[0x20];\n  int i;\n  int h;\n  int v;\n  for (i = 0; i < 0x20; i++)\n    ai[i] = state.CRTC.reg[i];\n\n  h = (ai[1] + 1) * 8;\n  v = (ai[18] | ((ai[7] & 0x02) << 7) | ((ai[7] & 0x40) << 3)) + 1;\n\n  if (state.graphics_ctrl.shift_reg == 0) {\n    *piWidth = 640;\n    *piHeight = 480;\n\n    if (state.CRTC.reg[6] == 0xBF) {\n      if (state.CRTC.reg[23] == 0xA3 && state.CRTC.reg[20] == 0x40 &&\n          state.CRTC.reg[9] == 0x41) {\n        *piWidth = 320;\n        *piHeight = 240;\n      } else {\n        if (state.x_dotclockdiv2)\n          h <<= 1;\n        *piWidth = h;\n        *piHeight = v;\n      }\n    } else if ((h >= 640) && (v >= 480)) {\n      *piWidth = h;\n      *piHeight = v;\n    }\n  } else if (state.graphics_ctrl.shift_reg == 2) {\n    if (state.sequencer.chain_four) {\n      *piWidth = h;\n      *piHeight = v;\n    } else {\n      *piWidth = h;\n      *piHeight = v;\n    }\n  } else {\n    if (state.x_dotclockdiv2)\n      h <<= 1;\n    *piWidth = h;\n    *piHeight = v;\n  }\n}\n\nu8 CS3Trio64::vga_mem_read(u32 addr) {\n  u32 offset;\n  u8 *plane0;\n  u8 *plane1;\n  u8 *plane2;\n  u8 *plane3;\n  u8 retval = 0;\n\n  switch (state.graphics_ctrl.memory_mapping) {\n  case 1: // 0xA0000 .. 0xAFFFF\n    if (addr > 0xAFFFF)\n      return 0xff;\n    offset = addr & 0xFFFF;\n    break;\n\n  case 2: // 0xB0000 .. 0xB7FFF\n    if ((addr < 0xB0000) || (addr > 0xB7FFF))\n      return 0xff;\n    offset = addr & 0x7FFF;\n    break;\n\n  case 3: // 0xB8000 .. 0xBFFFF\n    if (addr < 0xB8000)\n      return 0xff;\n    offset = addr & 0x7FFF;\n    break;\n\n  default: // 0xA0000 .. 0xBFFFF\n    offset = addr & 0x1FFFF;\n  }\n\n  if (state.sequencer.chain_four) {\n    // Mode 13h: 320 x 200 256 color mode: chained pixel representation\n    return state.memory[(offset & ~0x03) + (offset % 4) * 65536];\n  }\n\n  plane0 = &state.memory[0 << 16];\n  plane1 = &state.memory[1 << 16];\n  plane2 = &state.memory[2 << 16];\n  plane3 = &state.memory[3 << 16];\n\n  /* addr between 0xA0000 and 0xAFFFF */\n  if (state.graphics_ctrl.read_mode) {\n    u8 color_compare;\n\n    u8 color_dont_care;\n    u8 latch0;\n    u8 latch1;\n    u8 latch2;\n    u8 latch3;\n\n    color_compare = state.graphics_ctrl.color_compare & 0x0f;\n    color_dont_care = state.graphics_ctrl.color_dont_care & 0x0f;\n    latch0 = state.graphics_ctrl.latch[0] = plane0[offset];\n    latch1 = state.graphics_ctrl.latch[1] = plane1[offset];\n    latch2 = state.graphics_ctrl.latch[2] = plane2[offset];\n    latch3 = state.graphics_ctrl.latch[3] = plane3[offset];\n\n    latch0 ^= ccdat[color_compare][0];\n    latch1 ^= ccdat[color_compare][1];\n    latch2 ^= ccdat[color_compare][2];\n    latch3 ^= ccdat[color_compare][3];\n\n    latch0 &= ccdat[color_dont_care][0];\n    latch1 &= ccdat[color_dont_care][1];\n    latch2 &= ccdat[color_dont_care][2];\n    latch3 &= ccdat[color_dont_care][3];\n\n    retval = ~(latch0 | latch1 | latch2 | latch3);\n  } else {\n    state.graphics_ctrl.latch[0] = plane0[offset];\n    state.graphics_ctrl.latch[1] = plane1[offset];\n    state.graphics_ctrl.latch[2] = plane2[offset];\n    state.graphics_ctrl.latch[3] = plane3[offset];\n    retval = state.graphics_ctrl.latch[state.graphics_ctrl.read_map_select];\n  }\n\n  return retval;\n}\n\n/**\n * Write to Legacy VGA Memory\n **/\nvoid CS3Trio64::vga_mem_write(u32 addr, u8 value) {\n  u32 offset;\n  u8 new_val[4];\n  unsigned start_addr;\n  u8 *plane0;\n  u8 *plane1;\n  u8 *plane2;\n  u8 *plane3;\n\n  /* The memory_mapping bits of the graphics controller determine\n   * what window of VGA memory is available.\n   *\n   *  00: 0xA0000 .. 0xBFFFF (128K)\n   *  01: 0xA0000 .. 0xAFFFF (64K) (also used for VGA text mode)\n   *  02: 0xB0000 .. 0xB7FFF (32K)\n   *  03: 0xB8000 .. 0xBFFFF (32K) (also used for CGA text mode)\n   */\n  switch (state.graphics_ctrl.memory_mapping) {\n  // 0xA0000 .. 0xAFFFF\n  case 1:\n    if (addr > 0xAFFFF)\n      return;\n    offset = addr - 0xA0000;\n    break;\n\n  // 0xB0000 .. 0xB7FFF\n  case 2:\n    if ((addr < 0xB0000) || (addr > 0xB7FFF))\n      return;\n    offset = addr - 0xB0000;\n    break;\n\n  // 0xB8000 .. 0xBFFFF\n  case 3:\n    if (addr < 0xB8000)\n      return;\n    offset = addr - 0xB8000;\n    break;\n\n  // 0xA0000 .. 0xBFFFF\n  default:\n    offset = addr - 0xA0000;\n  }\n\n  start_addr = (state.CRTC.reg[0x0c] << 8) | state.CRTC.reg[0x0d];\n\n  if (state.graphics_ctrl.graphics_alpha) {\n    if (state.graphics_ctrl.memory_mapping == 3) {\n      // Text mode, and memory 0xB8000 .. 0xBFFFF selected => CGA text mode\n      unsigned x_tileno;\n      unsigned x_tileno2;\n      unsigned y_tileno;\n\n      /* CGA 320x200x4 / 640x200x2 start */\n      state.memory[offset] = value;\n      offset -= start_addr;\n      if (offset >= 0x2000) {\n        y_tileno = offset - 0x2000;\n        y_tileno /= (320 / 4);\n        y_tileno <<= 1; // 2 * y_tileno;\n        y_tileno++;\n        x_tileno = (offset - 0x2000) % (320 / 4);\n        x_tileno <<= 2; //*= 4;\n      } else {\n        y_tileno = offset / (320 / 4);\n        y_tileno <<= 1; // 2 * y_tileno;\n        x_tileno = offset % (320 / 4);\n        x_tileno <<= 2; //*=4;\n      }\n\n      x_tileno2 = x_tileno;\n      if (state.graphics_ctrl.shift_reg == 0) {\n        x_tileno *= 2;\n        x_tileno2 += 7;\n      } else {\n        x_tileno2 += 3;\n      }\n\n      if (state.x_dotclockdiv2) {\n        x_tileno /= (X_TILESIZE / 2);\n        x_tileno2 /= (X_TILESIZE / 2);\n      } else {\n        x_tileno /= X_TILESIZE;\n        x_tileno2 /= X_TILESIZE;\n      }\n\n      if (state.y_doublescan) {\n        y_tileno /= (Y_TILESIZE / 2);\n      } else {\n        y_tileno /= Y_TILESIZE;\n      }\n\n      state.vga_mem_updated = 1;\n      SET_TILE_UPDATED(x_tileno, y_tileno, 1);\n      if (x_tileno2 != x_tileno) {\n        SET_TILE_UPDATED(x_tileno2, y_tileno, 1);\n      }\n\n      return;\n\n      /* CGA 320x200x4 / 640x200x2 end */\n    }\n\n    if (state.graphics_ctrl.memory_mapping != 1) {\n      FAILURE_1(NotImplemented, \"mem_write: graphics: mapping = %u  \\n\",\n                (unsigned)state.graphics_ctrl.memory_mapping);\n    }\n\n    if (state.sequencer.chain_four) {\n      unsigned x_tileno;\n\n      unsigned y_tileno;\n\n      // 320 x 200 256 color mode: chained pixel representation\n      state.memory[(offset & ~0x03) + (offset % 4) * 65536] = value;\n      if (state.line_offset > 0) {\n        offset -= start_addr;\n        x_tileno = (offset % state.line_offset) / (X_TILESIZE / 2);\n        if (state.y_doublescan) {\n          y_tileno = (offset / state.line_offset) / (Y_TILESIZE / 2);\n        } else {\n          y_tileno = (offset / state.line_offset) / Y_TILESIZE;\n        }\n\n        state.vga_mem_updated = 1;\n        SET_TILE_UPDATED(x_tileno, y_tileno, 1);\n      }\n\n      return;\n    }\n  }\n\n  /* addr between 0xA0000 and 0xAFFFF */\n  plane0 = &state.memory[0 << 16];\n  plane1 = &state.memory[1 << 16];\n  plane2 = &state.memory[2 << 16];\n  plane3 = &state.memory[3 << 16];\n\n  switch (state.graphics_ctrl.write_mode) {\n    unsigned i;\n  // Write mode 0\n  case 0: {\n    /* Write Mode 0 is the standard and most general write mode.\n     * While the other write modes are designed to perform a specific\n     * task, this mode can be used to perform most tasks as all five\n     * operations are performed on the data:\n     *   - The data byte from the host is first rotated as specified\n     *     by the Rotate Count field, then is replicated across all\n     *     four planes.\n     *   - Then the Enable Set/Reset field selects which planes will\n     *     receive their values from the host data and which will\n     *     receive their data from that plane's Set/Reset field\n     *     location.\n     *   - Then the operation specified by the Logical Operation\n     *     field is performed on the resulting data and the data in\n     *     the read latches.\n     *   - The Bit Mask field is then used to select between the\n     *     resulting data and data from the latch register.\n     *   - Finally, the resulting data is written to the display\n     *     memory planes enabled in the Memory Plane Write Enable\n     *     field.\n     *   .\n     */\n    const u8 bitmask = state.graphics_ctrl.bitmask;\n    const u8 set_reset = state.graphics_ctrl.set_reset;\n    const u8 enable_set_reset = state.graphics_ctrl.enable_set_reset;\n\n    /* perform rotate on CPU data in case its needed */\n    if (state.graphics_ctrl.data_rotate) {\n      value = (value >> state.graphics_ctrl.data_rotate) |\n              (value << (8 - state.graphics_ctrl.data_rotate));\n    }\n\n    new_val[0] = state.graphics_ctrl.latch[0] & ~bitmask;\n    new_val[1] = state.graphics_ctrl.latch[1] & ~bitmask;\n    new_val[2] = state.graphics_ctrl.latch[2] & ~bitmask;\n    new_val[3] = state.graphics_ctrl.latch[3] & ~bitmask;\n    switch (state.graphics_ctrl.raster_op) {\n    case 0: // replace\n      new_val[0] |= ((enable_set_reset & 1) ? ((set_reset & 1) ? bitmask : 0)\n                                            : (value & bitmask));\n      new_val[1] |= ((enable_set_reset & 2) ? ((set_reset & 2) ? bitmask : 0)\n                                            : (value & bitmask));\n      new_val[2] |= ((enable_set_reset & 4) ? ((set_reset & 4) ? bitmask : 0)\n                                            : (value & bitmask));\n      new_val[3] |= ((enable_set_reset & 8) ? ((set_reset & 8) ? bitmask : 0)\n                                            : (value & bitmask));\n      break;\n\n    case 1: // AND\n      new_val[0] |=\n          ((enable_set_reset & 1)\n               ? ((set_reset & 1) ? (state.graphics_ctrl.latch[0] & bitmask)\n                                  : 0)\n               : (value & state.graphics_ctrl.latch[0]) & bitmask);\n      new_val[1] |=\n          ((enable_set_reset & 2)\n               ? ((set_reset & 2) ? (state.graphics_ctrl.latch[1] & bitmask)\n                                  : 0)\n               : (value & state.graphics_ctrl.latch[1]) & bitmask);\n      new_val[2] |=\n          ((enable_set_reset & 4)\n               ? ((set_reset & 4) ? (state.graphics_ctrl.latch[2] & bitmask)\n                                  : 0)\n               : (value & state.graphics_ctrl.latch[2]) & bitmask);\n      new_val[3] |=\n          ((enable_set_reset & 8)\n               ? ((set_reset & 8) ? (state.graphics_ctrl.latch[3] & bitmask)\n                                  : 0)\n               : (value & state.graphics_ctrl.latch[3]) & bitmask);\n      break;\n\n    case 2: // OR\n      new_val[0] |=\n          ((enable_set_reset & 1)\n               ? ((set_reset & 1) ? bitmask\n                                  : (state.graphics_ctrl.latch[0] & bitmask))\n               : ((value | state.graphics_ctrl.latch[0]) & bitmask));\n      new_val[1] |=\n          ((enable_set_reset & 2)\n               ? ((set_reset & 2) ? bitmask\n                                  : (state.graphics_ctrl.latch[1] & bitmask))\n               : ((value | state.graphics_ctrl.latch[1]) & bitmask));\n      new_val[2] |=\n          ((enable_set_reset & 4)\n               ? ((set_reset & 4) ? bitmask\n                                  : (state.graphics_ctrl.latch[2] & bitmask))\n               : ((value | state.graphics_ctrl.latch[2]) & bitmask));\n      new_val[3] |=\n          ((enable_set_reset & 8)\n               ? ((set_reset & 8) ? bitmask\n                                  : (state.graphics_ctrl.latch[3] & bitmask))\n               : ((value | state.graphics_ctrl.latch[3]) & bitmask));\n      break;\n\n    case 3: // XOR\n      new_val[0] |=\n          ((enable_set_reset & 1)\n               ? ((set_reset & 1) ? (~state.graphics_ctrl.latch[0] & bitmask)\n                                  : (state.graphics_ctrl.latch[0] & bitmask))\n               : (value ^ state.graphics_ctrl.latch[0]) & bitmask);\n      new_val[1] |=\n          ((enable_set_reset & 2)\n               ? ((set_reset & 2) ? (~state.graphics_ctrl.latch[1] & bitmask)\n                                  : (state.graphics_ctrl.latch[1] & bitmask))\n               : (value ^ state.graphics_ctrl.latch[1]) & bitmask);\n      new_val[2] |=\n          ((enable_set_reset & 4)\n               ? ((set_reset & 4) ? (~state.graphics_ctrl.latch[2] & bitmask)\n                                  : (state.graphics_ctrl.latch[2] & bitmask))\n               : (value ^ state.graphics_ctrl.latch[2]) & bitmask);\n      new_val[3] |=\n          ((enable_set_reset & 8)\n               ? ((set_reset & 8) ? (~state.graphics_ctrl.latch[3] & bitmask)\n                                  : (state.graphics_ctrl.latch[3] & bitmask))\n               : (value ^ state.graphics_ctrl.latch[3]) & bitmask);\n      break;\n\n    default:\n      FAILURE_1(NotImplemented, \"vga_mem_write: write mode 0: op = %u\",\n                (unsigned)state.graphics_ctrl.raster_op);\n    }\n  } break;\n\n  // Write mode 1\n  case 1:\n    /* Write Mode 1 is used to transfer the data in the latches\n     * register directly to the screen, affected only by the\n     * Memory Plane Write Enable field. This can facilitate\n     * rapid transfer of data on byte boundaries from one area\n     * of video memory to another or filling areas of the\n     * display with a pattern of 8 pixels.\n     * When Write Mode 0 is used with the Bit Mask field set to\n     * 00000000b the operation of the hardware is identical to\n     * this mode.\n     */\n    for (i = 0; i < 4; i++) {\n      new_val[i] = state.graphics_ctrl.latch[i];\n    }\n    break;\n\n  // Write mode 2\n  case 2: {\n    /* Write Mode 2 is used to unpack a pixel value packed into\n     * the lower 4 bits of the host data byte into the 4 display\n     * planes:\n     *   - In the byte from the host, the bit representing each\n     *     plane will be replicated across all 8 bits of the\n     *     corresponding planes.\n     *   - Then the operation specified by the Logical Operation\n     *     field is performed on the resulting data and the data\n     *     in the read latches.\n     *   - The Bit Mask field is then used to select between the\n     *     resulting data and data from the latch register.\n     *   - Finally, the resulting data is written to the display\n     *     memory planes enabled in the Memory Plane Write Enable\n     *     field.\n     *   .\n     */\n    const u8 bitmask = state.graphics_ctrl.bitmask;\n\n    new_val[0] = state.graphics_ctrl.latch[0] & ~bitmask;\n    new_val[1] = state.graphics_ctrl.latch[1] & ~bitmask;\n    new_val[2] = state.graphics_ctrl.latch[2] & ~bitmask;\n    new_val[3] = state.graphics_ctrl.latch[3] & ~bitmask;\n    switch (state.graphics_ctrl.raster_op) {\n    case 0: // write\n      new_val[0] |= (value & 1) ? bitmask : 0;\n      new_val[1] |= (value & 2) ? bitmask : 0;\n      new_val[2] |= (value & 4) ? bitmask : 0;\n      new_val[3] |= (value & 8) ? bitmask : 0;\n      break;\n\n    case 1: // AND\n      new_val[0] |= (value & 1) ? (state.graphics_ctrl.latch[0] & bitmask) : 0;\n      new_val[1] |= (value & 2) ? (state.graphics_ctrl.latch[1] & bitmask) : 0;\n      new_val[2] |= (value & 4) ? (state.graphics_ctrl.latch[2] & bitmask) : 0;\n      new_val[3] |= (value & 8) ? (state.graphics_ctrl.latch[3] & bitmask) : 0;\n      break;\n\n    case 2: // OR\n      new_val[0] |=\n          (value & 1) ? bitmask : (state.graphics_ctrl.latch[0] & bitmask);\n      new_val[1] |=\n          (value & 2) ? bitmask : (state.graphics_ctrl.latch[1] & bitmask);\n      new_val[2] |=\n          (value & 4) ? bitmask : (state.graphics_ctrl.latch[2] & bitmask);\n      new_val[3] |=\n          (value & 8) ? bitmask : (state.graphics_ctrl.latch[3] & bitmask);\n      break;\n\n    case 3: // XOR\n      new_val[0] |= (value & 1) ? (~state.graphics_ctrl.latch[0] & bitmask)\n                                : (state.graphics_ctrl.latch[0] & bitmask);\n      new_val[1] |= (value & 2) ? (~state.graphics_ctrl.latch[1] & bitmask)\n                                : (state.graphics_ctrl.latch[1] & bitmask);\n      new_val[2] |= (value & 4) ? (~state.graphics_ctrl.latch[2] & bitmask)\n                                : (state.graphics_ctrl.latch[2] & bitmask);\n      new_val[3] |= (value & 8) ? (~state.graphics_ctrl.latch[3] & bitmask)\n                                : (state.graphics_ctrl.latch[3] & bitmask);\n      break;\n    }\n  } break;\n\n  // Write mode 3\n  case 3: {\n    /* Write Mode 3 is used when the color written is fairly\n     * constant but the Bit Mask field needs to be changed\n     * frequently, such as when drawing single color lines or\n     * text:\n     *   - The value of the Set/Reset field is expanded as if\n     *     the Enable Set/Reset field were set to 1111b,\n     *     regardless of its actual value.\n     *   - The host data is first rotated as specified by the\n     *     Rotate Count field, then is ANDed with the Bit\n     *     Mask field.\n     *   - The resulting value is used where the Bit Mask\n     *     field normally would be used, selecting data from\n     *     either the expansion of the Set/Reset field or the\n     *     latch register.\n     *   - Finally, the resulting data is written to the\n     *     display memory planes enabled in the Memory Plane\n     *     Write Enable field.\n     *   .\n     */\n    const u8 bitmask = state.graphics_ctrl.bitmask & value;\n    const u8 set_reset = state.graphics_ctrl.set_reset;\n\n    /* perform rotate on CPU data */\n    if (state.graphics_ctrl.data_rotate) {\n      value = (value >> state.graphics_ctrl.data_rotate) |\n              (value << (8 - state.graphics_ctrl.data_rotate));\n    }\n\n    new_val[0] = state.graphics_ctrl.latch[0] & ~bitmask;\n    new_val[1] = state.graphics_ctrl.latch[1] & ~bitmask;\n    new_val[2] = state.graphics_ctrl.latch[2] & ~bitmask;\n    new_val[3] = state.graphics_ctrl.latch[3] & ~bitmask;\n\n    value &= bitmask;\n\n    switch (state.graphics_ctrl.raster_op) {\n    case 0: // write\n      new_val[0] |= (set_reset & 1) ? value : 0;\n      new_val[1] |= (set_reset & 2) ? value : 0;\n      new_val[2] |= (set_reset & 4) ? value : 0;\n      new_val[3] |= (set_reset & 8) ? value : 0;\n      break;\n\n    case 1: // AND\n      new_val[0] |=\n          ((set_reset & 1) ? value : 0) & state.graphics_ctrl.latch[0];\n      new_val[1] |=\n          ((set_reset & 2) ? value : 0) & state.graphics_ctrl.latch[1];\n      new_val[2] |=\n          ((set_reset & 4) ? value : 0) & state.graphics_ctrl.latch[2];\n      new_val[3] |=\n          ((set_reset & 8) ? value : 0) & state.graphics_ctrl.latch[3];\n      break;\n\n    case 2: // OR\n      new_val[0] |=\n          ((set_reset & 1) ? value : 0) | state.graphics_ctrl.latch[0];\n      new_val[1] |=\n          ((set_reset & 2) ? value : 0) | state.graphics_ctrl.latch[1];\n      new_val[2] |=\n          ((set_reset & 4) ? value : 0) | state.graphics_ctrl.latch[2];\n      new_val[3] |=\n          ((set_reset & 8) ? value : 0) | state.graphics_ctrl.latch[3];\n      break;\n\n    case 3: // XOR\n      new_val[0] |=\n          ((set_reset & 1) ? value : 0) ^ state.graphics_ctrl.latch[0];\n      new_val[1] |=\n          ((set_reset & 2) ? value : 0) ^ state.graphics_ctrl.latch[1];\n      new_val[2] |=\n          ((set_reset & 4) ? value : 0) ^ state.graphics_ctrl.latch[2];\n      new_val[3] |=\n          ((set_reset & 8) ? value : 0) ^ state.graphics_ctrl.latch[3];\n      break;\n    }\n  } break;\n\n  default:\n    FAILURE_1(NotImplemented, \"vga_mem_write: write mode %u ?\",\n              (unsigned)state.graphics_ctrl.write_mode);\n  }\n\n  // state.sequencer.map_mask determines which bitplanes the write should\n  // actually go to\n  if (state.sequencer.map_mask & 0x0f) {\n    state.vga_mem_updated = 1;\n    if (state.sequencer.map_mask & 0x01)\n      plane0[offset] = new_val[0];\n    if (state.sequencer.map_mask & 0x02)\n      plane1[offset] = new_val[1];\n    if (state.sequencer.map_mask & 0x04) {\n      // Plane 2 contains the character map\n      if ((offset & 0xe000) == state.charmap_address) {\n\n        // printf(\"Updating character map %04x with %02x...\\n  \", (offset &\n        // 0x1fff), new_val[2]);\n        bx_gui->lock();\n        bx_gui->set_text_charbyte((u16)(offset & 0x1fff), new_val[2]);\n        bx_gui->unlock();\n      }\n\n      plane2[offset] = new_val[2];\n    }\n\n    if (state.sequencer.map_mask & 0x08)\n      plane3[offset] = new_val[3];\n\n    unsigned x_tileno;\n\n    unsigned y_tileno;\n\n    if (state.graphics_ctrl.shift_reg == 2) {\n      offset -= start_addr;\n      x_tileno = (offset % state.line_offset) * 4 / (X_TILESIZE / 2);\n      if (state.y_doublescan) {\n        y_tileno = (offset / state.line_offset) / (Y_TILESIZE / 2);\n      } else {\n        y_tileno = (offset / state.line_offset) / Y_TILESIZE;\n      }\n\n      SET_TILE_UPDATED(x_tileno, y_tileno, 1);\n    } else {\n      if (state.line_compare < state.vertical_display_end) {\n        if (state.line_offset > 0) {\n          if (state.x_dotclockdiv2) {\n            x_tileno = (offset % state.line_offset) / (X_TILESIZE / 16);\n          } else {\n            x_tileno = (offset % state.line_offset) / (X_TILESIZE / 8);\n          }\n\n          if (state.y_doublescan) {\n            y_tileno =\n                ((offset / state.line_offset) * 2 + state.line_compare + 1) /\n                Y_TILESIZE;\n          } else {\n            y_tileno = ((offset / state.line_offset) + state.line_compare + 1) /\n                       Y_TILESIZE;\n          }\n\n          SET_TILE_UPDATED(x_tileno, y_tileno, 1);\n        }\n      }\n\n      if (offset >= start_addr) {\n        offset -= start_addr;\n        if (state.line_offset > 0) {\n          if (state.x_dotclockdiv2) {\n            x_tileno = (offset % state.line_offset) / (X_TILESIZE / 16);\n          } else {\n            x_tileno = (offset % state.line_offset) / (X_TILESIZE / 8);\n          }\n\n          if (state.y_doublescan) {\n            y_tileno = (offset / state.line_offset) / (Y_TILESIZE / 2);\n          } else {\n            y_tileno = (offset / state.line_offset) / Y_TILESIZE;\n          }\n\n          SET_TILE_UPDATED(x_tileno, y_tileno, 1);\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/S3Trio64.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_S3Trio64_H_)\n#define INCLUDED_S3Trio64_H_\n\n#include \"VGA.hpp\"\n#include \"gui/vga.hpp\"\n\n/* video card has 4M of ram */\n#define VIDEO_RAM_SIZE 22\n#define CRTC_MAX 0x57\n\n/**\n * \\brief S3 Trio 64 Video Card\n *\n * Documentation consulted:\n *  - VGADOC4b\n *   (http://home.worldonline.dk/~finth/)\n *  .\n **/\nclass CS3Trio64 : public CVGA {\npublic:\n  virtual int SaveState(FILE *f);\n  virtual int RestoreState(FILE *f);\n  virtual void check_state();\n  virtual void WriteMem_Legacy(int index, u32 address, int dsize, u32 data);\n  virtual u32 ReadMem_Legacy(int index, u32 address, int dsize);\n\n  virtual void WriteMem_Bar(int func, int bar, u32 address, int dsize,\n                            u32 data);\n  virtual u32 ReadMem_Bar(int func, int bar, u32 address, int dsize);\n\n  CS3Trio64(CConfigurator *cfg, class CSystem *c, int pcibus, int pcidev);\n  virtual ~CS3Trio64();\n\n  void update(void);\n  void run(void);\n\n  virtual u8 get_actl_palette_idx(u8 index);\n  virtual void redraw_area(unsigned x0, unsigned y0, unsigned width,\n                           unsigned height);\n\n  virtual void init();\n  virtual void start_threads();\n  virtual void stop_threads();\n\nprivate:\n  u32 mem_read(u32 address, int dsize);\n  void mem_write(u32 address, int dsize, u32 data);\n\n  u32 io_read(u32 address, int dsize);\n  void io_write(u32 address, int dsize, u32 data);\n\n  void io_write_b(u32 address, u8 data);\n\n  void write_b_3c0(u8 data);\n  void write_b_3c2(u8 data);\n  void write_b_3c4(u8 data);\n  void write_b_3c5(u8 data);\n  void write_b_3c6(u8 data);\n  void write_b_3c7(u8 data);\n  void write_b_3c8(u8 data);\n  void write_b_3c9(u8 data);\n  void write_b_3ce(u8 data);\n  void write_b_3cf(u8 data);\n  void write_b_3d4(u8 data);\n  void write_b_3d5(u8 data);\n\n  u8 read_b_3c0();\n  u8 read_b_3c1();\n  u8 read_b_3c2();\n  u8 read_b_3c3();\n  u8 read_b_3c4();\n  u8 read_b_3c5();\n  u8 read_b_3c9();\n  u8 read_b_3ca();\n  u8 read_b_3cc();\n  u8 read_b_3cf();\n  u8 read_b_3d4();\n  u8 read_b_3d5();\n  u8 read_b_3da();\n\n  u32 legacy_read(u32 address, int dsize);\n  void legacy_write(u32 address, int dsize, u32 data);\n\n  u32 rom_read(u32 address, int dsize);\n\n  void determine_screen_dimensions(unsigned *piHeight, unsigned *piWidth);\n\n  char bios_message[200];\n  int bios_message_size;\n\n  void vga_mem_write(u32 addr, u8 value);\n  u8 vga_mem_read(u32 addr);\n\n  std::unique_ptr<std::thread> myThread;\n  std::atomic_bool myThreadDead{false};\n  bool StopThread;\n\n  /// The state structure contains all elements that need to be saved to the\n  /// statefile.\n  struct SS3_state {\n    bool vga_enabled;\n    bool vga_mem_updated;\n    u16 charmap_address;\n    bool x_dotclockdiv2;\n    bool y_doublescan;\n    unsigned line_offset;\n    unsigned line_compare;\n    unsigned vertical_display_end;\n    u8 text_snapshot[32 * 1024]; // current text snapshot\n    bool vga_tile_updated[BX_NUM_X_TILES][BX_NUM_Y_TILES];\n    u8 *memory;\n    u32 memsize;\n    u8 last_bpp;\n    u8 tile[X_TILESIZE * Y_TILESIZE *\n            4]; /**< Currently allocates the tile as large as needed. */\n    unsigned x_tilesize;\n    unsigned y_tilesize;\n\n    struct SS3_attr {\n      bool flip_flop;   /* 0 = address, 1 = data-write */\n      unsigned address; /* register number */\n      bool video_enabled;\n      u8 palette_reg[16];\n      u8 overscan_color;\n      u8 color_plane_enable;\n      u8 horiz_pel_panning;\n      u8 color_select;\n      struct SS3_mode {\n        bool graphics_alpha;\n        bool display_type;\n        bool enable_line_graphics;\n        bool blink_intensity;\n        bool pixel_panning_compat;\n        bool pixel_clock_select;\n        bool internal_palette_size;\n      } mode_ctrl;\n    } attribute_ctrl;\n\n    struct SS3_misc {\n      bool color_emulation; // 1=color emulation, base address = 3Dx\n\n      // 0=mono emulation,  base address = 3Bx\n      bool enable_ram;       // enable CPU access to video memory if set\n      u8 clock_select;       // 0=25Mhz 1=28Mhz\n      bool select_high_bank; // when in odd/even modes, select\n\n      // high 64k bank if set\n      bool horiz_sync_pol; // bit6: negative if set\n      bool vert_sync_pol;  // bit7: negative if set\n\n      //   bit7,bit6 represent number of lines on display:\n      //   0 = reserved\n      //   1 = 400 lines\n      //   2 = 350 lines\n      //   3 - 480 lines\n    } misc_output;\n\n    struct SS3_seq {\n      u8 index;\n      u8 map_mask;\n      bool map_mask_bit[4];\n      bool reset1;\n      bool reset2;\n      u8 reg1;\n      u8 char_map_select;\n      bool extended_mem;\n      bool odd_even;\n      bool chain_four;\n    } sequencer;\n\n    struct SS3_pel {\n      u8 write_data_register;\n      u8 write_data_cycle; /* 0, 1, 2 */\n      u8 read_data_register;\n      u8 read_data_cycle; /* 0, 1, 2 */\n      u8 dac_state;\n      struct SS3_pel_data {\n        u8 red;\n        u8 green;\n        u8 blue;\n      } data[256];\n      u8 mask;\n    } pel;\n\n    struct SS3_gfx {\n      u8 index;\n      u8 set_reset;\n      u8 enable_set_reset;\n      u8 color_compare;\n      u8 data_rotate;\n      u8 raster_op;\n      u8 read_map_select;\n      u8 write_mode;\n      bool read_mode;\n      bool odd_even;\n      bool chain_odd_even;\n      u8 shift_reg;\n      bool graphics_alpha;\n      u8 memory_mapping; /* 0 = use A0000-BFFFF\n                          * 1 = use A0000-AFFFF EGA/VGA graphics modes\n                          * 2 = use B0000-B7FFF Monochrome modes\n                          * 3 = use B8000-BFFFF CGA modes\n                          */\n      u8 color_dont_care;\n      u8 bitmask;\n      u8 latch[4];\n    } graphics_ctrl;\n\n    struct SS3_crtc {\n      u8 address;\n      u8 reg[0x20];\n      bool write_protect;\n    } CRTC;\n  } state;\n};\n#endif // !defined(INCLUDED_S3Trio64_H_)\n"
  },
  {
    "path": "src/SCSIBus.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"SCSIBus.hpp\"\n#include \"StdAfx.hpp\"\n\n/**\n * \\brief Constructor.\n *\n * Initialize all disks to non-existing.\n **/\nCSCSIBus::CSCSIBus(CConfigurator *cfg, CSystem *c) : CSystemComponent(cfg, c) {\n  int i;\n  for (i = 0; i < 16; i++)\n    targets[i] = 0;\n\n  state.phase = SCSI_PHASE_FREE;\n  state.target = -1;\n  state.initiator = -1;\n}\n\n/**\n * \\brief Destructor.\n **/\nCSCSIBus::~CSCSIBus(void) {}\n\n/**\n * \\brief Register a SCSI device.\n *\n * Register a SCSI device as responding to a specific SCSI id.\n **/\nvoid CSCSIBus::scsi_register(CSCSIDevice *dev, int bus, int target) {\n  if (targets[target] && targets[target] != dev)\n    FAILURE(IllegalState, \"More than one SCSI device at the same ID\");\n  targets[target] = dev;\n  target_bus_no[target] = bus;\n}\n\n/**\n * \\brief Unregister a SCSI device.\n *\n * Unregister a SCSI device as responding to a specific SCSI id. Needed\n * for some controllers if software changes it's SCSI id.\n **/\nvoid CSCSIBus::scsi_unregister(CSCSIDevice *dev, int target) {\n  if (targets[target] != dev)\n    FAILURE(IllegalState, \"Attempt to unregister other SCSI device\");\n  targets[target] = 0;\n}\n\n/**\n * \\brief Arbitrate for the SCSI bus.\n *\n * Returns true on succesful arbitration.\n * Arbitration succeeds if the bus is free.\n **/\nbool CSCSIBus::arbitrate(int initiator) {\n  if (state.phase != SCSI_PHASE_FREE && state.initiator != initiator) {\n    printf(\"Could not arbitrate for the SCSI bus.\\n\");\n    return false;\n  }\n\n  state.initiator = initiator;\n  state.phase = SCSI_PHASE_ARBITRATION;\n  return true;\n}\n\n/**\n * \\brief Select a device as a target.\n *\n * Returns true on succesful selection (= if the device responds to the select\n * by changing the SCSI phase.\n * The initiator calling this function should have succesfully arbitrated\n * for the SCSI bus first.\n **/\nbool CSCSIBus::select(int initiator, int target) {\n  if (state.phase != SCSI_PHASE_ARBITRATION || state.initiator != initiator)\n    FAILURE(IllegalState,\n            \"Attempt to select while the device has not won SCSI arbitration\");\n\n  if (!targets[target])\n    return false;\n\n  state.target = target;\n  targets[target]->scsi_select_me(target_bus_no[target]);\n  return (state.phase >= 0);\n}\n\n/**\n * \\brief Change the SCSI phase.\n *\n * Only the selected target can do this.\n **/\nvoid CSCSIBus::set_phase(int target, int phase) {\n  if (targets[target] != targets[state.target])\n    FAILURE(IllegalState,\n            \"Attempt to set phase while the device has not been selected\");\n\n  state.phase = phase;\n}\n\n/**\n * \\brief Release the SCSI bus.\n *\n * In the Arbitration phase, only the initiator can do this; otherwise,\n * only the selected target can do this.\n **/\nvoid CSCSIBus::free_bus(int initiator) {\n\n  // nothing to do\n  if (state.phase == SCSI_PHASE_FREE)\n    return;\n\n  if (state.phase == SCSI_PHASE_ARBITRATION) {\n    if (initiator != state.initiator)\n      FAILURE(IllegalState, \"Attempt to free the scsi bus\");\n  } else {\n    if (targets[initiator] != targets[state.target])\n      FAILURE(IllegalState, \"Attempt to free the scsi bus\");\n  }\n\n  state.phase = SCSI_PHASE_FREE;\n}\n\nstatic u32 scsi_magic1 = 0x5C510123;\nstatic u32 scsi_magic2 = 0x32105c51;\n\n/**\n * Save state to a Virtual Machine State file.\n **/\nint CSCSIBus::SaveState(FILE *f) {\n  long ss = sizeof(state);\n\n  fwrite(&scsi_magic1, sizeof(u32), 1, f);\n  fwrite(&ss, sizeof(long), 1, f);\n  fwrite(&state, sizeof(state), 1, f);\n  fwrite(&scsi_magic2, sizeof(u32), 1, f);\n  printf(\"%s: %d bytes saved.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\n/**\n * Restore state from a Virtual Machine State file.\n **/\nint CSCSIBus::RestoreState(FILE *f) {\n  long ss;\n  u32 m1;\n  u32 m2;\n  size_t r;\n\n  r = fread(&m1, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m1 != scsi_magic1) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&ss, sizeof(long), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (ss != sizeof(state)) {\n    printf(\"%s: STRUCT SIZE does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&state, sizeof(state), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&m2, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m2 != scsi_magic2) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  printf(\"%s: %d bytes restored.\\n\", devid_string, (int)ss);\n  return 0;\n}\n"
  },
  {
    "path": "src/SCSIBus.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(__SCSIBUS__H__)\n#define __SCSIBUS__H__\n\n#include \"SCSIDevice.hpp\"\n#include \"StdAfx.hpp\"\n#include \"SystemComponent.hpp\"\n\n/**\n * \\brief Emulated SCSI bus.\n *\n * connects SCSI Devices (class CSCSIDevice) together; SCSI devices are\n * disks and controllers.\n **/\nclass CSCSIBus : public CSystemComponent {\npublic:\n  CSCSIBus(CConfigurator *cfg, CSystem *c);\n  ~CSCSIBus(void);\n  virtual int SaveState(FILE *f);\n  virtual int RestoreState(FILE *f);\n\n  void scsi_register(CSCSIDevice *dev, int bus, int target);\n  void scsi_unregister(CSCSIDevice *dev, int target);\n\n  bool arbitrate(int initiator);\n  bool select(int initiator, int target);\n  void set_phase(int target, int phase);\n  int get_phase() { return state.phase; };\n\n  /**< Get current SCSI bus phase **/\n  void free_bus(int initiator);\n\n  CSCSIDevice *targets[16]; /**< pointers to the SCSI devices that respond to\n                               the 15 possible target id's. **/\n  int target_bus_no[16]; /**< indicates what bus this is for each connected SCSI\n                     device. always 0 for disks, but controllers could have\n                     multiple SCSI busses. **/\n\n  /// The state structure contains all elements that need to be saved to the\n  /// statefile\n  struct SSCSI_state {\n    int initiator; /**< SCSI id of the initiator. **/\n    int target;    /**< SCSI id of the target. **/\n    int phase;     /**< SCSI bus phase. **/\n  } state;\n};\n\n#define SCSI_PHASE_FREE -2\n#define SCSI_PHASE_ARBITRATION -1\n#define SCSI_PHASE_DATA_OUT 0\n#define SCSI_PHASE_DATA_IN 1\n#define SCSI_PHASE_COMMAND 2\n#define SCSI_PHASE_STATUS 3\n#define SCSI_PHASE_MSG_OUT 6\n#define SCSI_PHASE_MSG_IN 7\n#endif\n"
  },
  {
    "path": "src/SCSIDevice.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"SCSIDevice.hpp\"\n#include \"SCSIBus.hpp\"\n\n/**\n * \\brief Constructor.\n *\n * Set this device as unregistered with any SCSI bus.\n **/\nCSCSIDevice::CSCSIDevice(void) {\n  int i;\n  for (i = 0; i < 10; i++) {\n    scsi_bus[i] = 0;\n    scsi_initiator_id[i] = -1;\n  }\n}\n\n/**\n * \\brief Destructor.\n **/\nCSCSIDevice::~CSCSIDevice(void) {}\n\n/**\n * \\brief Register this device with a SCSI bus.\n **/\nvoid CSCSIDevice::scsi_register(int busno, class CSCSIBus *with, int target) {\n  scsi_bus[busno] = with;\n  scsi_initiator_id[busno] = target;\n  scsi_bus[busno]->scsi_register(this, busno, target);\n}\n\n/**\n * \\brief Arbitrate for the SCSI bus.\n *\n * See CSCSIBus::arbitrate for a description.\n **/\nbool CSCSIDevice::scsi_arbitrate(int bus) {\n  return scsi_bus[bus]->arbitrate(scsi_initiator_id[bus]);\n}\n\n/**\n * \\brief Select a target on the SCSI bus.\n *\n * See CSCSIBus::select for a description.\n **/\nbool CSCSIDevice::scsi_select(int bus, int target) {\n  return scsi_bus[bus]->select(scsi_initiator_id[bus], target);\n}\n\n/**\n * \\brief Called when this device is selected.\n *\n * Override this to allow this device to be selected. Overrided\n * functions should at least call scsi_set_phase to set\n * the SCSI bus phase to a valid phase.\n **/\nvoid CSCSIDevice::scsi_select_me(int bus) {\n  FAILURE(NotImplemented, \"selected device doesn't implement scsi_select_me\");\n}\n\n/**\n * \\brief Change the SCSI bus phase.\n *\n * See CSCSIBus::set_phase for a description.\n **/\nvoid CSCSIDevice::scsi_set_phase(int bus, int phase) {\n  scsi_bus[bus]->set_phase(scsi_initiator_id[bus], phase);\n}\n\n/**\n * \\brief Get the current SCSI bus phase.\n *\n * See CSCSIBus::get_phase for a description.\n **/\nint CSCSIDevice::scsi_get_phase(int bus) { return scsi_bus[bus]->get_phase(); }\n\n/**\n * \\brief Release the SCSI bus.\n *\n * See CSCSIBus::free_bus for a description.\n **/\nvoid CSCSIDevice::scsi_free(int bus) {\n  return scsi_bus[bus]->free_bus(scsi_initiator_id[bus]);\n}\n\n/**\n * \\brief Return the number of bytes expected or available.\n *\n * Override this to return the number of bytes the device\n * expects to receive from the initiator, or has available\n * for the initiator, in the current SCSI phase.\n *\n * For an overview of data transfer during a SCSI bus phase,\n * see SCSIDevice::scsi_xfer_ptr.\n **/\nsize_t CSCSIDevice::scsi_expected_xfer_me(int bus) {\n  FAILURE(NotImplemented,\n          \"selected device doesn't implement scsi_expected_xfer_me\");\n}\n\n/**\n * \\brief Return the number of bytes expected or available.\n *\n * Returns the number of bytes the currently selected target\n * expects to receive from the initiator, or has available\n * for the initiator, in the current SCSI phase.\n *\n * For an overview of data transfer during a SCSI bus phase,\n * see SCSIDevice::scsi_xfer_ptr.\n **/\nsize_t CSCSIDevice::scsi_expected_xfer(int bus) {\n  return scsi_bus[bus]\n      ->targets[scsi_bus[bus]->state.target]\n      ->scsi_expected_xfer_me(\n          scsi_bus[bus]->target_bus_no[scsi_bus[bus]->state.target]);\n}\n\n/**\n * \\brief Return a pointer where the initiator can read or write data.\n *\n * Override this to return a pointer to where the initiator\n * can read or write data in the current SCSI phase.\n *\n * For an overview of data transfer during a SCSI bus phase,\n * see SCSIDevice::scsi_xfer_ptr.\n **/\nvoid *CSCSIDevice::scsi_xfer_ptr_me(int bus, size_t bytes) {\n  FAILURE(NotImplemented, \"selected device doesn't implement scsi_xfer_ptr_me\");\n}\n\n/**\n * \\brief Return a pointer where target data can be read or written.\n *\n * Returns a pointer to where the initiator can read or\n * write data from/to the currentlt selected target in\n * the current SCSI phase.\n *\n * The initiator should do the following for each transfer:\n *   - Check the current phase using CSCSIDevice::scsi_get_phase.\n *   - Check the amount of data to transfer using\n *     CSCSIDevice::scsi_expected_xfer.\n *   - Signal intent to transfer data, and obtain a pointer\n *     using SCSIDevice::scsi_xfer_ptr.\n *   - Transfer data using the returned pointer.\n *   - Call CSCSIDevice::scsi_xfer_done to the the target\n *     process the data and/or transfer to a new phase.\n *   .\n **/\nvoid *CSCSIDevice::scsi_xfer_ptr(int bus, size_t bytes) {\n  return scsi_bus[bus]->targets[scsi_bus[bus]->state.target]->scsi_xfer_ptr_me(\n      scsi_bus[bus]->target_bus_no[scsi_bus[bus]->state.target], bytes);\n}\n\n/**\n * \\brief Process data written or read.\n *\n * Override this to process data read or written in\n * the current SCSI phase.\n *\n * For an overview of data transfer during a SCSI bus phase,\n * see SCSIDevice::scsi_xfer_ptr.\n **/\nvoid CSCSIDevice::scsi_xfer_done_me(int bus) {\n  FAILURE(NotImplemented,\n          \"selected device doesn't implement scsi_xfer_done_me\");\n}\n\n/**\n * \\brief Mark data transfer done.\n *\n * Let the target know that data has been transfered for the\n * current SCSI phase.\n *\n * For an overview of data transfer during a SCSI bus phase,\n * see SCSIDevice::scsi_xfer_ptr.\n **/\nvoid CSCSIDevice::scsi_xfer_done(int bus) {\n  scsi_bus[bus]->targets[scsi_bus[bus]->state.target]->scsi_xfer_done_me(\n      scsi_bus[bus]->target_bus_no[scsi_bus[bus]->state.target]);\n}\n"
  },
  {
    "path": "src/SCSIDevice.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(__SCSIDEVICE__H__)\n#define __SCSIDEVICE__H__\n\n#include \"StdAfx.hpp\"\n\n/**\n * \\brief Base class for emulated SCSI devices.\n *\n * Connects to one or more SCSI busses (class CSCSIBus) together; derived\n * SCSI devices are disks and controllers.\n **/\nclass CSCSIDevice {\npublic:\n  CSCSIDevice(void);\n  virtual ~CSCSIDevice(void);\n\n  void scsi_register(int busno, class CSCSIBus *with, int target);\n\n  bool scsi_arbitrate(int bus);\n  bool scsi_select(int bus, int target);\n  virtual void scsi_select_me(int bus);\n  void scsi_set_phase(int bus, int phase);\n  int scsi_get_phase(int bus);\n  void scsi_free(int bus);\n\n  virtual size_t scsi_expected_xfer_me(int bus);\n  size_t scsi_expected_xfer(int bus);\n\n  virtual void *scsi_xfer_ptr_me(int bus, size_t bytes);\n  void *scsi_xfer_ptr(int bus, size_t bytes);\n\n  virtual void scsi_xfer_done_me(int bus);\n  void scsi_xfer_done(int bus);\n\nprotected:\n  class CSCSIBus *scsi_bus[10]; /**< SCSI busses this device connects to. Disks\n                        connect to 1 bus only, controllers can have\n                        several SCSI busses. **/\n  int scsi_initiator_id[10];    /**< Main SCSI id of this device on each of the\n                                   busses. **/\n};\n#endif\n"
  },
  {
    "path": "src/Serial.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"Serial.hpp\"\n#include \"AliM1543C.hpp\"\n#include \"StdAfx.hpp\"\n#include \"System.hpp\"\n\n#include \"lockstep.hpp\"\n\n#define RECV_TICKS 10\n\nint iCounter = 0;\n\n#define FIFO_SIZE 1024\n\n//#define DEBUG_SERIAL 1\n\n/**\n * Constructor.\n **/\nCSerial::CSerial(CConfigurator *cfg, CSystem *c, u16 number)\n    : CSystemComponent(cfg, c) {\n  state.iNumber = number;\n  breakHit = false;\n}\n\n/**\n * Initialize the Serial port device.\n **/\nvoid CSerial::init() {\n  listenPort = (int)myCfg->get_num_value(\"port\", false, 8000 + state.iNumber);\n  if (!(listenAddress = myCfg->get_text_value(\"address\"))) {\n    listenAddress = \"0.0.0.0\";\n  }\n  cSystem->RegisterMemory(this, 0,\n                          U64(0x00000801fc0003f8) - (0x100 * state.iNumber), 8);\n\n  // Start Telnet server\n#if defined(_WIN32)\n  // Windows Sockets only work after calling WSAStartup.\n  WSADATA wsa;\n  WSAStartup(0x0101, &wsa);\n#endif // defined (_WIN32)\n  struct sockaddr_in Address;\n\n  listenSocket = (int)socket(AF_INET, SOCK_STREAM, 0);\n  if (listenSocket == INVALID_SOCKET) {\n    printf(\"Could not open socket to listen on!\\n\");\n  }\n\n  inet_aton(listenAddress, (in_addr *) &Address.sin_addr.s_addr);\n  Address.sin_port = htons((u16)(listenPort));\n  Address.sin_family = AF_INET;\n\n  int optval = 1;\n  setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&optval,\n             sizeof(optval));\n  bind(listenSocket, (struct sockaddr *)&Address, sizeof(Address));\n  listen(listenSocket, 1);\n\n  printf(\"%s: Waiting for connection on port %d.\\n\", devid_string, listenPort);\n\n  WaitForConnection();\n\n#if defined(IDB) && defined(LS_MASTER)\n  struct sockaddr_in dest_addr;\n  int result = -1;\n\n  throughSocket = socket(AF_INET, SOCK_STREAM, 0);\n\n  dest_addr.sin_family = AF_INET;\n  dest_addr.sin_port = htons((u16)(base + number));\n  dest_addr.sin_addr.s_addr = inet_addr(ls_IP);\n\n  printf(\"%s: Waiting to initiate remote connection to %s.\\n\", devid_string,\n         ls_IP);\n\n  while (result == -1) {\n    result = connect(throughSocket, (struct sockaddr *)&dest_addr,\n                     sizeof(struct sockaddr));\n  }\n#endif\n  state.rcvW = 0;\n  state.rcvR = 0;\n\n  state.bLCR = 0x00;\n  state.bLSR = 0x60; // THRE, TSRE\n  state.bMSR = 0x30; // CTS, DSR\n  state.bIIR = 0x01; // no interrupt\n  state.irq_active = false;\n\n  printf(\"%s: $Id: Serial.cpp,v 1.51 2008/06/03 09:07:56 iamcamiel Exp $\\n\",\n         devid_string);\n}\n\nvoid CSerial::start_threads() {\n  char buffer[5];\n  if (!myThread) {\n    sprintf(buffer, \"srl%d\", state.iNumber);\n    printf(\" %s\", buffer);\n    StopThread = false;\n    myThread = std::make_unique<std::thread>([this](){ this->run(); });\n  }\n}\n\nvoid CSerial::stop_threads() {\n  char buffer[5];\n  StopThread = true;\n  if (myThread) {\n    sprintf(buffer, \"srl%d\", state.iNumber);\n    printf(\" %s\", buffer);\n    if (!acceptingSocket) {\n      myThread->join();\n    }\n    myThread = nullptr;\n  }\n}\n\n/**\n * Destructor.\n **/\nCSerial::~CSerial() { stop_threads(); }\n\nu64 CSerial::ReadMem(int index, u64 address, int dsize) {\n  u8 d;\n\n  switch (address) {\n  case 0: // data buffer\n    if (state.bLCR & 0x80) {\n      return state.bBRB_LSB;\n    } else {\n      if (state.rcvR != state.rcvW) {\n        state.bRDR = state.rcvBuffer[state.rcvR];\n        state.rcvR++;\n        if (state.rcvR == FIFO_SIZE)\n          state.rcvR = 0;\n        TRC_DEV4(\"Read character %02x (%c) on serial port %d\\n\", state.bRDR,\n                 printable(state.bRDR), state.iNumber);\n#if defined(DEBUG_SERIAL)\n        printf(\"Read character %02x (%c) on serial port %d\\n\", state.bRDR,\n               printable(state.bRDR), state.iNumber);\n#endif\n      } else {\n        TRC_DEV2(\"Read past FIFO on serial port %d\\n\", state.iNumber);\n#if defined(DEBUG_SERIAL)\n        printf(\"Read past FIFO on serial port %d\\n\", state.iNumber);\n#endif\n      }\n\n      return state.bRDR;\n    }\n\n  case 1:\n    if (state.bLCR & 0x80) {\n      return state.bBRB_MSB;\n    } else {\n      return state.bIER;\n    }\n\n  case 2: // interrupt cause\n    d = state.bIIR;\n    state.bIIR = 0x01;\n    return d;\n\n  case 3:\n    return state.bLCR;\n\n  case 4:\n    return state.bMCR;\n\n  case 5: // serialization state\n    if (state.rcvR != state.rcvW)\n      state.bLSR = 0x61; // THRE, TSRE, RxRD\n    else\n      state.bLSR = 0x60; // THRE, TSRE\n    return state.bLSR;\n\n  case 6:\n    return state.bMSR;\n\n  default:\n    return state.bSPR;\n  }\n}\n\nvoid CSerial::WriteMem(int index, u64 address, int dsize, u64 data) {\n  u8 d;\n  char s[5];\n  d = (u8)data;\n\n  switch (address) {\n  case 0:\n    if (state.bLCR & 0x80) // divisor latch access bit set\n    {\n\n      // LSB of divisor latch\n      state.bBRB_LSB = d;\n    } else {\n\n      // Transmit Hold Register\n      sprintf(s, \"%c\", d);\n      write(s);\n      TRC_DEV4(\"Write character %02x (%c) on serial port %d\\n\", d, printable(d),\n               state.iNumber);\n#if defined(DEBUG_SERIAL)\n      printf(\"Write character %02x (%c) on serial port %d\\n\", d, printable(d),\n             state.iNumber);\n#endif\n      eval_interrupts();\n    }\n    break;\n\n  case 1:\n    if (state.bLCR & 0x80) // divisor latch access bit set\n    {\n\n      // MSB of divisor latch\n      state.bBRB_MSB = d;\n    } else {\n\n      // Interrupt Enable Register\n      state.bIER = d;\n      eval_interrupts();\n    }\n    break;\n\n  case 2:\n    state.bFCR = d;\n    break;\n\n  case 3:\n    state.bLCR = d;\n    break;\n\n  case 4:\n    state.bMCR = d;\n    break;\n\n  default:\n    state.bSPR = d;\n  }\n}\n\nvoid CSerial::eval_interrupts() {\n  state.bIIR = 0x01; // no interrupt\n  if ((state.bIER & 0x01) && (state.rcvR != state.rcvW))\n    state.bIIR = 0x04;\n  else if (state.bIER & 0x2) // transmitter buffer empty enabled?\n    state.bIIR = 0x02;       // transmitter buffer empty\n  else\n    state.bIIR = 0x01; // no interrupt\n  if (state.bIIR > 0x01) {\n    if (!state.irq_active)\n      theAli->pic_interrupt(0, 4 - state.iNumber);\n  } else {\n    if (state.irq_active)\n      theAli->pic_deassert(0, 4 - state.iNumber);\n  }\n}\n\nvoid CSerial::write(const char *s) {\n  send(connectSocket, s, (int)strlen(s) + 1, 0);\n}\n\nvoid CSerial::receive(const char *data) {\n  char *x;\n\n  x = (char *)data;\n\n  while (*x) {\n    state.rcvBuffer[state.rcvW++] = *x;\n    if (state.rcvW == FIFO_SIZE)\n      state.rcvW = 0;\n    x++;\n    eval_interrupts();\n  }\n}\n\n/**\n * Thread entry point.\n **/\nvoid CSerial::run() {\n  try {\n    for (;;) {\n      if (StopThread)\n        return;\n      execute();\n      std::this_thread::sleep_for(std::chrono::milliseconds(5));\n    }\n  }\n\n  catch (CException &e) {\n    printf(\"Exception in Serial thread: %s.\\n\", e.displayText().c_str());\n    myThreadDead.store(true);\n    // Let the thread die...\n  }\n}\n\n/**\n * Check if threads are still running.\n *\n * Enter serial port menu if <break> was received.\n **/\nvoid CSerial::check_state() {\n  if (breakHit)\n    serial_menu();\n\n  if (myThreadDead.load())\n    FAILURE(Thread, \"Serial thread has died\");\n}\n\nvoid CSerial::serial_menu() {\n  fd_set readset;\n  unsigned char buffer[FIFO_SIZE + 1];\n  ssize_t size;\n  struct timeval tv;\n  bool exitLoop = false;\n\n  cSystem->stop_threads();\n\n  write(\"\\r\\n<BREAK> received. What do you want to do?\\r\\n\");\n  write(\"     0. Continue\\r\\n\");\n#if defined(IDB)\n  write(\"     1. End run\\r\\n\");\n#else\n  write(\"     1. Exit emulator gracefully\\r\\n\");\n  write(\"     2. Abort emulator (no changes saved)\\r\\n\");\n  write(\"     3. Save state to autosave.axp and continue\\r\\n\");\n  write(\"     4. Load state from autosave.axp and continue\\r\\n\");\n#endif\n  while (!exitLoop) {\n    FD_ZERO(&readset);\n    FD_SET(connectSocket, &readset);\n    tv.tv_sec = 60;\n    tv.tv_usec = 0;\n    if (select(connectSocket + 1, &readset, NULL, NULL, &tv) <= 0) {\n      write(\"%SRL-I-TIMEOUT: no timely answer received. Continuing \"\n            \"emulation.\\r\\n\");\n      break; // leave loop\n    }\n\n#if defined(_WIN32) || defined(__VMS)\n    size = recv(connectSocket, (char *)buffer, FIFO_SIZE, 0);\n#else\n    size = read(connectSocket, &buffer, FIFO_SIZE);\n#endif\n    switch (buffer[0]) {\n    case '0':\n      write(\"%SRL-I-CONTINUE: continuing emulation.\\r\\n\");\n      exitLoop = true;\n      break;\n\n    case '1':\n      write(\"%SRL-I-EXIT: exiting emulation gracefully.\\r\\n\");\n      FAILURE(Graceful, \"Graceful exit\");\n      exitLoop = true;\n      break;\n\n    case '2':\n      write(\"%SRL-I-ABORT: aborting emulation.\\r\\n\");\n      FAILURE(Abort, \"Aborting\");\n      exitLoop = true;\n      break;\n\n    case '3':\n      write(\"%SRL-I-SAVESTATE: Saving state to autosave.axp.\\r\\n\");\n      cSystem->SaveState(\"autosave.axp\");\n      write(\"%SRL-I-CONTINUE: continuing emulation.\\r\\n\");\n      exitLoop = true;\n      break;\n\n    case '4':\n      write(\"%SRL-I-LOADSTATE: Loading state from autosave.axp.\\r\\n\");\n      cSystem->RestoreState(\"autosave.axp\");\n      write(\"%SRL-I-CONTINUE: continuing emulation.\\r\\n\");\n      exitLoop = true;\n      break;\n\n    default:\n      write(\"%SRL-W-INVALID: Not a valid answer.\\r\\n\");\n    }\n  }\n\n  breakHit = false;\n  cSystem->start_threads();\n}\n\nvoid CSerial::execute() {\n  fd_set readset;\n  unsigned char buffer[FIFO_SIZE + 1];\n  unsigned char cbuffer[FIFO_SIZE + 1]; // cooked buffer\n  unsigned char *b;\n\n  // cooked buffer\n  unsigned char *c;\n  ssize_t size;\n  struct timeval tv;\n\n  state.serial_cycles++;\n  if (state.serial_cycles >= RECV_TICKS) {\n    FD_ZERO(&readset);\n    FD_SET(connectSocket, &readset);\n    tv.tv_sec = 0;\n    tv.tv_usec = 0;\n    if (select(connectSocket + 1, &readset, NULL, NULL, &tv) > 0) {\n#if defined(_WIN32) || defined(__VMS)\n\n      // Windows Sockets has no direct equivalent of BSD's read\n      size = recv(connectSocket, (char *)buffer, FIFO_SIZE, 0);\n#else\n      size = read(connectSocket, &buffer, FIFO_SIZE);\n#endif\n\n      extern int got_sigint;\n      if (size == 0 && !got_sigint) {\n        printf(\"%%SRL-W-DISCONNECT: Write socket closed on other end for \"\n               \"serial port %d.\\n\",\n               state.iNumber);\n        printf(\"-SRL-I-WAITFOR: Waiting for a new connection on port %d.\\n\",\n               listenPort);\n        WaitForConnection();\n        return;\n      }\n\n      buffer[size + 1] = 0; // force null termination.\n      b = buffer;\n      c = cbuffer;\n      while ((ssize_t)(b - buffer) < size) {\n        if (*b == 0x0a) {\n          b++; // skip LF\n          continue;\n        }\n\n        if (*b == IAC) {\n          if (*(b + 1) == IAC) { // escaped IAC.\n            b++;\n          } else if (*(b + 1) >= WILL) { // will/won't/do/don't\n            b += 3; // skip this byte, and following two. (telnet escape)\n            continue;\n          } else if (*(b + 1) == SB) { // skip until IAC SE\n            b += 2;                    // now we're at start of subnegotiation.\n            while (*b != IAC && *(b + 1) != SE)\n              b++;\n            b += 2;\n            continue;\n          } else if (*(b + 1) == BREAK) { // break (== halt button?)\n            b += 2;\n            breakHit = true;\n          } else if (*(b + 1) == AYT) { // are you there?\n          } else {                      // misc single byte command.\n            b += 2;\n            continue;\n          }\n        }\n\n        *c = *b;\n        c++;\n        b++;\n      }\n\n      *c = 0; // null terminate it.\n      this->receive((const char *)&cbuffer);\n    }\n\n    state.serial_cycles = 0;\n  }\n\n  eval_interrupts();\n}\n\nstatic u32 srl_magic1 = 0x5A15A15A;\nstatic u32 srl_magic2 = 0x1A51A51A;\n\n/**\n * Save state to a Virtual Machine State file.\n **/\nint CSerial::SaveState(FILE *f) {\n  long ss = sizeof(state);\n\n  fwrite(&srl_magic1, sizeof(u32), 1, f);\n  fwrite(&ss, sizeof(long), 1, f);\n  fwrite(&state, sizeof(state), 1, f);\n  fwrite(&srl_magic2, sizeof(u32), 1, f);\n  printf(\"%s: %d bytes saved.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\n/**\n * Restore state from a Virtual Machine State file.\n **/\nint CSerial::RestoreState(FILE *f) {\n  long ss;\n  u32 m1;\n  u32 m2;\n  size_t r;\n\n  r = fread(&m1, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m1 != srl_magic1) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&ss, sizeof(long), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (ss != sizeof(state)) {\n    printf(\"%s: STRUCT SIZE does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&state, sizeof(state), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&m2, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m2 != srl_magic2) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  printf(\"%s: %d bytes restored.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\nvoid CSerial::WaitForConnection() {\n  struct sockaddr_in Address;\n  socklen_t nAddressSize = sizeof(struct sockaddr_in);\n  const char *telnet_options = \"%c%c%c\";\n  char buffer[8];\n  char s[1000];\n  char *nargv = s;\n  int i = 0;\n\n#if !defined(LS_SLAVE)\n  char s2[200];\n  char *argv[20];\n\n  strncpy(s, myCfg->get_text_value(\"action\", \"\"), 999);\n  s[999] = '\\0';\n\n  // printf(\"%s: Specified : %s\\n\",devid_string,s);\n  if (strcmp(s, \"\")) {\n\n    // spawn external program (telnet client)...\n    while (*nargv) {\n      argv[i] = nargv;\n      if (nargv[0] == '\\\"')\n        nargv = strchr(nargv + 1, '\\\"');\n      if (nargv)\n        nargv = strchr(nargv, ' ');\n      if (!nargv)\n        break;\n      *nargv++ = '\\0';\n      i++;\n      argv[i] = NULL;\n    }\n\n    argv[i + 1] = NULL;\n    strcpy(s2, argv[0]);\n    nargv = s2;\n    if (nargv[0] == '\\\"') {\n      nargv++;\n      *(strchr(nargv, '\\\"')) = '\\0';\n    }\n\n    // printf(\"%s: Starting %s\\n\", devid_string,nargv);\n#if defined(_WIN32)\n    if (_spawnvp(_P_NOWAIT, nargv, argv) < 0)\n      FAILURE_1(Runtime, \"Exec of '%s' has failed.\\n\", argv[0]);\n#elif !defined(__VMS)\n    pid_t child;\n    int status;\n    if (!(child = fork())) {\n      execvp(argv[0], argv);\n      FAILURE_1(Runtime, \"Exec of '%s' failed.\\n\", argv[0]);\n    } else {\n      sleep(1);                         // give it a chance to start up.\n      waitpid(child, &status, WNOHANG); // reap it, if needed.\n      if (kill(child, 0) < 0) {         // uh oh, no kiddo.\n        FAILURE_1(Runtime, \"Exec of '%s' has failed.\\n\", argv[0]);\n      }\n    }\n#endif\n  }\n#endif\n  Address.sin_addr.s_addr = INADDR_ANY;\n  Address.sin_port = htons((u16)listenPort);\n  Address.sin_family = AF_INET;\n\n  //  Wait until we have a connection\n  connectSocket = INVALID_SOCKET;\n  while (connectSocket == INVALID_SOCKET) {\n    acceptingSocket = true;\n    connectSocket =\n        (int)accept(listenSocket, (struct sockaddr *)&Address, &nAddressSize);\n    acceptingSocket = false;\n  }\n\n  state.serial_cycles = 0;\n\n  // Send some control characters to the telnet client to handle\n  // character-at-a-time mode.\n  sprintf(buffer, telnet_options, IAC, DO, TELOPT_ECHO);\n  this->write(buffer);\n\n  sprintf(buffer, telnet_options, IAC, DO, TELOPT_NAWS);\n  write(buffer);\n\n  sprintf(buffer, telnet_options, IAC, DO, TELOPT_LFLOW);\n  this->write(buffer);\n\n  sprintf(buffer, telnet_options, IAC, WILL, TELOPT_ECHO);\n  this->write(buffer);\n\n  sprintf(buffer, telnet_options, IAC, WILL, TELOPT_SGA);\n  this->write(buffer);\n\n  sprintf(s, \"This is serial port #%d on ES40 Emulator\\r\\n\", state.iNumber);\n  this->write(s);\n}\n"
  },
  {
    "path": "src/Serial.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_SERIAL_H)\n#define INCLUDED_SERIAL_H\n\n#include \"SystemComponent.hpp\"\n#include \"telnet.hpp\"\n\n/**\n * \\brief Emulated serial port.\n *\n * The serial port is translated to a telnet port.\n **/\nclass CSerial : public CSystemComponent {\npublic:\n  void write(const char *s);\n  virtual void WriteMem(int index, u64 address, int dsize, u64 data);\n  virtual u64 ReadMem(int index, u64 address, int dsize);\n  CSerial(CConfigurator *cfg, CSystem *c, u16 number);\n  virtual ~CSerial();\n  void receive(const char *data);\n  virtual void check_state();\n  virtual int SaveState(FILE *f);\n  virtual int RestoreState(FILE *f);\n  void eval_interrupts();\n  void WaitForConnection();\n  void run();\n  void execute();\n\n  virtual void init();\n  virtual void start_threads();\n  virtual void stop_threads();\n\nprivate:\n  void serial_menu();\n  std::unique_ptr<std::thread> myThread;\n  std::atomic_bool myThreadDead{false};\n  bool StopThread = false;\n  bool acceptingSocket = false;\n  bool breakHit;\n\n  /// The state structure contains all elements that need to be saved to the\n  /// statefile.\n  struct SSrl_state {\n    u8 bTHR; /**< Transmit Hold Register */\n    u8 bRDR; /**< Received Data Register */\n    u8 bBRB_LSB;\n    u8 bBRB_MSB;\n    u8 bIER; /**< Interrupt Enable Register */\n    u8 bIIR; /**< Interrupt Identification Register */\n    u8 bFCR;\n    u8 bLCR; /**< Line Control Register (Data Format Register) */\n    u8 bMCR; /**< Modem Control Register */\n    u8 bLSR; /**< Line Status Register */\n    u8 bMSR; /**< Modem Status Register */\n    u8 bSPR; /**< Scratch Pad Register */\n    int serial_cycles;\n    char rcvBuffer[1024];\n    int rcvW;\n    int rcvR;\n    int iNumber;\n    bool irq_active;\n  } state;\n  int listenPort;\n  const char *listenAddress;\n  int listenSocket;\n  int connectSocket;\n#if defined(IDB) && defined(LS_MASTER)\n  int throughSocket;\n#endif\n};\n#endif // !defined(INCLUDED_SERIAL_H)\n"
  },
  {
    "path": "src/ShrinkingChoiceQuestion.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n/**\n * Question class implementing a \"Shrinking Choice\" question.\n *\n * A shrinking choice question is a multiple choice question\n * where each answer given is removed from the list of valid\n * answers.\n **/\nclass ShrinkingChoiceQuestion : public MultipleChoiceQuestion {\n  /**\n   * Overridden to remove the answer that was given from the\n   * allowed answer set.\n   **/\n  virtual void haveChosen(string choice) { dropChoice(choice); }\n};\n"
  },
  {
    "path": "src/StdAfx.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_STDAFX_H)\n#define INCLUDED_STDAFX_H\n\n// Include generated file with debugging flags (defines)\n#include \"config_debug.hpp\"\n\n#include \"config.hpp\"\n\n#include \"datatypes.hpp\"\n\n#ifdef _WIN32\n#pragma comment( lib, \"ws2_32.lib\")\n#endif /* _WIN32 */\n\n#if defined(HAVE_WINDOWS_H)\n#include \"windows.h\"\n#endif\n\n#if !defined(HAVE_STRCASECMP)\n#if defined(HAVE__STRICMP)\n        #define strcasecmp(a, b) _stricmp(a, b)\n    #else\n        #ifdef _MSC_VER\n            #define strcasecmp _stricmp\n        #else\n            #error \"Need strcasecmp\"\n        #endif\n    #endif\n#endif // !defined(HAVE_STRCASECMP)\n\n#if !defined(HAVE_STRNCASECMP)\n#if defined(HAVE__STRNICMP)\n        #define strncasecmp(a, b, c) _strnicmp(a, b, c)\n    #else\n        #ifdef _MSC_VER\n            #define strncasecmp _strnicmp\n        #else\n            #error \"Need strncasecmp\"\n        #endif\n    #endif\n#endif // !defined(HAVE_STRNCASECMP)\n\n#if defined(HAVE_PROCESS_H)\n#include <process.h>\n#endif\n\n#if !defined(HAVE__STRDUP)\n#if defined(HAVE_STRDUP)\n#define _strdup(a) strdup(a)\n#else\n#error \"Need strdup\"\n#endif\n#endif // !defined(HAVE__STRDUP)\n\n#if defined(HAVE_SYS_TIME_H)\n#include <sys/time.h>\n#endif\n\n#if defined(HAVE_UNISTD_H)\n#include <unistd.h>\n#endif\n\n#if defined(HAVE_PTHREAD_H)\n#include <pthread.h>\n#endif\n\n#if defined(HAVE_SIGNAL_H)\n#include <signal.h>\n#endif\n\n#if defined(HAVE_SYS_WAIT_H)\n#include <sys/wait.h>\n#endif\n\n#if defined(HAVE_STDLIB_H)\n#include <stdlib.h>\n#endif\n\n#if defined(HAVE_STDIO_H)\n#include <stdio.h>\n#endif\n\n#if defined(HAVE_STDDEF_H)\n#include <stddef.h>\n#endif\n\n#if defined(HAVE_STRING_H)\n#include <string.h>\n#endif\n\n#if defined(HAVE_MALLOC_H)\n#include <malloc.h>\n#endif\n\n#if defined(HAVE_TIME_H)\n#include <time.h>\n#endif\n\n#if defined(HAVE_CTYPE_H)\n#include <ctype.h>\n#endif\n\n#if !defined(HAVE_GMTIME_S)\ninline void gmtime_s(struct tm *t1, time_t *t2) {\n  struct tm *t3;\n  t3 = gmtime(t2);\n  memcpy(t1, t3, sizeof(struct tm));\n}\n#endif\n\n#if !defined(HAVE_LOCALTIME_S)\n#ifdef _WIN32\ninline struct tm *localtime_s(struct tm *buf, time_t *timer)\n#else\ninline struct tm *localtime_s(time_t *timer, struct tm *buf)\n#endif\n{\n  struct tm *tmp;\n  tmp = localtime(timer);\n  return (struct tm*) memcpy(buf, tmp, sizeof(struct tm));\n}\n#endif\n\n#if !defined(HAVE_ISBLANK)\ninline bool isblank(char c) {\n  if (c == ' ' || c == '\\t' || c == '\\n' || c == '\\r')\n    return true;\n  return false;\n}\n#endif\n\ninline char printable(char c) {\n  if (isprint((unsigned char)c))\n    return c;\n  return '.';\n}\n\n#if defined(HAVE__FSEEKI64)\n#define fseek_large _fseeki64\n#elif defined(HAVE_FSEEKO64)\n#define fseek_large fseeko64\n#elif defined(HAVE_FSEEKO)\n#define fseek_large fseeko\n#elif defined(HAVE_FSEEK)\n#define fseek_large fseek\n#else\n#error \"Need fseek\"\n#endif\n\n#if defined(HAVE__FTELLI64)\n#define ftell_large _ftelli64\n#define off_t_large __int64\n#elif defined(HAVE_FTELLO64)\n#define ftell_large ftello64\n#define off_t_large off64_t\n#elif defined(HAVE_FTELLO)\n#define ftell_large ftello\n#define off_t_large off_t\n#elif defined(HAVE_FTELL)\n#define ftell_large ftell\n#define off_t_large off_t\n#else\n#error \"Need ftell\"\n#endif\n\n#include <atomic>\n#include <memory>\n#include <thread>\n#include <typeinfo>\n\n#define POCO_NO_UNWINDOWS\n\n#include \"base/Mutex.hpp\"\n#include \"base/RWLock.hpp\"\n#include \"base/Semaphore.hpp\"\n#include \"base/Timestamp.hpp\"\n\n#include \"es40_debug.hpp\"\n\n#include \"es40_endian.hpp\"\n\n#if __cplusplus < 201402L\n#ifndef _WIN32\n#include \"make_unique.hpp\"\n#endif\n#endif\n\n#endif // !defined(INCLUDED_STDAFX_H)\n"
  },
  {
    "path": "src/Sym53C810.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if defined(DEBUG_SYM)\n#define DEBUG_SYM_REGS\n#define DEBUG_SYM_SCRIPTS\n#endif\n#include \"Sym53C810.hpp\"\n#include \"Disk.hpp\"\n#include \"SCSIBus.hpp\"\n#include \"StdAfx.hpp\"\n#include \"System.hpp\"\n\n/// Register 00: SCNTL0: SCSI Control 0\n#define R_SCNTL0 0x00\n#define R_SCNTL0_ARB1 0x80\n#define R_SCNTL0_ARB0 0x40\n#define R_SCNTL0_START 0x20\n#define R_SCNTL0_WATN 0x10\n#define R_SCNTL0_EPC 0x08\n#define R_SCNTL0_AAP 0x02\n#define R_SCNTL0_TRG 0x01\n#define SCNTL0_MASK 0xFB\n\n/// Register 01: SCNTL1: SCSI Control 1\n#define R_SCNTL1 0x01\n#define R_SCNTL1_CON 0x10\n#define R_SCNTL1_RST 0x08\n#define R_SCNTL1_IARB 0x02\n\n/// Register 02: SCNTL2: SCSI Control 2\n#define R_SCNTL2 0x02\n#define R_SCNTL2_SDU 0x80\n#define SCNTL2_MASK 0x80\n\n/// Register 03: SCNTL3: SCSI Control 3\n#define R_SCNTL3 0x03\n#define SCNTL3_MASK 0x77\n\n/// Register 04: SCID: SCSI Chip ID\n#define R_SCID 0x04\n#define R_SCID_ID 0x07\n#define SCID_MASK 0x67\n\n/// Register 05: SXFER: SCSI Transfer\n#define R_SXFER 0x05\n\n/// Register 06: SDID: SCSI Destination ID\n#define R_SDID 0x06\n#define R_SDID_ID 0x07\n#define SDID_MASK 0x07\n\n/// Register 07: GPREG: General Purpose\n#define R_GPREG 0x07\n#define GPREG_MASK 0x03\n\n/// Register 08: SFBR: SCSI First Byte REceived\n#define R_SFBR 0x08\n\n/// Register 09: SOCL: SCSI Output Control Latch\n#define R_SOCL 0x09\n#define R_SOCL_ACK 0x40\n#define R_SOCL_ATN 0x20\n\n/// Register 0A: SSID: SCSI Selector ID\n#define R_SSID 0x0A\n#define R_SSID_VAL 0x80\n#define R_SSID_ID 0x07\n\n/// Register 0B: SBCL: SCSI Bus Control Lines\n#define R_SBCL 0x0B\n#define R_SBCL_REQ 0x80\n#define R_SBCL_ACK 0x40\n#define R_SBCL_BSY 0x20\n#define R_SBCL_SEL 0x10\n#define R_SBCL_ATN 0x08\n#define R_SBCL_MSG 0x04\n#define R_SBCL_CD 0x02\n#define R_SBCL_IO 0x01\n#define R_SBCL_PHASE 0x07\n\n/// Register 0C: DSTAT: DMA Status\n#define R_DSTAT 0x0C\n#define R_DSTAT_DFE 0x80\n#define R_DSTAT_MDPE 0x40\n#define R_DSTAT_BF 0x20\n#define R_DSTAT_ABRT 0x10\n#define R_DSTAT_SSI 0x08\n#define R_DSTAT_SIR 0x04\n#define R_DSTAT_IID 0x01\n#define DSTAT_RC 0x7D\n#define DSTAT_FATAL 0x7D\n\n/// Register 0D: SSTAT0: SCSI Status 0\n#define R_SSTAT0 0x0D\n#define R_SSTAT0_RST 0x02\n#define R_SSTAT0_SDP0 0x01\n\n/// Register 0E: SSTAT1: SCSI Status 1\n#define R_SSTAT1 0x0E\n#define R_SSTAT1_SDP1 0x01\n\n/// Register 0F: SSTAT2: SCSI Status 2\n#define R_SSTAT2 0x0F\n#define R_SSTAT2_LDSC 0x02\n\n/// Register 10..13: DSA: Data Structure Address\n#define R_DSA 0x10\n\n/// Register 14: ISTAT: Interrupt Status\n#define R_ISTAT 0x14\n#define R_ISTAT_ABRT 0x80\n#define R_ISTAT_SRST 0x40\n#define R_ISTAT_SIGP 0x20\n#define R_ISTAT_SEM 0x10\n#define R_ISTAT_CON 0x08\n#define R_ISTAT_INTF 0x04\n#define R_ISTAT_SIP 0x02\n#define R_ISTAT_DIP 0x01\n#define ISTAT_MASK 0xF0\n#define ISTAT_W1C 0x04\n\n/// Register 18: CTEST0: Chip Test 0\n#define R_CTEST0 0x18\n\n/// Register 19: CTEST1: Chip Test 1\n#define R_CTEST1 0x19\n#define R_CTEST1_FMT 0xF0\n#define R_CTEST1_FFL 0x0F\n\n/// Register 1A: CTEST2: Chip Test 2\n#define R_CTEST2 0x1A\n#define R_CTEST2_DDIR 0x80\n#define R_CTEST2_SIGP 0x40\n#define R_CTEST2_CIO 0x20\n#define R_CTEST2_CM 0x10\n#define R_CTEST2_TEOP 0x04\n#define R_CTEST2_DREQ 0x02\n#define R_CTEST2_DACK 0x01\n\n/// Register 1B: CTEST3: Chip Test 3\n#define R_CTEST3 0x1B\n#define R_CTEST3_REV 0xf0\n#define R_CTEST3_FLF 0x08\n#define R_CTEST3_CLF 0x04\n#define R_CTEST3_FM 0x02\n#define CTEST3_MASK 0x0B\n\n/// Register 1C..1F: TEMP: Temporary\n#define R_TEMP 0x1C\n\n/// Register 20: DFIFO: DMA FIFO\n#define R_DFIFO 0x20\n\n/// Register 21: CTEST4: Chip Test 4\n#define R_CTEST4 0x21\n\n/// Register 22: CTEST5: Chip Test 5\n#define R_CTEST5 0x22\n#define R_CTEST5_ADCK 0x80\n#define R_CTEST5_BBCK 0x40\n#define CTEST5_MASK 0x18\n\n/// Register 24..26: DBC: DMA Byte Counter\n#define R_DBC 0x24\n\n/// Register 27: DCMD: DMA Command\n#define R_DCMD 0x27\n\n/// Register 28..2B: DNAD: DMA Next Address\n#define R_DNAD 0x28\n\n/// Register 2C..2F: DSP: DMA SCRIPTS Pointer\n#define R_DSP 0x2C\n\n/// Register 30..33: DSPS: DMA SCRIPTS Pointer Save\n#define R_DSPS 0x30\n\n/// Register 34..37: SCRATCHA: Scratch Register A\n#define R_SCRATCHA 0x34\n\n/// Register 38: DMODE: DMA Mode\n#define R_DMODE 0x38\n#define R_DMODE_MAN 0x01\n\n/// Register 39: DIEN: DMA Interrupt Enable\n#define R_DIEN 0x39\n#define DIEN_MASK 0x7D\n\n/// Register 3A: SBR: Scratch Byte Register\n#define R_SBR 0x3A\n\n/// Register 3B: DCNTL: DMA Control\n#define R_DCNTL 0x3B\n#define R_DCNTL_SSM 0x10\n#define R_DCNTL_STD 0x04\n#define R_DCNTL_IRQD 0x02\n#define R_DCNTL_COM 0x01\n#define DCNTL_MASK 0xFB\n\n/// Register 3C..37: ADDER: Adder Sum Output\n#define R_ADDER 0x3C\n\n/// Register 40: SIEN0: SCSI Interrupt Enable 0\n#define R_SIEN0 0x40\n#define SIEN0_MASK 0xFF\n\n/// Register 41: SIEN1: SCSI Interrupt Enable 1\n#define R_SIEN1 0x41\n#define SIEN1_MASK 0x07\n\n/// Register 42: SIST0: SCSI Interrupt Status 0\n#define R_SIST0 0x42\n#define R_SIST0_MA 0x80\n#define R_SIST0_CMP 0x40\n#define R_SIST0_SEL 0x20\n#define R_SIST0_RSL 0x10\n#define R_SIST0_SGE 0x08\n#define R_SIST0_UDC 0x04\n#define R_SIST0_RST 0x02\n#define R_SIST0_PAR 0x01\n#define SIST0_RC 0xFF\n#define SIST0_FATAL 0x8F\n\n/// Register 43: SIST1: SCSI Interrupt Status 1\n#define R_SIST1 0x43\n#define R_SIST1_STO 0x04\n#define R_SIST1_GEN 0x02\n#define R_SIST1_HTH 0x01\n#define SIST1_RC 0x07\n#define SIST1_FATAL 0x04\n\n/// Register 46: MACNTL: Memory Access Control\n#define R_MACNTL 0x46\n#define MACNTL_MASK 0x0F\n\n/// Register 47: GPCNTL: General Purpose Pin Control\n#define R_GPCNTL 0x47\n\n/// Register 48: STIME0: SCSI Timer 0\n#define R_STIME0 0x48\n\n/// Register 49: STIME1: SCSI Timer 1\n#define R_STIME1 0x49\n#define R_STIME1_GEN 0x0F\n#define STIME1_MASK 0x0F\n\n/// Register 4A: RESPID: SCSI Response ID\n#define R_RESPID 0x4A\n\n/// Register 4C: STEST0: SCSI Test 0\n#define R_STEST0 0x4C\n\n/// Register 4D: STEST1: SCSI Test 1\n#define R_STEST1 0x4D\n#define STEST1_MASK 0xC0\n\n/// Register 4E: STEST2: SCSI Test 2\n#define R_STEST2 0x4E\n#define R_STEST2_SCE 0x80\n#define R_STEST2_ROF 0x40\n#define R_STEST2_SLB 0x10\n#define R_STEST2_SZM 0x08\n#define R_STEST2_EXT 0x02\n#define R_STEST2_LOW 0x01\n#define STEST2_MASK 0x9B\n\n/// Register 4F: STEST3: SCSI Test 3\n#define R_STEST3 0x4F\n#define R_STEST3_TE 0x80\n#define R_STEST3_STR 0x40\n#define R_STEST3_HSC 0x20\n#define R_STEST3_DSI 0x10\n#define R_STEST3_TTM 0x04\n#define R_STEST3_CSF 0x02\n#define R_STEST3_STW 0x01\n#define STEST3_MASK 0xF7\n\n/// Register 58: SBDL: SCSI Bus Data Lines\n#define R_SBDL 0x58\n\n/// Registers 5C..5F: SCRATCHB: Scratch Register B\n#define R_SCRATCHB 0x5C\n\n/// Acces an 8-byte register\n#define R8(a) state.regs.reg8[R_##a]\n\n/// Acces a 16-byte register\n#define R16(a) state.regs.reg16[R_##a / 2]\n\n/// Access a 32-byte register\n#define R32(a) state.regs.reg32[R_##a / 4]\n\n/**\n * Test bit in register\n *\n * \\param a is the name of the register\n * \\param b is the name of the bit\n **/\n#define TB_R8(a, b) ((R8(a) & R_##a##_##b) == R_##a##_##b)\n\n/**\n * Set bit in register.\n *\n * \\param a is the name of the register\n * \\param b is the name of the bit\n * \\param c is the value for the bit\n **/\n#define SB_R8(a, b, c) R8(a) = (R8(a) & ~R_##a##_##b) | (c ? R_##a##_##b : 0)\n\n/**\n * Write to a register, using a mask\n *\n * \\param a is the name of the register\n * \\param b is the value to write.\n *\n * Only those bits that are set to 1 in <regname>_MASK will be changed.\n **/\n#define WRM_R8(a, b) R8(a) = (R8(a) & ~a##_MASK) | ((b)&a##_MASK)\n\n/**\n * Write to a register, using a mask, and using write-1-to-clear bits\n *\n * \\param a is the name of the register\n * \\param b is the value to write.\n *\n * Only those bits that are set to 1 in <regname>_MASK will be changed.\n * In addition, bits that are set to 1 in <regname>_W1C will be cleared\n * in the register if they are set to 1 in the value.\n **/\n#define WRMW1C_R8(a, b)                                                        \\\n  R8(a) =                                                                      \\\n      (R8(a) & ~a##_MASK & ~a##_W1C) | ((b)&a##_MASK) | (R8(a) & ~(b)&a##_W1C)\n\n/**\n * Raise an interrupt\n *\n * \\param a is the name of the interrupt register\n * \\param b is the name of the bit to set\n **/\n#define RAISE(a, b) set_interrupt(R_##a, R_##a##_##b)\n\n/**\n * Clear read-to-clear-bits\n *\n * \\param a is the name of the register\n *\n * Clear bits that are set to 1 in <regname>_RC\n **/\n#define RDCLR_R8(a) R8(a) &= ~a##_RC\n\n/**\n * Get the SCSI destination ID from the SDID register\n **/\n#define GET_DEST() (R8(SDID) & R_SCID_ID)\n\n/**\n * Set the SCSI destination ID in the SDID register\n **/\n#define SET_DEST(a) R8(SDID) = (a)&R_SCID_ID\n\n/**\n * Get the value of the DBC register (24-bits)\n **/\n#define GET_DBC() (R32(DBC) & 0x00ffffff)\n\n/**\n * Set the value of the DBC register (24-bits)\n **/\n#define SET_DBC(a) R32(DBC) = (R32(DBC) & 0xff000000) | ((a)&0x00ffffff)\n\n/**\n * PCI Configuration Data Block\n **/\nstatic u32 osym_cfg_data[64] = {\n    /*00*/ 0x00011000, // CFID: vendor + device\n    /*04*/ 0x02000001, // CFCS: command + status\n    /*08*/ 0x01000001, // CFRV: class + revision\n    /*0c*/ 0x00000000, // CFLT: latency timer + cache line size\n    /*10*/ 0x00000001, // BAR0: IO Space\n    /*14*/ 0x00000000, // BAR1: Memory space\n    /*18*/ 0x00000000, // BAR2: RAM space\n    /*1c*/ 0x00000000, // BAR3:\n    /*20*/ 0x00000000, // BAR4:\n    /*24*/ 0x00000000, // BAR5:\n    /*28*/ 0x00000000, // CCIC: CardBus\n    /*2c*/ 0x00000000, // CSID: subsystem + vendor\n    /*30*/ 0x00000000, // BAR6: expansion rom base\n    /*34*/ 0x00000000, // CCAP: capabilities pointer\n    /*38*/ 0x00000000,\n    /*3c*/ 0x401101ff, // CFIT: interrupt configuration\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0};\n\n/**\n * PCI Configuration Mask Block\n **/\nstatic u32 osym_cfg_mask[64] = {\n    /*00*/ 0x00000000, // CFID: vendor + device\n    /*04*/ 0x00000157, // CFCS: command + status\n    /*08*/ 0x00000000, // CFRV: class + revision\n    /*0c*/ 0x0000ffff, // CFLT: latency timer + cache line size\n    /*10*/ 0xffffff00, // BAR0: IO space (256 bytes)\n    /*14*/ 0xffffff00, // BAR1: Memory space (256 bytes)\n    /*18*/ 0x00000000, // BAR2: RAM space (4KB)\n    /*1c*/ 0x00000000, // BAR3:\n    /*20*/ 0x00000000, // BAR4:\n    /*24*/ 0x00000000, // BAR5:\n    /*28*/ 0x00000000, // CCIC: CardBus\n    /*2c*/ 0x00000000, // CSID: subsystem + vendor\n    /*30*/ 0x00000000, // BAR6: expansion rom base\n    /*34*/ 0x00000000, // CCAP: capabilities pointer\n    /*38*/ 0x00000000,\n    /*3c*/ 0x000000ff, // CFIT: interrupt configuration\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0};\n\n/**\n * Thread entry point.\n *\n * Repeat:\n *   - Waiting until the semaphore is set\n *   - Executing SCRIPTS code until execution ends.\n *   .\n **/\nvoid CSym53C810::run() {\n  try {\n    for (;;) {\n      mySemaphore.wait();\n      if (StopThread)\n        return;\n      while (state.executing) {\n        MUTEX_LOCK(myRegLock);\n        execute();\n        MUTEX_UNLOCK(myRegLock);\n      }\n    }\n  }\n\n  catch (CException &e) {\n    printf(\"Exception in SYM thread: %s.\\n\", e.displayText().c_str());\n    myThreadDead.store(true);\n    // Let the thread die...\n  }\n}\n\n/**\n * Constructor.\n *\n * Set up the SCSI bus, and defer the rest of initialization to\n * CSym53C895::init.\n **/\nCSym53C810::CSym53C810(CConfigurator *cfg, CSystem *c, int pcibus, int pcidev)\n    : CPCIDevice(cfg, c, pcibus, pcidev), CDiskController(1, 7),\n      mySemaphore(0, 1) {\n\n  // create scsi bus\n  CSCSIBus *a = new CSCSIBus(cfg, c);\n  scsi_register(0, a, 7); // scsi id 7 by default\n\n  // initialize state\n  memset(&state, 1, sizeof(struct SSym_state));\n}\n\n/**\n * Initialize the Symbios device.\n *\n * Reset PCI structures, reset the chipset, and set up locks.\n **/\nvoid CSym53C810::init() {\n  add_function(0, osym_cfg_data, osym_cfg_mask);\n\n  ResetPCI();\n\n  chip_reset();\n\n  myRegLock = new CMutex(\"sym-reg\");\n\n  printf(\"%s: $Id: Sym53C810.cpp,v 1.14 2008/05/31 15:47:13 iamcamiel Exp $\\n\",\n         devid_string);\n}\n\n/**\n * Create the thread, and start executing it.\n **/\nvoid CSym53C810::start_threads() {\n  if (!myThread) {\n    printf(\" sym\");\n    StopThread = false;\n    myThread = std::make_unique<std::thread>([this](){ this->run(); });\n    if (state.executing)\n      mySemaphore.set();\n  }\n}\n\n/**\n * Stop and destroy the thread.\n **/\nvoid CSym53C810::stop_threads() {\n  StopThread = true;\n  if (myThread) {\n    printf(\" sym\");\n    mySemaphore.set();\n    myThread->join();\n    myThread = nullptr;\n  }\n}\n\n/**\n * Destructor.\n *\n * Kill thread if still running.\n * Note: SCSI bus is destroyed when destroying the System.\n **/\nCSym53C810::~CSym53C810() { stop_threads(); }\n\n/**\n * Reset the chipset.\n *\n * Initialize all registers to their default values.\n **/\nvoid CSym53C810::chip_reset() {\n  state.executing = false;\n  state.wait_reselect = false;\n  state.irq_asserted = false;\n  state.gen_timer = 0;\n  memset(state.regs.reg32, 0, sizeof(state.regs.reg32));\n  R8(SCNTL0) = R_SCNTL0_ARB1 | R_SCNTL0_ARB0; // 810\n  R8(DSTAT) = R_DSTAT_DFE;                    // DMA FIFO empty // 810\n\n  //  R8(SSTAT2) = R_SSTAT2_LDSC; // 810\n  R8(CTEST1) = R_CTEST1_FMT;  // 810\n  R8(CTEST2) = R_CTEST2_DACK; // 810\n  R8(CTEST3) =\n      (u8)(pci_state.config_data[0][2] << 4) & R_CTEST3_REV; // Chip rev.\n  R8(MACNTL) = 0x40;                                         // 810 type ID\n  R8(GPCNTL) = 0x0F;                                         // 810\n  R8(STEST0) = 0x03;                                         // 810\n}\n\n/**\n * Register a disk\n *\n * Attach the disk to the SCSI bus.\n **/\nvoid CSym53C810::register_disk(class CDisk *dsk, int bus, int dev) {\n  CDiskController::register_disk(dsk, bus, dev);\n  dsk->scsi_register(0, scsi_bus[0], dev);\n}\n\nstatic u32 sym_magic1 = 0x53C810CC;\nstatic u32 sym_magic2 = 0xCC53C810;\n\n/**\n * Save state to a Virtual Machine State file.\n **/\nint CSym53C810::SaveState(FILE *f) {\n  long ss = sizeof(state);\n  int res;\n\n  if ((res = CPCIDevice::SaveState(f)))\n    return res;\n\n  fwrite(&sym_magic1, sizeof(u32), 1, f);\n  fwrite(&ss, sizeof(long), 1, f);\n  fwrite(&state, sizeof(state), 1, f);\n  fwrite(&sym_magic2, sizeof(u32), 1, f);\n  printf(\"%s: %d bytes saved.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\n/**\n * Restore state from a Virtual Machine State file.\n **/\nint CSym53C810::RestoreState(FILE *f) {\n  long ss;\n  u32 m1;\n  u32 m2;\n  int res;\n  size_t r;\n\n  if ((res = CPCIDevice::RestoreState(f)))\n    return res;\n\n  r = fread(&m1, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m1 != sym_magic1) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&ss, sizeof(long), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (ss != sizeof(state)) {\n    printf(\"%s: STRUCT SIZE does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&state, sizeof(state), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&m2, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m2 != sym_magic2) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  printf(\"%s: %d bytes restored.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\n/**\n * write data to one of the PCI BAR (relocatable) address ranges.\n **/\nvoid CSym53C810::WriteMem_Bar(int func, int bar, u32 address, int dsize,\n                              u32 data) {\n  void *p;\n\n  switch (bar) {\n  case 0:\n  case 1:\n    address &= 0x7f;\n    switch (dsize) {\n    case 8:\n      MUTEX_LOCK(myRegLock);\n#if defined(DEBUG_SYM_REGS)\n      printf(\"SYM: Write to register %02x: %02x.   \\n\", address, data);\n#endif\n      if (address >= R_SCRATCHB) {\n        state.regs.reg8[address] = (u8)data;\n        MUTEX_UNLOCK(myRegLock);\n        break;\n      }\n\n      switch (address) {\n\n      // SIMPLE CASES: JUST WRITE\n      case R_SXFER:        // 05\n      case R_DSA:          // 10\n      case R_DSA + 1:      // 11\n      case R_DSA + 2:      // 12\n      case R_DSA + 3:      // 13\n      case R_CTEST0:       // 18\n      case R_TEMP:         // 1C\n      case R_TEMP + 1:     // 1D\n      case R_TEMP + 2:     // 1E\n      case R_TEMP + 3:     // 1F\n      case R_DSP:          // 2C\n      case R_DSP + 1:      // 2D\n      case R_DSP + 2:      // 2E\n      case R_DSPS:         // 30\n      case R_DSPS + 1:     // 31\n      case R_DSPS + 2:     // 32\n      case R_DSPS + 3:     // 33\n      case R_SCRATCHA:     // 34\n      case R_SCRATCHA + 1: // 35\n      case R_SCRATCHA + 2: // 36\n      case R_SCRATCHA + 3: // 37\n      case R_DMODE:        // 38\n      case R_SBR:          // 3A     // 810\n      case R_GPCNTL:       // 47\n      case R_STIME0:       // 48\n      case R_RESPID:       // 4A\n      case R_STEST0:       // 4C\n        state.regs.reg8[address] = (u8)data;\n        break;\n\n      case R_SCNTL0: // 00\n        // side effects: start arbitration bit\n        write_b_scntl0((u8)data);\n        break;\n\n      case R_SCNTL1: // 01\n        // side effects: start immediate arbitration bit\n        write_b_scntl1((u8)data);\n        break;\n\n      case R_SCNTL2: // 02\n        WRM_R8(SCNTL2, (u8)data);\n        break;\n\n      case R_SCNTL3: // 03\n        // side effects: clearing EWS\n        WRM_R8(SCNTL3, (u8)data);\n        break;\n\n      case R_SCID: // 04\n        WRM_R8(SCID, (u8)data);\n        break;\n\n      case R_SDID: // 06\n        WRM_R8(SDID, (u8)data);\n        break;\n\n      case R_GPREG: // 07\n        WRM_R8(GPREG, (u8)data);\n        break;\n\n      case R_ISTAT: // 14\n        write_b_istat((u8)data);\n        break;\n\n      case R_CTEST3: // 1B\n        write_b_ctest3((u8)data);\n        break;\n\n      case R_CTEST4: // 21\n        write_b_ctest4((u8)data);\n        break;\n\n      case R_CTEST5: // 22\n        write_b_ctest5((u8)data);\n        break;\n\n      case R_DSP + 3: // 2F\n        state.regs.reg8[address] = (u8)data;\n        post_dsp_write();\n        break;\n\n      case R_DIEN: // 39\n        WRM_R8(DIEN, (u8)data);\n        eval_interrupts();\n        break;\n\n      case R_DCNTL: // 3B\n        write_b_dcntl((u8)data);\n        break;\n\n      case R_SIEN0: // 40\n        R8(SIEN0) = (u8)data;\n        eval_interrupts();\n        break;\n\n      case R_SIEN1: // 41\n        WRM_R8(SIEN1, (u8)data);\n        eval_interrupts();\n        break;\n\n      case R_MACNTL: // 46     // 810\n        WRM_R8(MACNTL, (u8)data);\n        break;\n\n      case R_STIME1: // 49\n        WRM_R8(STIME1, (u8)data);\n        state.gen_timer = (R8(STIME1) & R_STIME1_GEN) * 30;\n        break;\n\n      case R_STEST1: // 4D\n        WRM_R8(STEST1, (u8)data);\n        break;\n\n      case R_STEST2: // 4E\n        write_b_stest2((u8)data);\n        break;\n\n      case R_STEST3: // 4F\n        write_b_stest3((u8)data);\n        break;\n\n      case R_DSTAT:  // 0C\n      case R_SSTAT0: // 0D\n      case R_SSTAT1: // 0E\n      case R_SSTAT2: // 0F\n      case R_CTEST2: // 1A\n        // printf(\"SYM: Write to read-only register at %02x. FreeBSD driver\n        // cache test.\\n\", address);\n        break;\n\n      case 0x4b: // ??? Linux wants this\n        // printf(\"SYM: Write to non-existing register at %02x. Linux generic\n        // driver.\\n\", address);\n        break;\n\n      default:\n        FAILURE_2(NotImplemented,\n                  \"SYM: Write to unknown register at %02x with %08x.\\n\",\n                  address, data);\n      }\n\n      MUTEX_UNLOCK(myRegLock);\n      break;\n\n    case 16:\n      WriteMem_Bar(0, 1, address + 0, 8, (data >> 0) & 0xff);\n      WriteMem_Bar(0, 1, address + 1, 8, (data >> 8) & 0xff);\n      break;\n\n    case 32:\n      WriteMem_Bar(0, 1, address + 0, 8, (data >> 0) & 0xff);\n      WriteMem_Bar(0, 1, address + 1, 8, (data >> 8) & 0xff);\n      WriteMem_Bar(0, 1, address + 2, 8, (data >> 16) & 0xff);\n      WriteMem_Bar(0, 1, address + 3, 8, (data >> 24) & 0xff);\n      break;\n    }\n    break;\n\n  case 2:\n    p = (u8 *)state.ram + address;\n    switch (dsize) {\n    case 8:\n      *((u8 *)p) = (u8)data;\n      break;\n    case 16:\n      *((u16 *)p) = (u16)data;\n      break;\n    case 32:\n      *((u32 *)p) = (u32)data;\n      break;\n    }\n    break;\n  }\n}\n\n/**\n * Read data from one of the PCI BAR (relocatable) address ranges.\n **/\nu32 CSym53C810::ReadMem_Bar(int func, int bar, u32 address, int dsize) {\n  u32 data = 0;\n  void *p;\n\n  switch (bar) {\n  case 0:\n  case 1:\n    address &= 0x7f;\n    switch (dsize) {\n    case 8:\n      MUTEX_LOCK(myRegLock);\n      if (address >= R_SCRATCHB) {\n        data = state.regs.reg8[address];\n        MUTEX_UNLOCK(myRegLock);\n        break;\n      }\n\n      switch (address) {\n      case R_SCNTL0:       // 00\n      case R_SCNTL1:       // 01\n      case R_SCNTL2:       // 02\n      case R_SCNTL3:       // 03\n      case R_SCID:         // 04\n      case R_SXFER:        // 05\n      case R_SDID:         // 06\n      case R_GPREG:        // 07\n      case R_SFBR:         // 08\n      case R_SSID:         // 0A\n      case R_SBCL:         // 0B\n      case R_SSTAT0:       // 0D\n      case R_SSTAT1:       // 0E\n      case R_SSTAT2:       // 0F\n      case R_DSA:          // 10\n      case R_DSA + 1:      // 11\n      case R_DSA + 2:      // 12\n      case R_DSA + 3:      // 13\n      case R_ISTAT:        // 14\n      case R_CTEST0:       // 18\n      case R_CTEST1:       // 19\n      case R_CTEST3:       // 1B\n      case R_TEMP:         // 1C\n      case R_TEMP + 1:     // 1D\n      case R_TEMP + 2:     // 1E\n      case R_TEMP + 3:     // 1F\n      case R_CTEST4:       // 21\n      case R_CTEST5:       // 22\n      case R_DBC:          // 24  // 810\n      case R_DBC + 1:      // 25  // 810\n      case R_DBC + 2:      // 26  // 810\n      case R_DCMD:         // 27  // 810\n      case R_DNAD:         // 28  // 810\n      case R_DNAD + 1:     // 29  // 810\n      case R_DNAD + 2:     // 2A  // 810\n      case R_DNAD + 3:     // 2B  // 810\n      case R_DSP:          // 2C\n      case R_DSP + 1:      // 2D\n      case R_DSP + 2:      // 2E\n      case R_DSP + 3:      // 2F\n      case R_DSPS:         // 30\n      case R_DSPS + 1:     // 31\n      case R_DSPS + 2:     // 32\n      case R_DSPS + 3:     // 33\n      case R_SCRATCHA:     // 34\n      case R_SCRATCHA + 1: // 35\n      case R_SCRATCHA + 2: // 36\n      case R_SCRATCHA + 3: // 37\n      case R_DMODE:        // 38\n      case R_DIEN:         // 39\n      case R_SBR:          // 3A     // 810\n      case R_DCNTL:        // 3B\n      case R_SIEN0:        // 40\n      case R_SIEN1:        // 41\n      case R_MACNTL:       // 46     // 810\n      case R_GPCNTL:       // 47\n      case R_STIME0:       // 48\n      case R_STIME1:       // 49\n      case R_RESPID:       // 4A\n      case R_STEST0:       // 4C\n      case R_STEST1:       // 4D\n      case R_STEST2:       // 4E\n      case R_STEST3:       // 4F\n      case R_SBDL:         // 58\n        data = state.regs.reg8[address];\n        break;\n\n      case R_DSTAT: // 0C\n        data = read_b_dstat();\n        break;\n\n      case R_CTEST2: // 1A\n        data = read_b_ctest2();\n        break;\n\n      case R_DFIFO:            // 20\n        data = R8(DBC) & 0x7f; // 810 - fake the DFIFO count\n        break;\n\n      case R_SIST0: // 42\n      case R_SIST1: // 43\n        data = read_b_sist(address - R_SIST0);\n        break;\n\n      case 0x17: // ??? Linux wants this.\n      case 0x4b: // ??? Linux wants this\n      case 0x52: // ??? Linux wants this.\n      case 0x59: // ??? Linux wants this.\n        // printf(\"SYM: Read from non-existing register at %02x. Linux generic\n        // driver.\\n\", address);\n        data = 0;\n        break;\n\n      default:\n        FAILURE_2(\n            NotImplemented,\n            \"SYM: Attempt to read %d bytes from unknown register at %\" PRIx32\n            \"\\n\",\n            dsize, address);\n      }\n\n      MUTEX_UNLOCK(myRegLock);\n#if defined(DEBUG_SYM_REGS)\n      printf(\"SYM: Read frm register %02x: %02x.   \\n\", address, data);\n#endif\n      break;\n\n    case 16:\n      data = (ReadMem_Bar(0, 1, address + 0, 8) << 0) & 0x00ff;\n      data |= (ReadMem_Bar(0, 1, address + 1, 8) << 8) & 0xff00;\n      break;\n\n    case 32:\n      data = (ReadMem_Bar(0, 1, address + 0, 8) << 0) & 0x000000ff;\n      data |= (ReadMem_Bar(0, 1, address + 1, 8) << 8) & 0x0000ff00;\n      data |= (ReadMem_Bar(0, 1, address + 2, 8) << 16) & 0x00ff0000;\n      data |= (ReadMem_Bar(0, 1, address + 3, 8) << 24) & 0xff000000;\n      break;\n    }\n    break;\n\n  case 2:\n    p = (u8 *)state.ram + address;\n    switch (dsize) {\n    case 8:\n      return *((u8 *)p);\n    case 16:\n      return *((u16 *)p);\n    case 32:\n      return *((u32 *)p);\n    }\n    break;\n  }\n\n  return data;\n}\n\n/**\n * Override PCI Configuration Space read action.\n *\n * Lower 80 bytes are normal, upper 80 bytes reflect into the\n * register space.\n **/\nu32 CSym53C810::config_read_custom(int func, u32 address, int dsize, u32 data) {\n  if (address >= 0x80)\n    return ReadMem_Bar(func, 1, address - 0x80, dsize);\n  else\n    return data;\n}\n\n/**\n * Override PCI Configuration Space write action.\n *\n * Lower 80 bytes are normal, upper 80 bytes reflect into the\n * register space.\n **/\nvoid CSym53C810::config_write_custom(int func, u32 address, int dsize,\n                                     u32 old_data, u32 new_data, u32 data) {\n  if (address >= 0x80)\n    WriteMem_Bar(func, 1, address - 0x80, dsize, data);\n}\n\n/**\n * Write a byte to the SCSI Control 0 register.\n *\n * This is a normal masked write operation; implemented as a separate\n * function, because there are some bits in here (START and TRG) that\n * we should do something with if a driver sets these, but that we\n * don't implement.\n *\n * START: When this bit is set, the controller should start the\n * arbitration seqence indicated by the arbitration mode bits. Used\n * only in low-level mode. UNIMPLEMENTED.\n *\n * TRG: When this bit is set, the controller is a target device.\n * UNIMPLEMENTED.\n **/\nvoid CSym53C810::write_b_scntl0(u8 value) {\n  bool old_start = TB_R8(SCNTL0, START);\n\n  WRM_R8(SCNTL0, value);\n\n  if (TB_R8(SCNTL0, START) && !old_start)\n    FAILURE(NotImplemented,\n            \"SYM: Don't know how to start arbitration sequence\");\n\n  if (TB_R8(SCNTL0, TRG))\n    FAILURE(NotImplemented, \"SYM: Don't know how to operate in target mode\");\n}\n\n/**\n * Write a byte to the SCSI Control 1 register.\n *\n * This is implemented as a separate function, because there are\n * quite a few side-effects that occur when writing to this register\n *\n * CON (Connected): This bit is automatically set any time the\n * controller is connected to the SCSI bus. The CPU can force a\n * connection or disconnection by setting or clearing this bit.\n * UNIMPLEMENTED.\n *\n * RST: Asserts the SCSI RST/ signal. Has the \"side-effect\" of\n * resetting the SCSI bus. This effects a couple of other registers.\n *\n * \\todo: Implement real reset of the SCSI bus.\n **/\nvoid CSym53C810::write_b_scntl1(u8 value) {\n  bool old_rst = TB_R8(SCNTL1, RST);\n\n  R8(SCNTL1) = value;\n\n  //  if (TB_R8(SCNTL1,CON) != old_con)\n  //    printf(\"SYM: Don't know how to forcibly connect or disconnect\\n\");\n  if (TB_R8(SCNTL1, RST) != old_rst) {\n    SB_R8(SSTAT0, SDP0, false);\n    SB_R8(SSTAT1, SDP1, false);\n    R16(SBDL) = 0;\n    R8(SBCL) = 0;\n\n    SB_R8(SSTAT0, RST, !old_rst);\n\n    //    printf(\"SYM: %s SCSI bus reset.\\n\",old_rst?\"end\":\"start\");\n    if (!old_rst)\n      RAISE(SIST0, RST);\n  }\n}\n\n/**\n * Write a byte to the SCSI Interrupt Status.\n *\n * This is implemented as a separate function, because there are\n * quite a few side-effects that occur when writing to this register\n *\n * ABRT (Abort Operation): Aborts the currently executing SCRIP, and\n * generate an interrupt.\n *\n * SRST (Software Reset): Resets the SCSI chipset.\n *\n * SIGP (Signal Process): Aborts a Wait for (Re)Selection instruction\n * by jumping to the alternate address immediately.\n *\n * Since interrupt state is affected, call eval_interrupts.\n **/\nvoid CSym53C810::write_b_istat(u8 value) {\n  bool old_srst = TB_R8(ISTAT, SRST);\n\n  WRMW1C_R8(ISTAT, value);\n\n  if (TB_R8(ISTAT, ABRT)) {\n\n    //    printf(\"SYM: Aborting on request.\\n\");\n    RAISE(DSTAT, ABRT);\n  }\n\n  if (TB_R8(ISTAT, SRST) && !old_srst) {\n\n    //    printf(\"SYM: Resetting on request.\\n\");\n    chip_reset();\n  }\n\n  //  if (TB_R8(ISTAT,SEM) != old_sem)\n  //    printf(\"SYM: SEM %s.\\n\",old_sem?\"reset\":\"set\");\n  //  if (TB_R8(ISTAT,SIGP) != old_sigp)\n  //    printf(\"SYM: SIGP %s.\\n\",old_sigp?\"reset\":\"set\");\n  if (TB_R8(ISTAT, SIGP)) {\n    if (state.wait_reselect) {\n\n      //      printf(\"SYM: SIGP while wait_reselect. Jumping...\\n\");\n      R32(DSP) = state.wait_jump;\n      state.wait_reselect = false;\n      state.executing = true;\n      mySemaphore.set();\n    }\n  }\n\n  eval_interrupts();\n}\n\n/**\n * Reads a byte from the Chip Test 2 register.\n *\n * This is implemented as a separate function, because:\n *   - The SIGP flag read by this register comes from the ISTAT\n *     register.\n *   - The CIO (configured as I/O) and CM (configured as memory)\n *     flags are determined from PCI Configuration space.\n *   - Reading this register has the side effect of clearing the\n *     SIGP flag.\n *   .\n **/\nu8 CSym53C810::read_b_ctest2() {\n  SB_R8(CTEST2, CIO, pci_state.config_data[0][4] != 0);\n  SB_R8(CTEST2, CM, pci_state.config_data[0][5] != 0);\n  SB_R8(CTEST2, SIGP, TB_R8(ISTAT, SIGP));\n  SB_R8(ISTAT, SIGP, false);\n\n  //  printf(\"SYM: SIGP cleared by CTEST2 read.\\n\");\n  return R8(CTEST2);\n}\n\n/**\n * Write a byte to the Chip Test 3 register.\n *\n * This is implemented as a separate function, because there are\n * some unimplemented bits that probably should have a function if\n * a driver ever decides to use these.\n *\n * FM (Fetch Pin Mode): When set, this bit causes the FETCH/ pin to\n * deassert during indirect and table indirect read operations.\n * FETCH/ will only be active during the op codde portion of an\n * instruction fetch. This allows SCRIPTS to be stored in a PROM\n * while data tables are stored in RAM. UNIMPLEMENTED.\n **/\nvoid CSym53C810::write_b_ctest3(u8 value) {\n  WRM_R8(CTEST3, value);\n\n  // if ((value>>3) & 1)\n  //  printf(\"SYM: Don't know how to flush DMA FIFO\\n\");\n  // if ((value>>2) & 1)\n  //  printf(\"SYM: Don't know how to clear DMA FIFO\\n\");\n  if ((value >> 1) & 1)\n    FAILURE(NotImplemented, \"SYM: Don't know how to handle FM mode\");\n}\n\n/**\n * Write a byte to the Chip Test 4 register.\n *\n * This is implemented as a separate function, because there are\n * some unimplemented bits that probably should have a function if\n * a driver ever decides to use these.\n *\n * SRTM: Shadow Register Test Mode. Access shadow copies of TEMP and\n * DSA. Used for manufacturing diagnostics only. UNIMPLEMENTED.\n **/\nvoid CSym53C810::write_b_ctest4(u8 value) {\n  R8(CTEST4) = value;\n\n  if ((value >> 4) & 1)\n    FAILURE(NotImplemented, \"SYM: Don't know how to handle SRTM mode\");\n}\n\n/**\n * Write a byte to the Chip Test 5 register.\n *\n * This is implemented as a separate function, because there are\n * some unimplemented bits that probably should have a function if\n * a driver ever decides to use these.\n *\n * ADCK (Clock Address Incrementor): Setting this bit increments the\n * DNAD register. The DNAD register is incremented based on the DNAD\n * contents and the current DBC value. This bit automatically clears\n * itself after incrementing the  DNAD register. UNIMPLEMENTED.\n *\n * BBCK (Clock Byte Counter): Setting this bit decrements the byte\n * count contained in the 24-bit DBC register. It is decremented\n * based on the DBC contents and the current DNAD value. This bit\n * automatically clears itself after decrementing the DBC register.\n * UNIMPLEMENTED.\n **/\nvoid CSym53C810::write_b_ctest5(u8 value) {\n  WRM_R8(CTEST5, value);\n\n  if ((value >> 7) & 1)\n    FAILURE(NotImplemented,\n            \"SYM: Don't know how to do Clock Address increment\");\n\n  if ((value >> 6) & 1)\n    FAILURE(NotImplemented,\n            \"SYM: Don't know how to do Clock Byte Counter decrement\");\n}\n\n/**\n * Read a byte from the DSTAT register.\n *\n * This is implemented as a separate function, because it requires\n * interrupt re-evaluation.\n **/\nu8 CSym53C810::read_b_dstat() {\n  u8 retval = R8(DSTAT);\n\n  RDCLR_R8(DSTAT);\n\n  // printf(\"Read DSTAT --> eval int\\n\");\n  eval_interrupts();\n\n  // printf(\"Read DSTAT <-- eval int; retval: %02x; dstat:\n  // %02x.\\n\",retval,R8(DSTAT));\n  return retval;\n}\n\n/**\n * Read a byte from the SIST0 or SIST1 register.\n *\n * This is implemented as a separate function, because it requires\n * interrupt re-evaluation.\n **/\nu8 CSym53C810::read_b_sist(int id) {\n  u8 retval = state.regs.reg8[R_SIST0 + id];\n\n  if (id)\n    RDCLR_R8(SIST1);\n  else\n    RDCLR_R8(SIST0);\n\n  eval_interrupts();\n\n  return retval;\n}\n\n/**\n * Write a byte to the DMA Control register.\n *\n * This is implemented as a separate function, because there are\n * some side-effects.\n *\n * STD (Start DMA Operation): Start executing SCSI SCRIPT. Needs to\n * wake the thread.\n *\n * IRQD (IRQ Disable): disables the IRQ pin. Requires interrupt\n * re-evaluation.\n **/\nvoid CSym53C810::write_b_dcntl(u8 value) {\n  WRM_R8(DCNTL, value);\n\n  // start operation\n  if (value & R_DCNTL_STD) {\n    state.executing = true;\n    mySemaphore.set();\n  }\n\n  // IRQD bit...\n  eval_interrupts();\n}\n\n/**\n * Write a byte to the SCSI Test 2 register.\n *\n * This is implemented as a separate function, because there are\n * some unimplemented bits that probably should have a function if\n * a driver ever decides to use these.\n *\n * LOW (Low-level-mode). Switches the SCSI controller to low-level\n * mode operation. No SCRIPTS processor, but raw manipulation of\n * SCSI registers. Yuck. UNIMPLEMENTED.\n **/\nvoid CSym53C810::write_b_stest2(u8 value) {\n  WRM_R8(STEST2, value);\n\n  //  if (value & R_STEST2_ROF)\n  //    printf(\"SYM: Don't know how to reset SCSI offset!\\n\");\n  if (TB_R8(STEST2, LOW))\n    FAILURE(NotImplemented, \"SYM: I don't like LOW level mode\");\n}\n\n/**\n * Write a byte to the SCSI Test 3 register.\n *\n * This is implemented as a separate function, because there are\n * some unimplemented bits that probably should have a function if\n * a driver ever decides to use these.\n **/\nvoid CSym53C810::write_b_stest3(u8 value) {\n  WRM_R8(STEST3, value);\n\n  //  if (value & R_STEST3_CSF)\n  //    printf(\"SYM: Don't know how to clear the SCSI fifo.\\n\");\n}\n\n/**\n * Called after the DMA Scripts Pointer register has been written.\n *\n * Start executing SCSI SCRIPT. Needs to wake the thread.\n **/\nvoid CSym53C810::post_dsp_write() {\n  if (!TB_R8(DMODE, MAN)) {\n    state.executing = true;\n    mySemaphore.set();\n\n    // printf(\"SYM: Execution started @ %08x.\\n\",R32(DSP));\n  }\n}\n\n/**\n * Check if threads are still running.\n **/\nvoid CSym53C810::check_state() {\n  if (myThreadDead.load())\n    FAILURE(Thread, \"SYM thread has died\");\n\n  if (state.gen_timer) {\n    state.gen_timer--;\n    if (!state.gen_timer) {\n      state.gen_timer = (R8(STIME1) & R_STIME1_GEN) * 30;\n      RAISE(SIST1, GEN);\n      return;\n    }\n  }\n\n  /**\n\n  if (state.wait_reselect && PT.disconnected)\n  {\n    state.executing = true;\n    state.wait_reselect = false;\n    PT.disconnected = false;\n    //PT.disconnect_priv = false;\n    //PT.will_disconnect = false;\n    PT.reselected = true;\n    state.phase = 7; // msg in //PT.disconnect_phase;\n    R8(SSID) = GET_DEST() | R_SSID_VAL; // valid scsi selector id\n    if (TB_R8(DCNTL,COM))\n      R8(SFBR) = GET_DEST();\n    // don't expect a disconnect.\n    SB_R8(SCNTL2,SDU,true);\n    //RAISE(SIST0,RSL);\n    return 0;\n  }\n\n **/\n  if (state.disconnected) {\n    if (!TB_R8(SCNTL2, SDU)) {\n\n      // disconnect expected\n      // printf(\"SYM: Disconnect expected. stopping disconnect timer at\n      // %d.\\n\",state.disconnected);\n      state.disconnected = 0;\n      return;\n    }\n\n    state.disconnected--;\n    if (!state.disconnected) {\n\n      // printf(\"SYM: Disconnect unexpected. raising interrupt!\\n\");\n      // printf(\">\");\n      // getchar();\n      RAISE(SIST0, UDC);\n      return;\n    }\n  }\n}\n\n/**\n * Check SCSI Bus Phase.\n *\n * Returns -1 on timeout or similar, 0 on different phase, and 1 on same phase\n **/\n\nint CSym53C810::check_phase(int chk_phase) {\n  int real_phase = scsi_get_phase(0);\n\n  if (real_phase == SCSI_PHASE_ARBITRATION) {\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"Phase check... selection time-out!\\n\");\n#endif\n    RAISE(SIST1, STO); // select time-out\n    scsi_free(0);\n    state.select_timeout = false;\n    return -1;\n  }\n\n  if (real_phase == SCSI_PHASE_FREE && state.disconnected) {\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"Phase check... disconnected!\\n\");\n#endif\n    state.disconnected = 1;\n    R32(DSP) -= 8;\n    return -1;\n  }\n\n  if (real_phase == chk_phase)\n    return 1;\n  else\n    return 0;\n}\n\n/**\n * Execute one SCRIPTS Block Move instruction\n *\n * The Block Move instruction moves data between system memory and the\n * SCSI Bus. This is a two DWORD instruction. The instruction format in\n * the DCMD register is as follows:\n *\n * \\code\n * +---+-+-+-+-----+\n * |7 6|5|4|3|2 1 0| DCMD Register\n * +---+-+-+-+-----+\n *   |  | | |   +- 0..2: SCSI Phase (I/O, C/D and MSG/ signals):\n *   |  | | |            The data transfer only occurs if these bits\n *   |  | | |            match the actual SCSI bus phase.\n *   |  | | +- 3: Op Code: IGNORED\n *   |  | +- 4: Table Indirect Adressing:\n *   |  |         0: The DSPS register contains the address of the data,\n *   |  |            and the DBC register contains the number of bytes to\n *   |  |            transfer.\n *   |  |         1: The DSPS register contains a 24-bit signed offset\n *   |  |            that is added to the DSA register to get a pointer\n *   |  |            to a data structure that contains the address and\n *   |  |            byte count. This structure looks as follows:\n *   |  |                           +----+------------+\n *   |  |               DSA+DSPS:   | 00 | Byte Count |\n *   |  |                           +----+------------+\n *   |  |               DSA+DSPS+4: |  Data Address   |\n *   |  |                           +-----------------+\n *   |  +- 5: Indirect Addressing:\n *   |          0: The DSPS register contains the address of the data\n *   |          1: The DSPS register contains the address of a 32-bit\n *   |             pointer to the data.\n *   +- 6..7: Instruction Type: 00 = Block Move\n * \\endcode\n **/\nvoid CSym53C810::execute_bm_op() {\n  bool indirect = (R8(DCMD) >> 5) & 1;\n  bool table_indirect = (R8(DCMD) >> 4) & 1;\n  int scsi_phase = (R8(DCMD) >> 0) & 7;\n\n#if defined(DEBUG_SYM_SCRIPTS)\n  printf(\"SYM: INS = Block Move (i %d, t %d, opc %d, phase %d\\n\", indirect,\n         table_indirect, opcode, scsi_phase);\n#endif\n  // Compare phase\n  int phase_ok = check_phase(scsi_phase);\n  if (phase_ok == 0) {\n    RAISE(SIST0, MA);\n    return;\n  }\n\n  if (phase_ok > 0) {\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: Ready for transfer.\\n\");\n#endif\n\n    u32 start;\n    u32 count;\n\n    if (table_indirect) {\n      u32 add = R32(DSA) + sext_u32_24(R32(DSPS));\n\n      add &= ~0x03; // 810\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: Reading table at DSA(%08x)+DSPS(%08x) = %08x.\\n\", R32(DSA),\n             R32(DSPS), add);\n#endif\n      do_pci_read(add, &count, 4, 1);\n      count &= 0x00ffffff;\n      do_pci_read(add + 4, &start, 4, 1);\n    } else if (indirect) {\n      FAILURE(NotImplemented, \"SYM: Unsupported: indirect addressing\");\n    } else {\n      start = R32(DSPS);\n      count = GET_DBC();\n    }\n\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: %08x: MOVE Start/count %x, %x\\n\", R32(DSP) - 8, start, count);\n#endif\n    R32(DNAD) = start;\n    SET_DBC(count);\n    if (count == 0) {\n\n      // printf(\"SYM: Count equals zero!\\n\");\n      RAISE(DSTAT, IID); // page 5-32\n      return;\n    }\n\n    for (;;) {\n      size_t expected = scsi_expected_xfer(0);\n      u32 remaining = GET_DBC();\n      u32 xfer = remaining;\n\n      if ((size_t)xfer > expected) {\n#if defined(DEBUG_SYM_SCRIPTS)\n        printf(\"SYM: xfer %d bytes, max %zu expected, in phase %d.\\n\", xfer,\n               expected, scsi_phase);\n#endif\n        xfer = (u32)expected;\n      }\n\n      if (xfer == 0) {\n        RAISE(SIST0, MA);\n        return;\n      }\n\n      u8 *scsi_data_ptr = (u8 *)scsi_xfer_ptr(0, xfer);\n      u8 *org_sdata_ptr = scsi_data_ptr;\n\n      switch (scsi_phase) {\n      case SCSI_PHASE_COMMAND:\n      case SCSI_PHASE_DATA_OUT:\n      case SCSI_PHASE_MSG_OUT:\n        do_pci_read(R32(DNAD), scsi_data_ptr, 1, xfer);\n        R32(DNAD) += xfer;\n        break;\n\n      case SCSI_PHASE_STATUS:\n      case SCSI_PHASE_DATA_IN:\n      case SCSI_PHASE_MSG_IN:\n        do_pci_write(R32(DNAD), scsi_data_ptr, 1, xfer);\n        R32(DNAD) += xfer;\n        break;\n      }\n\n      SET_DBC(remaining - xfer);\n      R8(SFBR) = *org_sdata_ptr;\n      scsi_xfer_done(0);\n\n      if (GET_DBC() == 0)\n        return;\n\n      phase_ok = check_phase(scsi_phase);\n      if (phase_ok <= 0) {\n        if (phase_ok == 0) {\n          RAISE(SIST0, MA);\n        }\n        return;\n      }\n    }\n    return;\n  }\n}\n\n/* Execute one SCRIPTS I/O instruction\n *\n * The I/O instructions perform common SCSI hardware sequences, like\n * Selection and reselection. The instruction format in\n * the DCMD and DBC register is as follows:\n *\n * \\code\n * +---+-----+-+-+-+\n * |7 6|5 4 3|2|1|0| DCMD Register\n * +---+-----+-+-+-+\n *   |    |   | | +- 0: Select with ATN/:\n *   |    |   | |       Valid only for Select instruction. Assert ATN/ during\n *   |    |   | |       selection\n *   |    |   | +- 1: Table Indirect Mode:\n *   |    |   |         0: All information is taken from the instruction,\n *   |    |   |            and the contents of the SCNTL3 and SXFER registers.\n *   |    |   |         1: The DSPS register contains a 24-bit signed offset\n *   |    |   |            that is added to the DSA register to get a pointer\n *   |    |   |            to a data structure that contains the destination\n *   |    |   |            ID, SCNTL3 bits, and SXFER bits. This structure\n *   |    |   |            is 32 bits long and looks as follows:\n *   |    |   |                        +--------+--------+--------+--------+\n *   |    |   |            DSA+DSPS:   | SCNTL3 | ID     | SXFER  |        |\n *   |    |   |                        +--------+--------+--------+--------+\n *   |    |   +- 2: Relative Addrressing:\n *   |    |           0: The value in the DNAD register is an absolute address.\n *   |    |           1: The value in the DNAD register is a 24-bit signed\n *   |    |              displacement from the current DSP address.\n *   |    +- 3..5: Op Code\n *   +- 6..7 Instruction Type: 01 = I/O\n *\n * +-------+-------++--------+--+-+-++-+-+---+-+-----+\n * |       |19   16||        |10|9| || |6|   |3|     | DBC Register\n * +-------+-------++--------+--+-+-++-+-+---+-+-----+\n *             |              |  |      |     +- 3: Set/Clear ATN\n *             |              |  |      +- 6: Set/Clear ACK\n *             |              |  +- 9: Set/Clear Target Mode\n *             |              +- 10: Set/Clear Carry\n *             +- 16..19: Destination ID\n * \\endcode\n *\n * The Opcode determines the actual instruction:\n * \\code\n * +-----+-----------------+-------------+\n * | OPC | Initiator mode  | Target Mode |\n * +-----+-----------------+-------------+\n * | 000 | Select          | Reselect    |\n * | 001 | Wait Disconnect | Disconnect  |\n * | 010 | Wait Reselect   | Wait Select |\n * | 011 | Set             | Set         |\n * | 100 | Clear           | Clear       |\n * +-----+-----------------+-------------+\n * \\endcode\n *\n * Select:\n *   - Arbitrate for the SCSI bus until arbitration is won.\n *   - If arbitration is won, try to select the destination ID\n *   - If the controller is selected or reselected before winning\n *     arbitration, jump to the address in the DNAD register.\n *   .\n *\n * Wait Disconnect:\n *   - Wait for the target to disconnect from the SCSI bus.\n *   .\n *\n * Wait Reselect:\n *   - If the controller is reselected, go to the next instruction.\n *   - If the controller is selected before being reselected, or if\n *     the CPU sets the SIGP flag, jump to the address in the DNAD\n *     register\n *   .\n *\n * Set/Clear:\n *   - Set or Clear the flags whose Set/Clear bits are set in the\n *     instruction.\n *   .\n **/\nvoid CSym53C810::execute_io_op() {\n  int opcode = (R8(DCMD) >> 3) & 7;\n  bool relative = (R8(DCMD) >> 2) & 1;\n  bool table_indirect = (R8(DCMD) >> 1) & 1;\n  int destination = (GET_DBC() >> 16) & 0x0f;\n  bool sc_carry = (GET_DBC() >> 10) & 1;\n  bool sc_target = (GET_DBC() >> 9) & 1;\n  bool sc_ack = (GET_DBC() >> 6) & 1;\n  bool sc_atn = (GET_DBC() >> 3) & 1;\n\n  R32(DNAD) = R32(DSPS);\n\n  u32 dest_addr = R32(DNAD);\n\n  if (relative)\n    dest_addr = R32(DSP) + sext_u32_24(R32(DNAD));\n\n#if defined(DEBUG_SYM_SCRIPTS)\n  printf(\"SYM: INS = I/O (opc %d, r %d, t %d, a %d, dest %d, sc %d%d%d%d\\n\",\n         opcode, relative, table_indirect, atn, destination, sc_carry,\n         sc_target, sc_ack, sc_atn);\n#endif\n  if (table_indirect) {\n    u32 io_addr = R32(DSA) + sext_u32_24(GET_DBC());\n    io_addr &= ~3; // 810\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: Reading table at DSA(%08x)+DBC(%08x) = %08x.\\n\", R32(DSA),\n           sext_u32_24(GET_DBC()), io_addr);\n#endif\n\n    u32 io_struc;\n    do_pci_read(io_addr, &io_struc, 4, 1);\n    destination = (io_struc >> 16) & 0x0f;\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: table indirect. io_struct = %08x, new dest = %d.\\n\", io_struc,\n           destination);\n#endif\n  }\n\n  switch (opcode) {\n  case 0:\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: %08x: SELECT %d.\\n\", R32(DSP) - 8, destination);\n#endif\n    SET_DEST(destination);\n    if (!scsi_arbitrate(0)) {\n\n      // scsi bus busy, try again next clock...\n      printf(\"scsi bus busy...\\n\");\n      R32(DSP) -= 8;\n      return;\n    }\n\n    state.select_timeout = !scsi_select(0, destination);\n    if (!state.select_timeout)  // select ok\n      SB_R8(SCNTL2, SDU, true); // don't expect a disconnect\n    return;\n\n  case 1:\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: %08x: WAIT DISCONNECT\\n\", R32(DSP) - 8);\n#endif\n\n    // maybe we need to do more??\n    scsi_free(0);\n    return;\n\n  case 2:\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: %08x: WAIT RESELECT\\n\", R32(DSP) - 8);\n#endif\n    if (TB_R8(ISTAT, SIGP)) {\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: SIGP set before wait reselect; jumping!\\n\");\n#endif\n      R32(DSP) = dest_addr;\n    } else {\n      state.wait_reselect = true;\n      state.wait_jump = dest_addr;\n      state.executing = false;\n    }\n\n    return;\n\n  case 3:\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: %08x: SET %s%s%s%s\\n\", R32(DSP) - 8, sc_carry ? \"carry \" : \"\",\n           sc_target ? \"target \" : \"\", sc_ack ? \"ack \" : \"\",\n           sc_atn ? \"atn \" : \"\");\n#endif\n    if (sc_ack)\n      SB_R8(SOCL, ACK, true);\n    if (sc_atn) {\n      if (!TB_R8(SOCL, ATN)) {\n        SB_R8(SOCL, ATN, true);\n\n        // printf(\"SET ATN.\\n\");\n        // printf(\">\");\n        // getchar();\n      }\n    }\n\n    if (sc_target)\n      SB_R8(SCNTL0, TRG, true);\n    if (sc_carry)\n      state.alu.carry = true;\n    return;\n\n  case 4:\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: %08x: CLEAR %s%s%s%s\\n\", R32(DSP) - 8,\n           sc_carry ? \"carry \" : \"\", sc_target ? \"target \" : \"\",\n           sc_ack ? \"ack \" : \"\", sc_atn ? \"atn \" : \"\");\n#endif\n    if (sc_ack)\n      SB_R8(SOCL, ACK, false);\n    if (sc_atn) {\n      if (TB_R8(SOCL, ATN)) {\n        SB_R8(SOCL, ATN, false);\n\n        // printf(\"RESET ATN.\\n\");\n        // printf(\">\");\n        // getchar();\n      }\n    }\n\n    if (sc_target)\n      SB_R8(SCNTL0, TRG, false);\n    if (sc_carry)\n      state.alu.carry = false;\n    return;\n\n    break;\n  }\n}\n\n/**\n * Execute one SCRIPTS R/W instruction\n *\n * The R/W instructions perform arithmetic or logic operations on\n * registers. The instruction format in the DCMD and DBC register is as follows:\n *\n * \\code\n * +---+-----+-----+\n * |7 6|5 4 3|2 1 0| DCMD Register\n * +---+-----+-----+\n *   |    |     +- 2..0: operator:\n *   |    |                000: data8\n *   |    |                001: reg << 1\n *   |    |                010: reg | data8\n *   |    |                011: reg ^ data8\n *   |    |                100: reg & data8\n *   |    |                101: reg >> 1\n *   |    |                110: reg + data8\n *   |    |                111: reg + data8 + carry\n *   |    +- 3..5: Op Code\n *   |               101: regA = operator(SFBR, data8)\n *   |               110: SFBR = operator(RegA, data8)\n *   |               111: regA = operator(RegA, data8)\n *   +- 6..7 Instruction Type: 01 = R/W\n *\n * +--+------------++---------------++-+-------------+\n * |23|22        16||15            8||7|             | DBC Register\n * +--+------------++---------------++-+-------------+\n *  |  A6--------A0         |         A7\n *  |        +--------------|---------+- 7,22..16: RegA address\n *  |                       |\n *  |                       +- 15..8: Immediate data\n *  +- 23: Use data8/SFBR\n *         0: data8 = Immediate data\n *         1: data8 = SFBR\n * \\endcode\n */\nvoid CSym53C810::execute_rw_op() {\n  int opcode = (R8(DCMD) >> 3) & 7;\n  int oper = (R8(DCMD) >> 0) & 7;\n  bool use_data8_sfbr = (GET_DBC() >> 23) & 1;\n  int reg_address =\n      ((GET_DBC() >> 16) &\n       0x7f); //| (GET_DBC() & 0x80); // manual is unclear about bit 7.\n  u8 imm_data = (u8)(GET_DBC() >> 8) & 0xff;\n  u8 op_data;\n\n#if defined(DEBUG_SYM_SCRIPTS)\n  printf(\"SYM: INS = R/W (opc %d, oper %d, use %d, add %d, imm %02x\\n\", opcode,\n         oper, use_data8_sfbr, reg_address, imm_data);\n#endif\n  if (use_data8_sfbr)\n    imm_data = R8(SFBR);\n\n  if (oper != 0) {\n    if (opcode == 5 || reg_address == 0x08) {\n      op_data = R8(SFBR);\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: %08x: sfbr (%02x) \", R32(DSP) - 8, op_data);\n#endif\n    } else {\n      op_data = (u8)ReadMem_Bar(0, 1, reg_address, 8);\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: %08x: reg%02x (%02x) \", R32(DSP) - 8, reg_address, op_data);\n#endif\n    }\n  }\n\n  u16 tmp16;\n\n  switch (oper) {\n  case 0:\n    op_data = imm_data;\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: %08x: %02x \", R32(DSP) - 8, imm_data);\n#endif\n    break;\n\n  case 1:\n    tmp16 = (op_data << 1) + (state.alu.carry ? 1 : 0);\n    state.alu.carry = (tmp16 >> 8) & 1;\n    op_data = tmp16 & 0xff;\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"<< 1 = %02x \", op_data);\n#endif\n    break;\n\n  case 2:\n    op_data |= imm_data;\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"| %02x = %02x \", imm_data, op_data);\n#endif\n    break;\n\n  case 3:\n    op_data ^= imm_data;\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"^ %02x = %02x \", imm_data, op_data);\n#endif\n    break;\n\n  case 4:\n    op_data &= imm_data;\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"& %02x = %02x \", imm_data, op_data);\n#endif\n    break;\n\n  case 5:\n    tmp16 = (op_data >> 1) + (state.alu.carry ? 0x80 : 0x00);\n    state.alu.carry = op_data & 1;\n    op_data = tmp16 & 0xff;\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\">> 1 = %02x \", op_data);\n#endif\n    break;\n\n  case 6:\n    tmp16 = op_data + imm_data;\n    state.alu.carry = (tmp16 > 0xff);\n    op_data = tmp16 & 0xff;\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"+ %02x = %02x (carry %d) \", imm_data, op_data, state.alu.carry);\n#endif\n    break;\n\n  case 7:\n    tmp16 = op_data + imm_data + (state.alu.carry ? 1 : 0);\n    state.alu.carry = (tmp16 > 0xff);\n    op_data = tmp16 & 0xff;\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"+ %02x (w/carry) = %02x (carry %d) \", imm_data, op_data,\n           state.alu.carry);\n#endif\n    break;\n  }\n\n  if (opcode == 6 || reg_address == 0x08) {\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"-> sfbr.\\n\");\n#endif\n    R8(SFBR) = op_data;\n  } else {\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"-> reg%02x.\\n\", reg_address);\n#endif\n    WriteMem_Bar(0, 1, reg_address, 8, op_data);\n  }\n}\n\n/**\n * Execute one SCRIPTS Transfer Control instruction\n *\n * The Transfer Control instructions perform conditional jumps, calls,\n * returns and interrupts. The instruction format in the DCMD and DBC\n * registers is as follows:\n *\n * \\code\n * +---+-----+-----+\n * |7 6|5 4 3|2 1 0| DCMD Register\n * +---+-----+-----+\n *   |    |     +- 0..2: SCSI Phase (I/O, C/D and MSG/ signals):\n *   |    |              The actual SCSI phase is compared against these\n *   |    |              bits.\n *   |    +- 3..5: Op Code\n *   |               000: Jump\n *   |               001: Call\n *   |               010: Return\n *   |               011: Interrupt\n *   |               1xx: reserved\n *   +- 6..7 Instruction Type: 10 = Transfer Control\n *\n * +--+-+--+--+--+--+--+--++---------------++---------------+\n * |23| |21|20|19|18|17|16||15            8||7             0| DBC Register\n * +--+-+--+--+--+--+--+--++---------------++---------------+\n *  |    |  |  |  |  |  |          |             +- 7..0: Data to compare\n *  |    |  |  |  |  |  |          |                      against SFBR\n *  |    |  |  |  |  |  |          +- 15..8: Mask that determines what bits\n *  |    |  |  |  |  |  |                    to compare against SFBR.\n *  |    |  |  |  |  |  +- 16: Wait for valid SCSI phase\n *  |    |  |  |  |  +- 17: Compare Phase\n *  |    |  |  |  +- 18: Compare SFBR data\n *  |    |  |  +- Jump if:\n *  |    |  |       0: Jump/Call/return/Interrupt if the equation is true\n *  |    |  |       0: Jump/Call/return/Interrupt if the equation is false\n *  |    |  +- Interrupt on the Fly\n *  |    +- Carry Test\n *  +- relative Addressing:\n *       0: The value in the DSPS register is an absolute address.\n *       1: The value in the DSPS register is a 24-bit signed\n *          displacement from the current DSP address.\n * \\endcode\n *\n * The equation evaluated is one of the following:\n *   - the value of the carry bit (if the Carry Test bit is set)\n *   - equality comparisons of SCSI phase and/or SFBR register data\n *   - true (if none of the compare/carry test bits are set)\n *   .\n *\n * An action is taken when the equation evaluates to either true or false\n * as determined by the \"Jump if\" bit.\n *\n * Jump:\n *   - Jump to the instruction addressed by the DSPS register.\n *   .\n *\n * Call:\n *   - Store the current DSP register value to the TEMP register.\n *   - Jump to the instruction addressed by the DSPS register.\n *   .\n *\n * Return:\n *   - Jump to the instruction addressed by the TEMP register.\n *   .\n *\n * Interrupt:\n *   - If the Interrupt on the Fly bit is set, raise the INTF interrupt.\n *   - Otherwise:\n *       - Raise the SIR interrupt\n *       - Terminate SCRIPTS execution\n *       - The DSPS value is used as an interrupt vector for the driver.\n *       .\n *   .\n **/\nvoid CSym53C810::execute_tc_op() {\n  int opcode = (R8(DCMD) >> 3) & 7;\n  int scsi_phase = (R8(DCMD) >> 0) & 7;\n  bool relative = (GET_DBC() >> 23) & 1;\n  bool carry_test = (GET_DBC() >> 21) & 1;\n  bool interrupt_fly = (GET_DBC() >> 20) & 1;\n  bool jump_if = (GET_DBC() >> 19) & 1;\n  bool cmp_data = (GET_DBC() >> 18) & 1;\n  bool cmp_phase = (GET_DBC() >> 17) & 1;\n  int cmp_mask = (GET_DBC() >> 8) & 0xff;\n  int cmp_dat = (GET_DBC() >> 0) & 0xff;\n  u32 dest_addr;\n\n  // wait_valid can be safely ignored, phases are always valid in this ideal\n  // world... bool wait_valid = (GET_DBC()>>16) & 1;\n\n  // We'll keep modifying this variable until we know what the result of the\n  // comparisons is.\n  bool do_it;\n\n  // Relative jump or not? (no effect on Return or Interrupt)\n  if (relative)\n    dest_addr = R32(DSP) + sext_u32_24(R32(DSPS));\n  else\n    dest_addr = R32(DSPS);\n\n#if defined(DEBUG_SYM_SCRIPTS)\n  printf(\"SYM: %08x: if (\", R32(DSP) - 8);\n#endif\n  if (carry_test) {\n    // All we need to check is the CARRY flag\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"(%scarry)\", jump_if ? \"\" : \"!\");\n#endif\n    do_it = (state.alu.carry == jump_if);\n  } else if (cmp_data || cmp_phase) {\n    // We need to compare data and/or phase\n    do_it = true;\n    if (cmp_data) {\n      // compare data\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"((data & 0x%02x) %s 0x%02x)\", (~cmp_mask) & 0xff,\n             jump_if ? \"==\" : \"!=\", cmp_dat & ~cmp_mask);\n#endif\n      if (((R8(SFBR) & ~cmp_mask) == (cmp_dat & ~cmp_mask)) != jump_if)\n        do_it = false;\n#if defined(DEBUG_SYM_SCRIPTS)\n      if (cmp_phase)\n        printf(\" && \");\n#endif\n    }\n\n    if (cmp_phase) {\n      // Compare phase\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"(phase %s %d)\", jump_if ? \"==\" : \"!=\", scsi_phase);\n#endif\n      if ((check_phase(scsi_phase) > 0) != jump_if)\n        do_it = false;\n    }\n  } else {\n\n    // no comparison\n    do_it = jump_if;\n  }\n\n#if defined(DEBUG_SYM_SCRIPTS)\n  printf(\") \");\n#endif\n  switch (opcode) {\n  case 0:\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"jump %x\\n\", R32(DSPS));\n#endif\n    if (do_it) {\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: Jumping %08x...\\n\", dest_addr);\n#endif\n      R32(DSP) = dest_addr;\n    }\n\n    return;\n    break;\n\n  case 1:\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"call %d\\n\", R32(DSPS));\n#endif\n    if (do_it) {\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: Calling %08x...\\n\", dest_addr);\n#endif\n      R32(TEMP) = R32(DSP);\n      R32(DSP) = dest_addr;\n    }\n\n    return;\n    break;\n\n  case 2:\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"return %d\\n\", R32(DSPS));\n#endif\n    if (do_it) {\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: Returning %08x...\\n\", R32(TEMP));\n#endif\n      R32(DSP) = R32(TEMP);\n    }\n\n    return;\n    break;\n\n  case 3:\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"interrupt%s.\\n\", interrupt_fly ? \" on the fly\" : \"\");\n#endif\n    if (do_it) {\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: Interrupt with vector %x...\\n\", R32(DSPS));\n#endif\n      if (interrupt_fly)\n        RAISE(ISTAT, INTF);\n      else\n        RAISE(DSTAT, SIR);\n    }\n\n    return;\n    break;\n\n  default:\n    FAILURE_1(NotImplemented,\n              \"SYM: Transfer Control Instruction with opcode %d is RESERVED.\\n\",\n              opcode);\n  }\n}\n\n/**\n * Execute one SCRIPTS Load/Store instruction\n *\n * The Load/Store instruction moves data between registers and memory.\n * The memory range could very well map back to the registers through\n * the PCI bus! The instruction format in the DCMD and DBC registers\n * is as follows:\n *\n * \\code\n * +-----+-+---+-+-+\n * |7 6 5|4|   |1|0| DCMD Register\n * +-----+-+---+-+-+\n *    |   |     | +- 0: Load/Store\n *    |   |     |         0: Store (register -> memory)\n *    |   |     |         1: Load (memory -> register)\n *    |   |     +- 1: No Flush (no effect)\n *    |   +- 4: DSA Relative\n *    |           0: The value in the DSPS register is absolute.\n *    |           1: The value in the DSPS register is a 24-bit\n *    |              signed offset from DSA.\n *    +- 7..5 Instruction Type: 111 = Load/Store\n *\n * +---------------++---------------++---------------+\n * |23           16||               ||         |2   0| DBC Register\n * +---------------++---------------++---------------+\n *          |                                     +- 2..0: Byte Count\n *          +- 23..16: Register Address\n * \\endcode\n *\n * This instructions moves up to 4 bytes between registers and memory.\n **/\nvoid CSym53C810::execute_ls_op() {\n  bool is_load = (R8(DCMD) >> 0) & 1;\n  bool dsa_relative = (R8(DCMD) >> 4) & 1;\n  int regaddr = (GET_DBC() >> 16) & 0x7f;\n  int byte_count = (GET_DBC() >> 0) & 7;\n  u32 memaddr;\n\n  // Relative Addressing\n  if (dsa_relative)\n    memaddr = R32(DSA) + sext_u32_24(R32(DSPS));\n  else\n    memaddr = R32(DSPS);\n\n#if defined(DEBUG_SYM_SCRIPTS)\n  printf(\"SYM: dsa_rel: %d, DSA: %04x, DSPS: %04x, mem %04x.\\n\", dsa_relative,\n         R32(DSA), R32(DSPS), memaddr);\n#endif\n  if (is_load) {\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: %08x: Load reg%02x\", R32(DSP) - 8, regaddr);\n    if (byte_count > 1)\n      printf(\"..%02x\", regaddr + byte_count - 1);\n    printf(\"from %x.\\n\", memaddr);\n#endif\n    // Perform Load Operation\n    for (int i = 0; i < byte_count; i++) {\n      u8 dat;\n      do_pci_read(memaddr + i, &dat, 1, 1);\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: %02x -> reg%02x\\n\", dat, regaddr + i);\n#endif\n      WriteMem_Bar(0, 1, regaddr + i, 8, dat);\n    }\n  } else {\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: %08x: Store reg%02x\", R32(DSP) - 8, regaddr);\n    if (byte_count > 1)\n      printf(\"..%02x\", regaddr + byte_count - 1);\n    printf(\"to %x.\\n\", memaddr);\n#endif\n    // Perform Store Operation\n    for (int i = 0; i < byte_count; i++) {\n      u8 dat = (u8)ReadMem_Bar(0, 1, regaddr + i, 8);\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: %02x <- reg%02x\\n\", dat, regaddr + i);\n#endif\n      do_pci_write(memaddr + i, &dat, 1, 1);\n    }\n  }\n}\n\n/**\n * Execute one SCRIPTS Memory Move instruction\n *\n * The Memory Move instruction is used to transfer data from one\n * region in host memory to another region through the SCSI\n * controller's. DMA. The instruction format in the DCMD register\n * is as follows:\n *\n * \\code\n * +-----+-------+-+\n * |7 6 5|       |0| DCMD Register\n * +-----+-------+-+\n *    |           +- No Flush (no effect)\n *    +- 7..5 Instruction Type: 110 = Memory Move\n * \\endcode\n *\n * This is a 3-DWORD instruction.\n *\n * The DBC register holds the number of bytes to be moved.\n * The DSPS register holds the source address.\n * The TEMP register holds the destination address.\n */\nvoid CSym53C810::execute_mm_op() {\n  u32 temp_shadow;\n  do_pci_read(R32(DSP), &temp_shadow, 4, 1);\n  R32(DSP) += 4;\n\n#if defined(DEBUG_SYM_SCRIPTS)\n  printf(\"SYM: %08x: Memory Move %06x bytes from %08x to %08x.\\n\",\n         R32(DSP) - 12, GET_DBC(), R32(DSPS), temp_shadow);\n#endif\n\n  // To speed things up, we set up a buffer and read all data\n  // at once, followed by writing all data at once.\n  void *buf = malloc(GET_DBC());\n  do_pci_read(R32(DSPS), buf, 1, GET_DBC());\n  do_pci_write(temp_shadow, buf, 1, GET_DBC());\n  free(buf);\n  return;\n}\n\n/**\n * Execute one SCRIPTS instruction.\n *\n * DSP (DMA Scripts Pointer) contains the address of the next instruction.\n * For each instruction, two DWORDS are read into the 8-bit DCMD (DMA Command),\n * 24-bit DBC (DMA Byte Counter), and 32-bit DSPS (DMA Scripts Pointer Save)\n * registers. For some commands, a third DWORD is read into the 32-bit TEMP\n * register:\n *\n * \\code\n *        +--------+------------------------+\n * DSP  : |  DCMD  |          DBC           |\n *        +--------+------------------------+\n * DSP+4: |              DSPS               |\n *        +---------------------------------+\n * DSP+8: |/ / / / / / / TEMP  / / / / / / /|\n *        +---------------------------------+\n * \\endcode\n **/\nvoid CSym53C810::execute() {\n  int optype;\n  int opcode;\n  bool is_load_store;\n\n#if defined(DEBUG_SYM_SCRIPTS)\n  printf(\"SYM: INS @ %x   \\n\", R32(DSP));\n#endif\n\n  // Read 2 DWORDS into the DCMD, DBC and DSPS registers.\n  do_pci_read(R32(DSP), &R32(DBC), 4, 1);\n  do_pci_read(R32(DSP) + 4, &R32(DSPS), 4, 1);\n\n  // Increase DSP to point to the next instruction\n  R32(DSP) += 8;\n\n#if defined(DEBUG_SYM_SCRIPTS)\n  printf(\"SYM: INS = %x, %x, %x   \\n\", R8(DCMD), GET_DBC(), R32(DSPS));\n#endif\n  /* The two most significant bits of the DCMD register determine the operation\n   * type. These are:\n   *   00: Block Move\n   *   01: I/O or R/W\n   *   10: Transfer Control\n   *   11: Memory Move or Load And Store\n   */\n  optype = (R8(DCMD) >> 6) & 3;\n  switch (optype) {\n  case 0:\n    execute_bm_op();\n    break;\n\n  case 1:\n    opcode = (R8(DCMD) >> 3) & 7;\n    if (opcode < 5)\n      execute_io_op();\n    else\n      execute_rw_op();\n    break;\n\n  case 2:\n    execute_tc_op();\n    break;\n\n  case 3:\n    is_load_store = (R8(DCMD) >> 5) & 1;\n    if (is_load_store)\n      execute_ls_op();\n    else\n      execute_mm_op();\n    break;\n  }\n\n  // single step mode\n  if (TB_R8(DCNTL, SSM)) {\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: Single step...\\n\");\n#endif\n    RAISE(DSTAT, SSI);\n  }\n}\n\n/**\n * Set an interrupt bit.\n *\n * This function checks if any other interrupt bits are active, if so,\n * the interrupt bit is set in the stacked interrupt registers. Otherwise\n * it goes straight to the respective interrupt register.\n *\n * According to the datasheet:\n * \"The SYM53C895 stacks interrupts if they occur one after another. If the SIP\n *or DIP bits in the ISTAT register are set (first level), then there is already\n *at least one pending interrupt, and any future interrupts will be stacked in\n *extra registers behind the SIST0, SIST1, and DSTAT registers (second level).\n *When two interrupts have occurred and the two levels of the stack are full,\n *any further interrupts will set additional bits in the extra registers behind\n *SIST0, SIST1 and DSTAT. When the first level of interrupts are cleared, all\n *the interrupts that came in afterward will move into the SIST0, SIST1 and\n *DSTAT. After the first interrupt is cleared by reading the appropriate\n *register, the IRQ/ pin will be deasserted for a minimum of three CLKs; the\n *stacked interrupt(s) will move into the SIST0, SIST1 or DSTAT; and the IRQ/\n *pin will be asserted once again.\n *\n * Since a masked non-fatal interrupt will not set the SIP or DIP bits,\n *interrupt stacking will not occur. A masked, non-fatal interrupt will still\n *post the interrupt in SIST0, but will not assert the IRQ/ pin. Since no\n *interrupt is generated, future interrupts will move right into the SIST0 or\n *SIST1 instead of being stacked behind another interrupt. When another\n *condition occurs that generates an interrupt, the bit corresponding to the\n *earlier masked non-fatal interrupt will still be set.\"\n **/\nvoid CSym53C810::set_interrupt(int reg, u8 interrupt) {\n  // printf(\"set interrupt %02x, %02x.\\n\",reg,interrupt);\n  switch (reg) {\n  case R_DSTAT:\n    if (TB_R8(ISTAT, DIP) || TB_R8(ISTAT, SIP)) {\n      state.dstat_stack |= interrupt;\n\n      // printf(\"DSTAT stacked.\\n\");\n    } else {\n      R8(DSTAT) |= interrupt;\n\n      // printf(\"DSTAT.\\n\");\n    }\n    break;\n\n  case R_SIST0:\n    if (TB_R8(ISTAT, DIP) || TB_R8(ISTAT, SIP)) {\n      state.sist0_stack |= interrupt;\n\n      // printf(\"SIST0 stacked.\\n\");\n    } else {\n      R8(SIST0) |= interrupt;\n\n      // printf(\"SIST0.\\n\");\n    }\n    break;\n\n  case R_SIST1:\n    if (TB_R8(ISTAT, DIP) || TB_R8(ISTAT, SIP)) {\n      state.sist1_stack |= interrupt;\n\n      // printf(\"SIST1 stacked.\\n\");\n    } else {\n      R8(SIST1) |= interrupt;\n\n      // printf(\"SIST1.\\n\");\n    }\n    break;\n\n  case R_ISTAT:\n\n    // printf(\"ISTAT.\\n\");\n    R8(ISTAT) |= interrupt;\n    break;\n\n  default:\n    FAILURE_1(NotImplemented, \"set_interrupt reg %02x!!\\n\", reg);\n  }\n\n  // printf(\"--> eval int\\n\");\n  eval_interrupts();\n\n  // printf(\"<-- eval_int\\n\");\n}\n\n/**\n * Evaluate interrupt status.\n *\n * Check interrupt registers, and determine if an interrupt should be generated.\n **/\nvoid CSym53C810::eval_interrupts() {\n  // will_assert: when this boolean value is true at the end of this function,\n  // an interrupt will be signalled to the system.\n  bool will_assert = false;\n\n  // will_halt: when this boolean value is true at the end of this function,\n  // program execution will be halted. (fatal interrupt)\n  bool will_halt = false;\n\n  // Check current interrupt status. If no interrupt is active, move interrupt\n  // flags from the interrupt stack down.\n  //\n  // (When an interrupt is signalled, but another interrupt bit is already\n  // active, the interrupt doesn't go to the interrupt register, but to the\n  // interrupt stack. The interrupt stack, however, doesn't keep track of the\n  // order in which interrupts come in, so when the interrupt stack is moved\n  // down into the interrupt registers, multiple interrupt bits may become\n  // active.)\n  if (!R8(SIST0) && !R8(SIST1) && !R8(DSTAT)) {\n    R8(SIST0) |= state.sist0_stack;\n    R8(SIST1) |= state.sist1_stack;\n    R8(DSTAT) |= state.dstat_stack;\n    state.sist0_stack = 0;\n    state.sist1_stack = 0;\n    state.dstat_stack = 0;\n  }\n\n  // Check for DMA interrupts.\n  if (R8(DSTAT) & DSTAT_FATAL) {\n    // DMA interrupt conditions always halt execution (always fatal)\n    will_halt = true;\n\n    // printf(\"  will halt(DSTAT).\\n\");\n\n    // Set the DMA interrupt pending bit.\n    SB_R8(ISTAT, DIP, true);\n\n    // If the interrupt is also enabled in the DIEN register, it will\n    // be signalled to the system.\n    if (R8(DSTAT) & R8(DIEN) & DSTAT_FATAL) {\n      will_assert = true;\n\n      // printf(\"  will assert(DSTAT).\\n\");\n    }\n  } else {\n    // Reset the DMA interrupt pending bit. (It may still be set).\n    SB_R8(ISTAT, DIP, false);\n  }\n\n  // Check for SCSI engine interrupts\n  if (R8(SIST0) || R8(SIST1)) {\n    // Set the SCSI interrupt pending bit.\n    SB_R8(ISTAT, SIP, true);\n\n    // Check if the interrupt is either fatal, or enabled.\n    if ((R8(SIST0) & (SIST0_FATAL | R8(SIEN0))) ||\n        (R8(SIST1) & (SIST1_FATAL | R8(SIEN1)))) {\n      // In either case, stop execution.\n      will_halt = true;\n\n      // printf(\"  will halt(SIST).\\n\");\n\n      // If the interrupt is enabled, signal it to the system.\n      if ((R8(SIST0) & R8(SIEN0)) || (R8(SIST1) & R8(SIEN1))) {\n        will_assert = true;\n\n        // printf(\"  will assert(SIST).\\n\");\n      }\n    }\n  } else {\n    // Reset the SCSI interrupt pending bit (It may still be set).\n    SB_R8(ISTAT, SIP, false);\n  }\n\n  // Check the interrupt on the fly bit.\n  if (TB_R8(ISTAT, INTF)) {\n    // Signal this to the system\n    will_assert = true;\n\n    // printf(\"  will assert(INTF).\\n\");\n  }\n\n  // If interrupts are disabled, don't signal any interrupt to the system.\n  if (TB_R8(DCNTL, IRQD)) {\n    will_assert = false;\n\n    // printf(\"  won't assert(IRQD).\\n\");\n  }\n\n  // Halt execution if will_halt is true.\n  if (will_halt)\n    state.executing = false;\n\n  // Assert or de-assert the interrupt line as needed\n  if (will_assert != state.irq_asserted) {\n\n    // printf(\"  doing...%d\\n\",will_assert);\n    do_pci_interrupt(0, will_assert);\n    state.irq_asserted = will_assert;\n  }\n}\n"
  },
  {
    "path": "src/Sym53C810.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_SYM53C810_H_)\n#define INCLUDED_SYM53C810_H_\n\n#include \"DiskController.hpp\"\n#include \"PCIDevice.hpp\"\n#include \"SCSIDevice.hpp\"\n\n/**\n * \\brief Symbios Sym53C810 SCSI disk controller.\n *\n * \\bug Exception below ASTDEL during OpenVMS boot when booting from SCSI.\n *\n * Documentation consulted:\n *  - SCSI 2 (http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf)\n *  - SCSI 3 Multimedia Commands (MMC)\n *(http://www.t10.org/ftp/t10/drafts/mmc/mmc-r10a.pdf)\n *  - SYM53C810A PCI-SCSI I/O Processor\n *(http://ftp.netbsd.org/pub/NetBSD/arch/bebox/doc/810a.pdf)\n *  - Symbios SCSI SCRIPTS Processors Programming Guide\n *(http://la.causeuse.org/hauke/macbsd/symbios_53cXXX_doc/lsilogic-53cXXX-scripts.pdf)\n *  .\n **/\nclass CSym53C810 : public CPCIDevice,\n                   public CDiskController,\n                   public CSCSIDevice {\npublic:\n  virtual int SaveState(FILE *f);\n  virtual int RestoreState(FILE *f);\n  virtual void check_state();\n\n  void run();\n  virtual void init();\n  virtual void start_threads();\n  virtual void stop_threads();\n\n  virtual void WriteMem_Bar(int func, int bar, u32 address, int dsize,\n                            u32 data);\n  virtual u32 ReadMem_Bar(int func, int bar, u32 address, int dsize);\n\n  virtual u32 config_read_custom(int func, u32 address, int dsize, u32 data);\n  virtual void config_write_custom(int func, u32 address, int dsize,\n                                   u32 old_data, u32 new_data, u32 data);\n\n  virtual void register_disk(class CDisk *dsk, int bus, int dev);\n\n  CSym53C810(CConfigurator *cfg, class CSystem *c, int pcibus, int pcidev);\n  virtual ~CSym53C810();\n\nprivate:\n  void write_b_scntl0(u8 value);\n  void write_b_scntl1(u8 value);\n  void write_b_istat(u8 value);\n  u8 read_b_ctest2();\n  void write_b_ctest3(u8 value);\n  void write_b_ctest4(u8 value);\n  void write_b_ctest5(u8 value);\n  void write_b_stest2(u8 value);\n  void write_b_stest3(u8 value);\n  u8 read_b_dstat();\n  u8 read_b_sist(int id);\n  void write_b_dcntl(u8 value);\n\n  void post_dsp_write();\n\n  int check_phase(int chk_phase);\n  void execute_io_op();\n  void execute_rw_op();\n  void execute_ls_op();\n  void execute_mm_op();\n  void execute_tc_op();\n  void execute_bm_op();\n  void execute();\n\n  void eval_interrupts();\n  void set_interrupt(int reg, u8 interrupt);\n  void chip_reset();\n\n  std::unique_ptr<std::thread> myThread;\n  std::atomic_bool myThreadDead{false};\n  CSemaphore mySemaphore;\n  CMutex *myRegLock;\n  bool StopThread;\n\n  /// The state structure contains all elements that need to be saved to the\n  /// statefile.\n  struct SSym_state {\n    bool irq_asserted;\n\n    union USym_regs {\n      u8 reg8[128];\n      u16 reg16[64];\n      u32 reg32[64];\n    } regs;\n\n    struct SSym_alu {\n      bool carry;\n    } alu;\n\n    u8 ram[4096];\n\n    bool executing;\n\n    bool wait_reselect;\n    bool select_timeout;\n    int disconnected;\n    u32 wait_jump;\n\n    u8 dstat_stack;\n    u8 sist0_stack;\n    u8 sist1_stack;\n\n    long gen_timer;\n\n    // int phase;\n  } state;\n};\n#endif // !defined(INCLUDED_SYM_H)\n"
  },
  {
    "path": "src/Sym53C895.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if defined(DEBUG_SYM)\n#define DEBUG_SYM_REGS\n#define DEBUG_SYM_SCRIPTS\n#endif\n#include \"Sym53C895.hpp\"\n#include \"Disk.hpp\"\n#include \"SCSIBus.hpp\"\n#include \"StdAfx.hpp\"\n#include \"System.hpp\"\n\n/// Register 00: SCNTL0: SCSI Control 0\n#define R_SCNTL0 0x00\n#define R_SCNTL0_ARB1 0x80\n#define R_SCNTL0_ARB0 0x40\n#define R_SCNTL0_START 0x20\n#define R_SCNTL0_WATN 0x10\n#define R_SCNTL0_EPC 0x08\n#define R_SCNTL0_AAP 0x02\n#define R_SCNTL0_TRG 0x01\n#define SCNTL0_MASK 0xFB\n\n/// Register 01: SCNTL1: SCSI Control 1\n#define R_SCNTL1 0x01\n#define R_SCNTL1_CON 0x10\n#define R_SCNTL1_RST 0x08\n#define R_SCNTL1_IARB 0x02\n\n/// Register 02: SCNTL2: SCSI Control 2\n#define R_SCNTL2 0x02\n#define R_SCNTL2_SDU 0x80\n#define R_SCNTL2_CHM 0x40\n#define R_SCNTL2_SLPMD 0x20\n#define R_SCNTL2_SLPHBEN 0x10\n#define R_SCNTL2_WSS 0x08\n#define R_SCNTL2_VUE0 0x04\n#define R_SCNTL2_VUE1 0x02\n#define R_SCNTL2_WSR 0x01\n#define SCNTL2_MASK 0xF2\n#define SCNTL2_W1C 0x09\n\n/// Register 03: SCNTL3: SCSI Control 3\n#define R_SCNTL3 0x03\n#define R_SCNTL3_EWS 0x08\n\n/// Register 04: SCID: SCSI Chip ID\n#define R_SCID 0x04\n#define R_SCID_ID 0x0F\n#define SCID_MASK 0x6F\n\n/// Register 05: SXFER: SCSI Transfer\n#define R_SXFER 0x05\n\n/// Register 06: SDID: SCSI Destination ID\n#define R_SDID 0x06\n#define R_SDID_ID 0x0F\n#define SDID_MASK 0x0F\n\n/// Register 07: GPREG: General Purpose\n#define R_GPREG 0x07\n#define GPREG_MASK 0x1F\n\n/// Register 08: SFBR: SCSI First Byte REceived\n#define R_SFBR 0x08\n\n/// Register 09: SOCL: SCSI Output Control Latch\n#define R_SOCL 0x09\n#define R_SOCL_ACK 0x40\n#define R_SOCL_ATN 0x20\n\n/// Register 0A: SSID: SCSI Selector ID\n#define R_SSID 0x0A\n#define R_SSID_VAL 0x80\n#define R_SSID_ID 0x0F\n\n/// Register 0B: SBCL: SCSI Bus Control Lines\n#define R_SBCL 0x0B\n#define R_SBCL_REQ 0x80\n#define R_SBCL_ACK 0x40\n#define R_SBCL_BSY 0x20\n#define R_SBCL_SEL 0x10\n#define R_SBCL_ATN 0x08\n#define R_SBCL_MSG 0x04\n#define R_SBCL_CD 0x02\n#define R_SBCL_IO 0x01\n#define R_SBCL_PHASE 0x07\n\n/// Register 0C: DSTAT: DMA Status\n#define R_DSTAT 0x0C\n#define R_DSTAT_DFE 0x80\n#define R_DSTAT_MDPE 0x40\n#define R_DSTAT_BF 0x20\n#define R_DSTAT_ABRT 0x10\n#define R_DSTAT_SSI 0x08\n#define R_DSTAT_SIR 0x04\n#define R_DSTAT_IID 0x01\n#define DSTAT_RC 0x7D\n#define DSTAT_FATAL 0x7D\n\n/// Register 0D: SSTAT0: SCSI Status 0\n#define R_SSTAT0 0x0D\n#define R_SSTAT0_RST 0x02\n#define R_SSTAT0_SDP0 0x01\n\n/// Register 0E: SSTAT1: SCSI Status 1\n#define R_SSTAT1 0x0E\n#define R_SSTAT1_SDP1 0x01\n\n/// Register 0F: SSTAT2: SCSI Status 2\n#define R_SSTAT2 0x0F\n#define R_SSTAT2_LDSC 0x02\n\n/// Register 10..13: DSA: Data Structure Address\n#define R_DSA 0x10\n\n/// Register 14: ISTAT: Interrupt Status\n#define R_ISTAT 0x14\n#define R_ISTAT_ABRT 0x80\n#define R_ISTAT_SRST 0x40\n#define R_ISTAT_SIGP 0x20\n#define R_ISTAT_SEM 0x10\n#define R_ISTAT_CON 0x08\n#define R_ISTAT_INTF 0x04\n#define R_ISTAT_SIP 0x02\n#define R_ISTAT_DIP 0x01\n#define ISTAT_MASK 0xF0\n#define ISTAT_W1C 0x04\n\n/// Register 18: CTEST0: Chip Test 0\n#define R_CTEST0 0x18\n\n/// Register 19: CTEST1: Chip Test 1\n#define R_CTEST1 0x19\n#define R_CTEST1_FMT 0xF0\n#define R_CTEST1_FFL 0x0F\n\n/// Register 1A: CTEST2: Chip Test 2\n#define R_CTEST2 0x1A\n#define R_CTEST2_DDIR 0x80\n#define R_CTEST2_SIGP 0x40\n#define R_CTEST2_CIO 0x20\n#define R_CTEST2_CM 0x10\n#define R_CTEST2_SRTCH 0x08\n#define R_CTEST2_TEOP 0x04\n#define R_CTEST2_DREQ 0x02\n#define R_CTEST2_DACK 0x01\n#define CTEST2_MASK 0x08\n\n/// Register 1B: CTEST3: Chip Test 3\n#define R_CTEST3 0x1B\n#define R_CTEST3_REV 0xf0\n#define R_CTEST3_FLF 0x08\n#define R_CTEST3_CLF 0x04\n#define R_CTEST3_FM 0x02\n#define CTEST3_MASK 0x0B\n\n/// Register 1C..1F: TEMP: Temporary\n#define R_TEMP 0x1C\n\n/// Register 20: DFIFO: DMA FIFO\n#define R_DFIFO 0x20\n\n/// Register 21: CTEST4: Chip Test 4\n#define R_CTEST4 0x21\n\n/// Register 22: CTEST5: Chip Test 5\n#define R_CTEST5 0x22\n#define R_CTEST5_ADCK 0x80\n#define R_CTEST5_BBCK 0x40\n#define CTEST5_MASK 0x3F\n\n/// Register 23: CTEST6: Chip Test 6\n#define R_CTEST6 0x23\n\n/// Register 24..26: DBC: DMA Byte Counter\n#define R_DBC 0x24\n\n/// Register 27: DCMD: DMA Command\n#define R_DCMD 0x27\n\n/// Register 28..2B: DNAD: DMA Next Address\n#define R_DNAD 0x28\n\n/// Register 2C..2F: DSP: DMA SCRIPTS Pointer\n#define R_DSP 0x2C\n\n/// Register 30..33: DSPS: DMA SCRIPTS Pointer Save\n#define R_DSPS 0x30\n\n/// Register 34..37: SCRATCHA: Scratch Register A\n#define R_SCRATCHA 0x34\n\n/// Register 38: DMODE: DMA Mode\n#define R_DMODE 0x38\n#define R_DMODE_MAN 0x01\n\n/// Register 39: DIEN: DMA Interrupt Enable\n#define R_DIEN 0x39\n#define DIEN_MASK 0x7D\n\n/// Register 3A: SBR: Scratch Byte Register\n#define R_SBR 0x3A\n\n/// Register 3B: DCNTL: DMA Control\n#define R_DCNTL 0x3B\n#define R_DCNTL_SSM 0x10\n#define R_DCNTL_STD 0x04\n#define R_DCNTL_IRQD 0x02\n#define R_DCNTL_COM 0x01\n#define DCNTL_MASK 0xFB\n\n/// Register 3C..37: ADDER: Adder Sum Output\n#define R_ADDER 0x3C\n\n/// Register 40: SIEN0: SCSI Interrupt Enable 0\n#define R_SIEN0 0x40\n#define SIEN0_MASK 0xFF\n\n/// Register 41: SIEN1: SCSI Interrupt Enable 1\n#define R_SIEN1 0x41\n#define SIEN1_MASK 0x17\n\n/// Register 42: SIST0: SCSI Interrupt Status 0\n#define R_SIST0 0x42\n#define R_SIST0_MA 0x80\n#define R_SIST0_CMP 0x40\n#define R_SIST0_SEL 0x20\n#define R_SIST0_RSL 0x10\n#define R_SIST0_SGE 0x08\n#define R_SIST0_UDC 0x04\n#define R_SIST0_RST 0x02\n#define R_SIST0_PAR 0x01\n#define SIST0_RC 0xFF\n#define SIST0_FATAL 0x8F\n\n/// Register 43: SIST1: SCSI Interrupt Status 1\n#define R_SIST1 0x43\n#define R_SIST1_SBMC 0x10\n#define R_SIST1_STO 0x04\n#define R_SIST1_GEN 0x02\n#define R_SIST1_HTH 0x01\n#define SIST1_RC 0x17\n#define SIST1_FATAL 0x14\n\n/// Register 44: SLPAR: SCSI Longitudinal Parity\n#define R_SLPAR 0x44\n\n/// Register 45: SWIDE: SCSI Wide Residue\n#define R_SWIDE 0x45\n\n/// Register 46: MACNTL: Memory Access Control\n#define R_MACNTL 0x46\n#define MACNTL_MASK 0x0F\n\n/// Register 47: GPCNTL: General Purpose Pin Control\n#define R_GPCNTL 0x47\n\n/// Register 48: STIME0: SCSI Timer 0\n#define R_STIME0 0x48\n\n/// Register 49: STIME1: SCSI Timer 1\n#define R_STIME1 0x49\n#define R_STIME1_GEN 0x0F\n#define STIME1_MASK 0x7F\n\n/// Register 4A..4B: RESPID: SCSI Response ID\n#define R_RESPID 0x4A\n\n/// Register 4C: STEST0: SCSI Test 0\n#define R_STEST0 0x4C\n\n/// Register 4D: STEST1: SCSI Test 1\n#define R_STEST1 0x4D\n#define STEST1_MASK 0xCC\n\n/// Register 4E: STEST2: SCSI Test 2\n#define R_STEST2 0x4E\n#define R_STEST2_SCE 0x80\n#define R_STEST2_ROF 0x40\n#define R_STEST2_DIF 0x20\n#define R_STEST2_SLB 0x10\n#define R_STEST2_SZM 0x08\n#define R_STEST2_AWS 0x04\n#define R_STEST2_EXT 0x02\n#define R_STEST2_LOW 0x01\n#define STEST2_MASK 0xBF\n\n/// Register 4F: STEST3: SCSI Test 3\n#define R_STEST3 0x4F\n#define R_STEST3_TE 0x80\n#define R_STEST3_STR 0x40\n#define R_STEST3_HSC 0x20\n#define R_STEST3_DSI 0x10\n#define R_STEST3_S16 0x08\n#define R_STEST3_TTM 0x04\n#define R_STEST3_CSF 0x02\n#define R_STEST3_STW 0x01\n#define STEST3_MASK 0xFF\n\n/// Register 50..51: SIDL: SCSI Input Data Latch\n#define R_SIDL 0x50\n\n/// Register 52: STEST4: SCSI Test 4\n#define R_STEST4 0x52\n\n/// Register 54..55: SODL: SCSI Output Data Latch\n#define R_SODL 0x54\n\n/// Register 58..59: SBDL: SCSI Bus Data Lines\n#define R_SBDL 0x58\n\n/// Registers 5C..5F: SCRATCHB: Scratch Register B\n#define R_SCRATCHB 0x5C\n\n/// Register 60..7F: SCRATCHC..SCRATCHJ: Scratch Register C..J\n#define R_SCRATCHC 0x60\n\n/// Acces an 8-byte register\n#define R8(a) state.regs.reg8[R_##a]\n\n/// Acces a 16-byte register\n#define R16(a) state.regs.reg16[R_##a / 2]\n\n/// Access a 32-byte register\n#define R32(a) state.regs.reg32[R_##a / 4]\n\n/**\n * Test bit in register\n *\n * \\param a is the name of the register\n * \\param b is the name of the bit\n **/\n#define TB_R8(a, b) ((R8(a) & R_##a##_##b) == R_##a##_##b)\n\n/**\n * Set bit in register.\n *\n * \\param a is the name of the register\n * \\param b is the name of the bit\n * \\param c is the value for the bit\n **/\n#define SB_R8(a, b, c) R8(a) = (R8(a) & ~R_##a##_##b) | (c ? R_##a##_##b : 0)\n\n/**\n * Write to a register, using a mask\n *\n * \\param a is the name of the register\n * \\param b is the value to write.\n *\n * Only those bits that are set to 1 in <regname>_MASK will be changed.\n **/\n#define WRM_R8(a, b) R8(a) = (R8(a) & ~a##_MASK) | ((b)&a##_MASK)\n\n/**\n * Write to a register, using a mask, and using write-1-to-clear bits\n *\n * \\param a is the name of the register\n * \\param b is the value to write.\n *\n * Only those bits that are set to 1 in <regname>_MASK will be changed.\n * In addition, bits that are set to 1 in <regname>_W1C will be cleared\n * in the register if they are set to 1 in the value.\n **/\n#define WRMW1C_R8(a, b)                                                        \\\n  R8(a) =                                                                      \\\n      (R8(a) & ~a##_MASK & ~a##_W1C) | ((b)&a##_MASK) | (R8(a) & ~(b)&a##_W1C)\n\n/**\n * Raise an interrupt\n *\n * \\param a is the name of the interrupt register\n * \\param b is the name of the bit to set\n **/\n#define RAISE(a, b) set_interrupt(R_##a, R_##a##_##b)\n\n/**\n * Clear read-to-clear-bits\n *\n * \\param a is the name of the register\n *\n * Clear bits that are set to 1 in <regname>_RC\n **/\n#define RDCLR_R8(a) R8(a) &= ~a##_RC\n\n/**\n * Get the SCSI destination ID from the SDID register\n **/\n#define GET_DEST() (R8(SDID) & R_SCID_ID)\n\n/**\n * Set the SCSI destination ID in the SDID register\n **/\n#define SET_DEST(a) R8(SDID) = (a)&R_SCID_ID\n\n/**\n * Get the value of the DBC register (24-bits)\n **/\n#define GET_DBC() (R32(DBC) & 0x00ffffff)\n\n/**\n * Set the value of the DBC register (24-bits)\n **/\n#define SET_DBC(a) R32(DBC) = (R32(DBC) & 0xff000000) | ((a)&0x00ffffff)\n\n/**\n * PCI Configuration Data Block\n **/\nu32 sym_cfg_data[64] = {\n    /*00*/ 0x000c1000, // CFID: vendor + device\n    /*04*/ 0x02000001, // CFCS: command + status\n    /*08*/ 0x01000000, // CFRV: class + revision\n    /*0c*/ 0x00000000, // CFLT: latency timer + cache line size\n    /*10*/ 0x00000001, // BAR0: IO Space\n    /*14*/ 0x00000000, // BAR1: Memory space\n    /*18*/ 0x00000000, // BAR2: RAM space\n    /*1c*/ 0x00000000, // BAR3:\n    /*20*/ 0x00000000, // BAR4:\n    /*24*/ 0x00000000, // BAR5:\n    /*28*/ 0x00000000, // CCIC: CardBus\n    /*2c*/ 0x00000000, // CSID: subsystem + vendor\n    /*30*/ 0x00000000, // BAR6: expansion rom base\n    /*34*/ 0x00000000, // CCAP: capabilities pointer\n    /*38*/ 0x00000000,\n    /*3c*/ 0x401101ff, // CFIT: interrupt configuration\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0};\n\n/**\n * PCI Configuration Mask Block\n **/\nu32 sym_cfg_mask[64] = {\n    /*00*/ 0x00000000, // CFID: vendor + device\n    /*04*/ 0x00000157, // CFCS: command + status\n    /*08*/ 0x00000000, // CFRV: class + revision\n    /*0c*/ 0x0000ffff, // CFLT: latency timer + cache line size\n    /*10*/ 0xffffff00, // BAR0: IO space (256 bytes)\n    /*14*/ 0xffffff00, // BAR1: Memory space (256 bytes)\n    /*18*/ 0xfffff000, // BAR2: RAM space (4KB)\n    /*1c*/ 0x00000000, // BAR3:\n    /*20*/ 0x00000000, // BAR4:\n    /*24*/ 0x00000000, // BAR5:\n    /*28*/ 0x00000000, // CCIC: CardBus\n    /*2c*/ 0x00000000, // CSID: subsystem + vendor\n    /*30*/ 0x00000000, // BAR6: expansion rom base\n    /*34*/ 0x00000000, // CCAP: capabilities pointer\n    /*38*/ 0x00000000,\n    /*3c*/ 0x000000ff, // CFIT: interrupt configuration\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0};\n\n/**\n * Thread entry point.\n *\n * Repeat:\n *   - Waiting until the semaphore is set\n *   - Executing SCRIPTS code until execution ends.\n *   .\n **/\nvoid CSym53C895::run() {\n  try {\n    for (;;) {\n      mySemaphore.wait();\n      if (StopThread)\n        return;\n      while (state.executing) {\n        MUTEX_LOCK(myRegLock);\n        execute();\n        MUTEX_UNLOCK(myRegLock);\n      }\n    }\n  }\n\n  catch (CException &e) {\n    printf(\"Exception in SYM thread: %s.\\n\", e.displayText().c_str());\n    myThreadDead.store(true);\n    // Let the thread die...\n  }\n}\n\n/**\n * Constructor.\n *\n * Set up the SCSI bus, and defer the rest of initialization to\n * CSym53C895::init.\n **/\nCSym53C895::CSym53C895(CConfigurator *cfg, CSystem *c, int pcibus, int pcidev)\n    : CPCIDevice(cfg, c, pcibus, pcidev), CDiskController(1, 16),\n      mySemaphore(0, 1) {\n\n  // create scsi bus\n  CSCSIBus *a = new CSCSIBus(cfg, c);\n  scsi_register(0, a, 7); // scsi id 7 by default\n}\n\n/**\n * Initialize the Symbios device.\n *\n * Reset PCI structures, reset the chipset, and set up locks.\n **/\nvoid CSym53C895::init() {\n  add_function(0, sym_cfg_data, sym_cfg_mask);\n\n  ResetPCI();\n\n  chip_reset();\n\n  myRegLock = new CMutex(\"sym-reg\");\n\n  printf(\"%s: $Id: Sym53C895.cpp,v 1.35 2008/05/31 15:47:14 iamcamiel Exp $\\n\",\n         devid_string);\n}\n\n/**\n * Create the thread, and start executing it.\n **/\nvoid CSym53C895::start_threads() {\n  if (!myThread) {\n    printf(\" sym\");\n    StopThread = false;\n    myThread = std::make_unique<std::thread>([this](){ this->run(); });\n    if (state.executing)\n      mySemaphore.set();\n  }\n}\n\n/**\n * Stop and destroy the thread.\n **/\nvoid CSym53C895::stop_threads() {\n  StopThread = true;\n  if (myThread) {\n    printf(\" sym\");\n    mySemaphore.set();\n    myThread->join();\n    myThread = nullptr;\n  }\n}\n\n/**\n * Destructor.\n *\n * Kill thread if still running, and destroy the SCSI bus.\n **/\nCSym53C895::~CSym53C895() {\n  stop_threads();\n  delete scsi_bus[0];\n}\n\n/**\n * Reset the chipset.\n *\n * Initialize all registers to their default values.\n **/\nvoid CSym53C895::chip_reset() {\n  state.executing = false;\n  state.wait_reselect = false;\n  state.irq_asserted = false;\n  state.gen_timer = 0;\n  memset(state.regs.reg32, 0, sizeof(state.regs.reg32));\n  R8(SCNTL0) = R_SCNTL0_ARB1 | R_SCNTL0_ARB0; // 810\n  R8(DSTAT) = R_DSTAT_DFE;                    // DMA FIFO empty // 810\n\n  //  R8(SSTAT2) = R_SSTAT2_LDSC; // 810\n  R8(CTEST1) = R_CTEST1_FMT;  // 810\n  R8(CTEST2) = R_CTEST2_DACK; // 810\n  R8(CTEST3) =\n      (u8)(pci_state.config_data[0][2] << 4) & R_CTEST3_REV; // Chip rev.\n  R8(MACNTL) = 0xD0;                                         // 895 type ID\n  R8(GPCNTL) = 0x0F;                                         // 810\n  R8(STEST0) = 0x03;                                         // 810\n}\n\n/**\n * Register a disk\n *\n * Attach the disk to the SCSI bus.\n **/\nvoid CSym53C895::register_disk(class CDisk *dsk, int bus, int dev) {\n  CDiskController::register_disk(dsk, bus, dev);\n  dsk->scsi_register(0, scsi_bus[0], dev);\n}\n\n/// Magic number 1 for save/restore state\nstatic u32 sym_magic1 = 0x53C895CC;\n/// Magic number 2 for save/restore state\nstatic u32 sym_magic2 = 0xCC53C895;\n\n/**\n * Save state to a Virtual Machine State file.\n **/\nint CSym53C895::SaveState(FILE *f) {\n  long ss = sizeof(state);\n  int res;\n\n  if ((res = CPCIDevice::SaveState(f)))\n    return res;\n\n  fwrite(&sym_magic1, sizeof(u32), 1, f);\n  fwrite(&ss, sizeof(long), 1, f);\n  fwrite(&state, sizeof(state), 1, f);\n  fwrite(&sym_magic2, sizeof(u32), 1, f);\n  printf(\"%s: %d bytes saved.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\n/**\n * Restore state from a Virtual Machine State file.\n **/\nint CSym53C895::RestoreState(FILE *f) {\n  long ss;\n  u32 m1;\n  u32 m2;\n  int res;\n  size_t r;\n\n  if ((res = CPCIDevice::RestoreState(f)))\n    return res;\n\n  r = fread(&m1, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m1 != sym_magic1) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&ss, sizeof(long), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (ss != sizeof(state)) {\n    printf(\"%s: STRUCT SIZE does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&state, sizeof(state), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  r = fread(&m2, sizeof(u32), 1, f);\n  if (r != 1) {\n    printf(\"%s: unexpected end of file!\\n\", devid_string);\n    return -1;\n  }\n\n  if (m2 != sym_magic2) {\n    printf(\"%s: MAGIC 1 does not match!\\n\", devid_string);\n    return -1;\n  }\n\n  printf(\"%s: %d bytes restored.\\n\", devid_string, (int)ss);\n  return 0;\n}\n\n/**\n * write data to one of the PCI BAR (relocatable) address ranges.\n **/\nvoid CSym53C895::WriteMem_Bar(int func, int bar, u32 address, int dsize,\n                              u32 data) {\n  void *p;\n\n  switch (bar) {\n  case 0:\n  case 1:\n    address &= 0x7f;\n    switch (dsize) {\n    case 8:\n      MUTEX_LOCK(myRegLock);\n#if defined(DEBUG_SYM_REGS)\n      printf(\"SYM: Write to register %02x: %02x.   \\n\", address, data);\n#endif\n      if (address >= R_SCRATCHC) {\n        state.regs.reg8[address] = (u8)data;\n        MUTEX_UNLOCK(myRegLock);\n        break;\n      }\n\n      switch (address) {\n\n      // SIMPLE CASES: JUST WRITE\n      case R_SXFER:        // 05\n      case R_DSA:          // 10\n      case R_DSA + 1:      // 11\n      case R_DSA + 2:      // 12\n      case R_DSA + 3:      // 13\n      case R_CTEST0:       // 18\n      case R_TEMP:         // 1C\n      case R_TEMP + 1:     // 1D\n      case R_TEMP + 2:     // 1E\n      case R_TEMP + 3:     // 1F\n      case R_DSP:          // 2C\n      case R_DSP + 1:      // 2D\n      case R_DSP + 2:      // 2E\n      case R_DSPS:         // 30\n      case R_DSPS + 1:     // 31\n      case R_DSPS + 2:     // 32\n      case R_DSPS + 3:     // 33\n      case R_SCRATCHA:     // 34\n      case R_SCRATCHA + 1: // 35\n      case R_SCRATCHA + 2: // 36\n      case R_SCRATCHA + 3: // 37\n      case R_DMODE:        // 38\n      case R_SBR:          // 3A     // 810\n      case R_GPCNTL:       // 47\n      case R_STIME0:       // 48\n      case R_RESPID:       // 4A\n      case R_RESPID + 1:   // 4B\n      case R_STEST0:       // 4C\n      case R_SCRATCHB:     // 5C\n      case R_SCRATCHB + 1: // 5D\n      case R_SCRATCHB + 2: // 5E\n      case R_SCRATCHB + 3: // 5F\n        state.regs.reg8[address] = (u8)data;\n        break;\n\n      case R_SCNTL0: // 00\n        // side effects: start arbitration bit\n        write_b_scntl0((u8)data);\n        break;\n\n      case R_SCNTL1: // 01\n        // side effects: start immediate arbitration bit\n        write_b_scntl1((u8)data);\n        break;\n\n      case R_SCNTL2: // 02\n        WRMW1C_R8(SCNTL2, (u8)data);\n        break;\n\n      case R_SCNTL3: // 03\n        // side effects: clearing EWS\n        write_b_scntl3((u8)data);\n        break;\n\n      case R_SCID: // 04\n        WRM_R8(SCID, (u8)data);\n        break;\n\n      case R_SDID: // 06\n        WRM_R8(SDID, (u8)data);\n        break;\n\n      case R_GPREG: // 07\n        WRM_R8(GPREG, (u8)data);\n        break;\n\n      case R_ISTAT: // 14\n        write_b_istat((u8)data);\n        break;\n\n      case R_CTEST2: // 1A\n        WRM_R8(CTEST2, (u8)data);\n        break;\n\n      case R_CTEST3: // 1B\n        write_b_ctest3((u8)data);\n        break;\n\n      case R_CTEST4: // 21\n        write_b_ctest4((u8)data);\n        break;\n\n      case R_CTEST5: // 22\n        write_b_ctest5((u8)data);\n        break;\n\n      case R_DSP + 3: // 2F\n        state.regs.reg8[address] = (u8)data;\n        post_dsp_write();\n        break;\n\n      case R_DIEN: // 39\n        WRM_R8(DIEN, (u8)data);\n        eval_interrupts();\n        break;\n\n      case R_DCNTL: // 3B\n        write_b_dcntl((u8)data);\n        break;\n\n      case R_SIEN0: // 40\n        R8(SIEN0) = (u8)data;\n        eval_interrupts();\n        break;\n\n      case R_SIEN1: // 41\n        WRM_R8(SIEN1, (u8)data);\n        eval_interrupts();\n        break;\n\n      case R_MACNTL: // 46     // 810\n        WRM_R8(MACNTL, (u8)data);\n        break;\n\n      case R_STIME1: // 49\n        WRM_R8(STIME1, (u8)data);\n        state.gen_timer = (R8(STIME1) & R_STIME1_GEN) * 30;\n        break;\n\n      case R_STEST1: // 4D\n        WRM_R8(STEST1, (u8)data);\n        break;\n\n      case R_STEST2: // 4E\n        write_b_stest2((u8)data);\n        break;\n\n      case R_STEST3: // 4F\n        write_b_stest3((u8)data);\n        break;\n\n      case R_DSTAT:  // 0C\n      case R_SSTAT0: // 0D\n      case R_SSTAT1: // 0E\n      case R_SSTAT2: // 0F\n        // printf(\"SYM: Write to read-only memory at %02x. FreeBSD driver cache\n        // test.\\n\" ,address);\n        break;\n\n      default:\n        FAILURE_2(NotImplemented,\n                  \"SYM: Write to unknown register at %02x with %08x.\\n\",\n                  address, data);\n      }\n\n      MUTEX_UNLOCK(myRegLock);\n      break;\n\n    case 16:\n      WriteMem_Bar(0, 1, address + 0, 8, (data >> 0) & 0xff);\n      WriteMem_Bar(0, 1, address + 1, 8, (data >> 8) & 0xff);\n      break;\n\n    case 32:\n      WriteMem_Bar(0, 1, address + 0, 8, (data >> 0) & 0xff);\n      WriteMem_Bar(0, 1, address + 1, 8, (data >> 8) & 0xff);\n      WriteMem_Bar(0, 1, address + 2, 8, (data >> 16) & 0xff);\n      WriteMem_Bar(0, 1, address + 3, 8, (data >> 24) & 0xff);\n      break;\n    }\n    break;\n\n  case 2:\n    p = (u8 *)state.ram + address;\n    switch (dsize) {\n    case 8:\n      *((u8 *)p) = (u8)data;\n      break;\n    case 16:\n      *((u16 *)p) = (u16)data;\n      break;\n    case 32:\n      *((u32 *)p) = (u32)data;\n      break;\n    }\n    break;\n  }\n}\n\n/**\n * Read data from one of the PCI BAR (relocatable) address ranges.\n **/\nu32 CSym53C895::ReadMem_Bar(int func, int bar, u32 address, int dsize) {\n  u32 data = 0;\n  void *p;\n\n  switch (bar) {\n  case 0:\n  case 1:\n    address &= 0x7f;\n    switch (dsize) {\n    case 8:\n      MUTEX_LOCK(myRegLock);\n      if (address >= R_SCRATCHC) {\n        data = state.regs.reg8[address];\n        MUTEX_UNLOCK(myRegLock);\n        break;\n      }\n\n      switch (address) {\n      case R_SCNTL0:     // 00\n      case R_SCNTL1:     // 01\n      case R_SCNTL2:     // 02\n      case R_SCNTL3:     // 03\n      case R_SCID:       // 04\n      case R_SXFER:      // 05\n      case R_SDID:       // 06\n      case R_GPREG:      // 07\n      case R_SFBR:       // 08\n      case R_SSID:       // 0A\n      case R_SBCL:       // 0B\n      case R_SSTAT0:     // 0D\n      case R_SSTAT1:     // 0E\n      case R_SSTAT2:     // 0F\n      case R_DSA:        // 10\n      case R_DSA + 1:    // 11\n      case R_DSA + 2:    // 12\n      case R_DSA + 3:    // 13\n      case R_ISTAT:      // 14\n      case R_CTEST0:     // 18\n      case R_CTEST1:     // 19\n      case R_CTEST3:     // 1B\n      case R_TEMP:       // 1C\n      case R_TEMP + 1:   // 1D\n      case R_TEMP + 2:   // 1E\n      case R_TEMP + 3:   // 1F\n      case R_CTEST4:     // 21\n      case R_CTEST5:     // 22\n      case R_DBC:        // 24  // 810\n      case R_DBC + 1:    // 25  // 810\n      case R_DBC + 2:    // 26  // 810\n      case R_DCMD:       // 27  // 810\n      case R_DNAD:       // 28  // 810\n      case R_DNAD + 1:   // 29  // 810\n      case R_DNAD + 2:   // 2A  // 810\n      case R_DNAD + 3:   // 2B  // 810\n      case R_DSP:        // 2C\n      case R_DSP + 1:    // 2D\n      case R_DSP + 2:    // 2E\n      case R_DSP + 3:    // 2F\n      case R_DSPS:       // 30\n      case R_DSPS + 1:   // 31\n      case R_DSPS + 2:   // 32\n      case R_DSPS + 3:   // 33\n      case R_DMODE:      // 38\n      case R_DIEN:       // 39\n      case R_SBR:        // 3A     // 810\n      case R_DCNTL:      // 3B\n      case R_SIEN0:      // 40\n      case R_SIEN1:      // 41\n      case R_MACNTL:     // 46     // 810\n      case R_GPCNTL:     // 47\n      case R_STIME0:     // 48\n      case R_STIME1:     // 49\n      case R_RESPID:     // 4A\n      case R_RESPID + 1: // 4B\n      case R_STEST0:     // 4C\n      case R_STEST1:     // 4D\n      case R_STEST2:     // 4E\n      case R_STEST3:     // 4F\n      case R_STEST4:     // 52\n      case R_SBDL:       // 58\n      case R_SBDL + 1:   // 59\n        data = state.regs.reg8[address];\n        break;\n\n      case R_DSTAT: // 0C\n        data = read_b_dstat();\n        break;\n\n      case R_CTEST2: // 1A\n        data = read_b_ctest2();\n        break;\n\n      case R_DFIFO:            // 20\n        data = R8(DBC) & 0x7f; // 810 - fake the DFIFO count\n        break;\n\n      case R_SCRATCHA:     // 34\n      case R_SCRATCHA + 1: // 35\n      case R_SCRATCHA + 2: // 36\n      case R_SCRATCHA + 3: // 37\n        data = read_b_scratcha(address - R_SCRATCHA);\n        break;\n\n      case R_SIST0: // 42\n      case R_SIST1: // 43\n        data = read_b_sist(address - R_SIST0);\n        break;\n\n      case R_SCRATCHB:     // 5C\n      case R_SCRATCHB + 1: // 5D\n      case R_SCRATCHB + 2: // 5E\n      case R_SCRATCHB + 3: // 5F\n        data = read_b_scratchb(address - R_SCRATCHB);\n        break;\n\n      default:\n        FAILURE_2(\n            NotImplemented,\n            \"SYM: Attempt to read %d bytes from unknown register at %\" PRIx32\n            \"\\n\",\n            dsize, address);\n      }\n\n      MUTEX_UNLOCK(myRegLock);\n#if defined(DEBUG_SYM_REGS)\n      printf(\"SYM: Read frm register %02x: %02x.   \\n\", address, data);\n#endif\n      break;\n\n    case 16:\n      data = (ReadMem_Bar(0, 1, address + 0, 8) << 0) & 0x00ff;\n      data |= (ReadMem_Bar(0, 1, address + 1, 8) << 8) & 0xff00;\n      break;\n\n    case 32:\n      data = (ReadMem_Bar(0, 1, address + 0, 8) << 0) & 0x000000ff;\n      data |= (ReadMem_Bar(0, 1, address + 1, 8) << 8) & 0x0000ff00;\n      data |= (ReadMem_Bar(0, 1, address + 2, 8) << 16) & 0x00ff0000;\n      data |= (ReadMem_Bar(0, 1, address + 3, 8) << 24) & 0xff000000;\n      break;\n    }\n    break;\n\n  case 2:\n    p = (u8 *)state.ram + address;\n    switch (dsize) {\n    case 8:\n      return *((u8 *)p);\n    case 16:\n      return *((u16 *)p);\n    case 32:\n      return *((u32 *)p);\n    }\n    break;\n  }\n\n  return data;\n}\n\n/**\n * Override PCI Configuration Space read action.\n *\n * Lower 80 bytes are normal, upper 80 bytes reflect into the\n * register space.\n **/\nu32 CSym53C895::config_read_custom(int func, u32 address, int dsize, u32 data) {\n  if (address >= 0x80)\n    return ReadMem_Bar(func, 1, address - 0x80, dsize);\n  else\n    return data;\n}\n\n/**\n * Override PCI Configuration Space write action.\n *\n * Lower 80 bytes are normal, upper 80 bytes reflect into the\n * register space.\n **/\nvoid CSym53C895::config_write_custom(int func, u32 address, int dsize,\n                                     u32 old_data, u32 new_data, u32 data) {\n  if (address >= 0x80)\n    WriteMem_Bar(func, 1, address - 0x80, dsize, data);\n}\n\n/**\n * Write a byte to the SCSI Control 0 register.\n *\n * This is a normal masked write operation; implemented as a separate\n * function, because there are some bits in here (START and TRG) that\n * we should do something with if a driver sets these, but that we\n * don't implement.\n *\n * START: When this bit is set, the controller should start the\n * arbitration seqence indicated by the arbitration mode bits. Used\n * only in low-level mode. UNIMPLEMENTED.\n *\n * TRG: When this bit is set, the controller is a target device.\n * UNIMPLEMENTED.\n **/\nvoid CSym53C895::write_b_scntl0(u8 value) {\n  bool old_start = TB_R8(SCNTL0, START);\n\n  WRM_R8(SCNTL0, value);\n\n  if (TB_R8(SCNTL0, START) && !old_start)\n    FAILURE(NotImplemented,\n            \"SYM: Don't know how to start arbitration sequence\");\n\n  if (TB_R8(SCNTL0, TRG))\n    FAILURE(NotImplemented, \"SYM: Don't know how to operate in target mode\");\n}\n\n/**\n * Write a byte to the SCSI Control 1 register.\n *\n * This is implemented as a separate function, because there are\n * quite a few side-effects that occur when writing to this register\n *\n * CON (Connected): This bit is automatically set any time the\n * controller is connected to the SCSI bus. The CPU can force a\n * connection or disconnection by setting or clearing this bit.\n * UNIMPLEMENTED.\n *\n * RST: Asserts the SCSI RST/ signal. Has the \"side-effect\" of\n * resetting the SCSI bus. This effects a couple of other registers.\n *\n * \\todo: Implement real reset of the SCSI bus.\n **/\nvoid CSym53C895::write_b_scntl1(u8 value) {\n  bool old_rst = TB_R8(SCNTL1, RST);\n\n  R8(SCNTL1) = value;\n\n  if (TB_R8(SCNTL1, RST) != old_rst) {\n    SB_R8(SSTAT0, SDP0, false);\n    SB_R8(SSTAT1, SDP1, false);\n    R16(SBDL) = 0;\n    R8(SBCL) = 0;\n\n    SB_R8(SSTAT0, RST, !old_rst);\n\n    //    printf(\"SYM: %s SCSI bus reset.\\n\",old_rst?\"end\":\"start\");\n    if (!old_rst)\n      RAISE(SIST0, RST);\n  }\n}\n\n/**\n * Write a byte to the SCSI Control 3 register.\n *\n * The Enable Wide SCSI bit has a side-effect on the SCSI Control 2\n * register.\n **/\nvoid CSym53C895::write_b_scntl3(u8 value) {\n  R8(SCNTL3) = value;\n\n  /* If Wide SCSI is disabled, the Wide SCSI Receive flag can't\n     be set. */\n  if (!TB_R8(SCNTL3, EWS))\n    SB_R8(SCNTL2, WSR, false);\n}\n\n/**\n * Write a byte to the SCSI Interrupt Status.\n *\n * This is implemented as a separate function, because there are\n * quite a few side-effects that occur when writing to this register\n *\n * ABRT (Abort Operation): Aborts the currently executing SCRIP, and\n * generate an interrupt.\n *\n * SRST (Software Reset): Resets the SCSI chipset.\n *\n * SIGP (Signal Process): Aborts a Wait for (Re)Selection instruction\n * by jumping to the alternate address immediately.\n *\n * Since interrupt state is affected, call eval_interrupts.\n **/\nvoid CSym53C895::write_b_istat(u8 value) {\n  bool old_srst = TB_R8(ISTAT, SRST);\n\n  WRMW1C_R8(ISTAT, value);\n\n  if (TB_R8(ISTAT, ABRT)) {\n\n    //    printf(\"SYM: Aborting on request.\\n\");\n    RAISE(DSTAT, ABRT);\n  }\n\n  if (TB_R8(ISTAT, SRST) && !old_srst) {\n\n    //    printf(\"SYM: Resetting on request.\\n\");\n    chip_reset();\n  }\n\n  if (TB_R8(ISTAT, SIGP)) {\n    if (state.wait_reselect) {\n      //      printf(\"SYM: SIGP while wait_reselect. Jumping...\\n\");\n      R32(DSP) = state.wait_jump;\n      state.wait_reselect = false;\n      state.executing = true;\n      mySemaphore.set();\n    }\n  }\n\n  eval_interrupts();\n}\n\n/**\n * Reads a byte from the Chip Test 2 register.\n *\n * This is implemented as a separate function, because:\n *   - The SIGP flag read by this register comes from the ISTAT\n *     register.\n *   - The CIO (configured as I/O) and CM (configured as memory)\n *     flags are determined from PCI Configuration space.\n *   - Reading this register has the side effect of clearing the\n *     SIGP flag.\n *   .\n **/\nu8 CSym53C895::read_b_ctest2() {\n  SB_R8(CTEST2, CIO, pci_state.config_data[0][4] != 0);\n  SB_R8(CTEST2, CM, pci_state.config_data[0][5] != 0);\n  SB_R8(CTEST2, SIGP, TB_R8(ISTAT, SIGP));\n  SB_R8(ISTAT, SIGP, false);\n\n  //  printf(\"SYM: SIGP cleared by CTEST2 read.\\n\");\n  return R8(CTEST2);\n}\n\n/**\n * Write a byte to the Chip Test 3 register.\n *\n * This is implemented as a separate function, because there are\n * some unimplemented bits that probably should have a function if\n * a driver ever decides to use these.\n *\n * FM (Fetch Pin Mode): When set, this bit causes the FETCH/ pin to\n * deassert during indirect and table indirect read operations.\n * FETCH/ will only be active during the op codde portion of an\n * instruction fetch. This allows SCRIPTS to be stored in a PROM\n * while data tables are stored in RAM. UNIMPLEMENTED.\n **/\nvoid CSym53C895::write_b_ctest3(u8 value) {\n  WRM_R8(CTEST3, value);\n\n  // if ((value>>3) & 1)\n  //  printf(\"SYM: Don't know how to flush DMA FIFO\\n\");\n  // if ((value>>2) & 1)\n  //  printf(\"SYM: Don't know how to clear DMA FIFO\\n\");\n  if ((value >> 1) & 1)\n    FAILURE(NotImplemented, \"SYM: Don't know how to handle FM mode\");\n}\n\n/**\n * Write a byte to the Chip Test 4 register.\n *\n * This is implemented as a separate function, because there are\n * some unimplemented bits that probably should have a function if\n * a driver ever decides to use these.\n *\n * SRTM: Shadow Register Test Mode. Access shadow copies of TEMP and\n * DSA. Used for manufacturing diagnostics only. UNIMPLEMENTED.\n **/\nvoid CSym53C895::write_b_ctest4(u8 value) {\n  R8(CTEST4) = value;\n\n  if ((value >> 4) & 1)\n    FAILURE(NotImplemented, \"SYM: Don't know how to handle SRTM mode\");\n}\n\n/**\n * Write a byte to the Chip Test 5 register.\n *\n * This is implemented as a separate function, because there are\n * some unimplemented bits that probably should have a function if\n * a driver ever decides to use these.\n *\n * ADCK (Clock Address Incrementor): Setting this bit increments the\n * DNAD register. The DNAD register is incremented based on the DNAD\n * contents and the current DBC value. This bit automatically clears\n * itself after incrementing the  DNAD register. UNIMPLEMENTED.\n *\n * BBCK (Clock Byte Counter): Setting this bit decrements the byte\n * count contained in the 24-bit DBC register. It is decremented\n * based on the DBC contents and the current DNAD value. This bit\n * automatically clears itself after decrementing the DBC register.\n * UNIMPLEMENTED.\n **/\nvoid CSym53C895::write_b_ctest5(u8 value) {\n  WRM_R8(CTEST5, value);\n\n  if ((value >> 7) & 1)\n    FAILURE(NotImplemented,\n            \"SYM: Don't know how to do Clock Address increment\");\n\n  if ((value >> 6) & 1)\n    FAILURE(NotImplemented,\n            \"SYM: Don't know how to do Clock Byte Counter decrement\");\n}\n\n/**\n * Read a byte from the DSTAT register.\n *\n * This is implemented as a separate function, because it requires\n * interrupt re-evaluation.\n **/\nu8 CSym53C895::read_b_dstat() {\n  u8 retval = R8(DSTAT);\n\n  RDCLR_R8(DSTAT);\n\n  // printf(\"Read DSTAT --> eval int\\n\");\n  eval_interrupts();\n\n  // printf(\"Read DSTAT <-- eval int; retval: %02x; dstat:\n  // %02x.\\n\",retval,R8(DSTAT));\n  return retval;\n}\n\n/**\n * Read a byte from the SIST0 or SIST1 register.\n *\n * This is implemented as a separate function, because it requires\n * interrupt re-evaluation.\n **/\nu8 CSym53C895::read_b_sist(int id) {\n  u8 retval = state.regs.reg8[R_SIST0 + id];\n\n  if (id)\n    RDCLR_R8(SIST1);\n  else\n    RDCLR_R8(SIST0);\n\n  eval_interrupts();\n\n  return retval;\n}\n\n/**\n * Write a byte to the DMA Control register.\n *\n * This is implemented as a separate function, because there are\n * some side-effects.\n *\n * STD (Start DMA Operation): Start executing SCSI SCRIPT. Needs to\n * wake the thread.\n *\n * IRQD (IRQ Disable): disables the IRQ pin. Requires interrupt\n * re-evaluation.\n **/\nvoid CSym53C895::write_b_dcntl(u8 value) {\n  WRM_R8(DCNTL, value);\n\n  // start operation\n  if (value & R_DCNTL_STD) {\n    state.executing = true;\n    mySemaphore.set();\n  }\n\n  // IRQD bit...\n  eval_interrupts();\n}\n\n/**\n * Read a byte from the Scratch Register A.\n *\n * This is implemented as a separate function, because depending on\n * the SRTCH bit in CTEST2, the data comes from either the Scratch\n * Register A, or the memory mapped base address of the registers.\n **/\nu8 CSym53C895::read_b_scratcha(int reg) {\n  if (TB_R8(CTEST2, SRTCH)) {\n\n    // printf(\"SYM: SCRATCHA from PCI\\n\");\n    return (u8)(pci_state.config_data[0][4] >> (reg * 8)) & 0xff;\n  } else\n    return state.regs.reg8[R_SCRATCHA + reg];\n}\n\n/**\n * Read a byte from the Scratch Register B.\n *\n * This is implemented as a separate function, because depending on\n * the SRTCH bit in CTEST2, the data comes from either the Scratch\n * Register B, or the memory mapped base address of the internal RAM.\n **/\nu8 CSym53C895::read_b_scratchb(int reg) {\n  if (TB_R8(CTEST2, SRTCH)) {\n\n    // printf(\"SYM: SCRATCHB from PCI\\n\");\n    return (u8)(pci_state.config_data[0][5] >> (reg * 8)) & 0xff;\n  } else\n    return state.regs.reg8[R_SCRATCHB + reg];\n}\n\n/**\n * Write a byte to the SCSI Test 2 register.\n *\n * This is implemented as a separate function, because there are\n * some unimplemented bits that probably should have a function if\n * a driver ever decides to use these.\n *\n * LOW (Low-level-mode). Switches the SCSI controller to low-level\n * mode operation. No SCRIPTS processor, but raw manipulation of\n * SCSI registers. Yuck. UNIMPLEMENTED.\n **/\nvoid CSym53C895::write_b_stest2(u8 value) {\n  WRM_R8(STEST2, value);\n\n  //  if (value & R_STEST2_ROF)\n  //    printf(\"SYM: Don't know how to reset SCSI offset!\\n\");\n  if (TB_R8(STEST2, LOW))\n    FAILURE(NotImplemented, \"SYM: I don't like LOW level mode\");\n}\n\n/**\n * Write a byte to the SCSI Test 3 register.\n *\n * This is implemented as a separate function, because there are\n * some unimplemented bits that probably should have a function if\n * a driver ever decides to use these.\n **/\nvoid CSym53C895::write_b_stest3(u8 value) {\n  WRM_R8(STEST3, value);\n\n  //  if (value & R_STEST3_CSF)\n  //    printf(\"SYM: Don't know how to clear the SCSI fifo.\\n\");\n}\n\n/**\n * Called after the DMA Scripts Pointer register has been written.\n *\n * Start executing SCSI SCRIPT. Needs to wake the thread.\n **/\nvoid CSym53C895::post_dsp_write() {\n  if (!TB_R8(DMODE, MAN)) {\n    state.executing = true;\n    mySemaphore.set();\n\n    // printf(\"SYM: Execution started @ %08x.\\n\",R32(DSP));\n  }\n}\n\n/**\n * Check if threads are still running.\n **/\nvoid CSym53C895::check_state() {\n  if (myThreadDead.load())\n    FAILURE(Thread, \"SYM thread has died\");\n\n  if (state.gen_timer) {\n    state.gen_timer--;\n    if (!state.gen_timer) {\n      state.gen_timer = (R8(STIME1) & R_STIME1_GEN) * 30;\n      RAISE(SIST1, GEN);\n      return;\n    }\n  }\n\n  /**\n\n  if (state.wait_reselect && PT.disconnected)\n  {\n    state.executing = true;\n    state.wait_reselect = false;\n    PT.disconnected = false;\n    //PT.disconnect_priv = false;\n    //PT.will_disconnect = false;\n    PT.reselected = true;\n    state.phase = 7; // msg in //PT.disconnect_phase;\n    R8(SSID) = GET_DEST() | R_SSID_VAL; // valid scsi selector id\n    if (TB_R8(DCNTL,COM))\n      R8(SFBR) = GET_DEST();\n    // don't expect a disconnect.\n    SB_R8(SCNTL2,SDU,true);\n    //RAISE(SIST0,RSL);\n    return 0;\n  }\n\n **/\n  if (state.disconnected) {\n    if (!TB_R8(SCNTL2, SDU)) {\n\n      // disconnect expected\n      // printf(\"SYM: Disconnect expected. stopping disconnect timer at\n      // %d.\\n\",state.disconnected);\n      state.disconnected = 0;\n      return;\n    }\n\n    state.disconnected--;\n    if (!state.disconnected) {\n\n      // printf(\"SYM: Disconnect unexpected. raising interrupt!\\n\");\n      // printf(\">\");\n      // getchar();\n      RAISE(SIST0, UDC);\n      return;\n    }\n  }\n}\n\n/**\n * Check SCSI Bus Phase.\n *\n * Returns -1 on timeout or similar, 0 on different phase, and 1 on same phase\n **/\n\nint CSym53C895::check_phase(int chk_phase) {\n  int real_phase = scsi_get_phase(0);\n\n  if (real_phase == SCSI_PHASE_ARBITRATION) {\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"Phase check... selection time-out!\\n\");\n#endif\n    RAISE(SIST1, STO); // select time-out\n    scsi_free(0);\n    state.select_timeout = false;\n    return -1;\n  }\n\n  if (real_phase == SCSI_PHASE_FREE && state.disconnected) {\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"Phase check... disconnected!\\n\");\n#endif\n    state.disconnected = 1;\n    R32(DSP) -= 8;\n    return -1;\n  }\n\n  if (real_phase == chk_phase)\n    return 1;\n  else\n    return 0;\n}\n\n/**\n * Execute one SCRIPTS Block Move instruction\n *\n * The Block Move instruction moves data between system memory and the\n * SCSI Bus. This is a two DWORD instruction. The instruction format in\n * the DCMD register is as follows:\n *\n * \\code\n * +---+-+-+-+-----+\n * |7 6|5|4|3|2 1 0| DCMD Register\n * +---+-+-+-+-----+\n *   |  | | |   +- 0..2: SCSI Phase (I/O, C/D and MSG/ signals):\n *   |  | | |            The data transfer only occurs if these bits\n *   |  | | |            match the actual SCSI bus phase.\n *   |  | | +- 3: Op Code: IGNORED\n *   |  | +- 4: Table Indirect Adressing:\n *   |  |         0: The DSPS register contains the address of the data,\n *   |  |            and the DBC register contains the number of bytes to\n *   |  |            transfer.\n *   |  |         1: The DSPS register contains a 24-bit signed offset\n *   |  |            that is added to the DSA register to get a pointer\n *   |  |            to a data structure that contains the address and\n *   |  |            byte count. This structure looks as follows:\n *   |  |                           +----+------------+\n *   |  |               DSA+DSPS:   | 00 | Byte Count |\n *   |  |                           +----+------------+\n *   |  |               DSA+DSPS+4: |  Data Address   |\n *   |  |                           +-----------------+\n *   |  +- 5: Indirect Addressing:\n *   |          0: The DSPS register contains the address of the data\n *   |          1: The DSPS register contains the address of a 32-bit\n *   |             pointer to the data.\n *   +- 6..7: Instruction Type: 00 = Block Move\n * \\endcode\n **/\nvoid CSym53C895::execute_bm_op() {\n  bool indirect = (R8(DCMD) >> 5) & 1;\n  bool table_indirect = (R8(DCMD) >> 4) & 1;\n  int scsi_phase = (R8(DCMD) >> 0) & 7;\n\n#if defined(DEBUG_SYM_SCRIPTS)\n  printf(\"SYM: INS = Block Move (i %d, t %d, opc %d, phase %d\\n\", indirect,\n         table_indirect, opcode, scsi_phase);\n#endif\n  // Compare phase\n  if (check_phase(scsi_phase) > 0) {\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: Ready for transfer.\\n\");\n#endif\n\n    u32 start;\n    u32 count;\n\n    if (table_indirect) {\n      u32 add = R32(DSA) + sext_u32_24(R32(DSPS));\n\n      add &= ~0x03; // 810\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: Reading table at DSA(%08x)+DSPS(%08x) = %08x.\\n\", R32(DSA),\n             R32(DSPS), add);\n#endif\n      do_pci_read(add, &count, 4, 1);\n      count &= 0x00ffffff;\n      do_pci_read(add + 4, &start, 4, 1);\n    } else if (indirect) {\n      FAILURE(NotImplemented, \"SYM: Unsupported: indirect addressing\");\n    } else {\n      start = R32(DSPS);\n      count = GET_DBC();\n    }\n\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: %08x: MOVE Start/count %x, %x\\n\", R32(DSP) - 8, start, count);\n#endif\n    R32(DNAD) = start;\n    SET_DBC(count); // page 5-32\n    if (count == 0) {\n\n      // printf(\"SYM: Count equals zero!\\n\");\n      RAISE(DSTAT, IID); // page 5-32\n      return;\n    }\n\n    if ((size_t)count > scsi_expected_xfer(0)) {\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: xfer %d bytes, max %d expected, in phase %d.\\n\", count,\n             scsi_expected_xfer(0), scsi_phase);\n#endif\n      count = (u32)scsi_expected_xfer(0);\n    }\n\n    u8 *scsi_data_ptr = (u8 *)scsi_xfer_ptr(0, count);\n    u8 *org_sdata_ptr = scsi_data_ptr;\n\n    switch (scsi_phase) {\n    case SCSI_PHASE_COMMAND:\n    case SCSI_PHASE_DATA_OUT:\n    case SCSI_PHASE_MSG_OUT:\n      do_pci_read(R32(DNAD), scsi_data_ptr, 1, count);\n      R32(DNAD) += count;\n      break;\n\n    case SCSI_PHASE_STATUS:\n    case SCSI_PHASE_DATA_IN:\n    case SCSI_PHASE_MSG_IN:\n      do_pci_write(R32(DNAD), scsi_data_ptr, 1, count);\n      R32(DNAD) += count;\n      break;\n    }\n\n    R8(SFBR) = *org_sdata_ptr;\n    scsi_xfer_done(0);\n    return;\n  }\n}\n\n/* Execute one SCRIPTS I/O instruction\n *\n * The I/O instructions perform common SCSI hardware sequences, like\n * Selection and reselection. The instruction format in\n * the DCMD and DBC register is as follows:\n *\n * \\code\n * +---+-----+-+-+-+\n * |7 6|5 4 3|2|1|0| DCMD Register\n * +---+-----+-+-+-+\n *   |    |   | | +- 0: Select with ATN/:\n *   |    |   | |       Valid only for Select instruction. Assert ATN/ during\n *   |    |   | |       selection\n *   |    |   | +- 1: Table Indirect Mode:\n *   |    |   |         0: All information is taken from the instruction,\n *   |    |   |            and the contents of the SCNTL3 and SXFER registers.\n *   |    |   |         1: The DSPS register contains a 24-bit signed offset\n *   |    |   |            that is added to the DSA register to get a pointer\n *   |    |   |            to a data structure that contains the destination\n *   |    |   |            ID, SCNTL3 bits, and SXFER bits. This structure\n *   |    |   |            is 32 bits long and looks as follows:\n *   |    |   |                        +--------+--------+--------+--------+\n *   |    |   |            DSA+DSPS:   | SCNTL3 | ID     | SXFER  |        |\n *   |    |   |                        +--------+--------+--------+--------+\n *   |    |   +- 2: Relative Addrressing:\n *   |    |           0: The value in the DNAD register is an absolute address.\n *   |    |           1: The value in the DNAD register is a 24-bit signed\n *   |    |              displacement from the current DSP address.\n *   |    +- 3..5: Op Code\n *   +- 6..7 Instruction Type: 01 = I/O\n *\n * +-------+-------++--------+--+-+-++-+-+---+-+-----+\n * |       |19   16||        |10|9| || |6|   |3|     | DBC Register\n * +-------+-------++--------+--+-+-++-+-+---+-+-----+\n *             |              |  |      |     +- 3: Set/Clear ATN\n *             |              |  |      +- 6: Set/Clear ACK\n *             |              |  +- 9: Set/Clear Target Mode\n *             |              +- 10: Set/Clear Carry\n *             +- 16..19: Destination ID\n * \\endcode\n *\n * The Opcode determines the actual instruction:\n * \\code\n * +-----+-----------------+-------------+\n * | OPC | Initiator mode  | Target Mode |\n * +-----+-----------------+-------------+\n * | 000 | Select          | Reselect    |\n * | 001 | Wait Disconnect | Disconnect  |\n * | 010 | Wait Reselect   | Wait Select |\n * | 011 | Set             | Set         |\n * | 100 | Clear           | Clear       |\n * +-----+-----------------+-------------+\n * \\endcode\n *\n * Select:\n *   - Arbitrate for the SCSI bus until arbitration is won.\n *   - If arbitration is won, try to select the destination ID\n *   - If the controller is selected or reselected before winning\n *     arbitration, jump to the address in the DNAD register.\n *   .\n *\n * Wait Disconnect:\n *   - Wait for the target to disconnect from the SCSI bus.\n *   .\n *\n * Wait Reselect:\n *   - If the controller is reselected, go to the next instruction.\n *   - If the controller is selected before being reselected, or if\n *     the CPU sets the SIGP flag, jump to the address in the DNAD\n *     register\n *   .\n *\n * Set/Clear:\n *   - Set or Clear the flags whose Set/Clear bits are set in the\n *     instruction.\n *   .\n **/\nvoid CSym53C895::execute_io_op() {\n  int opcode = (R8(DCMD) >> 3) & 7;\n  bool relative = (R8(DCMD) >> 2) & 1;\n  bool table_indirect = (R8(DCMD) >> 1) & 1;\n  int destination = (GET_DBC() >> 16) & 0x0f;\n  bool sc_carry = (GET_DBC() >> 10) & 1;\n  bool sc_target = (GET_DBC() >> 9) & 1;\n  bool sc_ack = (GET_DBC() >> 6) & 1;\n  bool sc_atn = (GET_DBC() >> 3) & 1;\n\n  R32(DNAD) = R32(DSPS);\n\n  u32 dest_addr = R32(DNAD);\n\n  if (relative)\n    dest_addr = R32(DSP) + sext_u32_24(R32(DNAD));\n\n#if defined(DEBUG_SYM_SCRIPTS)\n  printf(\"SYM: INS = I/O (opc %d, r %d, t %d, a %d, dest %d, sc %d%d%d%d\\n\",\n         opcode, relative, table_indirect, atn, destination, sc_carry,\n         sc_target, sc_ack, sc_atn);\n#endif\n  if (table_indirect) {\n    u32 io_addr = R32(DSA) + sext_u32_24(GET_DBC());\n    io_addr &= ~3; // 810\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: Reading table at DSA(%08x)+DBC(%08x) = %08x.\\n\", R32(DSA),\n           sext_u32_24(GET_DBC()), io_addr);\n#endif\n\n    u32 io_struc;\n    do_pci_read(io_addr, &io_struc, 4, 1);\n    destination = (io_struc >> 16) & 0x0f;\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: table indirect. io_struct = %08x, new dest = %d.\\n\", io_struc,\n           destination);\n#endif\n  }\n\n  switch (opcode) {\n  case 0:\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: %08x: SELECT %d.\\n\", R32(DSP) - 8, destination);\n#endif\n    SET_DEST(destination);\n    if (!scsi_arbitrate(0)) {\n\n      // scsi bus busy, try again next clock...\n      printf(\"scsi bus busy...\\n\");\n      R32(DSP) -= 8;\n      return;\n    }\n\n    state.select_timeout = !scsi_select(0, destination);\n    if (!state.select_timeout)  // select ok\n      SB_R8(SCNTL2, SDU, true); // don't expect a disconnect\n    return;\n\n  case 1:\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: %08x: WAIT DISCONNECT\\n\", R32(DSP) - 8);\n#endif\n\n    // maybe we need to do more??\n    scsi_free(0);\n    return;\n\n  case 2:\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: %08x: WAIT RESELECT\\n\", R32(DSP) - 8);\n#endif\n    if (TB_R8(ISTAT, SIGP)) {\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: SIGP set before wait reselect; jumping!\\n\");\n#endif\n      R32(DSP) = dest_addr;\n    } else {\n      state.wait_reselect = true;\n      state.wait_jump = dest_addr;\n      state.executing = false;\n    }\n\n    return;\n\n  case 3:\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: %08x: SET %s%s%s%s\\n\", R32(DSP) - 8, sc_carry ? \"carry \" : \"\",\n           sc_target ? \"target \" : \"\", sc_ack ? \"ack \" : \"\",\n           sc_atn ? \"atn \" : \"\");\n#endif\n    if (sc_ack)\n      SB_R8(SOCL, ACK, true);\n    if (sc_atn) {\n      if (!TB_R8(SOCL, ATN)) {\n        SB_R8(SOCL, ATN, true);\n\n        // printf(\"SET ATN.\\n\");\n        // printf(\">\");\n        // getchar();\n      }\n    }\n\n    if (sc_target)\n      SB_R8(SCNTL0, TRG, true);\n    if (sc_carry)\n      state.alu.carry = true;\n    return;\n\n  case 4:\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: %08x: CLEAR %s%s%s%s\\n\", R32(DSP) - 8,\n           sc_carry ? \"carry \" : \"\", sc_target ? \"target \" : \"\",\n           sc_ack ? \"ack \" : \"\", sc_atn ? \"atn \" : \"\");\n#endif\n    if (sc_ack)\n      SB_R8(SOCL, ACK, false);\n    if (sc_atn) {\n      if (TB_R8(SOCL, ATN)) {\n        SB_R8(SOCL, ATN, false);\n\n        // printf(\"RESET ATN.\\n\");\n        // printf(\">\");\n        // getchar();\n      }\n    }\n\n    if (sc_target)\n      SB_R8(SCNTL0, TRG, false);\n    if (sc_carry)\n      state.alu.carry = false;\n    return;\n\n    break;\n  }\n}\n\n/**\n * Execute one SCRIPTS R/W instruction\n *\n * The R/W instructions perform arithmetic or logic operations on\n * registers. The instruction format in the DCMD and DBC register is as follows:\n *\n * \\code\n * +---+-----+-----+\n * |7 6|5 4 3|2 1 0| DCMD Register\n * +---+-----+-----+\n *   |    |     +- 2..0: operator:\n *   |    |                000: data8\n *   |    |                001: reg << 1\n *   |    |                010: reg | data8\n *   |    |                011: reg ^ data8\n *   |    |                100: reg & data8\n *   |    |                101: reg >> 1\n *   |    |                110: reg + data8\n *   |    |                111: reg + data8 + carry\n *   |    +- 3..5: Op Code\n *   |               101: regA = operator(SFBR, data8)\n *   |               110: SFBR = operator(RegA, data8)\n *   |               111: regA = operator(RegA, data8)\n *   +- 6..7 Instruction Type: 01 = R/W\n *\n * +--+------------++---------------++-+-------------+\n * |23|22        16||15            8||7|             | DBC Register\n * +--+------------++---------------++-+-------------+\n *  |  A6--------A0         |         A7\n *  |        +--------------|---------+- 7,22..16: RegA address\n *  |                       |\n *  |                       +- 15..8: Immediate data\n *  +- 23: Use data8/SFBR\n *         0: data8 = Immediate data\n *         1: data8 = SFBR\n * \\endcode\n */\nvoid CSym53C895::execute_rw_op() {\n  int opcode = (R8(DCMD) >> 3) & 7;\n  int oper = (R8(DCMD) >> 0) & 7;\n  bool use_data8_sfbr = (GET_DBC() >> 23) & 1;\n  int reg_address =\n      ((GET_DBC() >> 16) &\n       0x7f); //| (GET_DBC() & 0x80); // manual is unclear about bit 7.\n  u8 imm_data = (u8)(GET_DBC() >> 8) & 0xff;\n  u8 op_data;\n\n#if defined(DEBUG_SYM_SCRIPTS)\n  printf(\"SYM: INS = R/W (opc %d, oper %d, use %d, add %d, imm %02x\\n\", opcode,\n         oper, use_data8_sfbr, reg_address, imm_data);\n#endif\n  if (use_data8_sfbr)\n    imm_data = R8(SFBR);\n\n  if (oper != 0) {\n    if (opcode == 5 || reg_address == 0x08) {\n      op_data = R8(SFBR);\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: %08x: sfbr (%02x) \", R32(DSP) - 8, op_data);\n#endif\n    } else {\n      op_data = (u8)ReadMem_Bar(0, 1, reg_address, 8);\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: %08x: reg%02x (%02x) \", R32(DSP) - 8, reg_address, op_data);\n#endif\n    }\n  }\n\n  u16 tmp16;\n\n  switch (oper) {\n  case 0:\n    op_data = imm_data;\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: %08x: %02x \", R32(DSP) - 8, imm_data);\n#endif\n    break;\n\n  case 1:\n    tmp16 = (op_data << 1) + (state.alu.carry ? 1 : 0);\n    state.alu.carry = (tmp16 >> 8) & 1;\n    op_data = tmp16 & 0xff;\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"<< 1 = %02x \", op_data);\n#endif\n    break;\n\n  case 2:\n    op_data |= imm_data;\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"| %02x = %02x \", imm_data, op_data);\n#endif\n    break;\n\n  case 3:\n    op_data ^= imm_data;\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"^ %02x = %02x \", imm_data, op_data);\n#endif\n    break;\n\n  case 4:\n    op_data &= imm_data;\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"& %02x = %02x \", imm_data, op_data);\n#endif\n    break;\n\n  case 5:\n    tmp16 = (op_data >> 1) + (state.alu.carry ? 0x80 : 0x00);\n    state.alu.carry = op_data & 1;\n    op_data = tmp16 & 0xff;\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\">> 1 = %02x \", op_data);\n#endif\n    break;\n\n  case 6:\n    tmp16 = op_data + imm_data;\n    state.alu.carry = (tmp16 > 0xff);\n    op_data = tmp16 & 0xff;\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"+ %02x = %02x (carry %d) \", imm_data, op_data, state.alu.carry);\n#endif\n    break;\n\n  case 7:\n    tmp16 = op_data + imm_data + (state.alu.carry ? 1 : 0);\n    state.alu.carry = (tmp16 > 0xff);\n    op_data = tmp16 & 0xff;\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"+ %02x (w/carry) = %02x (carry %d) \", imm_data, op_data,\n           state.alu.carry);\n#endif\n    break;\n  }\n\n  if (opcode == 6 || reg_address == 0x08) {\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"-> sfbr.\\n\");\n#endif\n    R8(SFBR) = op_data;\n  } else {\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"-> reg%02x.\\n\", reg_address);\n#endif\n    WriteMem_Bar(0, 1, reg_address, 8, op_data);\n  }\n}\n\n/**\n * Execute one SCRIPTS Transfer Control instruction\n *\n * The Transfer Control instructions perform conditional jumps, calls,\n * returns and interrupts. The instruction format in the DCMD and DBC\n * registers is as follows:\n *\n * \\code\n * +---+-----+-----+\n * |7 6|5 4 3|2 1 0| DCMD Register\n * +---+-----+-----+\n *   |    |     +- 0..2: SCSI Phase (I/O, C/D and MSG/ signals):\n *   |    |              The actual SCSI phase is compared against these\n *   |    |              bits.\n *   |    +- 3..5: Op Code\n *   |               000: Jump\n *   |               001: Call\n *   |               010: Return\n *   |               011: Interrupt\n *   |               1xx: reserved\n *   +- 6..7 Instruction Type: 10 = Transfer Control\n *\n * +--+-+--+--+--+--+--+--++---------------++---------------+\n * |23| |21|20|19|18|17|16||15            8||7             0| DBC Register\n * +--+-+--+--+--+--+--+--++---------------++---------------+\n *  |    |  |  |  |  |  |          |             +- 7..0: Data to compare\n *  |    |  |  |  |  |  |          |                      against SFBR\n *  |    |  |  |  |  |  |          +- 15..8: Mask that determines what bits\n *  |    |  |  |  |  |  |                    to compare against SFBR.\n *  |    |  |  |  |  |  +- 16: Wait for valid SCSI phase\n *  |    |  |  |  |  +- 17: Compare Phase\n *  |    |  |  |  +- 18: Compare SFBR data\n *  |    |  |  +- Jump if:\n *  |    |  |       0: Jump/Call/return/Interrupt if the equation is true\n *  |    |  |       0: Jump/Call/return/Interrupt if the equation is false\n *  |    |  +- Interrupt on the Fly\n *  |    +- Carry Test\n *  +- relative Addressing:\n *       0: The value in the DSPS register is an absolute address.\n *       1: The value in the DSPS register is a 24-bit signed\n *          displacement from the current DSP address.\n * \\endcode\n *\n * The equation evaluated is one of the following:\n *   - the value of the carry bit (if the Carry Test bit is set)\n *   - equality comparisons of SCSI phase and/or SFBR register data\n *   - true (if none of the compare/carry test bits are set)\n *   .\n *\n * An action is taken when the equation evaluates to either true or false\n * as determined by the \"Jump if\" bit.\n *\n * Jump:\n *   - Jump to the instruction addressed by the DSPS register.\n *   .\n *\n * Call:\n *   - Store the current DSP register value to the TEMP register.\n *   - Jump to the instruction addressed by the DSPS register.\n *   .\n *\n * Return:\n *   - Jump to the instruction addressed by the TEMP register.\n *   .\n *\n * Interrupt:\n *   - If the Interrupt on the Fly bit is set, raise the INTF interrupt.\n *   - Otherwise:\n *       - Raise the SIR interrupt\n *       - Terminate SCRIPTS execution\n *       - The DSPS value is used as an interrupt vector for the driver.\n *       .\n *   .\n **/\nvoid CSym53C895::execute_tc_op() {\n  int opcode = (R8(DCMD) >> 3) & 7;\n  int scsi_phase = (R8(DCMD) >> 0) & 7;\n  bool relative = (GET_DBC() >> 23) & 1;\n  bool carry_test = (GET_DBC() >> 21) & 1;\n  bool interrupt_fly = (GET_DBC() >> 20) & 1;\n  bool jump_if = (GET_DBC() >> 19) & 1;\n  bool cmp_data = (GET_DBC() >> 18) & 1;\n  bool cmp_phase = (GET_DBC() >> 17) & 1;\n  int cmp_mask = (GET_DBC() >> 8) & 0xff;\n  int cmp_dat = (GET_DBC() >> 0) & 0xff;\n  u32 dest_addr;\n\n  // wait_valid can be safely ignored, phases are always valid in this ideal\n  // world... bool wait_valid = (GET_DBC()>>16) & 1;\n\n  // We'll keep modifying this variable until we know what the result of the\n  // comparisons is.\n  bool do_it;\n\n  // Relative jump or not? (no effect on Return or Interrupt)\n  if (relative)\n    dest_addr = R32(DSP) + sext_u32_24(R32(DSPS));\n  else\n    dest_addr = R32(DSPS);\n\n#if defined(DEBUG_SYM_SCRIPTS)\n  printf(\"SYM: %08x: if (\", R32(DSP) - 8);\n#endif\n  if (carry_test) {\n    // All we need to check is the CARRY flag\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"(%scarry)\", jump_if ? \"\" : \"!\");\n#endif\n    do_it = (state.alu.carry == jump_if);\n  } else if (cmp_data || cmp_phase) {\n    // We need to compare data and/or phase\n    do_it = true;\n    if (cmp_data) {\n      // compare data\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"((data & 0x%02x) %s 0x%02x)\", (~cmp_mask) & 0xff,\n             jump_if ? \"==\" : \"!=\", cmp_dat & ~cmp_mask);\n#endif\n      if (((R8(SFBR) & ~cmp_mask) == (cmp_dat & ~cmp_mask)) != jump_if)\n        do_it = false;\n#if defined(DEBUG_SYM_SCRIPTS)\n      if (cmp_phase)\n        printf(\" && \");\n#endif\n    }\n\n    if (cmp_phase) {\n      // Compare phase\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"(phase %s %d)\", jump_if ? \"==\" : \"!=\", scsi_phase);\n#endif\n      if ((check_phase(scsi_phase) > 0) != jump_if)\n        do_it = false;\n    }\n  } else {\n\n    // no comparison\n    do_it = jump_if;\n  }\n\n#if defined(DEBUG_SYM_SCRIPTS)\n  printf(\") \");\n#endif\n  switch (opcode) {\n  case 0:\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"jump %x\\n\", R32(DSPS));\n#endif\n    if (do_it) {\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: Jumping %08x...\\n\", dest_addr);\n#endif\n      R32(DSP) = dest_addr;\n    }\n\n    return;\n    break;\n\n  case 1:\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"call %d\\n\", R32(DSPS));\n#endif\n    if (do_it) {\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: Calling %08x...\\n\", dest_addr);\n#endif\n      R32(TEMP) = R32(DSP);\n      R32(DSP) = dest_addr;\n    }\n\n    return;\n    break;\n\n  case 2:\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"return %d\\n\", R32(DSPS));\n#endif\n    if (do_it) {\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: Returning %08x...\\n\", R32(TEMP));\n#endif\n      R32(DSP) = R32(TEMP);\n    }\n\n    return;\n    break;\n\n  case 3:\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"interrupt%s.\\n\", interrupt_fly ? \" on the fly\" : \"\");\n#endif\n    if (do_it) {\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: Interrupt with vector %x...\\n\", R32(DSPS));\n#endif\n      if (interrupt_fly)\n        RAISE(ISTAT, INTF);\n      else\n        RAISE(DSTAT, SIR);\n    }\n\n    return;\n    break;\n\n  default:\n    FAILURE_1(NotImplemented,\n              \"SYM: Transfer Control Instruction with opcode %d is RESERVED.\\n\",\n              opcode);\n  }\n}\n\n/**\n * Execute one SCRIPTS Load/Store instruction\n *\n * The Load/Store instruction moves data between registers and memory.\n * The memory range could very well map back to the registers through\n * the PCI bus! The instruction format in the DCMD and DBC registers\n * is as follows:\n *\n * \\code\n * +-----+-+---+-+-+\n * |7 6 5|4|   |1|0| DCMD Register\n * +-----+-+---+-+-+\n *    |   |     | +- 0: Load/Store\n *    |   |     |         0: Store (register -> memory)\n *    |   |     |         1: Load (memory -> register)\n *    |   |     +- 1: No Flush (no effect)\n *    |   +- 4: DSA Relative\n *    |           0: The value in the DSPS register is absolute.\n *    |           1: The value in the DSPS register is a 24-bit\n *    |              signed offset from DSA.\n *    +- 7..5 Instruction Type: 111 = Load/Store\n *\n * +---------------++---------------++---------------+\n * |23           16||               ||         |2   0| DBC Register\n * +---------------++---------------++---------------+\n *          |                                     +- 2..0: Byte Count\n *          +- 23..16: Register Address\n * \\endcode\n *\n * This instructions moves up to 4 bytes between registers and memory.\n **/\nvoid CSym53C895::execute_ls_op() {\n  bool is_load = (R8(DCMD) >> 0) & 1;\n  bool dsa_relative = (R8(DCMD) >> 4) & 1;\n  int regaddr = (GET_DBC() >> 16) & 0x7f;\n  int byte_count = (GET_DBC() >> 0) & 7;\n  u32 memaddr;\n\n  // Relative Addressing\n  if (dsa_relative)\n    memaddr = R32(DSA) + sext_u32_24(R32(DSPS));\n  else\n    memaddr = R32(DSPS);\n\n#if defined(DEBUG_SYM_SCRIPTS)\n  printf(\"SYM: dsa_rel: %d, DSA: %04x, DSPS: %04x, mem %04x.\\n\", dsa_relative,\n         R32(DSA), R32(DSPS), memaddr);\n#endif\n  if (is_load) {\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: %08x: Load reg%02x\", R32(DSP) - 8, regaddr);\n    if (byte_count > 1)\n      printf(\"..%02x\", regaddr + byte_count - 1);\n    printf(\"from %x.\\n\", memaddr);\n#endif\n    // Perform Load Operation\n    for (int i = 0; i < byte_count; i++) {\n      u8 dat;\n      do_pci_read(memaddr + i, &dat, 1, 1);\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: %02x -> reg%02x\\n\", dat, regaddr + i);\n#endif\n      WriteMem_Bar(0, 1, regaddr + i, 8, dat);\n    }\n  } else {\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: %08x: Store reg%02x\", R32(DSP) - 8, regaddr);\n    if (byte_count > 1)\n      printf(\"..%02x\", regaddr + byte_count - 1);\n    printf(\"to %x.\\n\", memaddr);\n#endif\n    // Perform Store Operation\n    for (int i = 0; i < byte_count; i++) {\n      u8 dat = (u8)ReadMem_Bar(0, 1, regaddr + i, 8);\n#if defined(DEBUG_SYM_SCRIPTS)\n      printf(\"SYM: %02x <- reg%02x\\n\", dat, regaddr + i);\n#endif\n      do_pci_write(memaddr + i, &dat, 1, 1);\n    }\n  }\n}\n\n/**\n * Execute one SCRIPTS Memory Move instruction\n *\n * The Memory Move instruction is used to transfer data from one\n * region in host memory to another region through the SCSI\n * controller's. DMA. The instruction format in the DCMD register\n * is as follows:\n *\n * \\code\n * +-----+-------+-+\n * |7 6 5|       |0| DCMD Register\n * +-----+-------+-+\n *    |           +- No Flush (no effect)\n *    +- 7..5 Instruction Type: 110 = Memory Move\n * \\endcode\n *\n * This is a 3-DWORD instruction.\n *\n * The DBC register holds the number of bytes to be moved.\n * The DSPS register holds the source address.\n * The TEMP register holds the destination address.\n */\nvoid CSym53C895::execute_mm_op() {\n  u32 temp_shadow;\n  do_pci_read(R32(DSP), &temp_shadow, 4, 1);\n  R32(DSP) += 4;\n\n#if defined(DEBUG_SYM_SCRIPTS)\n  printf(\"SYM: %08x: Memory Move %06x bytes from %08x to %08x.\\n\",\n         R32(DSP) - 12, GET_DBC(), R32(DSPS), temp_shadow);\n#endif\n\n  // To speed things up, we set up a buffer and read all data\n  // at once, followed by writing all data at once.\n  void *buf = malloc(GET_DBC());\n  do_pci_read(R32(DSPS), buf, 1, GET_DBC());\n  do_pci_write(temp_shadow, buf, 1, GET_DBC());\n  free(buf);\n  return;\n}\n\n/**\n * Execute one SCRIPTS instruction.\n *\n * DSP (DMA Scripts Pointer) contains the address of the next instruction.\n * For each instruction, two DWORDS are read into the 8-bit DCMD (DMA Command),\n * 24-bit DBC (DMA Byte Counter), and 32-bit DSPS (DMA Scripts Pointer Save)\n * registers. For some commands, a third DWORD is read into the 32-bit TEMP\n * register:\n *\n * \\code\n *        +--------+------------------------+\n * DSP  : |  DCMD  |          DBC           |\n *        +--------+------------------------+\n * DSP+4: |              DSPS               |\n *        +---------------------------------+\n * DSP+8: |/ / / / / / / TEMP  / / / / / / /|\n *        +---------------------------------+\n * \\endcode\n **/\nvoid CSym53C895::execute() {\n  int optype;\n  int opcode;\n  bool is_load_store;\n\n#if defined(DEBUG_SYM_SCRIPTS)\n  printf(\"SYM: INS @ %x   \\n\", R32(DSP));\n#endif\n\n  // Read 2 DWORDS into the DCMD, DBC and DSPS registers.\n  do_pci_read(R32(DSP), &R32(DBC), 4, 1);\n  do_pci_read(R32(DSP) + 4, &R32(DSPS), 4, 1);\n\n  // Increase DSP to point to the next instruction\n  R32(DSP) += 8;\n\n#if defined(DEBUG_SYM_SCRIPTS)\n  printf(\"SYM: INS = %x, %x, %x   \\n\", R8(DCMD), GET_DBC(), R32(DSPS));\n#endif\n  /* The two most significant bits of the DCMD register determine the operation\n   * type. These are:\n   *   00: Block Move\n   *   01: I/O or R/W\n   *   10: Transfer Control\n   *   11: Memory Move or Load And Store\n   */\n  optype = (R8(DCMD) >> 6) & 3;\n  switch (optype) {\n  case 0:\n    execute_bm_op();\n    break;\n\n  case 1:\n    opcode = (R8(DCMD) >> 3) & 7;\n    if (opcode < 5)\n      execute_io_op();\n    else\n      execute_rw_op();\n    break;\n\n  case 2:\n    execute_tc_op();\n    break;\n\n  case 3:\n    is_load_store = (R8(DCMD) >> 5) & 1;\n    if (is_load_store)\n      execute_ls_op();\n    else\n      execute_mm_op();\n    break;\n  }\n\n  // single step mode\n  if (TB_R8(DCNTL, SSM)) {\n#if defined(DEBUG_SYM_SCRIPTS)\n    printf(\"SYM: Single step...\\n\");\n#endif\n    RAISE(DSTAT, SSI);\n  }\n}\n\n/**\n * Set an interrupt bit.\n *\n * This function checks if any other interrupt bits are active, if so,\n * the interrupt bit is set in the stacked interrupt registers. Otherwise\n * it goes straight to the respective interrupt register.\n *\n * According to the datasheet:\n * \"The SYM53C895 stacks interrupts if they occur one after another. If the SIP\n *or DIP bits in the ISTAT register are set (first level), then there is already\n *at least one pending interrupt, and any future interrupts will be stacked in\n *extra registers behind the SIST0, SIST1, and DSTAT registers (second level).\n *When two interrupts have occurred and the two levels of the stack are full,\n *any further interrupts will set additional bits in the extra registers behind\n *SIST0, SIST1 and DSTAT. When the first level of interrupts are cleared, all\n *the interrupts that came in afterward will move into the SIST0, SIST1 and\n *DSTAT. After the first interrupt is cleared by reading the appropriate\n *register, the IRQ/ pin will be deasserted for a minimum of three CLKs; the\n *stacked interrupt(s) will move into the SIST0, SIST1 or DSTAT; and the IRQ/\n *pin will be asserted once again.\n *\n * Since a masked non-fatal interrupt will not set the SIP or DIP bits,\n *interrupt stacking will not occur. A masked, non-fatal interrupt will still\n *post the interrupt in SIST0, but will not assert the IRQ/ pin. Since no\n *interrupt is generated, future interrupts will move right into the SIST0 or\n *SIST1 instead of being stacked behind another interrupt. When another\n *condition occurs that generates an interrupt, the bit corresponding to the\n *earlier masked non-fatal interrupt will still be set.\"\n **/\nvoid CSym53C895::set_interrupt(int reg, u8 interrupt) {\n  // printf(\"set interrupt %02x, %02x.\\n\",reg,interrupt);\n  switch (reg) {\n  case R_DSTAT:\n    if (TB_R8(ISTAT, DIP) || TB_R8(ISTAT, SIP)) {\n      state.dstat_stack |= interrupt;\n\n      // printf(\"DSTAT stacked.\\n\");\n    } else {\n      R8(DSTAT) |= interrupt;\n\n      // printf(\"DSTAT.\\n\");\n    }\n    break;\n\n  case R_SIST0:\n    if (TB_R8(ISTAT, DIP) || TB_R8(ISTAT, SIP)) {\n      state.sist0_stack |= interrupt;\n\n      // printf(\"SIST0 stacked.\\n\");\n    } else {\n      R8(SIST0) |= interrupt;\n\n      // printf(\"SIST0.\\n\");\n    }\n    break;\n\n  case R_SIST1:\n    if (TB_R8(ISTAT, DIP) || TB_R8(ISTAT, SIP)) {\n      state.sist1_stack |= interrupt;\n\n      // printf(\"SIST1 stacked.\\n\");\n    } else {\n      R8(SIST1) |= interrupt;\n\n      // printf(\"SIST1.\\n\");\n    }\n    break;\n\n  case R_ISTAT:\n\n    // printf(\"ISTAT.\\n\");\n    R8(ISTAT) |= interrupt;\n    break;\n\n  default:\n    FAILURE_1(NotImplemented, \"set_interrupt reg %02x!!\\n\", reg);\n  }\n\n  // printf(\"--> eval int\\n\");\n  eval_interrupts();\n\n  // printf(\"<-- eval_int\\n\");\n}\n\n/**\n * Evaluate interrupt status.\n *\n * Check interrupt registers, and determine if an interrupt should be generated.\n **/\nvoid CSym53C895::eval_interrupts() {\n  // will_assert: when this boolean value is true at the end of this function,\n  // an interrupt will be signalled to the system.\n  bool will_assert = false;\n\n  // will_halt: when this boolean value is true at the end of this function,\n  // program execution will be halted. (fatal interrupt)\n  bool will_halt = false;\n\n  // Check current interrupt status. If no interrupt is active, move interrupt\n  // flags from the interrupt stack down.\n  //\n  // (When an interrupt is signalled, but another interrupt bit is already\n  // active, the interrupt doesn't go to the interrupt register, but to the\n  // interrupt stack. The interrupt stack, however, doesn't keep track of the\n  // order in which interrupts come in, so when the interrupt stack is moved\n  // down into the interrupt registers, multiple interrupt bits may become\n  // active.)\n  if (!R8(SIST0) && !R8(SIST1) && !R8(DSTAT)) {\n    R8(SIST0) |= state.sist0_stack;\n    R8(SIST1) |= state.sist1_stack;\n    R8(DSTAT) |= state.dstat_stack;\n    state.sist0_stack = 0;\n    state.sist1_stack = 0;\n    state.dstat_stack = 0;\n  }\n\n  // Check for DMA interrupts.\n  if (R8(DSTAT) & DSTAT_FATAL) {\n    // DMA interrupt conditions always halt execution (always fatal)\n    will_halt = true;\n\n    // printf(\"  will halt(DSTAT).\\n\");\n\n    // Set the DMA interrupt pending bit.\n    SB_R8(ISTAT, DIP, true);\n\n    // If the interrupt is also enabled in the DIEN register, it will\n    // be signalled to the system.\n    if (R8(DSTAT) & R8(DIEN) & DSTAT_FATAL) {\n      will_assert = true;\n\n      // printf(\"  will assert(DSTAT).\\n\");\n    }\n  } else {\n    // Reset the DMA interrupt pending bit. (It may still be set).\n    SB_R8(ISTAT, DIP, false);\n  }\n\n  // Check for SCSI engine interrupts\n  if (R8(SIST0) || R8(SIST1)) {\n    // Set the SCSI interrupt pending bit.\n    SB_R8(ISTAT, SIP, true);\n\n    // Check if the interrupt is either fatal, or enabled.\n    if ((R8(SIST0) & (SIST0_FATAL | R8(SIEN0))) ||\n        (R8(SIST1) & (SIST1_FATAL | R8(SIEN1)))) {\n      // In either case, stop execution.\n      will_halt = true;\n\n      // printf(\"  will halt(SIST).\\n\");\n\n      // If the interrupt is enabled, signal it to the system.\n      if ((R8(SIST0) & R8(SIEN0)) || (R8(SIST1) & R8(SIEN1))) {\n        will_assert = true;\n\n        // printf(\"  will assert(SIST).\\n\");\n      }\n    }\n  } else {\n    // Reset the SCSI interrupt pending bit (It may still be set).\n    SB_R8(ISTAT, SIP, false);\n  }\n\n  // Check the interrupt on the fly bit.\n  if (TB_R8(ISTAT, INTF)) {\n    // Signal this to the system\n    will_assert = true;\n\n    // printf(\"  will assert(INTF).\\n\");\n  }\n\n  // If interrupts are disabled, don't signal any interrupt to the system.\n  if (TB_R8(DCNTL, IRQD)) {\n    will_assert = false;\n\n    // printf(\"  won't assert(IRQD).\\n\");\n  }\n\n  // Halt execution if will_halt is true.\n  if (will_halt)\n    state.executing = false;\n\n  // Assert or de-assert the interrupt line as needed\n  if (will_assert != state.irq_asserted) {\n\n    // printf(\"  doing...%d\\n\",will_assert);\n    do_pci_interrupt(0, will_assert);\n    state.irq_asserted = will_assert;\n  }\n}\n"
  },
  {
    "path": "src/Sym53C895.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_SYM53C895_H_)\n#define INCLUDED_SYM53C895_H_\n\n#include \"DiskController.hpp\"\n#include \"PCIDevice.hpp\"\n#include \"SCSIDevice.hpp\"\n\n/**\n * \\brief Symbios Sym53C895 SCSI disk controller.\n *\n * \\bug PROCGONE bugcheck during OpenVMS boot, probably because proper option\n *ROM is missing.\n *\n * Documentation consulted:\n *  - SCSI 2 (http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf)\n *  - SCSI 3 Multimedia Commands (MMC)\n *(http://www.t10.org/ftp/t10/drafts/mmc/mmc-r10a.pdf)\n *  - SYM53C895 PCI-Ultra2 SCSI I/O Processor\n *(http://www.datasheet4u.com/html/S/Y/M/SYM53C895_LSILogic.pdf.html)\n *  - Symbios SCSI SCRIPTS Processors Programming Guide\n *(http://la.causeuse.org/hauke/macbsd/symbios_53cXXX_doc/lsilogic-53cXXX-scripts.pdf)\n *  .\n **/\nclass CSym53C895 : public CPCIDevice,\n                   public CDiskController,\n                   public CSCSIDevice {\npublic:\n  virtual int SaveState(FILE *f);\n  virtual int RestoreState(FILE *f);\n  virtual void check_state();\n\n  void run();\n  virtual void init();\n  virtual void start_threads();\n  virtual void stop_threads();\n\n  virtual void WriteMem_Bar(int func, int bar, u32 address, int dsize,\n                            u32 data);\n  virtual u32 ReadMem_Bar(int func, int bar, u32 address, int dsize);\n\n  virtual u32 config_read_custom(int func, u32 address, int dsize, u32 data);\n  virtual void config_write_custom(int func, u32 address, int dsize,\n                                   u32 old_data, u32 new_data, u32 data);\n\n  virtual void register_disk(class CDisk *dsk, int bus, int dev);\n\n  CSym53C895(CConfigurator *cfg, class CSystem *c, int pcibus, int pcidev);\n  virtual ~CSym53C895();\n\nprivate:\n  void write_b_scntl0(u8 value);\n  void write_b_scntl1(u8 value);\n  void write_b_scntl3(u8 value);\n  void write_b_istat(u8 value);\n  u8 read_b_ctest2();\n  void write_b_ctest3(u8 value);\n  void write_b_ctest4(u8 value);\n  void write_b_ctest5(u8 value);\n  void write_b_stest2(u8 value);\n  void write_b_stest3(u8 value);\n  u8 read_b_dstat();\n  u8 read_b_sist(int id);\n  void write_b_dcntl(u8 value);\n  u8 read_b_scratcha(int reg);\n  u8 read_b_scratchb(int reg);\n\n  void post_dsp_write();\n\n  int check_phase(int chk_phase);\n  void execute_io_op();\n  void execute_rw_op();\n  void execute_ls_op();\n  void execute_mm_op();\n  void execute_tc_op();\n  void execute_bm_op();\n  void execute();\n\n  void eval_interrupts();\n  void set_interrupt(int reg, u8 interrupt);\n  void chip_reset();\n\n  std::unique_ptr<std::thread> myThread;\n  std::atomic_bool myThreadDead{false};\n  CSemaphore mySemaphore;\n  CMutex *myRegLock;\n  bool StopThread;\n\n  /// The state structure contains all elements that need to be saved to the\n  /// statefile.\n  struct SSym_state {\n    bool irq_asserted;\n\n    union USym_regs {\n      u8 reg8[128];\n      u16 reg16[64];\n      u32 reg32[64];\n    } regs;\n\n    struct SSym_alu {\n      bool carry;\n    } alu;\n\n    u8 ram[4096];\n\n    bool executing;\n\n    bool wait_reselect;\n    bool select_timeout;\n    int disconnected;\n    u32 wait_jump;\n\n    u8 dstat_stack;\n    u8 sist0_stack;\n    u8 sist1_stack;\n\n    long gen_timer;\n\n    // int phase;\n  } state;\n};\n#endif // !defined(INCLUDED_SYM_H)\n"
  },
  {
    "path": "src/System.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"System.hpp\"\n#include \"AlphaCPU.hpp\"\n#include \"DPR.hpp\"\n#include \"StdAfx.hpp\"\n#include \"lockstep.hpp\"\n\n#include <ctype.h>\n#include <signal.h>\n#include <stdlib.h>\n\n#define CLOCK_RATIO 10000\n\n#if defined(LS_MASTER) || defined(LS_SLAVE)\nchar debug_string[10000] = \"\";\nchar *dbg_strptr = debug_string;\n#endif\n\n/**\n * Constructor.\n **/\nCSystem::CSystem(CConfigurator *cfg) {\n  int i;\n\n  if (theSystem != 0)\n    FAILURE(Configuration, \"More than one system\");\n  theSystem = this;\n  myCfg = cfg;\n\n  iNumComponents = 0;\n  iNumMemories = 0;\n  iNumCPUs = 0;\n  iNumMemoryBits = (int)myCfg->get_num_value(\"memory.bits\", false, 27);\n\n  //  iNumConfig = 0;\n#if defined(IDB)\n  iSingleStep = 0;\n  iSSCycles = 0;\n#endif\n  for (i = 0; i < 4; i++)\n    state.cchip.dim[i] = 0;\n  state.cchip.drir = 0;\n  state.cchip.misc = U64(0x0000000800000000);\n  state.cchip.csc = U64(0x3142444014157803);\n\n  state.dchip.drev = 0x01;\n  state.dchip.dsc = 0x43;\n  state.dchip.dsc2 = 0x03;\n  state.dchip.str = 0x25;\n\n  // initialize pchip data\n  for (i = 0; i < 2; i++) {\n    memset(&state.pchip[i], 0, sizeof(struct SSys_state::SSys_pchip));\n    state.pchip[i].wsba[3] = 2;\n  }\n\n  state.pchip[0].pctl = U64(0x0000104401440081);\n  state.pchip[1].pctl = U64(0x0000504401440081);\n\n  state.tig.FwWrite = 0;\n  state.tig.HaltA = 0;\n  state.tig.HaltB = 0;\n\n  state.cpu_lock_flags = 0;\n\n  if (iNumMemoryBits > 30) {\n\n    // size_t may not be big enough, and makes 2^31 negative, so the\n    // alloc fails.  We're going to allocate the memory in\n    //  2^(iNumMemoryBits-10) chunks of 2^10.\n    CHECK_ALLOCATION(memory = calloc(1 << (iNumMemoryBits - 10), 1 << 10));\n  } else\n    CHECK_ALLOCATION(memory = calloc(1 << iNumMemoryBits, 1));\n\n  cpu_lock_mutex = new CFastMutex(\"cpu-locking-lock\");\n\n  printf(\"%s(%s): $Id: System.cpp,v 1.79 2008/06/12 07:29:44 iamcamiel Exp $\\n\",\n         cfg->get_myName(), cfg->get_myValue());\n}\n\n/**\n * Destructor. Calls the destructors for registered devices, and\n * frees used memory.\n **/\nCSystem::~CSystem() {\n  int i;\n\n  printf(\"Freeing memory in use by system...\\n\");\n\n  for (i = 0; i < iNumComponents; i++)\n    delete acComponents[i];\n\n  for (i = 0; i < iNumMemories; i++)\n    free(asMemories[i]);\n\n  free(memory);\n}\n\n/**\n * free memory, and allocate and clear new memory.\n **/\nvoid CSystem::ResetMem(unsigned int membits) {\n  free(memory);\n  iNumMemoryBits = membits;\n  CHECK_ALLOCATION(memory = calloc(1 << iNumMemoryBits, 1));\n}\n\n/**\n * Register a device.\n **/\nvoid CSystem::RegisterComponent(CSystemComponent *component) {\n  acComponents[iNumComponents] = component;\n  iNumComponents++;\n}\n\nvoid CSystem::UnregisterComponent(CSystemComponent *component) {\n iNumComponents--;\n}\n\n/**\n * Get the number of bits that corresponds to the amount of RAM installed.\n * (e.g. 28 = 256 MB, 29 = 512 MB, 30 = 1 GB)\n **/\nunsigned int CSystem::get_memory_bits() { return iNumMemoryBits; }\n\n/**\n * Obtain a pointer to system memory.\n **/\nchar *CSystem::PtrToMem(u64 address) {\n  if (address >> iNumMemoryBits) // Non Memory\n    return 0;\n\n  return &(((char *)memory)[(int)address]);\n}\n\n/**\n * Register a device as being a CPU. Return the CPU number.\n **/\nint CSystem::RegisterCPU(class CAlphaCPU *cpu) {\n  if (iNumCPUs >= 4)\n    return -1;\n  acCPUs[iNumCPUs] = cpu;\n  iNumCPUs++;\n  return iNumCPUs - 1;\n}\n\n/**\n * Reserve a range of the 64-bit system address space for a device.\n **/\nint CSystem::RegisterMemory(CSystemComponent *component, int index, u64 base,\n                            u64 length) {\n  struct SMemoryUser *m;\n  int i;\n\n#if defined(CHECK_MEM_RANGES)\n  for (i = 0; i < iNumMemories; i++) {\n    if (component == asMemories[i]->component)\n      continue;\n\n    // check for overlaps\n    if (base >= asMemories[i]->base &&\n        base <= (asMemories[i]->base + asMemories[i]->length - 1)) {\n      printf(\n          \"WARNING: Start address for %s/%d (%016\" PRIx64 \"-%016\" PRIx64 \")\\n\"\n          \"  is within memory range of %s/%d (%016\" PRIx64 \"-%016\" PRIx64\n          \").\\n\",\n          component->devid_string, index, base, base + length - 1,\n          asMemories[i]->component->devid_string, asMemories[i]->index,\n          asMemories[i]->base, asMemories[i]->base + asMemories[i]->length - 1);\n    }\n\n    if (base + length - 1 >= asMemories[i]->base &&\n        base + length - 1 <=\n            (asMemories[i]->base + asMemories[i]->length - 1)) {\n      printf(\"WARNING: End address for %s/%d (%016\" PRIx64 \"-%016\" PRIx64 \")\\n\"\n             \"  is within memory range of %s/%d (%016\" PRIx64 \"-%016\" PRIx64\n             \").\\n\",\n             component->devid_string, index, base, base + length - 1,\n             asMemories[i]->component->devid_string, asMemories[i]->index,\n             asMemories[i]->base,\n             asMemories[i]->base + asMemories[i]->length - 1);\n    }\n  }\n#endif // defined(CHECK_MEM_RANGES)\n\n  for (i = 0; i < iNumMemories; i++) {\n    if ((asMemories[i]->component == component) &&\n        (asMemories[i]->index == index)) {\n      asMemories[i]->base = base;\n      asMemories[i]->length = length;\n      return 0;\n    }\n  }\n\n  CHECK_ALLOCATION(\n      m = (struct SMemoryUser *)malloc(sizeof(struct SMemoryUser)));\n  m->component = component;\n  m->base = base;\n  m->length = length;\n  m->index = index;\n\n  asMemories[iNumMemories] = m;\n  iNumMemories++;\n  return 0;\n}\n\nint got_sigint = 0;\n\n/**\n * Handle a SIGINT by setting a flag that terminates the emulator.\n **/\nvoid sigint_handler(int signum) { got_sigint = 1; }\n\n/**\n * Run the system by clocking the CPU(s) and devices.\n **/\nvoid CSystem::Run() {\n  int i;\n\n  int k;\n\n#if defined(DUMP_MEMMAP)\n  printf(\"ES40 Memory Map\\n\");\n  printf(\"Physical Address Size     Device/Index\\n\");\n  printf(\"---------------- -------- -------------------------\\n\");\n  for (i = 0; i < iNumMemories; i++) {\n    printf(\"%016\" PRIx64 \" %8x %s/%d\\n\", asMemories[i]->base,\n           asMemories[i]->length, asMemories[i]->component->devid_string,\n           asMemories[i]->index);\n  }\n#endif // defined(DUMP_MEMMAP)\n\n  /* catch CTRL-C and shutdown gracefully */\n  signal(SIGINT, &sigint_handler);\n\n  start_threads();\n\n  for (k = 0;; k++) {\n    if (got_sigint)\n      FAILURE(Graceful, \"CTRL-C detected\");\n    std::this_thread::sleep_for(std::chrono::milliseconds(100));\n    for (i = 0; i < iNumComponents; i++)\n      acComponents[i]->check_state();\n#if !defined(HIDE_COUNTER)\n#if defined(PROFILE)\n    printf(\"%d | %016\" PRIx64 \" | %\" PRId64 \" profiled instructions.  \\r\", k,\n           acCPUs[0]->get_pc(), profiled_insts);\n#else  // defined(PROFILE)\n    printf(\"%d | %016\" PRIx64 \"\\r\", k, acCPUs[0]->get_pc());\n#endif // defined(PROFILE)\n#endif // defined(HIDE_COUNTER)\n  }\n\n  //  printf (\"%%SYS-W-SHUTDOWN: CTRL-C or Device Failed\\n\");\n  //  return 1;\n}\n\n/**\n * Do one clock tick. The cpu(s) will execute one single instruction, and\n * some devices may be clocked.\n **/\nint CSystem::SingleStep() {\n  for (int i = 0; i < iNumCPUs; i++)\n    if (!acCPUs[i]->get_waiting())\n      acCPUs[i]->execute();\n\n      //  iSingleStep++;\n#if defined(LS_MASTER) || defined(LS_SLAVE)\n  if (!(iSingleStep % 50)) {\n    lockstep_sync_m2s(\"sync1\");\n    *dbg_strptr = '\\0';\n    lockstep_compare(debug_string);\n    dbg_strptr = debug_string;\n    *dbg_strptr = '\\0';\n  }\n#endif // defined(LS_MASTER) || defined(LS_SLAVE)\n\n  //  if (iSingleStep >= CLOCK_RATIO)\n  //  {\n  //     iSingleStep = 0;\n  //     for(i=0;i<iNumSlowClocks;i++)\n  //     {\n  //        result = acSlowClocks[i]->DoClock();\n  //      if (result)\n  //        return result;\n  //     }\n  //#ifdef IDB\n  //     iSSCycles++;\n  //#if !defined(LS_SLAVE)\n  //     if (bHashing)\n  //#endif\n  //       printf(\"%d | %016\" PRIx64 \"\\r\",iSSCycles,acCPUs[0]->get_pc());\n  //#endif\n  //  }\n  return 0;\n}\n\n#if defined(DEBUG_PORTACCESS)\nu64 lastport;\n#endif // defined(DEBUG_PORTACCESS)\nvoid CSystem::cpu_lock(int cpuid, u64 address) {\n  SCOPED_FM_LOCK(cpu_lock_mutex);\n\n  //  printf(\"cpu%d: lock %\" PRIx64 \".   \\n\",cpuid,address);\n  state.cpu_lock_flags |= (1 << cpuid);\n  state.cpu_lock_address[cpuid] = address;\n}\n\nbool CSystem::cpu_unlock(int cpuid) {\n  SCOPED_FM_LOCK(cpu_lock_mutex);\n\n  bool retval;\n  retval = state.cpu_lock_flags & (1 << cpuid);\n\n  //  printf(\"cpu%d: unlock (%s).   \\n\",cpuid,retval?\"ok\":\"failed\");\n  state.cpu_lock_flags &= ~(1 << cpuid);\n  return retval;\n}\n\nvoid CSystem::cpu_break_lock(int cpuid, CSystemComponent *source) {\n  SCOPED_FM_LOCK(cpu_lock_mutex);\n  printf(\"cpu%d: lock broken by %s.   \\n\", cpuid, source->devid_string);\n  state.cpu_lock_flags &= ~(1 << cpuid);\n}\n\n/**\n * \\brief Write 8, 4, 2 or 1 byte(s) to a 64-bit system address. This could be\n *memory, internal chipset registers, nothing or some device.\n *\n * Source: HRM, 10.1.1:\n *\n * System Space and Address Map\n *\n * The system address space is divided into two parts: system memory and PIO.\n *This division is indicated by physical memory bit <43> = 1 for PIO accesses\n *from the CPU, and by the PTP bit in the window registers for PTP accesses from\n *the Pchip. While the operating system may choose bit <40> instead of bit <43>\n *to represent PIO space, bit <43> is used throughout this chapter. In general,\n *bits <42:35> are don�t cares if bit <43> is asserted.\n *\n * There is 16GB of PIO space available on the 21272 chipset with 8GB assigned\n *to each Pchip. The Pchip supports up to bit <34> (35 bits total) of system\n *address. However, the Version 1 Cchip only supports 4GB of system memory (32\n *bits total). As described in Chapter 6, the CAPbus protocol between the Pchip\n *and Cchip does support up to bit <34>, as does the Cchip�s interface to the\n *CPU. The Typhoon Cchip supports 32GB of system memory (35 bits total).\n *\n * The system address space is divided as shown in the following table:\n *\n * \\code\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Space             | Size   | System Address <43:0>         | Comments |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | System memory     |    4GB | 000.0000.0000 - 000.FFFF.FFFF | Cacheable and\n *prefetchable.     |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Reserved          | 8188GB | 001.0000.0000 - 7FF.FFFF.FFFF | � |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Pchip0 PCI memory |    4GB | 800.0000.0000 - 800.FFFF.FFFF | Linear\n *addressing.              |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | TIGbus            |    1GB | 801.0000.0000 - 801.3FFF.FFFF | addr<5:0> = 0.\n *Single byte      | |                   |        | | valid in quadword access.\n *| |                   |        |                               | 16MB\n *accessible.                |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Reserved          |    1GB | 801.4000.0000 - 801.7FFF.FFFF | � |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Pchip0 CSRs       |  256MB | 801.8000.0000 - 801.8FFF.FFFF | addr<5:0> = 0.\n *Quadword access. |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Reserved          |  256MB | 801.9000.0000 - 801.9FFF.FFFF | � |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Cchip CSRs        |  256MB | 801.A000.0000 - 801.AFFF.FFFF | addr<5:0> = 0.\n *Quadword access. |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Dchip CSRs        |  256MB | 801.B000.0000 - 801.BFFF.FFFF | addr<5:0> = 0.\n *All eight bytes  | |                   |        | | in quadword access must be\n *| |                   |        |                               | identical. |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Reserved          |  768MB | 801.C000.0000 - 801.EFFF.FFFF | � | | Reserved\n *|  128MB | 801.F000.0000 - 801.F7FF.FFFF | �                               |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Pchip 0 PCI IACK  |   64MB | 801.F800.0000 - 801.FBFF.FFFF | Linear\n *addressing.              |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Pchip0 PCI I/O    |   32MB | 801.FC00.0000 - 801.FDFF.FFFF | Linear\n *addressing.              |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Pchip0 PCI conf   |   16MB | 801.FE00.0000 - 801.FEFF.FFFF | Linear\n *addressing.              |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Reserved          |   16MB | 801.FF00.0000 - 801.FFFF.FFFF | � |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Pchip1 PCI memory |    4GB | 802.0000.0000 - 802.FFFF.FFFF | Linear\n *addressing.              |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Reserved          |    2GB | 803.0000.0000 - 803.7FFF.FFFF | � |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Pchip1 CSRs       |  256MB | 803.8000.0000 - 803.8FFF.FFFF | addr<5:0> = 0,\n *quadword access. |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Reserved          | 1536MB | 803.9000.0000 - 803.EFFF.FFFF | � | | Reserved\n *|  128MB | 803.F000.0000 - 803.F7FF.FFFF | �                               |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Pchip 1 PCI IACK  |   64MB | 803.F800.0000 - 803.FBFF.FFFF | Linear\n *addressing.              |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Pchip1 PCI I/O    |   32MB | 803.FC00.0000 - 803.FDFF.FFFF | Linear\n *addressing.              |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Pchip1 PCI conf   |   16MB | 803.FE00.0000 - 803.FEFF.FFFF | Linear\n *addressing.              |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Reserved          |   16MB | 803.FF00.0000 - 803.FFFF.FFFF | � | | Reserved\n *| 8172GB | 804.0000.0000 - FFF.FFFF.FFFF | Bits <42:35> are don�t cares if |\n * |                   |        |                               | bit <43> is\n *asserted.           |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * \\endcode\n **/\nvoid CSystem::WriteMem(u64 address, int dsize, u64 data,\n                       CSystemComponent *source) {\n  u64 a;\n  int i;\n  u8 *p;\n#if defined(ALIGN_MEM_ACCESS)\n  u64 t64;\n  u32 t32;\n  u16 t16;\n#endif // defined(ALIGN_MEM_ACCESS)\n  if (state.cpu_lock_flags) {\n    for (i = 0; i < iNumCPUs; i++) {\n      if ((state.cpu_lock_flags & (1 << i)) &&\n          (!((state.cpu_lock_address[i] ^ address) &\n             U64(0x00000807ffffff00))) &&\n          (source != acCPUs[i]))\n        cpu_break_lock(i, source);\n    }\n  }\n\n  a = address & U64(0x00000807ffffffff);\n\n  if (a >> iNumMemoryBits) // non-memory\n  {\n\n    // check registered device memory ranges\n    for (i = 0; i < iNumMemories; i++) {\n      if ((a >= asMemories[i]->base) &&\n          (a < asMemories[i]->base + asMemories[i]->length)) {\n        asMemories[i]->component->WriteMem(\n            asMemories[i]->index, a - asMemories[i]->base, dsize, data);\n        return;\n      }\n    }\n\n    if ((a == U64(0x00000801FC000CF8)) && (dsize == 32)) {\n      state.cf8_address[0] = (u32)data & 0x00ffffff;\n      return;\n    }\n\n    if ((a == U64(0x00000803FC000CF8)) && (dsize == 32)) {\n      state.cf8_address[1] = (u32)data & 0x00ffffff;\n      return;\n    }\n\n    if ((a == U64(0x00000801FC000CFC)) && (dsize == 32)) {\n      printf(\"PCI 0 config space write through CF8/CFC mechanism.   \\n\");\n      getc(stdin);\n      WriteMem(U64(0x00000801FE000000) | state.cf8_address[0], dsize, data,\n               source);\n      return;\n    }\n\n    if ((a == U64(0x00000803FC000CFC)) && (dsize == 32)) {\n      printf(\"PCI 1 config space write through CF8/CFC mechanism.   \\n\");\n      getc(stdin);\n      WriteMem(U64(0x00000803FE000000) | state.cf8_address[1], dsize, data,\n               source);\n      return;\n    }\n\n    if (a >= U64(0x00000801A0000000) && a <= U64(0x00000801AFFFFFFF)) {\n      cchip_csr_write((u32)a & 0xFFFFFFF, data, source);\n      return;\n    }\n\n    if (a >= U64(0x0000080180000000) && a <= U64(0x000008018FFFFFFF)) {\n      pchip_csr_write(0, (u32)a & 0xFFFFFFF, data);\n      return;\n    }\n\n    if (a >= U64(0x0000080380000000) && a <= U64(0x000008038FFFFFFF)) {\n      pchip_csr_write(1, (u32)a & 0xFFFFFFF, data);\n      return;\n    }\n\n    if (a >= U64(0x00000801B0000000) && a <= U64(0x00000801BFFFFFFF)) {\n      dchip_csr_write((u32)a & 0xFFFFFFF, (u8)data & 0xff);\n      return;\n    }\n\n    if (a >= U64(0x0000080100000000) && a <= U64(0x000008013FFFFFFF)) {\n      tig_write((u32)a & 0x3FFFFFFF, (u8)data);\n      return;\n    }\n\n    if (a >= U64(0x801fc000000) && a < U64(0x801fe000000)) {\n\n      // Unused PCI I/O space\n      //      if (source)\n      //        printf(\"Write to unknown IO port %\" LL\"x on PCI 0 from %s \\n\",a\n      //        & U64(0x1ffffff),source->devid_string);\n      //      else\n      //        printf(\"Write to unknown IO port %\" LL\"x on PCI 0   \\n\",a &\n      //        U64(0x1ffffff));\n      return;\n    }\n\n    if (a >= U64(0x803fc000000) && a < U64(0x803fe000000)) {\n\n      // Unused PCI I/O space\n      if (source) {\n        printf(\"Write to unknown IO port %\" PRIx64 \" on PCI 1 from %s   \\n\",\n               a & U64(0x1ffffff), source->devid_string);\n      } else\n        printf(\"Write to unknown IO port %\" PRIx64 \" on PCI 1   \\n\",\n               a & U64(0x1ffffff));\n      return;\n    }\n\n    if (a >= U64(0x80000000000) && a < U64(0x80100000000)) {\n\n      // Unused PCI memory space\n      u64 paddr = a & U64(0xffffffff);\n      if (paddr > 0xb8fff || paddr < 0xb8000) { // skip legacy video\n        if (source) {\n          printf(\"Write to unknown memory %\" PRIx64 \" on PCI 0 from %s   \\n\",\n                 a & U64(0xffffffff), source->devid_string);\n        } else\n          printf(\"Write to unknown memory %\" PRIx64 \" on PCI 0   \\n\",\n                 a & U64(0xffffffff));\n      }\n    }\n\n    if (a >= U64(0x80200000000) && a < U64(0x80300000000)) {\n\n      // Unused PCI memory space\n      if (source) {\n        printf(\"Write to unknown memory %\" PRIx64 \" on PCI 1 from %s   \\n\",\n               a & U64(0xffffffff), source->devid_string);\n      } else\n        printf(\"Write to unknown memory %\" PRIx64 \" on PCI 1   \\n\",\n               a & U64(0xffffffff));\n      return;\n    }\n\n#ifdef DEBUG_UNKMEM\n    if (source)\n      printf(\"Write to unknown memory %\" PRIx64 \" from %s   \\n\", a,\n             source->devid_string);\n    else\n      printf(\"Write to unknown memory %\" PRIx64 \"   \\n\", a);\n#endif // defined(DEBUG_UNKMEM)\n    return;\n  }\n\n  p = (u8 *)memory + a;\n\n  switch (dsize) {\n  case 8:\n    *((u8 *)p) = (u8)data;\n    break;\n  case 16:\n    *((u16 *)p) = endian_16((u16)data);\n    break;\n  case 32:\n    *((u32 *)p) = endian_32((u32)data);\n    break;\n  default:\n    *((u64 *)p) = endian_64((u64)data);\n  }\n}\n\n/**\n * \\brief Read 8, 4, 2 or 1 byte(s) from a 64-bit system address. This could be\n *memory, internal chipset registers, nothing or some device.\n *\n * Source: HRM, 10.1.1:\n *\n * System Space and Address Map\n *\n * The system address space is divided into two parts: system memory and PIO.\n *This division is indicated by physical memory bit <43> = 1 for PIO accesses\n *from the CPU, and by the PTP bit in the window registers for PTP accesses from\n *the Pchip. While the operating system may choose bit <40> instead of bit <43>\n *to represent PIO space, bit <43> is used throughout this chapter. In general,\n *bits <42:35> are don�t cares if bit <43> is asserted.\n *\n * There is 16GB of PIO space available on the 21272 chipset with 8GB assigned\n *to each Pchip. The Pchip supports up to bit <34> (35 bits total) of system\n *address. However, the Version 1 Cchip only supports 4GB of system memory (32\n *bits total). As described in Chapter 6, the CAPbus protocol between the Pchip\n *and Cchip does support up to bit <34>, as does the Cchip�s interface to the\n *CPU. The Typhoon Cchip supports 32GB of system memory (35 bits total).\n *\n * The system address space is divided as shown in the following table:\n *\n * \\code\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Space             | Size   | System Address <43:0>         | Comments |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | System memory     |    4GB | 000.0000.0000 - 000.FFFF.FFFF | Cacheable and\n *prefetchable.     |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Reserved          | 8188GB | 001.0000.0000 - 7FF.FFFF.FFFF | � |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Pchip0 PCI memory |    4GB | 800.0000.0000 - 800.FFFF.FFFF | Linear\n *addressing.              |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | TIGbus            |    1GB | 801.0000.0000 - 801.3FFF.FFFF | addr<5:0> = 0.\n *Single byte      | |                   |        | | valid in quadword access.\n *| |                   |        |                               | 16MB\n *accessible.                |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Reserved          |    1GB | 801.4000.0000 - 801.7FFF.FFFF | � |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Pchip0 CSRs       |  256MB | 801.8000.0000 - 801.8FFF.FFFF | addr<5:0> = 0.\n *Quadword access. |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Reserved          |  256MB | 801.9000.0000 - 801.9FFF.FFFF | � |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Cchip CSRs        |  256MB | 801.A000.0000 - 801.AFFF.FFFF | addr<5:0> = 0.\n *Quadword access. |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Dchip CSRs        |  256MB | 801.B000.0000 - 801.BFFF.FFFF | addr<5:0> = 0.\n *All eight bytes  | |                   |        | | in quadword access must be\n *| |                   |        |                               | identical. |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Reserved          |  768MB | 801.C000.0000 - 801.EFFF.FFFF | � | | Reserved\n *|  128MB | 801.F000.0000 - 801.F7FF.FFFF | �                               |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Pchip 0 PCI IACK  |   64MB | 801.F800.0000 - 801.FBFF.FFFF | Linear\n *addressing.              |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Pchip0 PCI I/O    |   32MB | 801.FC00.0000 - 801.FDFF.FFFF | Linear\n *addressing.              |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Pchip0 PCI conf   |   16MB | 801.FE00.0000 - 801.FEFF.FFFF | Linear\n *addressing.              |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Reserved          |   16MB | 801.FF00.0000 - 801.FFFF.FFFF | � |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Pchip1 PCI memory |    4GB | 802.0000.0000 - 802.FFFF.FFFF | Linear\n *addressing.              |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Reserved          |    2GB | 803.0000.0000 - 803.7FFF.FFFF | � |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Pchip1 CSRs       |  256MB | 803.8000.0000 - 803.8FFF.FFFF | addr<5:0> = 0,\n *quadword access. |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Reserved          | 1536MB | 803.9000.0000 - 803.EFFF.FFFF | � | | Reserved\n *|  128MB | 803.F000.0000 - 803.F7FF.FFFF | �                               |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Pchip 1 PCI IACK  |   64MB | 803.F800.0000 - 803.FBFF.FFFF | Linear\n *addressing.              |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Pchip1 PCI I/O    |   32MB | 803.FC00.0000 - 803.FDFF.FFFF | Linear\n *addressing.              |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Pchip1 PCI conf   |   16MB | 803.FE00.0000 - 803.FEFF.FFFF | Linear\n *addressing.              |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * | Reserved          |   16MB | 803.FF00.0000 - 803.FFFF.FFFF | � | | Reserved\n *| 8172GB | 804.0000.0000 - FFF.FFFF.FFFF | Bits <42:35> are don�t cares if |\n * |                   |        |                               | bit <43> is\n *asserted.           |\n * +-------------------+--------+-------------------------------+---------------------------------+\n * \\endcode\n **/\nu64 CSystem::ReadMem(u64 address, int dsize, CSystemComponent *source) {\n  u64 a;\n  int i;\n  u8 *p;\n\n  a = address & U64(0x00000807ffffffff);\n  if (a >> iNumMemoryBits) // Non Memory\n  {\n\n    // check registered device memory ranges\n    for (i = 0; i < iNumMemories; i++) {\n      if ((a >= asMemories[i]->base) &&\n          (a < asMemories[i]->base + asMemories[i]->length))\n        return asMemories[i]->component->ReadMem(\n            asMemories[i]->index, a - asMemories[i]->base, dsize);\n    }\n\n    if ((a == U64(0x00000801FC000CFC)) && (dsize == 32)) {\n      printf(\"PCI 0 config space read through CF8/CFC mechanism.   \\n\");\n      getc(stdin);\n      return ReadMem(U64(0x00000801FE000000) | state.cf8_address[0], dsize,\n                     source);\n    }\n\n    if ((a == U64(0x00000803FC000CFC)) && (dsize == 32)) {\n      printf(\"PCI 1 config space read through CF8/CFC mechanism.   \\n\");\n      getc(stdin);\n      return ReadMem(U64(0x00000803FE000000) | state.cf8_address[1], dsize,\n                     source);\n    }\n\n    if (a >= U64(0x00000801A0000000) && a <= U64(0x00000801AFFFFFFF))\n      return cchip_csr_read((u32)a & 0xFFFFFFF, source);\n\n    if (a >= U64(0x0000080180000000) && a <= U64(0x000008018FFFFFFF))\n      return pchip_csr_read(0, (u32)a & 0xFFFFFFF);\n\n    if (a >= U64(0x0000080380000000) && a <= U64(0x000008038FFFFFFF))\n      return pchip_csr_read(1, (u32)a & 0xFFFFFFF);\n\n    if (a >= U64(0x00000801B0000000) && a <= U64(0x00000801BFFFFFFF))\n      return dchip_csr_read((u32)a & 0xFFFFFFF) * U64(0x0101010101010101);\n\n    if (a >= U64(0x0000080100000000) && a <= U64(0x000008013FFFFFFF))\n      return tig_read((u32)a & 0x3FFFFFFF);\n\n    if ((a >= U64(0x801fe000000) && a < U64(0x801ff000000)) ||\n        (a >= U64(0x803fe000000) && a < U64(0x803ff000000))) {\n\n      // Unused PCI configuration space\n      switch (dsize) {\n      case 8:\n        return X64_BYTE;\n      case 16:\n        return X64_WORD;\n      case 32:\n        return X64_LONG;\n      case 64:\n        return X64_QUAD;\n      }\n    }\n\n    if (a >= U64(0x800000c0000) && a < U64(0x801000e0000)) {\n\n      // Unused PCI ROM BIOS space\n      return 0;\n    }\n\n    if (a >= U64(0x801fc000000) && a < U64(0x801fe000000)) {\n\n      // Unused PCI I/O space\n      // if (source)\n      //  printf(\"Read from unknown IO port %\" LL\"x on PCI 0 from %s   \\n\",a &\n      //  U64(0x1ffffff),source->devid_string);\n      // else\n      //  printf(\"Read from unknown IO port %\" LL\"x on PCI 0   \\n\",a &\n      //  U64(0x1ffffff));\n      return 0;\n    }\n\n    if (a >= U64(0x803fc000000) && a < U64(0x803fe000000)) {\n\n      // Unused PCI I/O space\n      if (source) {\n        printf(\"Read from unknown IO port %\" PRIx64 \" on PCI 1 from %s   \\n\",\n               a & U64(0x1ffffff), source->devid_string);\n      } else\n        printf(\"Read from unknown IO port %\" PRIx64 \" on PCI 1   \\n\",\n               a & U64(0x1ffffff));\n      return 0;\n    }\n\n    if (a >= U64(0x80000000000) && a < U64(0x80100000000)) {\n\n      // Unused PCI memory space\n      u64 paddr = a & U64(0xffffffff);\n      if (paddr > 0xb8fff || paddr < 0xb8000) { // skip legacy video\n        if (source) {\n          printf(\"Read from unknown memory %\" PRIx64 \" on PCI 0 from %s   \\n\",\n                 a & U64(0xffffffff), source->devid_string);\n        } else\n          printf(\"Read from unknown memory %\" PRIx64 \" on PCI 0   \\n\",\n                 a & U64(0xffffffff));\n      }\n\n      return 0;\n    }\n\n    if (a >= U64(0x80200000000) && a < U64(0x80300000000)) {\n\n      // Unused PCI memory space\n      if (source) {\n        printf(\"Read from unknown memory %\" PRIx64 \" on PCI 1 from %s   \\n\",\n               a & U64(0xffffffff), source->devid_string);\n      } else\n        printf(\"Read from unknown memory %\" PRIx64 \" on PCI 1   \\n\",\n               a & U64(0xffffffff));\n      return 0;\n    }\n\n#if defined(DEBUG_UNKMEM)\n    if (source)\n      printf(\"Read from unknown memory %\" PRIx64 \" from %s   \\n\", a,\n             source->devid_string);\n    else\n      printf(\"Read from unknown memory %\" PRIx64 \"   \\n\", a);\n#endif // defined(DEBUG_UNKMEM)\n    return 0x00;\n\n    //                    return 0x77; // 7f\n  }\n\n  p = (u8 *)memory + a;\n\n  switch (dsize) {\n  case 8:\n    return *((u8 *)p);\n  case 16:\n    return endian_16(*((u16 *)p));\n  case 32:\n    return endian_32(*((u32 *)p));\n  default:\n    return endian_64(*((u64 *)p));\n  }\n}\n\n/**\n * \\brief Read one of the PCHIP registers.\n *\n * Source: HRM, 10.2.5:\n *\n * \\code\n * +-------------+---------------+------+----+\n * |Register     | Address       | Type | ## |\n * +-------------+---------------+------+----+\n * | P0-WSBA0    | 801.8000.0000 | RW   | 00 |\n * | P0-WSBA1    | 801.8000.0040 | RW   | 01 |\n * | P0-WSBA2    | 801.8000.0080 | RW   | 02 |\n * | P0-WSBA3    | 801.8000.00C0 | RW   | 03 |\n * +-------------+---------------+------+----+\n * | P0-WSM0     | 801.8000.0100 | RW   | 04 |\n * | P0-WSM1     | 801.8000.0140 | RW   | 05 |\n * | P0-WSM2     | 801.8000.0180 | RW   | 06 |\n * | P0-WSM3     | 801.8000.01C0 | RW   | 07 |\n * +-------------+---------------+------+----+\n * | P0-TBA0     | 801.8000.0200 | RW   | 08 |\n * | P0-TBA1     | 801.8000.0240 | RW   | 09 |\n * | P0-TBA2     | 801.8000.0280 | RW   | 0A |\n * | P0-TBA3     | 801.8000.02C0 | RW   | 0B |\n * +-------------+---------------+------+----+\n * | P0-PCTL     | 801.8000.0300 | RW   | 0C |\n * +-------------+---------------+------+----+\n * | P0-PLAT     | 801.8000.0340 | RW   | 0D |\n * +-------------+---------------+------+----+\n * | P0-RES      | 801.8000.0380 | RW   | 0E |\n * +-------------+---------------+------+----+\n * | P0-PERROR   | 801.8000.03C0 | RW   | 0F |\n * | P0-PERRMASK | 801.8000.0400 | RW   | 10 |\n * | P0-PERRSET  | 801.8000.0440 | WO   | 11 |\n * +-------------+---------------+------+----+\n * | P0-TLBIV    | 801.8000.0480 | WO   | 12 |\n * | P0-TLBIA    | 801.8000.04C0 | WO   | 13 |\n * +-------------+---------------+------+----+\n * | P0-PMONCTL  | 801.8000.0500 | RW   | 14 |\n * | P0-PMONCNT  | 801.8000.0540 | RO   | 15 |\n * +-------------+---------------+------+----+\n * | P0-SPRST    | 801.8000.0800 | WO   | 20 |\n * +-------------+---------------+------+----+\n * \\endcode\n *\n * Window Space Base Address Register (WSBAn - RW)\n *\n * Because the information in the WSBAn registers and WSMn registers\n * is used to compare against the PCI address, a clock-domain crossing (from\n * i_sysclk to i_pclko<7:0>) is made when these registers are written.\n *Therefore, for a period of several clock cycles, a window is disabled when its\n *contents are disabled. If PCI bus activity, which accesses the window in\n *question, is not stopped before updating that window, the Pchip might fail to\n *respond with b_devsel_l when it should. This would result in a master abort\n *condition on the PCI bus. Therefore, before a window (base or mask) is\n *updated, all PCI activity accessing that window must be stopped, even if only\n *some activity is being added or deleted.\n *\n * The contents of the window may be read back to confirm that the update has\n *taken place. Then PCI activity through that window can be resumed.\n *\n * \\code\n * +-------+---------+---------+------+--------------------------+\n * | Field | Bits    | Type    | Init | Description              |\n * +-------+---------+---------+------+--------------------------+\n * | RES   | <63:40> | MBZ,RAZ | 0    | Reserved                 |\n * +-------+---------+---------+------+--------------------------+\n * | DAC   | <39>    | RW      | 0    | DAC enable (WSBA3 only!) |\n * +-------+---------+---------+------+--------------------------+\n * | RES   | <38:32> | MBZ,RAZ | 0    | Reserved                 |\n * +-------+---------+---------+------+--------------------------+\n * | ADDR  | <31:20> | RW      | 0    | Base address (not used   |\n * |       |         |         |      | DAC enable = 1)          |\n * +-------+---------+---------+------+--------------------------+\n * | RES   | <19:2>  | MBZ,RAZ | 0    | Reserved                 |\n * +-------+---------+---------+------+--------------------------+\n * | SG    | <1>     | RW      | 0    | Scatter-gather           |\n * +-------+---------+---------+------+--------------------------+\n * | ENA   | <0>     | RW      | 0    | Enable                   |\n * +-------+---------+---------+------+--------------------------+\n * \\endcode\n *\n * Window Space Mask Register (WSM0, WSM1, WSM2, WSM3 - RW)\n *\n * \\code\n * +-------+---------+---------+------+--------------------------+\n * | Field | Bits    | Type    | Init | Description              |\n * +-------+---------+---------+------+--------------------------+\n * | RES   | <63:32> | MBZ,RAZ | 0    | Reserved                 |\n * +-------+---------+---------+------+--------------------------+\n * | AM    | <31:20> | RW      | 0    | Address mask             |\n * +-------+---------+---------+------+--------------------------+\n * | RES   | <19:0>  | MBZ,RAZ | 0    | Reserved                 |\n * +-------+---------+---------+------+--------------------------+\n * \\endcode\n *\n * Translated Base Address Register (TBAn - RW)\n *\n * \\code\n * +-------+---------+---------+------+--------------------------+\n * | Field | Bits    | Type    | Init | Description              |\n * +-------+---------+---------+------+--------------------------+\n * | RES   | <63:35> | MBZ,RAZ | 0    | Reserved                 |\n * +-------+---------+---------+------+--------------------------+\n * | ADDR  | <34:10> | RW      | 0    | Translated base address  |\n * |       |         |         |      | (if DAC enable = 1, bits |\n * |       |         |         |      | <34:22> are the PT Origin|\n * |       |         |         |      | address <34:22> and bits |\n * |       |         |         |      | <21:10> are ignored)     |\n * +-------+---------+---------+------+--------------------------+\n * | RES   | <9:0>   | MBZ,RAZ | 0    | Reserved                 |\n * +-------+---------+---------+------+--------------------------+\n * \\encode\n *\n * Pchip Control Register (PCTL - RW)\n *\n * \\code\n * +---------+---------+---------+------+-------------------------------------+\n * | Field   | Bits    | Type    | Init | Description                         |\n * +---------+---------+---------+------+-------------------------------------+\n * | RES     | <63:48> | MBZ,RAZ | 0    | Reserved.                           |\n * +---------+---------+---------+------+-------------------------------------+\n * | PID     | <47:46> | RO      | 1)   | Pchip ID.                           |\n * +---------+---------+---------+------+-------------------------------------+\n * | RPP     | <45>    | RO      | 2)   | Remote Pchip present.               |\n * +---------+---------+---------+------+-------------------------------------+\n * | PTEVRFY | <44>    | RW      |      | PTE verify for DMA read.            |\n * |         |         |         |      |   Val Description                   |\n * |         |         |         |      |   0   If TLB miss, then make DMA    |\n * |         |         |         |      |       read request as soon as possi-|\n * |         |         |         |      |       ble and discard data if PTE   |\n * |         |         |         |      |       was not valid - could cause   |\n * |         |         |         |      |       Cchip nonexistent mem. error. |\n * |         |         |         |      |   1   If TLB miss, then delay read  |\n * |         |         |         |      |       request until PTE is verified |\n * |         |         |         |      |       as valid - no request if not  |\n * |         |         |         |      |       valid.                        |\n * +---------+---------+---------+------+-------------------------------------+\n * | FDWDIS  | <43>    | RW      |      | Fast DMA read cache block wrap      |\n * |         |         |         |      | request disable.                    |\n * |         |         |         |      |   Val Description                   |\n * |         |         |         |      |   0   Normal operation.             |\n * |         |         |         |      |   1   Reserved for testing purposes |\n * |         |         |         |      |       only.                         |\n * +---------+---------+---------+------+-------------------------------------+\n * | FDSDIS  | <42>    | RW      |      | Fast DMA start and SGTE request     |\n * |         |         |         |      | disable.                            |\n * |         |         |         |      |   Val Description                   |\n * |         |         |         |      |   0   Normal operation.             |\n * |         |         |         |      |   1   Reserved for testing purposes |\n * |         |         |         |      |       only.                         |\n * +---------+---------+---------+------+-------------------------------------+\n * | PCLKX   | <41:40> | RO      | 3)   | PCI clock frequency multiplier      |\n * |         |         |         |      |   Val Multiplier                    |\n * |         |         |         |      |   0   x6                            |\n * |         |         |         |      |   1   x4                            |\n * |         |         |         |      |   2   x5                            |\n * |         |         |         |      |   3   Reserved                      |\n * +---------+---------+---------+------+-------------------------------------+\n * | PTPMAX  | <39:36> | RW      | 2    | Maximum PTP requests to Cchip from  |\n * |         |         |         |      | both Pchips until returned on       |\n * |         |         |         |      | CAPbus, modulo 16 (minimum = 2)     |\n * |         |         |         |      | (use 4 for pass 1 Cchip and Dchip). |\n * +---------+---------+---------+------+-------------------------------------+\n * | CRQMAX  | <35:32> | RW      | 1    | Maximum requests to Cchip from both |\n * |         |         |         |      | Pchips until Ack, modulo 16 (use 4  |\n * |         |         |         |      | for Cchip). (Use 3 or less for      |\n * |         |         |         |      | Typhoon because there is one less   |\n * |         |         |         |      | skid buffer in the C4 chip.)        |\n * +---------+---------+---------+------+-------------------------------------+\n * | REV     | <31:24> | RO      | 0    | In conjunction with the state of    |\n * |         |         |         |      | PMONCTL<0>, this field indicates    |\n * |         |         |         |      | the revision of the Pchip.          |\n * +---------+---------+---------+------+-------------------------------------+\n * | CDQMAX  | <23:20> | RW      | 1    | Maximum data transfers to Dchips    |\n * |         |         |         |      | from both Pchips until Ack, modulo  |\n * |         |         |         |      | 16 (use 4 for Dchip). Must be same  |\n * |         |         |         |      | as Cchip CSR CSC<FPQPMAX>.          |\n * +---------+---------+---------+------+-------------------------------------+\n * | PADM    | <19>    | RW      | 4)   | PADbus mode.                        |\n * |         |         |         |      |   Val Mode                          |\n * |         |         |         |      |   0   8-nibble, 8-check bit mode    |\n * |         |         |         |      |   1   4-byte, 4-check bit mode      |\n * +---------+---------+---------+------+-------------------------------------+\n * | ECCEN   | <18>    | RW      | 0    | ECC enable for DMA and SGTE access. |\n * +---------+---------+---------+------+-------------------------------------+\n * | RES     | <17:16> | MBZ,RAZ | 0    | Reserved.                           |\n * +---------+---------+---------+------+-------------------------------------+\n * | PPRI    | <15>    |         | 0    | Arbiter prio group for the Pchip.   |\n * +---------+---------+---------+------+-------------------------------------+\n * | PRIGRP  | <14:8>  | RW      | 0    | Arbiter prio group; one bit per PCI |\n * |         |         |         |      | slot with bits <14:8> corresponding |\n * |         |         |         |      | to input b_req_l<6:0>.              |\n * |         |         |         |      |   Val Group                         |\n * |         |         |         |      |   0   Low-priority group            |\n * |         |         |         |      |   1   High-priority group           |\n * +---------+---------+---------+------+-------------------------------------+\n * | ARBENA  | <7>     | RW      | 0    | Internal arbiter enable.            |\n * +---------+---------+---------+------+-------------------------------------+\n * | MWIN    | <6>     | RW      | 0    | Monster window enable.              |\n * +---------+---------+---------+------+-------------------------------------+\n * | HOLE    | <5>     | RW      | 0    | 512KB-to-1MB window hole enable.    |\n * +---------+---------+---------+------+-------------------------------------+\n * | TGTLAT  | <4>     | RW      | 0    | Target latency timers enable.       |\n * |         |         |         |      |   Val Mode                          |\n * |         |         |         |      |   0   Retry/disconnect after 128    |\n * |         |         |         |      |       PCI clocks without data.      |\n * |         |         |         |      |   1   Retry initial request after   |\n * |         |         |         |      |       32 PCI clocks without data;   |\n * |         |         |         |      |       disconnect subsequent trans-  |\n * |         |         |         |      |       fers after 8 PCI clocks       |\n * |         |         |         |      |       without data.                 |\n * +---------+---------+---------+------+-------------------------------------+\n * | CHAINDIS| <3>     | RW      | 0    | Disable chaining.                   |\n * +---------+---------+---------+------+-------------------------------------+\n * | THDIS   | <2>     | RW      | 0    | Disable antithrash mechan. for TLB. |\n * |         |         |         |      |   Val Mode                          |\n * |         |         |         |      |   0   Normal operation              |\n * |         |         |         |      |   1   Testing purposes only         |\n * +---------+---------+---------+------+-------------------------------------+\n * | FBTB    | <1>     | RW      | 0    | Fast back-to-back enable.           |\n * +---------+---------+---------+------+-------------------------------------+\n * | FDSC    | <0>     | RW      | 0    | Fast discard enable.                |\n * |         |         |         |      |   Val Mode                          |\n * |         |         |         |      |   0   Discard data if no retry      |\n * |         |         |         |      |       after 215 PCI clocks.         |\n * |         |         |         |      |   1   Discard data if no retry      |\n * |         |         |         |      |       after 210 PCI clocks.         |\n * +---------+---------+---------+------+-------------------------------------+\n *\n * 1) This field is initialized from the PID pins.\n * 2) This field is initialized from the assertion of CREQRMT_L pin at system\n *reset. 3) This field is initialized from the PCI i_pclkdiv<1:0> pins. 4) This\n *field is initialized from a decode of the b_cap<1:0> pins. \\endcode\n *\n * Pchip Error Register (PERROR - RW)\n *\n * If any of bits <11:0> are set, then this entire register is frozen and the\n *Pchip output signal b_error is asserted. Only bit <0> can be set after that.\n *All other values will be held until all of bits <11:0> are clear. When an\n *error is detected and one of bits <11:0> becomes set, the associated\n *information is captured in bits <63:16> of this register. After the\n *information is captured, the INV bit is cleared, but the information is not\n *valid and should not be used if INV is set.\n *\n * In rare circumstances involving more than one error, INV may remain set\n *because the Pchip cannot correctly capture the SYN, CMD, or ADDR field.\n *\n * Furthermore, if software reads PERROR in a polling loop, or reads PERROR\n *before the Pchip�s error signal is reflected in the Cchip�s DRIR CSR, the INV\n *bit may also be set.\n *\n * To avoid the latter condition, read PERROR only after receiving an IRQ0\n *interrupt, then read the Cchip DIR CSR to determine that this Pchip has\n *detected an error.\n *\n * \\code\n * +---------+---------+---------+------+-------------------------------------+\n * | Field   | Bits    | Type    | Init | Description                         |\n * +---------+---------+---------+------+-------------------------------------+\n * | SYN     | <63:56> | RO      | 0    | errors ECC syndrome if CRE or UECC. |\n * +---------+---------+---------+------+-------------------------------------+\n * | CMD     | <55:52> | RO      | 0    | PCI command of transaction when     |\n * |         |         |         |      | error detected if not CRE and not   |\n * |         |         |         |      | UECC. If CRE or UECC, then:         |\n * |         |         |         |      |   Val    Command                    |\n * |         |         |         |      |   0000   DMA read                   |\n * |         |         |         |      |   0001   DMA RMW                    |\n * |         |         |         |      |   0011   SGTE read                  |\n * |         |         |         |      |   Others Reserved                   |\n * +---------+---------+---------+------+-------------------------------------+\n * | INV     | <51>    | RO Rev1 | 0    | Info Not Valid - only meaningful    |\n * |         |         | RAZ Rev0|      | when one of bits <11:0> is set.     |\n * |         |         |         |      | Indicates validity of <SYN>, <CMD>, |\n * |         |         |         |      | and <ADDR> fields.                  |\n * |         |         |         |      |   Val Mode                          |\n * |         |         |         |      |   0   Info fields are valid.        |\n * |         |         |         |      |   1   Info fields are not valid.    |\n * +---------+---------+---------+------+-------------------------------------+\n * | ADDR    | <50:16> | RO      | 0    | If CRE or UECC, then ADDR<50:19> =  |\n * |         |         |         |      | system address <34:3> of erroneous  |\n * |         |         |         |      | quadword and ADDR<18:16> = 0.       |\n * |         |         |         |      | If not CRE and not UECC, then       |\n * |         |         |         |      | ADDR<50:48> = 0; ADDR<47:18> = star-|\n * |         |         |         |      | ting PCI address <31:2> of trans-   |\n * |         |         |         |      | action when error was detected;     |\n * |         |         |         |      | ADDR<17:16> = 00 --> not a DAC      |\n * |         |         |         |      |                      operation;     |\n * |         |         |         |      | ADDR<17:16> = 01 --> via DAC SG     |\n * |         |         |         |      |                      Window 3;      |\n * |         |         |         |      | ADDR<17> = 1 --> via Monster Window |\n * +---------+---------+---------+------+-------------------------------------+\n * | RES     | <15:12> | MBZ,RAZ | 0    | Reserved.                           |\n * +---------+---------+---------+------+-------------------------------------+\n * | CRE     | <11>    | R,W1C   | 0    | Correctable ECC error.              |\n * +---------+---------+---------+------+-------------------------------------+\n * | UECC    | <10>    | R,W1C   | 0    | Uncorrectable ECC error.            |\n * +---------+---------+---------+------+-------------------------------------+\n * | RES     | <9>     | MBZ,RAZ | 0    | Reserved.                           |\n * +---------+---------+---------+------+-------------------------------------+\n * | NDS     | <8>     | R,W1C   | 0    | No b_devsel_l as PCI master.        |\n * +---------+---------+---------+------+-------------------------------------+\n * | RDPE    | <7>     | R,W1C   | 0    | PCI read data parity error as PCI   |\n * |         |         |         |      | master.                             |\n * +---------+---------+---------+------+-------------------------------------+\n * | TA      | <6>     | R,W1C   | 0    | Target abort as PCI master.         |\n * +---------+---------+---------+------+-------------------------------------+\n * | APE     | <5>     | R,W1C   | 0    | Address parity error detected as    |\n * |         |         |         |      | potential PCI target.               |\n * +---------+---------+---------+------+-------------------------------------+\n * | SGE     | <4>     | R,W1C   | 0    | Scatter-gather had invalid page     |\n * |         |         |         |      | table entry.                        |\n * +---------+---------+---------+------+-------------------------------------+\n * | DCRTO   | <3>     | R,W1C   | 0    | Delayed completion retry timeout as |\n * |         |         |         |      | PCI target.                         |\n * +---------+---------+---------+------+-------------------------------------+\n * | PERR    | <2>     | R,W1C   | 0    | b_perr_l sampled asserted.          |\n * +---------+---------+---------+------+-------------------------------------+\n * | SERR    | <1>     | R,W1C   | 0    | b_serr_l sampled asserted.          |\n * +---------+---------+---------+------+-------------------------------------+\n * | LOST    | <0>     | R,W1C   | 0    | Lost an error because it was detec- |\n * |         |         |         |      | ted after this register was frozen, |\n * |         |         |         |      | or while in the process of clearing |\n * |         |         |         |      | this register.                      |\n * +---------+---------+---------+------+-------------------------------------+\n * \\endcode\n *\n * Pchip Error Mask Register (PERRMASK - RW)\n *\n * If any of the MASK bits have the value 0, they prevent the setting of the\n *corresponding bit in the PERROR register, regardless of the detection of\n *errors or writing to PERRSET.\n *\n * The default is for all errors to be disabled.\n *\n * Beside masking the reporting of errors in PERROR, certain bits of PERRMASK\n *have the following additional effects:\n *   - If PERRMASK<RDPE> = 0, the Pchip ignores read data parity as the PCI\n *master.\n *   - If PERRMASK<PERR> = 0, the Pchip ignores write data parity as the PCI\n *target.\n *   - If PERRMASK<APE> = 0, the Pchip ignores address parity.\n *   .\n *\n * \\code\n * +---------+---------+---------+------+-------------------------------------+\n * | Field   | Bits    | Type    | Init | Description                         |\n * +---------+---------+---------+------+-------------------------------------+\n * | RES     | <63:12> | MBZ,RAZ | 0    | Reserved                            |\n * +---------+---------+---------+------+-------------------------------------+\n * | MASK    | <11:0>  | RW      | 0    | PERROR register bit enables         |\n * +---------+---------+---------+------+-------------------------------------+\n * \\endcode\n *\n * Pchip Master Latency Register (PLAT - RW)\n *\n * Bits <15:8> are the master latency timer.\n *\n * Translation Buffer Invalidate Virtual Register (TLBIV - WO)\n *\n * A write to this register invalidates all scatter-gather TLB entries that\n *correspond to PCI addresses whose bits <31:16> and bit 39 match the value\n *written in bits <19:4> and 27 respectively. This invalidates up to eight PTEs\n *at a time, which are the number that can be defined in one 21264 cache block\n *(64 bytes). Because a single TLB PCI tag covers four entries, at most two tags\n *are actually invalidated. PTE bits <22:4> correspond to system address bits\n *<34:16> - where PCI<34:32> must be zeros for scatter- gather window hits - in\n *generating the resulting system address, providing 8-page (8KB) granularity.\n *\n * Translation Buffer Invalidate All Register (TLBIA - WO)\n *\n * A write to this register invalidates the scatter-gather TLB. The value\n *written is ignored.\n **/\nu64 CSystem::pchip_csr_read(int num, u32 a) {\n  switch (a) {\n  case 0x000:\n  case 0x040:\n  case 0x080:\n  case 0x0c0:\n    return state.pchip[num].wsba[(a >> 6) & 3];\n\n  case 0x100:\n  case 0x140:\n  case 0x180:\n  case 0x1c0:\n    return state.pchip[num].wsm[(a >> 6) & 3];\n\n  case 0x200:\n  case 0x240:\n  case 0x280:\n  case 0x2c0:\n    return state.pchip[num].tba[(a >> 6) & 3];\n\n  case 0x300:\n    return state.pchip[num].pctl;\n\n  case 0x3c0:\n    return state.pchip[num].perr;\n\n  case 0x400:\n    return state.pchip[num].perrmask;\n\n  case 0x480: // TLBIV\n  case 0x4c0: // TLBIA\n    return 0;\n\n  case 0x800: // PCI reset\n    return 0;\n\n  default:\n    printf(\"Unknown PCHIP %d CSR %07x read attempted.\\n\", num, a);\n    return 0;\n  }\n}\n\n/**\n * \\brief Write one of the PCHIP registers.\n *\n * For a description of the PCHIP registers, see pchip_csr_read.\n **/\nvoid CSystem::pchip_csr_write(int num, u32 a, u64 data) {\n  switch (a) {\n  case 0x000:\n  case 0x040:\n  case 0x080:\n    state.pchip[num].wsba[(a >> 6) & 3] = data & U64(0x00000000fff00003);\n    return;\n\n  case 0x0c0:\n    state.pchip[num].wsba[3] = (data & U64(0x00000080fff00001)) | 2;\n    return;\n\n  case 0x100:\n  case 0x140:\n  case 0x180:\n  case 0x1c0:\n    state.pchip[num].wsm[(a >> 6) & 3] = data & U64(0x00000000fff00000);\n    return;\n\n  case 0x200:\n  case 0x240:\n  case 0x280:\n  case 0x2c0:\n    state.pchip[num].tba[(a >> 6) & 3] = data & U64(0x00000007fffffc00);\n    return;\n\n  case 0x300:\n    state.pchip[num].pctl &= U64(0xffffe300f0300000);\n    state.pchip[num].pctl |= (data & U64(0x00001cff0fcfffff));\n    return;\n\n  case 0x340:\n    state.pchip[num].plat = data;\n    return;\n\n  case 0x3c0: // PERR\n    return;\n\n  case 0x400:\n    state.pchip[num].perrmask = data;\n    return;\n\n  case 0x480: // TLBIV\n  case 0x4c0: // TLBIA\n    return;\n\n  case 0x800: // PCI reset\n    for (int i = 0; i < iNumComponents; i++)\n      acComponents[i]->ResetPCI();\n    return;\n\n  default:\n    printf(\"Unknown PCHIP %d CSR %07x write with %016\" PRIx64 \" attempted.\\n\",\n           num, a, data);\n  }\n}\n\nu64 CSystem::cchip_csr_read(u32 a, CSystemComponent *source) {\n  CAlphaCPU *cpu = (CAlphaCPU *)source;\n  switch (a) {\n  case 0x000:\n    return state.cchip.csc;\n\n  case 0x080:\n\n    //    printf(\"MISC: %016\" PRIx64 \" from CPU %d (@%\" PRIx64 \") (other @ %\" LL\n    //    \"x).\\n\",state.cchip.misc | cpu->get_cpuid(),cpu->get_cpuid(),\n    //    cpu->get_pc()-4, acCPUs[1-cpu->get_cpuid()]->get_pc());\n    return state.cchip.misc | cpu->get_cpuid();\n\n  case 0x100:\n\n    // WE PUT ALL OUR MEMORY IN A SINGLE ARRAY FOR NOW...\n    return ((u64)(iNumMemoryBits - 23) << 12); // size\n\n  case 0x140:\n  case 0x180:\n  case 0x1c0:\n\n    // WE PUT ALL OUR MEMORY IN A SINGLE ARRAY FOR NOW...\n    return 0;\n\n  case 0x200:\n  case 0x240:\n  case 0x600:\n  case 0x640:\n    return state.cchip.dim[((a >> 10) & 2) | ((a >> 6) & 1)];\n\n  case 0x280:\n  case 0x2c0:\n  case 0x680:\n  case 0x6c0:\n    return state.cchip.drir & state.cchip.dim[((a >> 10) & 2) | ((a >> 6) & 1)];\n\n  case 0x300:\n    return state.cchip.drir;\n\n  default:\n    printf(\"Unknown CCHIP CSR %07x read attempted.\\n\", a);\n    return 0;\n  }\n}\n\nvoid CSystem::cchip_csr_write(u32 a, u64 data, CSystemComponent *source) {\n  CAlphaCPU *cpu = (CAlphaCPU *)source;\n  switch (a) {\n  case 0x000: // CSC\n    state.cchip.csc &= ~U64(0x0777777fff3f0000);\n    state.cchip.csc |= (data & U64(0x0777777fff3f0000));\n    return;\n\n  case 0x080:                                              // MISC\n    state.cchip.misc |= (data & U64(0x00000f0000f00000));  // W1S\n    state.cchip.misc &= ~(data & U64(0x0000000010000ff0)); // W1C\n    if (data & U64(0x0000000001000000)) {\n      state.cchip.misc &= ~U64(0x0000000000ff0000); // Arbitration Clear\n      printf(\"Arbitration clear from CPU %d (@%\" PRIx64 \").\\n\",\n             cpu->get_cpuid(), cpu->get_pc() - 4);\n    }\n\n    if (data & U64(0x00000000000f0000)) {\n      printf(\"Arbitration %016\" PRIx64 \" from CPU %d (@%\" PRIx64 \")... \", data,\n             cpu->get_cpuid(), cpu->get_pc() - 4);\n      if (!(state.cchip.misc & U64(0x00000000000f0000))) {\n        state.cchip.misc |= (data & U64(0x00000000000f0000)); // Arbitration won\n        printf(\"won  %016\" PRIx64 \"\\n\", state.cchip.misc);\n      } else\n        printf(\"lost %016\" PRIx64 \"\\n\", state.cchip.misc);\n    }\n\n    // stop interval timer interrupt\n    if (data & U64(0x00000000000000f0)) {\n      for (int i = 0; i < iNumCPUs; i++) {\n        if (data & (U64(0x10) << i)) {\n          acCPUs[i]->irq_h(2, false, 0);\n\n          // printf(\"*** TIMER interrupt cleared for CPU %d\\n\",i);\n        }\n      }\n    }\n\n    // stop inter processor interrupt\n    if (data & U64(0x0000000000000f00)) {\n      for (int i = 0; i < iNumCPUs; i++) {\n        if (data & (U64(0x100) << i)) {\n          acCPUs[i]->irq_h(3, false, 0);\n          printf(\"*** IP interrupt cleared for CPU %d from CPU %d(@ %\" PRIx64\n                 \").\\n\",\n                 i, cpu->get_cpuid(), cpu->get_pc() - 4);\n        }\n      }\n    }\n\n    // set inter processor interrupt\n    if (data & U64(0x000000000000f000)) {\n      for (int i = 0; i < iNumCPUs; i++) {\n        if (data & (U64(0x1000) << i)) {\n          state.cchip.misc |= U64(0x100) << i;\n          acCPUs[i]->irq_h(3, true, 0);\n          printf(\"*** IP interrupt set for CPU %d from CPU %d(@ %\" PRIx64 \")\\n\",\n                 i, cpu->get_cpuid(), cpu->get_pc() - 4);\n\n          //          std::this_thread::sleep_for(std::chrono::milliseconds(10));\n        }\n      }\n    }\n\n    return;\n\n  case 0x200:\n  case 0x240:\n  case 0x600:\n  case 0x640:\n    state.cchip.dim[((a >> 10) & 2) | ((a >> 6) & 1)] = data;\n    return;\n\n  default:\n    printf(\"Unknown CCHIP CSR %07x write with %016\" PRIx64 \" attempted.\\n\", a,\n           data);\n  }\n}\n\nu8 CSystem::dchip_csr_read(u32 a) {\n  switch (a) {\n  case 0x800: // DSC\n    return state.dchip.dsc;\n  case 0x840: // STR\n    return state.dchip.str;\n  case 0x880: // DREV\n    return state.dchip.drev;\n  case 0x8c0: // DSC2\n    return state.dchip.dsc2;\n  default:\n    printf(\"Unknown DCHIP CSR %07x read attempted.\\n\", a);\n    return 0;\n  }\n}\n\nvoid CSystem::dchip_csr_write(u32 a, u8 data) {\n  printf(\"Unknown DCHIP CSR %07x write with %02x attempted.\\n\", a, data);\n}\n\n/**\n * Read a byte from the TIGbus\n *\n * What information we have is sketchy at best. Following is extracted from T64,\n * Although we're not 100% sure that this is actually for ES40:\n *\n * \\code\n * +-----------------+--------+\n * | register        | offset |\n * +-----------------+--------+\n * | trr             | 000    |\n * | smir            | 040    | system management IR\n * | cpuir           | 080    | CPU IR\n * | psir            | 0c0    | powe supply IR\n * | mod_info        | 100    |\n * | clk_info        | 140    |\n * | chip_info       | 180    |\n * | tpcr            | 200    |\n * | pll_data        | 280    |\n * | pll_clk         | 2c0    |\n * | ev6_init        | 300    |\n * | csleep          | 340    |\n * | smcr            | 380    |\n * | ttcr            | 3c0    |\n * | clr_irq5        | 400    |\n * | clr_irq4        | 440    |\n * | clr_pwr_flt_det | 480    |\n * | clr_temp_warn   | 4c0    |\n * | clr_temp_fail   | 500    |\n * | ev6_halt        | 5c0    |\n * | srcr0           | 600    |\n * | srcr1           | 640    |\n * | frar0           | 700    |\n * | frar1           | 740    |\n * | fwmr0           | 800    |\n * | fwmr1           | 840    |\n * | fwmr2           | 880    |\n * | fwmr3           | 8c0    |\n * | ipcr0           | a00    | inter-processor communications register for\n *arbiter (?) | ipcr1           | a40    | | ipcr2           | a80    | | ipcr3\n *| ac0    | | ipcr4           | b00    |\n * +-----------------+--------+\n * \\endcode\n **/\nu8 CSystem::tig_read(u32 a) {\n  switch (a) {\n  case 0x30000000: // trr\n    return 0;\n  case 0x30000040: // smir\n    return state.tig.FwWrite;\n  case 0x30000100: // mod_info\n    return 0;\n  case 0x300003c0: // ttcr\n    return state.tig.HaltA;\n  case 0x30000480: // clr_pwr_flt_det\n    return 0;\n  case 0x300005c0: // ev6_halt\n    return state.tig.HaltB;\n  case 0x38000180: // Arbiter revision\n    return 0xfe;\n  default:\n    printf(\"Unknown TIG %08x read attempted.\\n\", a);\n    return 0;\n  }\n}\n\nvoid CSystem::tig_write(u32 a, u8 data) {\n  switch (a) {\n  case 0x30000000: // trr\n    return;\n  case 0x30000040: // smir\n    state.tig.FwWrite = data;\n    return;\n  case 0x30000100: // mod_info\n    printf(\"Soft reset: %02x\\n\", data);\n    return;\n  case 0x300003c0: // ttcr\n    state.tig.HaltA = data;\n    return;\n  case 0x30000480: // clr_pwr_flt_det\n    return;\n  case 0x300005c0: // ev6_halt\n    state.tig.HaltB = data;\n    return;\n  default:\n    printf(\"Unknown TIG %07x write with %02x attempted.\\n\", a, data);\n  }\n}\n\n/**\n * Load ROM contents from file. Try if the decompressed ROM image\n * is available, otherwise create it first.\n **/\nint CSystem::LoadROM() {\n  FILE *f;\n  char *buffer;\n  int i;\n  int j;\n  u64 temp;\n  u32 scratch;\n\n  f = fopen(myCfg->get_text_value(\"rom.decompressed\", \"decompressed.rom\"),\n            \"rb\");\n  if (!f) {\n    f = fopen(myCfg->get_text_value(\"rom.srm\", \"cl67srmrom.exe\"), \"rb\");\n    if (!f)\n      FAILURE(Runtime, \"No original or decompressed SRM ROM image found\");\n    printf(\"%%SYS-I-READROM: Reading original ROM image from %s.\\n\",\n           myCfg->get_text_value(\"rom.srm\", \"cl67srmrom.exe\"));\n    for (i = 0; i < 0x240; i++) {\n      if (feof(f))\n        break;\n      (void)!fread(&scratch, 1, 1, f);\n    }\n\n    if (feof(f))\n      FAILURE(Runtime, \"File is too short to be a SRM ROM image\");\n    buffer = PtrToMem(0x900000);\n    while (!feof(f))\n      (void)!fread(buffer++, 1, 1, f);\n    fclose(f);\n\n    printf(\"%%SYS-I-DECOMP: Decompressing ROM image.\\n0%%\");\n    acCPUs[0]->set_pc(0x900001);\n    acCPUs[0]->set_PAL_BASE(0x900000);\n    acCPUs[0]->enable_icache();\n\n    j = 0;\n    while (acCPUs[0]->get_clean_pc() > 0x200000) {\n      for (i = 0; i < 1800000; i++) {\n        SingleStep();\n        if (acCPUs[0]->get_clean_pc() < 0x200000)\n          break;\n      }\n\n      j++;\n      if (((j % 5) == 0) && (j < 50))\n        printf(\"%d%%\", j * 2);\n      else\n        printf(\".\");\n      fflush(stdout);\n    }\n\n    printf(\"100%%\\n\");\n    acCPUs[0]->restore_icache();\n\n    f = fopen(myCfg->get_text_value(\"rom.decompressed\", \"decompressed.rom\"),\n              \"wb\");\n    if (!f) {\n      printf(\"%%SYS-W-NOWRITE: Couldn't write decompressed rom to %s.\\n\",\n             myCfg->get_text_value(\"rom.decompressed\", \"decompressed.rom\"));\n    } else {\n      printf(\"%%SYS-I-ROMWRT: Writing decompressed rom to %s.\\n\",\n             myCfg->get_text_value(\"rom.decompressed\", \"decompressed.rom\"));\n      temp = endian_64(acCPUs[0]->get_pc());\n      fwrite(&temp, 1, sizeof(u64), f);\n      temp = endian_64(acCPUs[0]->get_pal_base());\n      fwrite(&temp, 1, sizeof(u64), f);\n      buffer = PtrToMem(0);\n      fwrite(buffer, 1, 0x200000, f);\n      fclose(f);\n    }\n  } else {\n    printf(\"%%SYS-I-READROM: Reading decompressed ROM image from %s.\\n\",\n           myCfg->get_text_value(\"rom.decompressed\", \"decompressed.rom\"));\n    (void)!fread(&temp, 1, sizeof(u64), f);\n    for (int i = 0; i < iNumCPUs; i++)\n      acCPUs[i]->set_pc(endian_64(temp));\n    (void)!fread(&temp, 1, sizeof(u64), f);\n    for (int i = 0; i < iNumCPUs; i++)\n      acCPUs[i]->set_PAL_BASE(endian_64(temp));\n    buffer = PtrToMem(0);\n    (void)!fread(buffer, 1, 0x200000, f);\n    fclose(f);\n  }\n\n#if !defined(SRM_NO_SPEEDUPS) || !defined(SRM_NO_IDE)\n  printf(\"%%SYM-I-PATCHROM: Patching ROM for speed.\\n\");\n#endif\n#if !defined(SRM_NO_SPEEDUPS)\n  WriteMem(U64(0x14248), 32, 0xe7e00000, 0); // e7e00000 = BEQ r31, +0\n  WriteMem(U64(0x14288), 32, 0xe7e00000, 0);\n  WriteMem(U64(0x142c8), 32, 0xe7e00000, 0);\n  WriteMem(U64(0x68320), 32, 0xe7e00000, 0);\n  WriteMem(U64(0x8bb78), 32, 0xe7e00000, 0); // memory test (aa)\n  WriteMem(U64(0x8bc0c), 32, 0xe7e00000, 0); // memory test (bb)\n  WriteMem(U64(0x8bc94), 32, 0xe7e00000, 0); // memory test (00)\n\n  // WriteMem(U64(0xb1158),32,0xe7e00000,0);   // CPU sync?\n#endif\n  printf(\"%%SYS-I-ROMLOADED: ROM Image loaded successfully!\\n\");\n  return 0;\n}\n\n/**\n * \\brief Assert or deassert one of 64 possible interrupt lines on the Tsunami\n *chipset.\n *\n * Source: HRM, 6.3:\n *\n * TIGbus and Interrupts\n *\n * The TIGbus supports miscellaneous system logic such as flash ROM and\n * interrupt inputs. The Cchip TIG controller polls interrupts continuously\n * except when a read or write to flash is requested. The 64 possible interrupt\n *inputs are polled eight at a time by selecting a byte with the b_tia<2:0>\n *pins, and asserting b_toe_l to allow the selected byte to be driven onto\n *b_td<7:0>. Using the polled interrupts, the Cchip calculates the b_irq values\n *that should be delivered to the CPUs. When any change occurs in these b_irq\n *values, the Cchip drives the b_irq<3:0> data for both CPUs onto b_td<7:0>, and\n *asserts signal b_tis to strobe it into a register on the module. If there is\n *no flash read or write outstanding, the polling process is repeated. If there\n * is a flash read or write outstanding, it is serviced between interrupt reads\n *after any pending b_irq updates. Thus, the rounds of interrupt polling are not\n *atomic, but the b_irq values reflect the most recently polled interrupts.\n *Furthermore, b_irq<1> may be artificially suppressed for one full polling loop\n *using the CSR bit MISC<DEVSUP>.\n * [...]\n *\n * Device and Error Interrupt Delivery - b_irq<1:0>\n *\n * As interrupts are read into the Cchip through the TIGbus, the corresponding\n *bits are set in DRIR. These bits are ANDed with the mask bits in DIMn and then\n *placed in DIRn. If any bits are set in DIRn<55:0>, then CPUn is interrupted\n *using CPU pin b_irq<1>.\n *\n * Interrupt bits <62:58> cause b_irq<0> to be asserted and are intended for use\n *as error signals. Assertion of interrupt bits <62:58> causes b_irq<0> to be\n *asserted. Interrupt bits <62:61> can be used for Pchip 0 and Pchip 1 errors,\n *respectively. Interrupt bit <63> is special because it is not read from the\n *TIGbus, but is internally generated as the Cchip detected error interrupt\n *(currently used only for NXM requests). Assertion of interrupt bit <63> causes\n *b_irq<0> to be asserted. See Chapter 10 for descriptions of the\n *interrupt-related CSRs (DRIR, DIMn, DIRn, and MISC). A full mask register for\n * each CPU allows software to decide whether to send each of the 64 possible\n *interrupts to either or both CPUs.\n *\n * After handling all known outstanding interrupts, software may suppress\n *b_irq<1> device interrupts to allow the Cchip�s polling mechanism to detect\n *the updated (deasserted) value of the interrupt lines from the PCI devices and\n *thereby avoid giving the CPU �stale� interrupts, which require passive\n *release. The field MISC<DEVSUP> is provided for this purpose. When a CPU\n *writes a one to its bit in MISC<DEVSY> the Cchip deasserts b_irq<1> to that\n *CPU (regardless of the value in the DIRn) until it has completed an entire\n *polling loop. When the Cchip has completed an entire polling loop, b_irq<1>\n *will again reflect the value of DIRn<55:00>.\n *\n * Interval Timer Interrupts - b_irq<2>\n *\n * The interval timer interrupts the Cchip through a dedicated pin, i_intim_l,\n *and is asserted low. When the Cchip sees an asserting (falling) edge of this\n *pin, it asserts MISC<ITINTR> for both CPUs. Pin b_irq<2> remains asserted for\n *each CPU <ITINTR>. When the CPU has finished handling the interrupt, it writes\n *a one to its MISC<ITINTR> bit to clear it. Software can suppress interval\n *timer interrupts for n cycles by writing n into IICn.\n *\n * This table shows TIG Interrupts and IRQ Lines\n *\n * \\code\n * +---------------+-----------------+--------+----------------------------------------+\n * | TIG Interrupt | Assertion Level | irq<n> | Use |\n * +---------------+-----------------+--------+----------------------------------------+\n * |            63 | N/A             | irq<0> | N/C (internally generated Cchip\n *error) | |               |                 |        |     (currently NXM only)\n *|\n * +---------------+-----------------+--------+----------------------------------------+\n * |         62:58 | High            | irq<0> | Errors (Pchips, and so on) | |\n *|                 |        | Recommended:                           | | | | |\n ** Bit <62> - Pchip0 error            | |               |                 | |\n ** Bit <61> - Pchip1 error            |\n * +---------------+-----------------+--------+----------------------------------------+\n * |         57:56 | N/A             | N/A    | Reserved |\n * +---------------+-----------------+--------+----------------------------------------+\n * |          55:0 | Low             | irq<1> | PCI devices (level sensitive) |\n * +---------------+-----------------+--------+----------------------------------------+\n * \\endcode\n *\n * It is not clear from the documentation how exactly the interval timer is\n *connected to the CChip. It looks like this is tied to the interrupt-line from\n *the real-time clock (TOY), as the periodic interval rate for the TOY is set to\n *1024 Hz by SRM. 1024 Hz is the frequency of the system timer interrupt\n *according to the OpenVMS Alpha Internals and Data Structures Handbook.\n *\n **/\nvoid CSystem::interrupt(int number, bool assert) {\n  int i;\n\n  if (number == -1) {\n\n    // timer int...\n    state.cchip.misc |= 0xf0;\n    for (i = 0; i < iNumCPUs; i++)\n      acCPUs[i]->irq_h(2, true, 0); // timer interrupt is immediate\n  } else if (assert) {\n\n    //    if (!(state.cchip.drir & (1i64<<number)))\n    //      printf(\"%%TYP-I-INTERRUPT: Interrupt %d asserted.\\n\",number);\n    state.cchip.drir |= (U64(0x1) << number);\n  } else {\n\n    //    if (state.cchip.drir & (1i64<<number))\n    //      printf(\"%%TYP-I-INTERRUPT: Interrupt %d deasserted.\\n\",number);\n    state.cchip.drir &= ~(U64(0x1) << number);\n  }\n\n  for (i = 0; i < iNumCPUs; i++) {\n    if (state.cchip.drir & state.cchip.dim[i] & U64(0x00ffffffffffffff))\n      acCPUs[i]->irq_h(1, true, 100); // device interrupts delayed by 100 clocks\n    else\n      acCPUs[i]->irq_h(1, false, 0);\n\n    if (state.cchip.drir & state.cchip.dim[i] & U64(0xfc00000000000000))\n      acCPUs[i]->irq_h(0, true, 100); // device interrupts delayed by 100 clocks\n    else\n      acCPUs[i]->irq_h(0, false, 0);\n  }\n}\n\n/**\n * \\brief Translate a 32-bit address coming off the PCI bus into a\n * 64-bit system address. Used by PCI devices when accessing\n * memory (or other PCI devices) as bus master.\n *\n * Source: HRM, 10.1.4:\n *\n * DMA Address Translation (PCI-to-System)\n * The 21272 chipset supports some PCI commands as a target and does not support\n * (ignores) others as a target. The Pchip does not respond as a target when it\n *acts as a PCI master.\n *\n * The Pchip ignores all of the following commands as a target:\n *  - Interrupt acknowledge\n *  - Special cycle\n *  - I/O read\n *  - I/O write\n *  - Configuration read\n *  - Configuration write\n *  .\n *\n * The Pchips may respond to the following commands as a target:\n *  - Memory read\n *  - Memory read line\n *  - Memory write\n *  - Memory write and invalidate\n *  - Memory read multiple\n *  - Dual-address cycle: This command is accepted by the Pchip when the address\n *lies inside the DMA monster window.\n *\n * There are two kinds of DMA address translation: direct mapped and\n *scatter-gather mapped. Each type starts by comparing the incoming PCI address\n *with the monster window (if it is enabled and if it is a DAC), and with the\n *four window base and window mask registers (the window base registers also\n *have an enable window bit and a scatter-gather enable bit). This process is\n *shown in the next figure:\n *\n * \\code\n *              31       n n-1      20 19    13 12       0\n *             +----------+-----------+--------+----------+\n * PCI Address |    Peripheral Page Number     |  Offset  |\n *             +----------+-----------+--------+----------+\n *             |<-------->|\n *                  ^\n *                  +-----------> COMPARE ----> Hit\n *                  v\n *             |<-------->|\n *              31       n n-1      20\n * Window Base +----------+-----------+\n * Register    |          |   xxxx    |\n *             +----------+-----------+\n *              31       n n-1      20\n * Window Mask +----------+-----------+\n * Register    |   0000   |   1111    | (Determines n)\n *             +----------+-----------+\n * \\endcode\n *\n * If the address resides in one of the windows, and the window is enabled, then\n *if the scatter-gather enable bit is set, the translation is as described for\n * PCI_Phys_scatter_gather. Otherwise, the translation described for\n *PCI_Phys_direct_mapped is used.\n *\n * In addition, if the matching window has the PTP bit set, then the result of\n *the address translation is treated as if it had bit <43> set. That is, it is\n *treated like a PIO address from the CPU. Otherwise, the address is a system\n *memory address.\n *\n * Window Hole\n *\n * All window registers are simultaneously subject to a hole that inhibits\n *matching, under the control of the PCTL<HOLE> CSR bit described in\n *Section 10.2.5.4. If that bit is set, the hole is enabled in all windows and\n *has the following extent:\n *  - From PCI address base 512K (address<31:0> = 0008.0000)\n *  - To PCI address limit 1M-1 (address<31:0> = 000F.FFFF)\n *  .\n *\n * If enabled, the hole applies whether or not the PTP bit is set for the\n *window.\n *\n * The documentation is not explicit on this, but the assumption was made that\n *if an address coming off the PCI-bus is not matched, the Pchip doesn't respond\n *to that address, and it is up to other PCI devices to respond to the address.\n *So, if no match is found, we treat the address as an address on the local PCI\n *bus.\n *\n * \\todo The documentation mentions a PTP bit set for a window, but the register\n *descriptions don't show a PTP bit in one of the three registers (WSBA, WSM and\n *TBA). So, for now, we can only do peer-to-peer through a scatter-gather PTE.\n *\n * \\todo Dual-Acces-Cycle (DAC) access from the PCI bus is not supported. If a\n *device is ever added that uses this, we should probably support it.\n **/\nu64 CSystem::PCI_Phys(int pcibus, u32 address) {\n  u64 a;\n  int j;\n\n#if defined(DEBUG_PCI)\n  printf(\"-------------- PCI MEMORY ACCESS FOR PCI HOSE %d --------------\\n\",\n         pcibus);\n\n  // Step through windows\n  for (j = 0; j < 4; j++) {\n    printf(\"WSBA%d: %016\" PRIx64 \" WSM: %016\" PRIx64 \" TBA: %016\" PRIx64 \"\\n\", j,\n           state.pchip[pcibus].wsba[j], state.pchip[pcibus].wsm[j],\n           state.pchip[pcibus].tba[j]);\n  }\n\n  printf(\"HOLE: %s\\n\",\n         test_bit_64(state.pchip[pcibus].pctl, 5) ? \"enabled\" : \"disabled\");\n  printf(\"--------------------------------------------------------------\\n\");\n#endif\n  if (!(state.pchip[pcibus].pctl & PCI_PCTL_HOLE) // hole disabled\n      || (address < PCI_PCTL_HOLE_START) ||\n      (address > PCI_PCTL_HOLE_END)) // or address outside hole\n  {\n\n    // Step through windows\n    for (j = 0; j < 4; j++) {\n      if ((state.pchip[pcibus].wsba[j] & 1) // window enabled...\n          && !((address ^ state.pchip[pcibus].wsba[j]) & 0xfff00000 &\n               ~state.pchip[pcibus].wsm[j])) // address in range...\n      {\n        if (state.pchip[pcibus].wsba[j] & 2) {\n          try {\n            a = PCI_Phys_scatter_gather(address, state.pchip[pcibus].wsm[j],\n                                        state.pchip[pcibus].tba[j]);\n          }\n\n          catch (char) {\n\n            // window disabled...\n            // not matched; treat as local PCI bus address\n            return U64(0x80000000000) | (pcibus * U64(0x200000000)) |\n                   (u64)address;\n          }\n        } else\n          a = PCI_Phys_direct_mapped(address, state.pchip[pcibus].wsm[j],\n                                     state.pchip[pcibus].tba[j]);\n#if defined(DEBUG_PCI)\n        printf(\"PCI memory address %08x translated to %016\" PRIx64 \"\\n\", address,\n               a);\n#endif\n        return a;\n      }\n    }\n  }\n\n  // not matched; treat as local PCI bus address\n  return U64(0x80000000000) | (pcibus * U64(0x200000000)) | (u64)address;\n}\n\n/**\n * Translate a 32-bit address coming off the PCI bus into a 64-bit\n * system address using direct-mapped DMA address translation.\n *\n * Source: HRM, 10.1.4.2:\n *\n * Direct-Mapped DMA Address Translation\n *\n * Direct-mapped addressing uses a base address register, a translated base\n *address (TBA) register, and a mask register. The block of PCI addresses at\n *base address, of a size as determined by the mask register, is translated to a\n *block of addresses at translated base address. Values in the WSMn field other\n *than those shown produce unspecified results.\n *\n * \\code\n * +-------------+----------------+---------------------------+\n * | Window Size | WSMn<31:20>    | Translated Address <34:0> |\n * +-------------+----------------+---------------------------+\n * |         1MB | 0000.0000.0000 | TBA<34:20>:ad<19:0>       |\n * +-------------+----------------+---------------------------+\n * |         2MB | 0000.0000.0001 | TBA<34:21>:ad<20:0>       |\n * +-------------+----------------+---------------------------+\n * |         4MB | 0000.0000.0011 | TBA<34:22>:ad<21:0>       |\n * +-------------+----------------+---------------------------+\n * |         8MB | 0000.0000.0111 | TBA<34:23>:ad<22:0>       |\n * |        ...  |           ...  |                ...        |\n * |         2GB | 0111.1111.1111 | TBA<34:31>:ad<30:0>       |\n * +-------------+----------------+---------------------------+\n * |         4GB |            N/A | 000:ad<31:0> (monster     |\n * |             |                | window only)              |\n * +-------------+----------------+---------------------------+\n * \\endcode\n **/\nu64 CSystem::PCI_Phys_direct_mapped(u32 address, u64 wsm, u64 tba) {\n  u64 a;\n\n  wsm &= PCI_WSM_MASK;\n\n  a = (address & (wsm | PCI_ADD_MASK)) | (tba & ~wsm & PCI_TBA_MASK);\n\n  return a;\n}\n\n/**\n * Translate a 32-bit address coming off the PCI bus into a 64-bit\n * system address using scatter-gather DMA address translation.\n *\n * If address can't be matched (PTE is invalid), an exception of type char\n * is thrown. The calling function should catch the exception, and do\n * The Right Thing(tm): treat the address as a local PCI-bus address.\n *\n * Source: HRM, 10.1.4.3:\n *\n * Scatter-Gather DMA Address Translation\n *\n * Scatter-gather addressing uses a base address register, a mask register, a\n *translated base address register, and a page table entry (PTE) in system\n *memory. An 8KB page of PCI addresses at base address is translated to an 8KB\n *page of system addresses through one level of indirection. The PTE contains\n *the address of the 8KB page.\n * [...]\n * At TBA is a region (of size SG PTE AREA) of PTEs, each of which is eight\n *bytes. Bits <22:1> of the PTE become bits <34:13> (the 8KB page) of the system\n *address, and bits <12:0> of the PCI address become bits <12:0> (the page\n *offset) of the system address.\n *\n * The following table shows how the address of the page table entry (to be used\n *as part of the final system address) is generated. Values in the WSM field\n *other than those shown produce unspecified results.\n *\n * \\code\n * +-------------+-------------+----------------+----------------------+\n * | Window Size | SG PTE AREA | WSMn<31:20>    | PTE Address <34:3>   |\n * +-------------+-------------+----------------+----------------------+\n * |         1MB |         1KB | 0000.0000.0000 | TBA<34:10>:ad<19:13> |\n * +-------------+-------------+----------------+----------------------+\n * |         2MB |         2KB | 0000.0000.0001 | TBA<34:11>:ad<20:13> |\n * +-------------+-------------+----------------+----------------------+\n * |         4MB |         4KB | 0000.0000.0011 | TBA<34:12>:ad<21:13> |\n * +-------------+-------------+----------------+----------------------+\n * |         8MB |         8KB | 0000.0000.0111 | TBA<34:13>:ad<22:13> |\n * |        ...  |        ...  |           ...  |                ...   |\n * |         2GB |         2MB | 0111.1111.1111 | TBA<34:21>:ad<30:13> |\n * +-------------+-------------+----------------+----------------------+\n * |         4GB |         4MB |            N/A | TBA<34:22>:ad<31:13> |\n * |             |             |                | (Window 3 in DAC     |\n * |             |             |                | mode only)           |\n * +-------------+-------------+----------------+----------------------+\n * \\endcode\n *\n * The following figure shows the structure of a page table entry in memory. If\n *either bit <31> or bit <28> is set, the address is interpreted as being a\n *peer-to-peer address.\n *\n * \\code\n *  63               32 31 30 29 28 27      23 22                   1 0\n * +-------------------+--+-----+--+----------+----------------------+-+\n * |                   |PP|     |PP|          | Page Address <34:13> |V|\n * +-------------------+--+-----+--+----------+----------------------+-+\n *                                                                    +--> V =\n *valid bit \\endcode\n *\n * The last figure shows how a page table entry is used in conjunction with an\n *incoming PCI address to generate a system address.\n *\n * \\code\n *        PTE <22:1>              PCI address <12:0>\n *             |                         |\n *  34         v              13 12      v         0\n * +----------------------------+-------------------+\n * |   Page addres <34:13>      |  Offset <12:0>    |\n * +----------------------------+-------------------+\n * \\endcode\n **/\nu64 CSystem::PCI_Phys_scatter_gather(u32 address, u64 wsm, u64 tba) {\n  u64 pte_a;\n\n  u64 pte;\n\n  u64 a;\n\n  wsm &= PCI_WSM_MASK;\n\n  pte_a = ((address & (wsm | PCI_PTE_ADD_MASK)) >>\n           PCI_PTE_ADD_SHIFT) // ad part of pte address\n          | (tba & PCI_PTE_TBA_MASK &\n             ~(wsm >> PCI_PTE_ADD_SHIFT)); // tba part of pte address\n  pte = ReadMem(pte_a, 64, 0);\n  if (pte & 1) {\n    a = ((pte << PCI_PTE_SHIFT) & PCI_PTE_MASK) | (address & PCI_PTE_ADD2_MASK);\n\n    if (pte & PCI_PTE_PEER_BIT) // peer-to-peer\n      a |= (PHYS_PIO_ACCESS);   // PIO access.\n    return a;\n  } else {\n    throw((char)'0');\n  }\n}\n\n/**\n * Initialize all devices.\n **/\nvoid CSystem::init() {\n  for (int i = 0; i < iNumComponents; i++)\n    acComponents[i]->init();\n}\n\nvoid CSystem::start_threads() {\n  int i;\n\n  printf(\"Start threads:\");\n  for (i = 0; i < iNumComponents; i++) {\n#ifdef IDB\n    // When running with IDB, the trace engine takes care of managing the CPU,\n    // so its thread shouldn't be started.\n    if (dynamic_cast<CAlphaCPU *>(acComponents[i]))\n      continue;\n#endif\n    acComponents[i]->start_threads();\n  }\n  printf(\"\\n\");\n\n  for (i = 0; i < iNumCPUs; i++)\n    acCPUs[i]->release_threads();\n}\n\nvoid CSystem::stop_threads() {\n  printf(\"Stop threads:\");\n  for (int i = 0; i < iNumComponents; i++)\n    acComponents[i]->stop_threads();\n  printf(\"\\n\");\n}\n\n/**\n * Save system state to a state file.\n **/\nvoid CSystem::SaveState(const char *fn) {\n  FILE *f;\n  int i;\n  unsigned int m;\n  unsigned int j;\n  int *mem = (int *)memory;\n  int int0 = 0;\n  unsigned int memints = (1 << iNumMemoryBits) / (unsigned int)sizeof(int);\n  u32 temp_32;\n\n  f = fopen(fn, \"wb\");\n  if (f) {\n    temp_32 = 0xa1fae540; // MAGIC NUMBER (ALFAES40 ==> A1FAE540 )\n    fwrite(&temp_32, sizeof(u32), 1, f);\n    temp_32 = 0x00020001; // File Format Version 2.1\n    fwrite(&temp_32, sizeof(u32), 1, f);\n\n    // memory\n    for (m = 0; m < memints; m++) {\n      if (mem[m]) {\n        fwrite(&(mem[m]), 1, sizeof(int), f);\n      } else {\n        j = 0;\n        m++;\n        while (!mem[m] && (m < memints)) {\n          m++;\n          j++;\n          if ((int)j == -1)\n            break;\n        }\n\n        if (mem[m])\n          m--;\n        fwrite(&int0, 1, sizeof(int), f);\n        fwrite(&j, 1, sizeof(int), f);\n      }\n    }\n\n    fwrite(&state, sizeof(state), 1, f);\n\n    // components\n    //\n    //  Components should also save any non-initial memory-registrations and\n    //  re-register upon restore!\n    //\n    for (i = 0; i < iNumComponents; i++)\n      acComponents[i]->SaveState(f);\n    fclose(f);\n  }\n}\n\n/**\n * Restore system state from a state file.\n **/\nvoid CSystem::RestoreState(const char *fn) {\n  FILE *f;\n  int i;\n  unsigned int m;\n  unsigned int j;\n  int *mem = (int *)memory;\n  unsigned int memints = (1 << iNumMemoryBits) / (unsigned int)sizeof(int);\n  u32 temp_32;\n\n  f = fopen(fn, \"rb\");\n  if (!f) {\n    printf(\"%%SYS-F-NOFILE: Can't open restore file %s\\n\", fn);\n    return;\n  }\n\n  (void)!fread(&temp_32, sizeof(u32), 1, f);\n  if (temp_32 != 0xa1fae540) // MAGIC NUMBER (ALFAES40 ==> A1FAE540 )\n  {\n    printf(\"%%SYS-F-FORMAT: %s does not appear to be a state file.\\n\", fn);\n    return;\n  }\n\n  (void)!fread(&temp_32, sizeof(u32), 1, f);\n\n  if (temp_32 != 0x00020001) // File Format Version 2.1\n  {\n    printf(\"%%SYS-I-VERSION: State file %s is a different version.\\n\", fn);\n    return;\n  }\n\n  // memory\n  for (m = 0; m < memints; m++) {\n    (void)!fread(&(mem[m]), 1, sizeof(int), f);\n    if (!mem[m]) {\n      (void)!fread(&j, 1, sizeof(int), f);\n      while (j--) {\n        mem[++m] = 0;\n      }\n    }\n  }\n\n  (void)!fread(&state, sizeof(state), 1, f);\n\n  // components\n  //\n  //  Components should also save any non-initial memory-registrations and\n  //  re-register upon restore!\n  //\n  for (i = 0; i < iNumComponents; i++) {\n    if (acComponents[i]->RestoreState(f))\n      FAILURE(Runtime, \"Unable to restore system state\");\n  }\n\n  fclose(f);\n}\n\n/**\n * Dump memory contents to a file.\n **/\nvoid CSystem::DumpMemory(unsigned int filenum) {\n  char file[100];\n  int x;\n  int *mem = (int *)memory;\n  FILE *f;\n\n  sprintf(file, \"memory_%012d.dmp\", filenum);\n  f = fopen(file, \"wb\");\n\n  x = (1 << iNumMemoryBits) / (unsigned int)sizeof(int) / 2;\n\n  while (!mem[x - 1])\n    x--;\n\n  fwrite(mem, 1, x * sizeof(int), f);\n  fclose(f);\n}\n\n/**\n *  Dump system state to stdout for debugging purposes.\n **/\nvoid CSystem::panic(char *message, int flags) {\n  int cpunum;\n\n  int i;\n  CAlphaCPU *cpu;\n  printf(\"\\n******** SYSTEM PANIC *********\\n\");\n  printf(\"* %s\\n\", message);\n  printf(\"*******************************\\n\");\n  for (cpunum = 0; cpunum < iNumCPUs; cpunum++) {\n    cpu = acCPUs[cpunum];\n    printf(\"\\n==================== STATE OF CPU %d ====================\\n\",\n           cpunum);\n\n    printf(\"PC: %016\" PRIx64 \"\\n\", cpu->get_pc());\n#ifdef IDB\n    printf(\"Physical PC: %016\" PRIx64 \"\\n\", cpu->get_current_pc_physical());\n    printf(\"Instruction Count: %\" PRId64 \"\\n\", cpu->get_instruction_count());\n#endif\n    printf(\"\\n\");\n\n    for (i = 0; i < 32; i++) {\n      if (i < 10)\n        printf(\"R\");\n      printf(\"%d:%016\" PRIx64, i, cpu->get_r(i, false));\n      if (i % 4 == 3)\n        printf(\"\\n\");\n      else\n        printf(\" \");\n    }\n\n    printf(\"\\n\");\n    for (i = 4; i < 8; i++) {\n      if (i < 10)\n        printf(\"S\");\n      printf(\"%d:%016\" PRIx64, i, cpu->get_r(i + 32, false));\n      if (i % 4 == 3)\n        printf(\"\\n\");\n      else\n        printf(\" \");\n    }\n\n    for (i = 20; i < 24; i++) {\n      if (i < 10)\n        printf(\"S\");\n      printf(\"%d:%016\" PRIx64, i, cpu->get_r(i + 32, false));\n      if (i % 4 == 3)\n        printf(\"\\n\");\n      else\n        printf(\" \");\n    }\n\n    printf(\"\\n\");\n    for (i = 0; i < 32; i++) {\n      if (i < 10)\n        printf(\"F\");\n      printf(\"%d:%016\" PRIx64, i, cpu->get_f(i));\n      if (i % 4 == 3)\n        printf(\"\\n\");\n      else\n        printf(\" \");\n    }\n  }\n\n  printf(\"\\n\");\n#ifdef IDB\n  if (flags & PANIC_LISTING) {\n    u64 start;\n\n    u64 end;\n    start = cpu->get_pc() - 64;\n    end = start + 128;\n    cpu->listing(start, end, cpu->get_pc());\n  }\n#endif\n  if (flags & PANIC_ASKSHUTDOWN) {\n    printf(\"Stop Emulation? \");\n\n    int c = getc(stdin);\n    if (c == 'y' || c == 'Y')\n      flags |= PANIC_SHUTDOWN;\n  }\n\n  if (flags & PANIC_SHUTDOWN) {\n    FAILURE(Abort, \"Panic shutdown\");\n  }\n\n  return;\n}\n\n/**\n * Clear the clock interrupt for a specific CPU. Used by the CPU to acknowledge\n *the interrupt.\n **/\nvoid CSystem::clear_clock_int(int ProcNum) {\n  state.cchip.misc &= ~(U64(0x10) << ProcNum);\n  acCPUs[ProcNum]->irq_h(2, false, 0);\n}\n\n#if defined(PROFILE)\nu64 profile_buckets[PROFILE_BUCKETS];\nu64 profiled_insts;\nbool profile_started = false;\n#endif\nCSystem *theSystem = 0;\n"
  },
  {
    "path": "src/System.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"SystemComponent.hpp\"\n#include \"TraceEngine.hpp\"\n\n#if !defined(INCLUDED_SYSTEM_H)\n#define INCLUDED_SYSTEM_H\n\n#define MAX_COMPONENTS 100\n\n#if defined(PROFILE)\n#define PROFILE_FROM U64(0x8000)\n#define PROFILE_TO U64(0x1a81c0)\n#define PROFILE_AFTER U64(0x200000)\n#define PROFILE_BUCKSIZE 16\n#define PROFILE_LENGTH (PROFILE_TO - PROFILE_FROM)\n#define PROFILE_INSTS (PROFILE_LENGTH / 4)\n#define PROFILE_BUCKETS (PROFILE_INSTS / PROFILE_BUCKSIZE)\n#define PROFILE_YN(a)                                                          \\\n  ((a >= PROFILE_FROM) && (a < PROFILE_TO) && profile_started)\n#define PROFILE_BUCKET(a)                                                      \\\n  profile_buckets[(a - PROFILE_FROM) / 4 / PROFILE_BUCKSIZE]\n#define PROFILE_DO(a)                                                          \\\n  if ((a & (~U64(0x3))) >= PROFILE_AFTER)                                      \\\n    profile_started = true;                                                    \\\n  if (PROFILE_YN(a)) {                                                         \\\n    PROFILE_BUCKET(a)++;                                                       \\\n    profiled_insts++;                                                          \\\n  }\n\nextern u64 profile_buckets[PROFILE_BUCKETS];\nextern u64 profiled_insts;\nextern bool profile_started;\n#endif\n#if defined(LS_MASTER) || defined(LS_SLAVE)\nextern char *dbg_strptr;\n#endif\n\n/// Structure used for mapping memory ranges to devices.\nstruct SMemoryUser {\n  CSystemComponent *component; /**< Device that occupies this range. */\n  int index; /**< Index within the device. Used by devices that occupy more than\n                one range. */\n  u64 base;  /**< Address of first byte. */\n  u64 length; /**< Number of bytes in range. */\n};\n\n/// Structure used for configuration values.\nstruct SConfig {\n  char *key;   /**< Name of the value. */\n  char *value; /**< Value of the value. */\n};\n\n/**\n * \\brief Emulated Typhoon 21272 chipset.\n *\n * Documentation consulted:\n *  - Tsunami/Typhoon 21272 Chipset Hardware Reference Manual  [HRM]\n *(http://download.majix.org/dec/tsunami_typhoon_21272_hrm.pdf)\n *  - AlphaServer ES40 and AlphaStation ES40 Service Guide [SG]\n *(http://www.dec-store.com/PD_00158.aspx)\n *  - Tru64 include file dc104x.h [T64]\n *(http://samy.pl/packet/MISC/tru64/usr/include/alpha/dc104x.h)\n *  .\n *\n * The ES40 emulator has the following chipset configuration:\n *   - 1 x 21274-C1 Cchip (controller chip) - The Cchip controls the other chips\n *in the chipset, as well as the DRAM memory array in a system. The Cchip\n *interfaces with the CPU's command and address buses.\n *   - 8 x 21274-D1 Dchip (data slice chip) - The Dchips interface with the\n *system data bus and provide the data path between the CPU, DRAM memory, and\n *the Pchip(s).\n *   - 2 x 21272-P1 Pchip (peripheral interface chip) - The interface to the PCI\n *bus.\n *   .\n **/\nclass CSystem {\npublic:\n  void DumpMemory(unsigned int filenum);\n  char *PtrToMem(u64 address);\n  unsigned int get_memory_bits();\n  void RestoreState(const char *fn);\n  void SaveState(const char *fn);\n  u64 PCI_Phys(int pcibus, u32 address);\n  u64 PCI_Phys_direct_mapped(u32 address, u64 wsm, u64 tba);\n  u64 PCI_Phys_scatter_gather(u32 address, u64 wsm, u64 tba);\n  void interrupt(int number, bool assert);\n  int LoadROM();\n  u64 ReadMem(u64 address, int dsize, CSystemComponent *source);\n  void WriteMem(u64 address, int dsize, u64 data, CSystemComponent *source);\n  void Run();\n  int SingleStep();\n\n  void init();\n  void start_threads();\n  void stop_threads();\n\n  int RegisterMemory(CSystemComponent *component, int index, u64 base,\n                     u64 length);\n  void RegisterComponent(CSystemComponent *component);\n  void UnregisterComponent(CSystemComponent *component);\n  int RegisterCPU(class CAlphaCPU *cpu);\n\n  CSystem(CConfigurator *cfg);\n  void ResetMem(unsigned int membits);\n\n  CAlphaCPU *get_cpu(int cpunum) { return acCPUs[cpunum]; };\n  int get_cpu_num() { return iNumCPUs; };\n\n  virtual ~CSystem();\n  unsigned int iNumMemoryBits;\n\n  void panic(char *message, int flags);\n\n#define PANIC_NOSHUTDOWN 0\n#define PANIC_SHUTDOWN 1\n#define PANIC_ASKSHUTDOWN 2\n#define PANIC_LISTING 4\n  void clear_clock_int(int ProcNum);\n  u64 get_c_misc();\n  u64 get_c_dir(int ProcNum);\n  u64 get_c_dim(int ProcNum);\n  void set_c_dim(int ProcNum, u64 value);\n\n  void cpu_lock(int cpuid, u64 address);\n  bool cpu_unlock(int cpuid);\n  void cpu_break_lock(int cpuid, CSystemComponent *source);\n\nprivate:\n  u64 cchip_csr_read(u32 address, CSystemComponent *source);\n  void cchip_csr_write(u32 address, u64 data, CSystemComponent *source);\n  u64 pchip_csr_read(int num, u32 address);\n  void pchip_csr_write(int num, u32 address, u64 data);\n  u8 dchip_csr_read(u32 address);\n  void dchip_csr_write(u32 address, u8 data);\n  u8 tig_read(u32 address);\n  void tig_write(u32 address, u8 data);\n\n  int iNumCPUs;\n  CFastMutex *cpu_lock_mutex;\n\n  /// The state structure contains all elements that need to be saved to the\n  /// statefile.\n  struct SSys_state {\n    int cpu_lock_flags;\n    u64 cpu_lock_address[4];\n\n    /**\n     * TIGbus state data\n     *\n     * More details in: HRM, 6.3; T64. Detailed information is hard to find...\n     *\n     * The TIGbus (TTL Integrated Glue Logic) is the interface between the\n     *chipset and the interrupt controller, flash ROM, and possibly some other\n     *system components.\n     **/\n    struct SSys_tig {\n      u8 FwWrite;\n      u8 HaltA;\n      u8 HaltB;\n    } tig;\n\n    /**\n     * CCHIP state data\n     *\n     * More details in: HRM, 1.2.1.\n     *\n     * The 21274-C1 Cchip (controller chip) is the heart of the ES40's Typhoon\n     *chipset. It interfaces directly with the CPU's through the System address\n     *ports, it issues controls to the Dchips (data slice chips) and Pchips\n     *(peripheral interface chips) using the Dchip control ports, and the CAPbus\n     *(C-And-P-chip bus). It controls memory using the DRAM command and address\n     *ports. It also controls the TIGbus.\n     **/\n    struct SSys_cchip {\n\n      /**\n       * DIM: Device Interrupt Mask Registers.\n       *\n       * These mask registers control which interrupts are allowed to go through\n       *to the CPUs. No interrupt in DRIR will get through to the masked\n       *interrupt registers (and on to interrupt the CPUs) unless the\n       *corresponding mask bit is set in DIMn. All bits are initialized to 0 at\n       *reset.\n       **/\n      u64 dim[4];\n\n      /**\n       * DRIR: Device Raw Interrupt Request Register.\n       *\n       * DRIR indicates which of the 64 possible device interrupts is asserted.\n       *\n       * \\code\n       * +---------+---------+---------+------+-------------------------------------+\n       * | Field   | Bits    | Type    | Init | Description |\n       * +---------+---------+---------+------+-------------------------------------+\n       * | ERR     | <63:58> | RO      | 0    | IRQ0 error interrupts | | | | |\n       *|    <63> Chip detected MISC<NXM>     | |         |         |         |\n       *|    <62> hookup to Pchip0 error      | |         |         |         |\n       *|    <61> hookup to Pchip1 errror     |\n       * +---------+---------+---------+------+-------------------------------------+\n       * | RES     | <57:56> | RO      | 0    | Reserved |\n       * +---------+---------+---------+------+-------------------------------------+\n       * | DEV     | <55:0>  | RO      | 0    | PCI interrupts pending to the\n       *CPU   |\n       * +---------+---------+---------+------+-------------------------------------+\n       * \\endcode\n       *\n       * Combined with DIM[n] to form DIR[n]:\n       *\n       * DIR: Device Interrupt Request Registers.\n       *\n       * These registers indicate which interrupts are pending to the CPUs. If a\n       *raw request bit is set and the corresponding mask bit is set, then the\n       *corresponding bit in this register will be set and the appropriate CPU\n       *will be interrupted.\n       **/\n      u64 drir;\n\n      /**\n       * Miscellaneous Register (MISC - RW).\n       *\n       * +---------+---------+---------+------+-------------------------------------+\n       * | Field   | Bits    | Type    | Init | Description |\n       * +---------+---------+---------+------+-------------------------------------+\n       * | RES     | <63:44> | MBZ,RAZ | 0    | Reserved. | | DEVSUP  | <43:40>\n       *| WO      | 0    | Suppress IRQ1 interrupts to the CPU | |         | |\n       *|      | corresponding to a 1 in this field  | |         |         | |\n       *| until the interrupt polling machine | |         |         |         |\n       *| has completed a poll of all PCI     | |         |         |         |\n       *| devices.                            |\n       * +---------+---------+---------+------+-------------------------------------+\n       * | REV     | <39:32> | RO      | 8    | Latest revision of Cchip |\n       * +---------+---------+---------+------+-------------------------------------+\n       * | NXS     | <31:29> | RO      | 0    | NXM source - Device that caused\n       *NXM | |         |         |         |      | - UNPREDICTABLE if NXM is\n       *not set.  | |         |         |         |      |   Value Source | | |\n       *|         |      |   0..3  CPU 0..3                    | |         | |\n       *|      |   4..5  Pchip 0..1                  |\n       * +---------+---------+---------+------+-------------------------------------+\n       * | NXM     | <28>    | R,W1C   | 0    | Nonexistent memory address\n       *detected.| |         |         |         |      | Sets DRIR<63> and\n       *locks the NXS     | |         |         |         |      | field until\n       *it is cleared.          |\n       * +---------+---------+---------+------+-------------------------------------+\n       * | RES     | <27:25> | MBZ,RAZ | 0    | Reserved. |\n       * +---------+---------+---------+------+-------------------------------------+\n       * | ACL     | <24>    | WO      | 0    | Arbitration clear - writing a 1\n       *to  | |         |         |         |      | this bit clears ABT and ABW\n       *fields. |\n       * +---------+---------+---------+------+-------------------------------------+\n       * | ABT     | <23:20> | R,W1S   | 0    | Arbitration try - writing a 1 to\n       *| |         |         |         |      | these bits sets them. |\n       * +---------+---------+---------+------+-------------------------------------+\n       * | ABW     | <19:16> | R,W1S   | 0    | Arbitration won - writing a 1 to\n       *| |         |         |         |      | these bits sets them unless one\n       *is  | |         |         |         |      | already set, in which case\n       *the      | |         |         |         |      | write is ignored. |\n       * +---------+---------+---------+------+-------------------------------------+\n       * | IPREQ   | <15:12> | WO      | 0    | Interprocessor interrupt request\n       *-  | |         |         |         |      | write a 1 to the bit\n       *corresponding  | |         |         |         |      | to the CPU you\n       *want to interrupt.   | |         |         |         |      | Writing a\n       *1 here sets the corres-   | |         |         |         |      |\n       *ponding bit in IPINTR.              |\n       * +---------+---------+---------+------+-------------------------------------+\n       * | IPINTR  | <11:8>  | R,W1C   | 0    | Interprocessor interrupt pending\n       *-  | |         |         |         |      | one bit per CPU. Pin irq<3>\n       *is      | |         |         |         |      | asserted to the CPU\n       *corresponding   | |         |         |         |      | to a 1 in this\n       *field.               |\n       * +---------+---------+---------+------+-------------------------------------+\n       * | ITINTR  | <7:4>   | R,W1C   | 0    | Interval timer interrupt pending\n       *-  | |         |         |         |      | one bit per CPU. Pin irq<2>\n       *is      | |         |         |         |      | asserted to the CPU\n       *corresponding   | |         |         |         |      | to a 1 in this\n       *field.               |\n       * +---------+---------+---------+------+-------------------------------------+\n       * | RES     | <3:2>   | MBZ,RAZ | 0    | Reserved. |\n       * +---------+---------+---------+------+-------------------------------------+\n       * | CPUID   | <1:0>   | RO      |      | ID of the CPU performing the\n       *read.  |\n       * +---------+---------+---------+------+-------------------------------------+\n       * \\endcode\n       **/\n      u64 misc;\n      u64 csc;\n    } cchip;\n\n    /**\n     * DCHIP state data\n     *\n     * More details in: HRM, 1.2.2.\n     *\n     * The ES40 contains eight 21274-D1 Dchips (data slice chips). Each Dchip is\n     * responsible for handling 8 bits of the 64-bit data bus (in the ES40,\n     *other configurations using less Dchips are possible). Each Dchip\n     *interfaces with the Cchip for control, with each of the Pchips, with each\n     *of the CPU's and with each of the DRAM arrays.\n     **/\n    struct SSys_dchip {\n      u8 drev;\n      u8 dsc;\n      u8 dsc2;\n      u8 str;\n    } dchip;\n\n    /**\n     * PCHIP state data\n     *\n     * More details in: HRM, 1.2.3.\n     *\n     * The ES40 contains two 21272-P1 Pchips (peripheral interface chips). Each\n     *Pchip controls one 64-bit PCI bus, and interfaces it to the Cchip and the\n     *Dchips.\n     *\n     * On PIO transfers from the CPU's (or PTP transfers from the other PCI\n     *bus), the Pchip acts as bus master on the PCI bus.\n     *\n     * On DMA or PTP transfers from a PCI device, the Pchip acts as target on\n     *the PCI bus. To determine on which addresses to respond, each Pchip\n     *contains 4 DMA/PTP windows, that support both direct mapped and\n     *scatter-gather DMA/PTP memory access.\n     **/\n    struct SSys_pchip {\n      u64 plat;\n      u64 perr;\n      u64 perrmask;\n      u64 pctl;\n      u64 wsba[4];\n      u64 wsm[4];\n      u64 tba[4];\n    } pchip[2];\n\n    u32 cf8_address[2];\n  } state;\n  void *memory;\n\n  //    void * memmap;\n  int iNumComponents;\n  CSystemComponent *acComponents[MAX_COMPONENTS];\n  int iNumMemories;\n  struct SMemoryUser *asMemories[MAX_COMPONENTS];\n\n  class CAlphaCPU *acCPUs[4];\n\n  CConfigurator *myCfg;\n\n  int iSingleStep;\n\n#if defined(IDB)\n  int iSSCycles;\n#endif\n};\n\ninline u64 CSystem::get_c_misc() { return state.cchip.misc; }\n\ninline u64 CSystem::get_c_dir(int ProcNum) {\n  return state.cchip.drir & state.cchip.dim[ProcNum];\n}\n\ninline u64 CSystem::get_c_dim(int ProcNum) { return state.cchip.dim[ProcNum]; }\n\ninline void CSystem::set_c_dim(int ProcNum, u64 value) {\n  state.cchip.dim[ProcNum] = value;\n}\n\nextern CSystem *theSystem;\n\n/* constants for P-Chip CSR's */\n#define PCI_PCTL_HOLE U64(0x0000000000000020) /* <5>     */\n#define PCI_PCTL_HOLE_START 0x00080000\n#define PCI_PCTL_HOLE_END 0x000fffff\n\n/* constants for pci-to-phys-address-mapping */\n#define PCI_WSM_MASK U64(0x00000000fff00000)     /* <31:20> */\n#define PCI_ADD_MASK U64(0x00000000000fffff)     /* <19:0>  */\n#define PCI_TBA_MASK U64(0x00000007fff00000)     /* <34:20> */\n#define PCI_PTE_ADD_MASK U64(0x00000000000fe000) /* <19:13> */\n#define PCI_PTE_ADD_SHIFT 10\n#define PCI_PTE_TBA_MASK U64(0x00000007fffffc00) /* <34:10> */\n#define PCI_PTE_MASK U64(0x00000007ffffe000)     /* <34:13> */\n#define PCI_PTE_SHIFT 12\n#define PCI_PTE_ADD2_MASK U64(0x0000000000001fff) /* <12:0>  */\n#define PCI_PTE_PEER_BIT U64(0x0000000090000000)  /* <31,28> */\n\n#define PHYS_PIO_ACCESS U64(0x0000080000000000) /* <43>    */\n#endif                                          // !defined(INCLUDED_SYSTEM_H)\n"
  },
  {
    "path": "src/SystemComponent.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"SystemComponent.hpp\"\n#include \"StdAfx.hpp\"\n#include \"System.hpp\"\n\n/**\n * Constructor.\n **/\nCSystemComponent::CSystemComponent(CConfigurator *cfg, CSystem *system) {\n  char *a;\n  char *b;\n\n  system->RegisterComponent(this);\n  cSystem = system;\n  myCfg = cfg;\n\n  a = myCfg->get_myName();\n  b = myCfg->get_myValue();\n\n  CHECK_ALLOCATION(devid_string = (char *)malloc(strlen(a) + strlen(b) + 3));\n  sprintf(devid_string, \"%s(%s)\", a, b);\n}\n\n/**\n * destructor.\n **/\nCSystemComponent::~CSystemComponent() {\n  cSystem->UnregisterComponent(this);\n  free(devid_string);\n  devid_string = nullptr;\n}\n"
  },
  {
    "path": "src/SystemComponent.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_SYSTEMCOMPONENT_H)\n#define INCLUDED_SYSTEMCOMPONENT_H\n\n#include \"Configurator.hpp\"\n\n/**\n * \\brief Abstract base class for devices that connect to the Typhoon chipset.\n **/\nclass CSystemComponent {\npublic:\n  virtual int RestoreState(FILE *f) = 0;\n  virtual int SaveState(FILE *f) = 0;\n\n  CSystemComponent(class CConfigurator *cfg, class CSystem *system);\n  virtual ~CSystemComponent();\n\n  //=== abstract ===\n  virtual u64 ReadMem(int index, u64 address, int dsize) { return 0; };\n  virtual void WriteMem(int index, u64 address, int dsize, u64 data){};\n  virtual void check_state(){};\n  virtual void ResetPCI(){};\n  virtual void init(){};\n  virtual void start_threads(){};\n  virtual void stop_threads(){};\n\n  char *devid_string;\n\nprotected:\n  class CSystem *cSystem;\n  class CConfigurator *myCfg;\n};\n#endif // !defined(INCLUDED_SYSTEMCOMPONENT_H)\n"
  },
  {
    "path": "src/TraceEngine.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"StdAfx.hpp\"\n\n#if defined(IDB)\n#include \"AlphaCPU.hpp\"\n#include \"DPR.hpp\"\n#include \"Flash.hpp\"\n#include \"System.hpp\"\n#include \"TraceEngine.hpp\"\n#include \"lockstep.hpp\"\n#include <signal.h>\n\nCTraceEngine *trc;\n\n/**\n * Convert a string to a new string that contains only printable characters.\n *\n * The maximum length of the resulting string is 100 characters.\n *\n * @param dest Destination string\n * @param org  Source string\n **/\ninline void write_printable_s(char *dest, const char *org) {\n  int cnt = 100;\n  while (*org && cnt--) {\n    *(dest++) = printable(*(org++));\n  }\n\n  *dest = '\\0';\n}\n\n/**\n * Get the physical address that matches a given virtual address.\n *\n * This never generates a CPU exception.\n **/\ninline u64 real_address(u64 address, CAlphaCPU *c, bool bIBOX) {\n  bool b;\n  u64 a;\n\n  if (bIBOX && (address & 1))\n    return address & U64(0xfffffffffffffffc);\n\n  if (!(c->virt2phys(address, &a, ACCESS_READ | NO_CHECK | FAKE, &b, 0)))\n    return a & (bIBOX ? U64(0xfffffffffffffffc) : U64(0xffffffffffffffff));\n\n  return ((address & U64(0xfffffffff0000000)) == U64(0x0000000020000000))\n             ? address - U64(0x000000001fe00000)\n             : (((address & U64(0xfffffffff0000000)) == U64(0x0000000010000000))\n                    ? address - U64(0x000000000fffe000)\n                    : address) &\n                   (bIBOX ? U64(0xfffffffffffffffc) : U64(0xffffffffffffffff));\n}\n\n/**\n * Constructor.\n **/\nCTraceEngine::CTraceEngine(CSystem *sys) {\n  int i;\n  iNumFunctions = 0;\n  iNumPRBRs = 0;\n  cSystem = sys;\n  for (i = 0; i < 4; i++) {\n    asCPUs[0].last_prbr = -1;\n  }\n\n  current_trace_file = stdout;\n  bBreakPoint = false;\n}\n\n/**\n * Destructor.\n **/\nCTraceEngine::~CTraceEngine(void) {\n  int i;\n  for (i = 0; i < iNumPRBRs; i++)\n    fclose(asPRBRs[i].f);\n}\n\n/**\n * Trace function calling.\n *\n * @param cpu   Pointer to the CPU that jumps\n * @param f     Address of the current instruction\n * @param t     Address being jumped to\n * @param down  This could be a function call\n * @param up    This could be a return from a call\n * @param x     Optional printf argument that describes what happens (eg \"GO PAL\n *%0x\")\n * @param y     Optional extra argument for the printf statement.\n **/\nvoid CTraceEngine::trace(CAlphaCPU *cpu, u64 f, u64 t, bool down, bool up,\n                         const char *x, int y) {\n  // Not a real jump.\n  if ((t == f + 4) || (t == f))\n    return;\n\n  // p = new process context\n  int p = get_prbr(cpu->get_prbr(), cpu->get_hwpcb());\n\n  // o = old process context\n  int o = asCPUs[cpu->get_cpuid()].last_prbr;\n\n  // Check for process context switch\n  if (p != o) {\n    if (o != -1) {\n      /* Process context switch has happened. Print this in the trace files for\n         both the old and the new process context. */\n      fprintf(asPRBRs[o].f,\n              \"\\n==>   Switch to PRBR %08\" PRIx64 \" %08\" PRIx64 \" (%s)\\n\",\n              asPRBRs[p].prbr, asPRBRs[p].hwpcb, asPRBRs[p].procname);\n      fprintf(asPRBRs[p].f, \"        This is PRBR %08\" PRIx64 \" %08\" PRIx64 \" (%s)\\n\",\n              asPRBRs[p].prbr, asPRBRs[p].hwpcb, asPRBRs[p].procname);\n      fprintf(asPRBRs[p].f,\n              \"<== Switch from PRBR %08\" PRIx64 \" %08\" PRIx64 \" (%s)\\n\\n\",\n              asPRBRs[o].prbr, asPRBRs[o].hwpcb, asPRBRs[o].procname);\n    }\n\n    // save process context in cpu record\n    asCPUs[cpu->get_cpuid()].last_prbr = p;\n  }\n\n  // Has tracing been temporarily disabled for this process?\n  if (asPRBRs[p].trc_waitfor) {\n    // Have we reached the point where tracing should be re-enabled?\n    if ((t & ~U64(0x3)) == asPRBRs[p].trc_waitfor)\n      asPRBRs[p].trc_waitfor = 0;\n\n    // Don't trace for now.\n    return;\n  }\n\n  // Get the physical to/from addresses.\n  u64 pc_f = real_address(f, cpu, true);\n  u64 pc_t = real_address(f, cpu, true);\n\n  /* This is where it gets tricky...\n   *\n   * If the up parameter is true, we check if the to address of this trace is\n   * equal to the from address of a previous trace (that was a function call),\n   * or equal to that from address + 4 (next instruction). If this is the case,\n   * we consider this a function return. (decreasing the trace level).\n   *\n   * If this is not the case, we then check if tracing is hidden at this level.\n   * If this is the case, we don't trace this call.\n   *\n   * Next, we check if the down parameter is false, if this is the case, we\n   * handle the trace through trace_br.\n   *\n   * Otherwise, we treat the trace as a function call (increasing the trace\n   * level). We will then check if the to address is a known function address.\n   * In either case we will print the address or the function name and either\n   * the formatted function list or the first few function argument registers.\n   */\n  int oldlvl = asPRBRs[p].trclvl;\n  int i;\n  int j;\n\n  if (up) {\n    // Check if this is a function return\n    for (i = oldlvl - 1; i >= 0; i--) {\n      // Is this a return to an old \"from\" address?\n      if ((asPRBRs[p].trcadd[i] == (pc_t - 4)) ||\n          (asPRBRs[p].trcadd[i] == (pc_t))) {\n        // Yes, return to this address' tracelevel\n        asPRBRs[p].trclvl = i;\n        // Should we stop hiding the trace again?\n        if (asPRBRs[p].trchide > i)\n          asPRBRs[p].trchide = -1;\n\n        // Is tracing hidden at this level?\n        if (asPRBRs[p].trchide != -1)\n          return;\n\n        // Indent to the pevious (higher) trace level\n        for (j = 0; j < oldlvl; j++)\n          fprintf(asPRBRs[p].f, \" \");\n\n        // And print the from address, and the value of the r0 register (return\n        // value)\n        fprintf(asPRBRs[p].f, \"%016\" PRIx64 \"(%08\" PRIx64 \") ($r0 = %\" PRIx64 \")\\n\", f,\n                pc_f, cpu->get_r(0, true));\n\n        // Indent to the new (lower) trace level\n        for (j = 0; j < asPRBRs[p].trclvl; j++)\n          fprintf(asPRBRs[p].f, \" \");\n\n        // Print the to address\n        fprintf(asPRBRs[p].f, \"%016\" PRIx64 \"(%08\" PRIx64 \") <--\\n\", t, pc_t);\n        return;\n      }\n    }\n  }\n\n  // Are traces hidden at this level?\n  if (asPRBRs[p].trchide != -1)\n    return;\n\n  if (!down) {\n    // If we're not allowed to consider this a function call, handle the trace\n    // through trace_br\n    trace_br(cpu, f, t);\n    return;\n  }\n\n  // Maximum trace level reached?\n  if (oldlvl < 700)\n    asPRBRs[p].trclvl = oldlvl + 1;\n\n  // Set the from address for the old (lower) trace level\n  asPRBRs[p].trcadd[oldlvl] = pc_f;\n\n  // Is there a special message to print?\n  if (x) {\n    // Indent to the old (lower) trace level\n    for (i = 0; i < oldlvl; i++)\n      fprintf(asPRBRs[p].f, \" \");\n\n    // Print the special message\n    fprintf(asPRBRs[p].f, x, y);\n    fprintf(asPRBRs[p].f, \"\\n\");\n  }\n\n  // Indent to the old (lower) trace level\n  for (i = 0; i < oldlvl; i++)\n    fprintf(asPRBRs[p].f, \" \");\n\n  // Print the from address\n  fprintf(asPRBRs[p].f, \"%016\" PRIx64 \"(%08\" PRIx64 \") -->\\n\", f, pc_f);\n\n  // Indent to the new (higher) trace level\n  for (i = 0; i < asPRBRs[p].trclvl; i++)\n    fprintf(asPRBRs[p].f, \" \");\n\n  // Check if this is a known function\n  for (i = 0; i < iNumFunctions; i++) {\n    if (asFunctions[i].address == pc_t) {\n      // Function found\n\n      // Print function name\n      fprintf(asPRBRs[p].f, \"%016\" PRIx64 \"(%s)\", t, asFunctions[i].fn_name);\n\n      // And print the argument list\n      write_arglist(cpu, asPRBRs[p].f, asFunctions[i].fn_arglist);\n      fprintf(asPRBRs[p].f, \"\\n\");\n\n      // If this is a \"step-over\" function, we hide tracing for higher levels.\n      if (asFunctions[i].step_over)\n        asPRBRs[p].trchide = asPRBRs[p].trclvl;\n      return;\n    }\n  }\n\n  // No known function\n\n  // Print the to address\n  fprintf(asPRBRs[p].f, \"%016\" PRIx64 \"(%08\" PRIx64 \")\", t, pc_t);\n\n  // Print a default argument list\n  write_arglist(cpu, asPRBRs[p].f, \"(%s|16%, %s|17%, %s|18%, %s|19%)\");\n  fprintf(asPRBRs[p].f, \"\\n\");\n}\n\n/**\n * Trace a branch.\n *\n * This can't be a function call or return; stay at the same trace level.\n *\n * @param cpu   Pointer to the CPU that jumps\n * @param f     Address of the current instruction\n * @param t     Address being jumped to\n **/\nvoid CTraceEngine::trace_br(CAlphaCPU *cpu, u64 f, u64 t) {\n  int p;\n  int o;\n\n  // Get the physical to/from addresses.\n  u64 pc_f = real_address(f, cpu, true);\n  u64 pc_t = real_address(t, cpu, true);\n\n  // p = new process context\n  p = get_prbr(cpu->get_prbr(), cpu->get_hwpcb());\n\n  // o = old process context\n  o = asCPUs[cpu->get_cpuid()].last_prbr;\n\n  // Has tracing been temporarily disabled for this process?\n  if (asPRBRs[p].trc_waitfor) {\n    // Have we reached the point where tracing should be re-enabled?\n    if ((t & ~U64(0x3)) == asPRBRs[p].trc_waitfor)\n      asPRBRs[p].trc_waitfor = 0;\n\n    // Don't trace for now\n    return;\n  }\n\n  // Is tracing hidden at this level?\n  if (asPRBRs[p].trchide != -1)\n    return;\n\n  // Check for process context switch\n  if (p != o) {\n    if (o != -1) {\n      /* Process context switch has happened. Print this in the trace files for\n         both the old and the new process context. */\n      fprintf(asPRBRs[o].f,\n              \"\\n==>   Switch to PRBR %08\" PRIx64 \" %08\" PRIx64 \" (%s)\\n\",\n              asPRBRs[p].prbr, asPRBRs[p].hwpcb, asPRBRs[p].procname);\n      fprintf(asPRBRs[p].f, \"        This is PRBR %08\" PRIx64 \" %08\" PRIx64 \" (%s)\\n\",\n              asPRBRs[p].prbr, asPRBRs[p].hwpcb, asPRBRs[p].procname);\n      fprintf(asPRBRs[p].f,\n              \"<== Switch from PRBR %08\" PRIx64 \" %08\" PRIx64 \" (%s)\\n\\n\",\n              asPRBRs[o].prbr, asPRBRs[o].hwpcb, asPRBRs[o].procname);\n    }\n\n    // save process context in cpu record\n    asCPUs[cpu->get_cpuid()].last_prbr = p;\n  }\n\n  int i;\n\n  // Is this a real jump?\n  if ((pc_t > pc_f + 4) || (pc_t < pc_f)) {\n    // Indent to the trace level\n    for (i = 0; i < asPRBRs[p].trclvl; i++)\n      fprintf(asPRBRs[p].f, \" \");\n\n    // Print from address\n    fprintf(asPRBRs[p].f, \"%016\" PRIx64 \"(%08\" PRIx64 \") --+\\n\", f, pc_f);\n\n    // Indent to the trace level\n    for (i = 0; i < asPRBRs[p].trclvl; i++)\n      fprintf(asPRBRs[p].f, \" \");\n\n    // Is this a known function?\n    for (i = 0; i < iNumFunctions; i++) {\n      if (asFunctions[i].address == pc_t) {\n        // Yes, this is a known function\n\n        // Print the function name\n        fprintf(asPRBRs[p].f, \"%016\" PRIx64 \"(%s)\", t, asFunctions[i].fn_name);\n\n        // Print the argument list\n        write_arglist(cpu, asPRBRs[p].f, asFunctions[i].fn_arglist);\n        fprintf(asPRBRs[p].f, \" <-+\\n\");\n\n        // If this is a \"step-over\" function, we hide tracing for higher levels.\n        if (asFunctions[i].step_over)\n          asPRBRs[p].trchide = asPRBRs[p].trclvl;\n        return;\n      }\n    }\n\n    // Print the to address. (No function call, so, no argument list)\n    fprintf(asPRBRs[p].f, \"%016\" PRIx64 \"(%08\" PRIx64 \") <-+\\n\", t, pc_t);\n  }\n}\n\n/**\n * Add a function to the database of known functions.\n **/\nvoid CTraceEngine::add_function(u64 address, const char *fn_name,\n                                const char *fn_arglist, bool step_over) {\n  asFunctions[iNumFunctions].address = (u32)address & ~3;\n  asFunctions[iNumFunctions].fn_name = strdup(fn_name);\n  asFunctions[iNumFunctions].fn_arglist = strdup(fn_arglist);\n  asFunctions[iNumFunctions].step_over = step_over;\n  iNumFunctions++;\n}\n\n/**\n * Suspend tracing until the given address is reached.\n **/\nvoid CTraceEngine::set_waitfor(CAlphaCPU *cpu, u64 address) {\n  int p;\n  p = get_prbr(cpu->get_prbr(), cpu->get_hwpcb());\n\n  if (asPRBRs[p].trc_waitfor == 0)\n    asPRBRs[p].trc_waitfor = address & ~U64(0x3);\n}\n\n/**\n * See if a function name is known for a given address.\n **/\nbool CTraceEngine::get_fnc_name(CAlphaCPU *c, u64 address, char **p_fn_name) {\n  int i;\n\n  u64 a = real_address(address, c, true);\n\n  for (i = 0; i < iNumFunctions; i++) {\n    if (asFunctions[i].address == a) {\n      *p_fn_name = asFunctions[i].fn_name;\n      return true;\n    }\n  }\n\n  *p_fn_name = (char *)0;\n  return false;\n}\n\n/**\n * Get process context record for a PRBR/HWPCB combination\n **/\nint CTraceEngine::get_prbr(u64 prbr, u64 hwpcb) {\n  int i;\n  char filename[100];\n\n  for (i = 0; i < iNumPRBRs; i++) {\n    if ((asPRBRs[i].prbr == prbr) && (asPRBRs[i].hwpcb == hwpcb)) {\n      if (asPRBRs[i].f == current_trace_file)\n        return i;\n      if (!strncmp(asPRBRs[i].procname, cSystem->PtrToMem(prbr + 0x154), 20)) {\n        current_trace_file = asPRBRs[i].f;\n        return i;\n      }\n\n      fclose(asPRBRs[i].f);\n      break;\n    }\n  }\n\n  if (i == iNumPRBRs) {\n    asPRBRs[i].generation = 0;\n    iNumPRBRs++;\n  }\n\n  asPRBRs[i].generation++;\n\n  asPRBRs[i].prbr = prbr;\n  asPRBRs[i].hwpcb = hwpcb;\n  if (prbr > 0 && prbr < (U64(0x1) << cSystem->get_memory_bits()))\n    strncpy(asPRBRs[i].procname, cSystem->PtrToMem(prbr + 0x154), 20);\n  else\n    strcpy(asPRBRs[i].procname, \"\");\n  sprintf(filename, \"trace_%08\" PRIx64 \"_%08\" PRIx64 \"_%02d_%s.trc\", prbr, hwpcb,\n          asPRBRs[i].generation, asPRBRs[i].procname);\n  asPRBRs[i].f = fopen(filename, \"w\");\n  if (asPRBRs[i].f == 0)\n    printf(\"Failed to open file!!\\n\");\n  asPRBRs[i].trclvl = 0;\n  asPRBRs[i].trchide = -1;\n  asPRBRs[i].trc_waitfor = 0;\n  current_trace_file = asPRBRs[i].f;\n  printf(\"Add PRBR: %08\" PRIx64 \"_%08\" PRIx64 \"\\n\", prbr, hwpcb);\n  return i;\n}\n\n/**\n * Parse the argument list string a, get the necessary registers from CPU c,\n * and print the formatted argument list to file fl.\n **/\nvoid CTraceEngine::write_arglist(CAlphaCPU *c, FILE *fl, const char *a) {\n  char o[500];\n  char *op = o;\n  const char *ap = a;\n  char f[20];\n  char *fp;\n  char *rp;\n  int r;\n  u64 value;\n\n  while (*ap) {\n    if (*ap == '%') {\n      ap++;\n      fp = f;\n      *(fp++) = '%';\n      while (*ap != '%')\n        *(fp++) = *(ap++);\n      ap++;\n      *fp = '\\0';\n\n      // now we have a formatter in f.\n      rp = strchr(f, '|');\n      *(rp++) = '\\0';\n\n      // and the register in rp;\n      r = atoi(rp);\n      value = c->get_r(r, true);\n      if (!strcmp(f, \"%s\")) {\n        sprintf(op, \"%\" PRIx64 \" (\", value);\n        while (*op)\n          op++;\n        value = real_address(value, c, false);\n        if ((value > 0) && (value < (U64(0x1) << cSystem->get_memory_bits())))\n          write_printable_s(op, cSystem->PtrToMem(value));\n        else\n          sprintf(op, \"INVPTR\");\n        while (*op)\n          op++;\n        *(op++) = ')';\n        *(op) = '\\0';\n      } else if (!strcmp(f, \"%c\"))\n        sprintf(op, \"%02\" PRIx64 \" (%c)\", value, printable((char)value));\n      else if (!strcmp(f, \"%d\"))\n        sprintf(op, \"%\" PRId64 \"\", value);\n      else if (!strcmp(f, \"%x\"))\n        sprintf(op, \"%\" PRIx64 \"\", value);\n      else if (!strcmp(f, \"%0x\"))\n        sprintf(op, \"%016\" PRIx64 \"\", value);\n      else if (!strcmp(f, \"%016x\"))\n        sprintf(op, \"%016\" PRIx64 \"\", value);\n      else if (!strcmp(f, \"%08x\"))\n        sprintf(op, \"%08\" PRIx64 \"\", value);\n      else if (!strcmp(f, \"%04x\"))\n        sprintf(op, \"%04\" PRIx64 \"\", value);\n      else if (!strcmp(f, \"%02x\"))\n        sprintf(op, \"%02\" PRIx64 \"\", value);\n      else\n        sprintf(op, f, value);\n      while (*op)\n        op++;\n    } else {\n      *(op++) = *(ap++);\n    }\n  }\n\n  *op = '\\0';\n\n  fprintf(fl, \"%s\", o);\n}\n\n/**\n * Read a procfile. This file contains lines of the form:\n * <address>;<function name>;<argument list>;<step over>\n **/\nvoid CTraceEngine::read_procfile(const char *filename) {\n  FILE *f;\n  u64 address;\n  char linebuffer[1000];\n  char *fn_name;\n  char *fn_args;\n  char *sov;\n  int step_over;\n  int result;\n  int i = 0;\n\n  f = fopen(filename, \"r\");\n\n  if (f) {\n    while (fscanf(f, \"%[^\\n] \", linebuffer) != EOF) {\n      address = U64(0x0);\n      fn_name = strchr(linebuffer, ';');\n      if (fn_name) {\n        *fn_name = '\\0';\n        fn_name++;\n        result = sscanf(linebuffer, \"%\" PRIx64 \"\", &address);\n        if ((result == 1) && address) {\n          fn_args = strchr(fn_name, ';');\n          if (fn_args) {\n            *fn_args = '\\0';\n            fn_args++;\n            sov = strchr(fn_args, ';');\n            if (sov) {\n              *sov = '\\0';\n              sov++;\n              result = sscanf(sov, \"%d\", &step_over);\n              if (result == 1) {\n                add_function(address, fn_name, fn_args,\n                             step_over ? true : false);\n                i++;\n              }\n            }\n          }\n        }\n      }\n    }\n\n    fclose(f);\n    printf(\"%%IDB-I-RDTRC : Read %d entries from trace-file %s\\n\", i, filename);\n  }\n}\n\n/**\n * Print a string to the current trace file.\n **/\nvoid CTraceEngine::trace_dev(const char *text) {\n  fprintf(current_trace_file, \"%s\", text);\n}\n\n/**\n * Get file handle for current trace file.\n **/\nFILE *CTraceEngine::trace_file() { return current_trace_file; }\n\n/**\n * Run an IDB script, or prompt user for input.\n **/\nvoid CTraceEngine::run_script(const char *filename) {\n  char s[100][100];\n  int i;\n\n#if !defined(LS_SLAVE)\n  char c = '\\0';\n  int j;\n  FILE *f = NULL;\n\n  if (filename) {\n    f = fopen(filename, \"r\");\n    if (!f) {\n      printf(\"%%IDB-F-NOLOAD: File %s could not be opened.\\n\", filename);\n      return;\n    }\n  } else {\n    printf(\"This is the ES40 interactive debugger. To start non-interactively, \"\n           \"run es40,\\n\");\n    printf(\"Or run this executable (es40_idb) with a last argument of \"\n           \"@<script-file>\\n\");\n    f = stdin;\n  }\n#endif\n  for (;;) {\n#if !defined(LS_SLAVE)\n    if (filename) {\n      if (feof(f))\n        break;\n    } else {\n      printf(\"IDB %016\" PRIx64 \" %c>\", theSystem->get_cpu(0)->get_clean_pc(),\n             (theSystem->get_cpu(0)->get_pc() & U64(0x1)) ? 'P' : '-');\n    }\n#endif\n    for (i = 0; i < 100;) {\n#if defined(LS_SLAVE)\n      lockstep_receive(s[i], 100);\n      if (!strcmp(s[i], \"TERM\"))\n        break;\n#else\n      bool u = false;\n      for (j = 0; j < 100;) {\n        fscanf(f, \"%c\", &c);\n        if (c != '\\n' && c != '\\r' && c != ' ' && c != '\\t') {\n          s[i][j++] = c;\n          u = true;\n        }\n\n        if (c == ' ' || c == '\\t' || c == '\\n')\n          break;\n      }\n\n      s[i][j] = '\\0';\n\n      if (u)\n#endif\n      {\n#if defined(LS_MASTER)\n        lockstep_send(s[i]);\n#endif\n        i++;\n      }\n\n#if !defined(LS_SLAVE)\n      if (c == '\\n') {\n#if defined(LS_MASTER)\n        lockstep_send(\"TERM\");\n#endif\n        break;\n      }\n#endif\n    }\n\n    s[i][0] = '\\0';\n    if (parse(s))\n      break;\n  }\n\n#if !defined(LS_SLAVE)\n  if (filename)\n    fclose(f);\n#endif\n}\n\n/**\n * Parse an IDB command\n **/\nint CTraceEngine::parse(char command[100][100]) {\n  int i = 0;\n  int numargs;\n  int result;\n  int RunCycles;\n  u64 iFrom;\n  u64 iTo;\n  u64 iJump;\n\n  for (numargs = 0; command[numargs][0] != '\\0'; numargs++)\n    ;\n\n  if ((numargs > 0) &&\n      (command[0][0] == '#' || command[0][0] == ';' || command[0][0] == '!' ||\n       (command[0][0] == '/' && command[0][1] == '/')))\n\n    // comment\n    return 0;\n  switch (numargs) {\n  case 0:\n\n    // empty command\n    return 0;\n\n  case 1:\n    if (!strncasecmp(command[0], \"EXIT\", strlen(command[0])) ||\n        !strncasecmp(command[0], \"QUIT\", strlen(command[0])))\n      return 1;\n    if (!strncasecmp(command[0], \"HELP\", strlen(command[0])) ||\n        !strncasecmp(command[0], \"?\", strlen(command[0]))) {\n      printf(\"                                                                 \"\n             \"    \\n\");\n      printf(\"Available commands:                                              \"\n             \"    \\n\");\n      printf(\"  HELP | ?                                                       \"\n             \"    \\n\");\n      printf(\"  EXIT | QUIT                                                    \"\n             \"    \\n\");\n      printf(\"  STEP                                                           \"\n             \"    \\n\");\n      printf(\"  TRACE [ ON | OFF ]                                             \"\n             \"    \\n\");\n      printf(\"  HASHING [ ON | OFF ]                                           \"\n             \"    \\n\");\n      printf(\"  BREAKPOINT [ OFF | [ > | < | = | INSTRUCTION                   \"\n             \"    \\n\");\n      printf(\"                         | WRITE | READ | ACCESS ] <hex value> ] \"\n             \"    \\n\");\n      printf(\"  DISASSEMBLE [ON | OFF ]\t                                       \"\n             \"    \\n\");\n#if defined(DEBUG_TB)\n      printf(\"  TBDEBUG [ON | OFF ]\t                                       \"\n             \"        \\n\");\n#endif\n      printf(\"  LIST [ ALL |<hex address> - <hex address> ]                    \"\n             \"    \\n\");\n      printf(\"  RUN [ <max cycles> ]                                           \"\n             \"    \\n\");\n      printf(\"  LOAD [ STATE | DPR | FLASH | CSV ] <file>                      \"\n             \"    \\n\");\n      printf(\"  SAVE [ STATE | DPR | FLASH ] <file>                            \"\n             \"    \\n\");\n      printf(\"  JUMP <hex address>                                             \"\n             \"    \\n\");\n      printf(\"  PAL [ ON | OFF ]                                               \"\n             \"    \\n\");\n      printf(\"  DUMPREGS                                                       \"\n             \"    \\n\");\n      printf(\"  LOADREG <register> <value>                                     \"\n             \"    \\n\");\n      printf(\"  LOADFPREG <register> <value>                                   \"\n             \"    \\n\");\n      printf(\"  @<script-file>                                                 \"\n             \"    \\n\");\n      printf(\"  # | // | ; | ! <comment>                                       \"\n             \"    \\n\");\n      printf(\"                                                                 \"\n             \"    \\n\");\n      printf(\"The words of each command can be abbreviated, e.g. B or BRE for  \"\n             \"    \\n\");\n      printf(\"BREAKPOINT; S F for save flash.                                  \"\n             \"    \\n\");\n      printf(\"                                                                 \"\n             \"    \\n\");\n      return 0;\n    }\n\n    if (!strncasecmp(command[0], \"STEP\", strlen(command[0]))) {\n      printf(\"%%IDB-I-SSTEP : Single step.\\n\");\n      theSystem->SingleStep();\n      return 0;\n    }\n\n    if (!strncasecmp(command[0], \"DUMPREGS\", strlen(command[0]))) {\n      printf(\"\\n==================== SYSTEM STATE =======================\\n\");\n      printf(\"PC: %\" PRIx64 \"\\n\", theSystem->get_cpu(0)->get_pc());\n      printf(\"Physical PC: %\" PRIx64 \"\\n\",\n             theSystem->get_cpu(0)->get_current_pc_physical());\n      printf(\"Instruction count: %\" PRId64 \"\\n\",\n             theSystem->get_cpu(0)->get_instruction_count());\n      printf(\"\\n==================== REGISTER VALUES ====================\\n\");\n      for (i = 0; i < 32; i++) {\n        if (i < 10)\n          printf(\"R\");\n        printf(\"%d:%016\" PRIx64 \"\", i, theSystem->get_cpu(0)->get_r(i, false));\n        if (i % 4 == 3)\n          printf(\"\\n\");\n        else\n          printf(\" \");\n      }\n\n      printf(\"\\n\");\n      for (i = 4; i < 8; i++) {\n        if (i < 10)\n          printf(\"S\");\n        printf(\"%d:%016\" PRIx64 \"\", i,\n               theSystem->get_cpu(0)->get_r(i + 32, false));\n        if (i % 4 == 3)\n          printf(\"\\n\");\n        else\n          printf(\" \");\n      }\n\n      for (i = 20; i < 24; i++) {\n        if (i < 10)\n          printf(\"S\");\n        printf(\"%d:%016\" PRIx64 \"\", i,\n               theSystem->get_cpu(0)->get_r(i + 32, false));\n        if (i % 4 == 3)\n          printf(\"\\n\");\n        else\n          printf(\" \");\n      }\n\n      printf(\"\\n\");\n      for (i = 0; i < 32; i++) {\n        if (i < 10)\n          printf(\"F\");\n        printf(\"%d:%016\" PRIx64 \"\", i, theSystem->get_cpu(0)->get_f(i));\n        if (i % 4 == 3)\n          printf(\"\\n\");\n        else\n          printf(\" \");\n      }\n\n      printf(\"=========================================================\\n\");\n      return 0;\n    }\n\n    if (!strncasecmp(command[0], \"RUN\", strlen(command[0]))) {\n      if (!bBreakPoint) {\n        printf(\"%%IDB-F-NOBRKP: No breakpoint set, press Ctrl-C to end run.\\n\");\n\n        /* catch CTRL-C and shutdown gracefully */\n        extern int got_sigint;\n        void sigint_handler(int);\n        signal(SIGINT, &sigint_handler);\n        while (!got_sigint) {\n          theSystem->SingleStep();\n        }\n\n        got_sigint = 0;\n        return 0;\n      }\n\n      printf(\"%%IDB-I-RUNBPT: Running until breakpoint found.\\n\");\n      switch (iBreakPointMode) {\n      case -1:\n        for (i = 0;; i++) {\n          if (theSystem->SingleStep()) {\n            printf(\"%%IDB-I-ABORT : Abort run requested (probably from serial \"\n                   \"port)\\n\");\n            break;\n          }\n\n          if (theSystem->get_cpu(0)->get_clean_pc() < iBreakPoint) {\n            printf(\"%%IDB-I-BRKPT : Breakpoint encountered.\\n\");\n            break;\n          }\n        }\n        break;\n\n      case 0:\n        for (i = 0;; i++) {\n          if (theSystem->SingleStep()) {\n            printf(\"%%IDB-I-ABORT : Abort run requested (probably from serial \"\n                   \"port)\\n\");\n            break;\n          }\n\n          if (theSystem->get_cpu(0)->get_clean_pc() == iBreakPoint) {\n            printf(\"%%IDB-I-BRKPT : Breakpoint encountered.\\n\");\n            break;\n          }\n        }\n        break;\n\n      case 1:\n        for (i = 0;; i++) {\n          if (theSystem->SingleStep()) {\n            printf(\"%%IDB-I-ABORT : Abort run requested (probably from serial \"\n                   \"port)\\n\");\n            break;\n          }\n\n          if (theSystem->get_cpu(0)->get_clean_pc() > iBreakPoint) {\n            printf(\"%%IDB-I-BRKPT : Breakpoint encountered.\\n\");\n            break;\n          }\n        }\n        break;\n\n      case 2:\n\n        // break when the instruction matches.  Great for stopping when\n        // pal_halt is called!\n        extern int got_sigint;\n\n        void sigint_handler(int);\n        signal(SIGINT, &sigint_handler);\n        while (1) {\n          theSystem->SingleStep();\n          if (theSystem->get_cpu(0)->get_last_instruction() ==\n                  iBreakPointInstruction ||\n              got_sigint) {\n            printf(\"%%IDB-I-BRKPT: Found trapped instruction or control-c\\n\");\n            break;\n          }\n        }\n\n        got_sigint = 0;\n        break;\n\n      case 3: // access\n        for (i = 0;; i++) {\n          if (theSystem->SingleStep()) {\n            printf(\"%%IDB-I-ABORT : Abort run requested (probably from serial \"\n                   \"port)\\n\");\n            break;\n          }\n\n          if (theSystem->get_cpu(0)->get_last_read_loc() == iBreakPoint ||\n              theSystem->get_cpu(0)->get_last_write_loc() == iBreakPoint) {\n            printf(\"%%IDB-I-BRKPT : Breakpoint encountered.\\n\");\n            break;\n          }\n        }\n        break;\n\n      case 4: // read\n        for (i = 0;; i++) {\n          if (theSystem->SingleStep()) {\n            printf(\"%%IDB-I-ABORT : Abort run requested (probably from serial \"\n                   \"port)\\n\");\n            break;\n          }\n\n          if (theSystem->get_cpu(0)->get_last_read_loc() == iBreakPoint) {\n            printf(\"%%IDB-I-BRKPT : Breakpoint encountered.\\n\");\n            break;\n          }\n        }\n        break;\n\n      case 5: // write\n        for (i = 0;; i++) {\n          if (theSystem->SingleStep()) {\n            printf(\"%%IDB-I-ABORT : Abort run requested (probably from serial \"\n                   \"port)\\n\");\n            break;\n          }\n\n          if (theSystem->get_cpu(0)->get_last_write_loc() == iBreakPoint) {\n            printf(\"%%IDB-I-BRKPT : Breakpoint encountered.\\n\");\n            break;\n          }\n        }\n        break;\n\n      default:\n        break;\n      }\n\n      printf(\"%%IDB-I-ENDRUN: End of run.\\n\");\n      return 0;\n    }\n\n#if !defined(IDB) || !defined(LS_SLAVE)\n    if (command[0][0] == '@') {\n      run_script(command[0] + 1);\n      return 0;\n    }\n#endif // !defined(IDB) || !defined(LS_SLAVE)\n    break;\n\n  case 2:\n    if (!strncasecmp(command[0], \"LIST\", strlen(command[0])) &&\n        !strncasecmp(command[1], \"ALL\", strlen(command[1]))) {\n      list_all();\n      return 0;\n    }\n\n    if (!strncasecmp(command[0], \"TRACE\", strlen(command[0]))) {\n      if (!strcasecmp(command[1], \"ON\")) {\n        printf(\"%%IDB-I-TRCON : Tracing enabled.\\n\");\n        bTrace = true;\n        return 0;\n      }\n\n      if (!strcasecmp(command[1], \"OFF\")) {\n        printf(\"%%IDB-I-TRCOFF: Tracing disabled.\\n\");\n        bTrace = false;\n        return 0;\n      }\n    }\n\n#if defined(DEBUG_TB)\n    if (!strncasecmp(command[0], \"TBDEBUG\", strlen(command[0]))) {\n      if (!strcasecmp(command[1], \"ON\")) {\n        printf(\"%%IDB-I-TBDON : Translation Buffer Debugging enabled.\\n\");\n        bTB_Debug = true;\n        return 0;\n      }\n\n      if (!strcasecmp(command[1], \"OFF\")) {\n        printf(\"%%IDB-I-TBDOFF: Translation Buffer Debugging disabled.\\n\");\n        bTB_Debug = false;\n        return 0;\n      }\n    }\n#endif\n    if (!strncasecmp(command[0], \"HASHING\", strlen(command[0]))) {\n      if (!strcasecmp(command[1], \"ON\")) {\n        printf(\"%%IDB-I-HSHON : Hashing enabled.\\n\");\n        bHashing = true;\n        return 0;\n      }\n\n      if (!strcasecmp(command[1], \"OFF\")) {\n        printf(\"%%IDB-I-HSHOFF: Hashing disabled.\\n\");\n        bHashing = false;\n        return 0;\n      }\n    }\n\n    if (!strncasecmp(command[0], \"PAL\", strlen(command[0]))) {\n      if (!strcasecmp(command[1], \"ON\")) {\n        printf(\"%%IDB-I-PALON : PALmode enabled.\\n\");\n        theSystem->get_cpu(0)->set_pc(theSystem->get_cpu(0)->get_clean_pc() +\n                                      1);\n        return 0;\n      }\n\n      if (!strcasecmp(command[1], \"OFF\")) {\n        printf(\"%%IDB-I-PALOFF: PALmode disabled.\\n\");\n        theSystem->get_cpu(0)->set_pc(theSystem->get_cpu(0)->get_clean_pc());\n        return 0;\n      }\n    }\n\n    if (!strncasecmp(command[0], \"DISASSEMBLE\", strlen(command[0]))) {\n      if (!strcasecmp(command[1], \"ON\")) {\n        printf(\"%%IDB-I-DISON : Disassembling enabled.\\n\");\n        bDisassemble = true;\n        return 0;\n      }\n\n      if (!strcasecmp(command[1], \"OFF\")) {\n        printf(\"%%IDB-I-DISOFF: Disassembling disabled.\\n\");\n        bDisassemble = false;\n        return 0;\n      }\n    }\n\n    if (!strncasecmp(command[0], \"BREAKPOINT\", strlen(command[0]))) {\n      if (!strncasecmp(command[1], \"OFF\", strlen(command[1]))) {\n        printf(\"%%IDB-I-BRKOFF: Breakpoint disabled.\\n\");\n        bBreakPoint = false;\n        return 0;\n      }\n    }\n\n    if (!strncasecmp(command[0], \"RUN\", strlen(command[0]))) {\n      result = sscanf(command[1], \"%d\", &RunCycles);\n      if (result != 1) {\n        printf(\"%%IDB-F-INVVAL: Invalid decimal value.\\n\");\n        return 0;\n      }\n\n      if (bBreakPoint) {\n        printf(\"%%IDB-I-RUNCBP: Running until breakpoint found or max cycles \"\n               \"reached.\\n\");\n        switch (iBreakPointMode) {\n        case -1:\n          for (i = 0; i < RunCycles; i++) {\n            if (theSystem->SingleStep()) {\n              printf(\"%%IDB-I-ABORT : Abort run requested (probably from \"\n                     \"serial port)\\n\");\n              break;\n            }\n\n            if (theSystem->get_cpu(0)->get_clean_pc() < iBreakPoint) {\n              printf(\"%%IDB-I-BRKPT : Breakpoint encountered.\\n\");\n              break;\n            }\n          }\n          break;\n\n        case 0:\n          for (i = 0; i < RunCycles; i++) {\n            if (theSystem->SingleStep()) {\n              printf(\"%%IDB-I-ABORT : Abort run requested (probably from \"\n                     \"serial port)\\n\");\n              break;\n            }\n\n            if (theSystem->get_cpu(0)->get_clean_pc() == iBreakPoint) {\n              printf(\"%%IDB-I-BRKPT : Breakpoint encountered.\\n\");\n              break;\n            }\n          }\n          break;\n\n        case 1:\n          for (i = 0; i < RunCycles; i++) {\n            if (theSystem->SingleStep()) {\n              printf(\"%%IDB-I-ABORT : Abort run requested (probably from \"\n                     \"serial port)\\n\");\n              break;\n            }\n\n            if (theSystem->get_cpu(0)->get_clean_pc() > iBreakPoint) {\n              printf(\"%%IDB-I-BRKPT : Breakpoint encountered.\\n\");\n              break;\n            }\n          }\n          break;\n\n        case 2:\n          for (i = 0; i < RunCycles; i++) {\n            if (theSystem->SingleStep()) {\n              printf(\"%%IDB-I-ABORT : Abort run requested (probably from \"\n                     \"serial port)\\n\");\n              break;\n            }\n\n            if (theSystem->get_cpu(0)->get_last_instruction() ==\n                iBreakPointInstruction) {\n              printf(\"%%IDB-I-BRKPT: Found trapped instruction\\n\");\n              break;\n            }\n          }\n          break;\n\n        case 3: // access\n          for (i = 0; i < RunCycles; i++) {\n            if (theSystem->SingleStep()) {\n              printf(\"%%IDB-I-ABORT : Abort run requested (probably from \"\n                     \"serial port)\\n\");\n              break;\n            }\n\n            if (theSystem->get_cpu(0)->get_last_read_loc() == iBreakPoint ||\n                theSystem->get_cpu(0)->get_last_write_loc() == iBreakPoint) {\n              printf(\"%%IDB-I-BRKPT : Breakpoint encountered.\\n\");\n              break;\n            }\n          }\n          break;\n\n        case 4: // read\n          for (i = 0; i < RunCycles; i++) {\n            if (theSystem->SingleStep()) {\n              printf(\"%%IDB-I-ABORT : Abort run requested (probably from \"\n                     \"serial port)\\n\");\n              break;\n            }\n\n            if (theSystem->get_cpu(0)->get_last_read_loc() == iBreakPoint) {\n              printf(\"%%IDB-I-BRKPT : Breakpoint encountered.\\n\");\n              break;\n            }\n          }\n          break;\n\n        case 5: // write\n          for (i = 0; i < RunCycles; i++) {\n            if (theSystem->SingleStep()) {\n              printf(\"%%IDB-I-ABORT : Abort run requested (probably from \"\n                     \"serial port)\\n\");\n              break;\n            }\n\n            if (theSystem->get_cpu(0)->get_last_write_loc() == iBreakPoint) {\n              printf(\"%%IDB-I-BRKPT : Breakpoint encountered.\\n\");\n              break;\n            }\n          }\n          break;\n\n        default:\n          break;\n        }\n      } else {\n        printf(\"%%IDB-I-RUNCYC: Running until max cycles reached.\\n\");\n\n        extern int got_sigint;\n        void sigint_handler(int);\n        signal(SIGINT, &sigint_handler);\n        for (i = 0; i < RunCycles; i++) {\n          if (theSystem->SingleStep()) {\n            printf(\"%%IDB-I-ABORT : Abort run requested (probably from serial \"\n                   \"port)\\n\");\n            break;\n          }\n\n          if (got_sigint)\n            break;\n        }\n\n        got_sigint = 0;\n      }\n\n      printf(\"%%IDB-I-ENDRUN: End of run.\\n\");\n      return 0;\n    }\n\n    if (!strncasecmp(command[0], \"JUMP\", strlen(command[0]))) {\n      result = sscanf(command[1], \"%\" PRIx64 \"\", &iJump);\n      if (result != 1) {\n        printf(\"%%IDB-F-INVVAL: Invalid hexadecimal value.\\n\");\n        return 0;\n      }\n\n      if (iJump & U64(0x3)) {\n        printf(\"%%IDB-F-ALGVAL: Value not aligned on a 4-byte bounday.\\n\");\n        return 0;\n      }\n\n      printf(\"%%IDB-I-JUMPTO: Jumping.\\n\");\n      theSystem->get_cpu(0)->set_pc(\n          iJump + (theSystem->get_cpu(0)->get_pc() & U64(0x1)));\n      return 0;\n    }\n    break;\n\n  case 3:\n    if (!strncasecmp(command[0], \"BREAKPOINT\", strlen(command[0]))) {\n      if (!strcmp(command[1], \"=\") || !strcmp(command[1], \">\") ||\n          !strcmp(command[1], \"<\")) {\n        result = sscanf(command[2], \"%\" PRIx64 \"\", &iBreakPoint);\n        if (result != 1) {\n          printf(\"%%IDB-F-INVVAL: Invalid hexadecimal value.\\n\");\n          bBreakPoint = false;\n          return 0;\n        }\n\n        if (iBreakPoint & U64(0x3)) {\n          printf(\"%%IDB-F-ALGVAL: Value not aligned on a 4-byte bounday.\\n\");\n          bBreakPoint = false;\n          return 0;\n        }\n\n        switch (command[1][0]) {\n        case '=':\n          iBreakPointMode = 0;\n          break;\n        case '>':\n          iBreakPointMode = 1;\n          break;\n        case '<':\n          iBreakPointMode = -1;\n          break;\n        }\n\n        printf(\"%%IDB-I-BRKSET: Breakpoint set when PC %c %016\" PRIx64 \".\\n\",\n               command[1][0], iBreakPoint);\n        bBreakPoint = true;\n        return 0;\n      } else {\n        if (!strncasecmp(command[1], \"INSTRUCTION\", strlen(command[1]))) {\n          result = sscanf(command[2], \"%\" PRIx64 \"\", &iBreakPointInstruction);\n          if (result != 1) {\n            printf(\"%%IDB-F-INVVAL: Invalid hexadecimal value.\\n\");\n            bBreakPoint = false;\n            return 0;\n          }\n\n          printf(\"%%IDB-I-BRKSET: Breakpoint set when instruction %08x is \"\n                 \"executed.\\n\",\n                 iBreakPointInstruction);\n          bBreakPoint = true;\n          iBreakPointMode = 2;\n          return 0;\n        } else if (!strncasecmp(command[1], \"ACCESS\", strlen(command[1]))) {\n          result = sscanf(command[2], \"%\" PRIx64 \"\", &iBreakPoint);\n          if (result != 1) {\n            printf(\"%%IDB-F-INVVAL: Invalid hexadecimal value.\\n\");\n            bBreakPoint = false;\n            return 0;\n          }\n\n          printf(\"%%IDB-I-BRKSET: Breakpoint set when data is read/written at \"\n                 \"%016\" PRIx64 \".\\n\",\n                 iBreakPoint);\n          bBreakPoint = true;\n          iBreakPointMode = 3;\n          return 0;\n        } else if (!strncasecmp(command[1], \"READ\", strlen(command[1]))) {\n          result = sscanf(command[2], \"%\" PRIx64 \"\", &iBreakPoint);\n          if (result != 1) {\n            printf(\"%%IDB-F-INVVAL: Invalid hexadecimal value.\\n\");\n            bBreakPoint = false;\n            return 0;\n          }\n\n          printf(\"%%IDB-I-BRKSET: Breakpoint set when data is read at %016\" PRIx64\n                 \"x.\\n\",\n                 iBreakPoint);\n          bBreakPoint = true;\n          iBreakPointMode = 4;\n          return 0;\n        } else if (!strncasecmp(command[1], \"WRITE\", strlen(command[1]))) {\n          result = sscanf(command[2], \"%\" PRIx64 \"\", &iBreakPoint);\n          if (result != 1) {\n            printf(\"%%IDB-F-INVVAL: Invalid hexadecimal value.\\n\");\n            bBreakPoint = false;\n            return 0;\n          }\n\n          printf(\n              \"%%IDB-I-BRKSET: Breakpoint set when data is written at %016\" PRIx64\n              \"x.\\n\",\n              iBreakPoint);\n          bBreakPoint = true;\n          iBreakPointMode = 5;\n          return 0;\n        }\n      }\n    }\n\n    if (!strncasecmp(command[0], \"LOAD\", strlen(command[0]))) {\n      if (!strncasecmp(command[1], \"CSV\", strlen(command[1]))) {\n        read_procfile(command[2]);\n        return 0;\n      }\n\n      if (!strncasecmp(command[1], \"STATE\", strlen(command[1]))) {\n        theSystem->RestoreState(command[2]);\n        return 0;\n      }\n\n      if (!strncasecmp(command[1], \"DPR\", strlen(command[1]))) {\n        theDPR->RestoreStateF(command[2]);\n        return 0;\n      }\n\n      if (!strncasecmp(command[1], \"FLASH\", strlen(command[1]))) {\n        theSROM->RestoreStateF(command[2]);\n        return 0;\n      }\n    }\n\n    if (!strncasecmp(command[0], \"SAVE\", strlen(command[0]))) {\n      if (!strncasecmp(command[1], \"STATE\", strlen(command[1]))) {\n        theSystem->SaveState(command[2]);\n        return 0;\n      }\n\n      if (!strncasecmp(command[1], \"DPR\", strlen(command[1]))) {\n        theDPR->SaveStateF(command[2]);\n        return 0;\n      }\n\n      if (!strncasecmp(command[1], \"FLASH\", strlen(command[1]))) {\n        theSROM->SaveStateF(command[2]);\n        return 0;\n      }\n    }\n\n    if (!strncasecmp(command[0], \"LOADREG\", strlen(command[0]))) {\n      int reg;\n      u64 value;\n      result = sscanf(command[1], \"%d\", &reg);\n      if (result != 1 || reg > 31) {\n        printf(\"%%IDB-F-INVREG: Invalid register number.\\n\");\n        return 0;\n      }\n\n      result = sscanf(command[2], \"%\" PRIx64 \"\", &value);\n      if (result != 1) {\n        printf(\"%%IDB-F-INVVAL: Invalid hexadecimal value.\\n\");\n        return 0;\n      }\n\n      theSystem->get_cpu(0)->set_r(reg, value);\n      return 0;\n    }\n\n    if (!strncasecmp(command[0], \"LOADFPREG\", strlen(command[0]))) {\n      int reg;\n      u64 value;\n      result = sscanf(command[1], \"%d\", &reg);\n      if (result != 1 || reg > 31) {\n        printf(\"%%IDB-F-INVREG: Invalid register number.\\n\");\n        return 0;\n      }\n\n      result = sscanf(command[2], \"%\" PRIx64 \"\", &value);\n      if (result != 1) {\n        printf(\"%%IDB-F-INVVAL: Invalid hexadecimal value.\\n\");\n        return 0;\n      }\n\n      theSystem->get_cpu(0)->set_f(reg, value);\n      return 0;\n    }\n    break;\n\n  case 4:\n    if (!strncasecmp(command[0], \"LIST\", strlen(command[0])) &&\n        !strcmp(command[2], \"-\")) {\n      result = sscanf(command[1], \"%\" PRIx64 \"\", &iFrom);\n      if (result == 1)\n        result = sscanf(command[3], \"%\" PRIx64 \"\", &iTo);\n      if (result != 1) {\n        printf(\"%%IDB-F-INVVAL: Invalid hexadecimal value.\\n\");\n        return 0;\n      }\n\n      if (iFrom & U64(0x3) || iTo & U64(0x3)) {\n        printf(\"%%IDB-F-ALGVAL: Value not aligned on a 4-byte bounday.\\n\");\n        return 0;\n      }\n\n      if (iFrom > iTo) {\n        printf(\"%%IDB-F-FRLTTO: From value exceeds to value.\\n\");\n        return 0;\n      }\n\n      theSystem->get_cpu(0)->listing(iFrom, iTo);\n      return 0;\n    }\n    break;\n\n  default:\n    break;\n  }\n\n  printf(\"%%IDB-F-SYNTAX: Syntax error. Type \\\"?\\\" or \\\"HELP\\\" for help.\\n\");\n  return 0;\n}\n\nstruct sRegion {\n  u64 from;\n  u64 to;\n  struct sRegion *pNext;\n};\n\n/**\n * List all memory contents. Try to leave out memory that is only 00's, ef's or\n *ff's.\n **/\nvoid CTraceEngine::list_all() {\n  struct sRegion *pR = NULL;\n  struct sRegion **ppN = &pR;\n  struct sRegion *p = NULL;\n  int f = 0;\n  int t = 0;\n  int ms = 1 << (theSystem->get_memory_bits() - 3);\n  u64 *pM = (u64 *)theSystem->PtrToMem(0);\n\n  for (;;) {\n    while ((!pM[f] || pM[f] == U64(0xefefefefefefefef) ||\n            pM[f] == U64(0xffffffffffffffff)) &&\n           f < ms) {\n      f++;\n      if (!(f & 0x1ffff))\n        printf(\".\");\n    }\n\n    if (f >= ms)\n      break;\n    t = f;\n    for (;;) {\n      while (pM[t] && pM[t] != U64(0xefefefefefefefef) &&\n             pM[t] != U64(0xffffffffffffffff) && t < ms) {\n        t++;\n        if (!(t & 0x1ffff))\n          printf(\"x\");\n      }\n\n      if (t + 3 < ms) {\n        if ((!pM[t + 1] || pM[t + 1] == U64(0xefefefefefefefef) ||\n             pM[t + 1] == U64(0xffffffffffffffff)) &&\n            (!pM[t + 2] || pM[t + 2] == U64(0xefefefefefefefef) ||\n             pM[t + 2] == U64(0xffffffffffffffff)) &&\n            (!pM[t + 3] || pM[t + 3] == U64(0xefefefefefefefef) ||\n             pM[t + 3] == U64(0xffffffffffffffff)))\n          break;\n      }\n\n      if (t >= ms)\n        break;\n      t++;\n      if (!(t & 0x1ffff))\n        printf(\"x\");\n    }\n\n    *ppN = new sRegion;\n    (*ppN)->from = (u64)f * 8;\n    (*ppN)->to = (u64)((t - 1) * 8) + 4;\n    (*ppN)->pNext = NULL;\n    ppN = &((*ppN)->pNext);\n    f = t;\n  }\n\n  printf(\"\\n\");\n\n  p = pR;\n\n  while (p) {\n    printf(\"\\n======== DISASSEMBLING %08\" PRIx64 \" TO %08\" PRIx64 \" ========\\n\\n\",\n           p->from, p->to);\n    theSystem->get_cpu(0)->listing(p->from, p->to);\n    p = p->pNext;\n  }\n}\n\nbool bTrace = false;\nbool bDisassemble = false;\nbool bHashing = false;\nbool bListing = false;\n\n#if defined(DEBUG_TB)\nbool bTB_Debug = false;\n#endif\n#endif // IDB\n"
  },
  {
    "path": "src/TraceEngine.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_TRACEENGINE_H)\n#define INCLUDED_TRACEENGINE_H\n\n#if defined(IDB)\n#include \"datatypes.hpp\"\n\n/// Structure used to define named functions within memory.\nstruct STraceFunction {\n  u32 address;\n  char *fn_name;\n  char *fn_arglist;\n  bool step_over;\n};\n\n/// Structure used to keep track of PRBR values.\nstruct STracePRBR {\n  u64 prbr;\n  u64 hwpcb;\n  FILE *f;\n  u64 trcadd[701];\n  int trclvl;\n  int trchide;\n  u64 trc_waitfor;\n  char procname[30];\n  int generation;\n};\n\n/// Structure used to keep track of CPU's\nstruct STraceCPU {\n  int last_prbr;\n};\n\n/**\n * \\brief CPU tracing engine.\n **/\nclass CTraceEngine {\npublic:\n  void read_procfile(const char *filename);\n  CTraceEngine(class CSystem *sys);\n  ~CTraceEngine(void);\n  void trace(class CAlphaCPU *cpu, u64 f, u64 t, bool down, bool up,\n             const char *x, int y);\n  void trace_br(class CAlphaCPU *cpu, u64 f, u64 t);\n  void add_function(u64 address, const char *fn_name, const char *fn_arglist,\n                    bool step_over);\n  bool get_fnc_name(class CAlphaCPU *cpu, u64 address, char **p_fn_name);\n  void set_waitfor(class CAlphaCPU *cpu, u64 address);\n  FILE *trace_file();\n  void trace_dev(const char *text);\n  int parse(char command[100][100]);\n  void run_script(const char *filename);\n  void list_all();\n\nprotected:\n  class CSystem *cSystem;\n  int trcfncs;\n  int iNumFunctions;\n  int iNumPRBRs;\n  struct STraceFunction asFunctions[25000];\n  struct STraceCPU asCPUs[4];\n  struct STracePRBR asPRBRs[1000];\n  int get_prbr(u64 prbr, u64 hwpcb);\n  void write_arglist(CAlphaCPU *c, FILE *f, const char *a);\n  FILE *current_trace_file;\n  u64 iBreakPoint;\n  int iBreakPointMode;\n  bool bBreakPoint;\n  u32 iBreakPointInstruction;\n};\n\nextern bool bTrace;\nextern bool bDisassemble;\nextern bool bHashing;\nextern bool bListing;\n\n#if defined(DEBUG_TB)\nextern bool bTB_Debug;\n#endif\nextern CTraceEngine *trc;\n\n#define TRC_DEV(a)                                                             \\\n  {                                                                            \\\n    if (bTrace) {                                                              \\\n      char t[1000];                                                            \\\n      sprintf(t, a);                                                           \\\n      trc->trace_dev(t);                                                       \\\n    }                                                                          \\\n  }\n#define TRC_DEV2(a, b)                                                         \\\n  {                                                                            \\\n    if (bTrace) {                                                              \\\n      char t[1000];                                                            \\\n      sprintf(t, a, b);                                                        \\\n      trc->trace_dev(t);                                                       \\\n    }                                                                          \\\n  }\n#define TRC_DEV3(a, b, c)                                                      \\\n  {                                                                            \\\n    if (bTrace) {                                                              \\\n      char t[1000];                                                            \\\n      sprintf(t, a, b, c);                                                     \\\n      trc->trace_dev(t);                                                       \\\n    }                                                                          \\\n  }\n#define TRC_DEV4(a, b, c, d)                                                   \\\n  {                                                                            \\\n    if (bTrace) {                                                              \\\n      char t[1000];                                                            \\\n      sprintf(t, a, b, c, d);                                                  \\\n      trc->trace_dev(t);                                                       \\\n    }                                                                          \\\n  }\n#define TRC_DEV5(a, b, c, d, e)                                                \\\n  {                                                                            \\\n    if (bTrace) {                                                              \\\n      char t[1000];                                                            \\\n      sprintf(t, a, b, c, d, e);                                               \\\n      trc->trace_dev(t);                                                       \\\n    }                                                                          \\\n  }\n#define TRC_DEV6(a, b, c, d, e, f)                                             \\\n  {                                                                            \\\n    if (bTrace) {                                                              \\\n      char t[1000];                                                            \\\n      sprintf(t, a, b, c, d, e, f);                                            \\\n      trc->trace_dev(t);                                                       \\\n    }                                                                          \\\n  }\n\n#define DO_ACTION !bListing\n\n#else // IDB\n#define TRC_DEV(a) ;\n#define TRC_DEV2(a, b) ;\n#define TRC_DEV3(a, b, c) ;\n#define TRC_DEV4(a, b, c, d) ;\n#define TRC_DEV5(a, b, c, d, e) ;\n#define TRC_DEV6(a, b, c, d, e, f) ;\n\n#define DO_ACTION 1\n#endif\n#endif\n"
  },
  {
    "path": "src/VGA.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"VGA.hpp\"\n#include \"StdAfx.hpp\"\n\n/**\n * Constructor.\n *\n * Checks if more than one VGA card is present. If so, throws a failure.\n **/\nCVGA::CVGA(class CConfigurator *cfg, class CSystem *c, int pcibus, int pcidev)\n    : CPCIDevice(cfg, c, pcibus, pcidev) {\n  if (theVGA != 0)\n    FAILURE(Configuration, \"More than one VGA\");\n  theVGA = this;\n}\n\n/**\n * Destructor.\n **/\nCVGA::~CVGA(void) {}\n\n/**\n * Variable pointer to the one and only VGA card.\n **/\nCVGA *theVGA = 0;\n"
  },
  {
    "path": "src/VGA.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(__VGA_H__)\n#define __VGA_H__\n\n#include \"PCIDevice.hpp\"\n\n/**\n * \\brief Abstract base class for PCI VGA cards.\n **/\nclass CVGA : public CPCIDevice {\npublic:\n  CVGA(class CConfigurator *cfg, class CSystem *c, int pcibus, int pcidev);\n  ~CVGA(void);\n\n  virtual u8 get_actl_palette_idx(u8 index) = 0;\n  virtual void redraw_area(unsigned x0, unsigned y0, unsigned width,\n                           unsigned height) = 0;\n};\n\nextern CVGA *theVGA;\n#endif\n"
  },
  {
    "path": "src/base/Bugcheck.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Bugcheck.cpp\n//\n// $Id: Bugcheck.cpp,v 1.1 2008/05/31 15:47:19 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Core\n// Module:  Bugcheck\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#include \"Bugcheck.hpp\"\n#include \"Exception.hpp\"\n#include <sstream>\n\nvoid CBugcheck::assertion(const char *cond, const char *file, int line) {\n  throw CAssertionViolationException(what(cond, file, line));\n}\n\nvoid CBugcheck::nullPointer(const char *ptr, const char *file, int line) {\n  throw CNullPointerException(what(ptr, file, line));\n}\n\nvoid CBugcheck::bugcheck(const char *file, int line) {\n  throw CBugcheckException(what(0, file, line));\n}\n\nvoid CBugcheck::bugcheck(const char *msg, const char *file, int line) {\n  std::string m(\"Bugcheck\");\n  if (msg) {\n    m.append(\": \");\n    m.append(msg);\n  }\n  throw CBugcheckException(what(msg, file, line));\n}\n\nvoid CBugcheck::debugger(const char *file, int line) {\n  // Debugger::enter(file, line);\n}\n\nvoid CBugcheck::debugger(const char *msg, const char *file, int line) {\n  // Debugger::enter(msg, file, line);\n}\n\nstd::string CBugcheck::what(const char *msg, const char *file, int line) {\n  std::ostringstream str;\n  if (msg)\n    str << msg << \" \";\n  str << \"in file \\\"\" << file << \"\\\", line \" << line;\n  return str.str();\n}\n"
  },
  {
    "path": "src/base/Bugcheck.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Bugcheck.h\n//\n// $Id: Bugcheck.h,v 1.1 2008/05/31 15:47:20 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Core\n// Module:  Bugcheck\n//\n// Definition of the Bugcheck class and the self-testing macros.\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_Bugcheck_INCLUDED\n#define Foundation_Bugcheck_INCLUDED\n\n#include \"Foundation.hpp\"\n#include <string>\n\nclass CBugcheck\n/// This class provides some static methods that are\n/// used by the\n/// poco_assert_dbg(), poco_assert(), poco_check_ptr()\n/// and poco_bugcheck() macros.\n/// You should not invoke these methods\n/// directly. Use the macros instead, as they\n/// automatically provide useful context information.\n{\npublic:\n  static void assertion(const char *cond, const char *file, int line);\n  /// An assertion failed. Break into the debugger, if\n  /// possible, then throw an AssertionViolationException.\n\n  static void nullPointer(const char *ptr, const char *file, int line);\n  /// An null pointer was encountered. Break into the debugger, if\n  /// possible, then throw an NullPointerException.\n\n  static void bugcheck(const char *file, int line);\n  /// An internal error was encountered. Break into the debugger, if\n  /// possible, then throw an BugcheckException.\n\n  static void bugcheck(const char *msg, const char *file, int line);\n  /// An internal error was encountered. Break into the debugger, if\n  /// possible, then throw an BugcheckException.\n\n  static void debugger(const char *file, int line);\n  /// An internal error was encountered. Break into the debugger, if\n  /// possible.\n\n  static void debugger(const char *msg, const char *file, int line);\n  /// An internal error was encountered. Break into the debugger, if\n  /// possible.\n\nprotected:\n  static std::string what(const char *msg, const char *file, int line);\n};\n\n//\n// useful macros (these automatically supply line number and file name)\n//\n#define poco_assert(cond)                                                      \\\n  if (!(cond))                                                                 \\\n    CBugcheck::assertion(#cond, __FILE__, __LINE__);                           \\\n  else                                                                         \\\n    (void)0\n\n#define poco_check_ptr(ptr)                                                    \\\n  if (!(ptr))                                                                  \\\n    CBugcheck::nullPointer(#ptr, __FILE__, __LINE__);                          \\\n  else                                                                         \\\n    (void)0\n\n#define poco_bugcheck() CBugcheck::bugcheck(__FILE__, __LINE__)\n\n#define poco_bugcheck_msg(msg) CBugcheck::bugcheck(msg, __FILE__, __LINE__)\n\n#define poco_debugger() CBugcheck::debugger(__FILE__, __LINE__)\n\n#define poco_debugger_msg(msg) CBugcheck::debugger(msg, __FILE__, __LINE__)\n\n#endif // Foundation_Bugcheck_INCLUDED\n"
  },
  {
    "path": "src/base/ErrorHandler.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// ErrorHandler.cpp\n//\n// $Id: ErrorHandler.cpp,v 1.1 2008/05/31 15:47:20 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  ErrorHandler\n//\n// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#include \"ErrorHandler.hpp\"\n#include \"SingletonHolder.hpp\"\n\nCErrorHandler *CErrorHandler::_pHandler = CErrorHandler::defaultHandler();\nCFastMutex CErrorHandler::_mutex;\n\nCErrorHandler::CErrorHandler() {}\n\nCErrorHandler::~CErrorHandler() {}\n\nvoid CErrorHandler::exception(const CException &exc) {\n  poco_debugger_msg(exc.what());\n}\n\nvoid CErrorHandler::exception(const std::exception &exc) {\n  poco_debugger_msg(exc.what());\n}\n\nvoid CErrorHandler::exception() { poco_debugger_msg(\"unknown exception\"); }\n\nvoid CErrorHandler::handle(const CException &exc) {\n  CFastMutex::CScopedLock lock(&_mutex);\n  try {\n    _pHandler->exception(exc);\n  } catch (...) {\n  }\n}\n\nvoid CErrorHandler::handle(const std::exception &exc) {\n  CFastMutex::CScopedLock lock(&_mutex);\n  try {\n    _pHandler->exception(exc);\n  } catch (...) {\n  }\n}\n\nvoid CErrorHandler::handle() {\n  CFastMutex::CScopedLock lock(&_mutex);\n  try {\n    _pHandler->exception();\n  } catch (...) {\n  }\n}\n\nCErrorHandler *CErrorHandler::set(CErrorHandler *pHandler) {\n  poco_check_ptr(pHandler);\n\n  CFastMutex::CScopedLock lock(&_mutex);\n  CErrorHandler *pOld = _pHandler;\n  _pHandler = pHandler;\n  return pOld;\n}\n\nCErrorHandler *CErrorHandler::defaultHandler() {\n  static CSingletonHolder<CErrorHandler> sh;\n  return sh.get();\n}\n"
  },
  {
    "path": "src/base/ErrorHandler.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// ErrorHandler.h\n//\n// $Id: ErrorHandler.h,v 1.1 2008/05/31 15:47:20 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  ErrorHandler\n//\n// Definition of the ErrorHandler class.\n//\n// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_ErrorHandler_INCLUDED\n#define Foundation_ErrorHandler_INCLUDED\n\n#include \"Exception.hpp\"\n#include \"Foundation.hpp\"\n#include \"Mutex.hpp\"\n\nclass CErrorHandler\n/// This is the base class for thread error handlers.\n///\n/// An unhandled exception that causes a thread to terminate is usually\n/// silently ignored, since the class library cannot do anything meaningful\n/// about it.\n///\n/// The Thread class provides the possibility to register a\n/// global ErrorHandler that is invoked whenever a thread has\n/// been terminated by an unhandled exception.\n/// The ErrorHandler must be derived from this class and can\n/// provide implementations of all three handleException() overloads.\n///\n/// The ErrorHandler is always invoked within the context of\n/// the offending thread.\n{\npublic:\n  CErrorHandler();\n  /// Creates the ErrorHandler.\n\n  virtual ~CErrorHandler();\n  /// Destroys the ErrorHandler.\n\n  virtual void exception(const CException &exc);\n  /// Called when a Poco::Exception (or a subclass)\n  /// caused the thread to terminate.\n  ///\n  /// This method should not throw any exception - it would\n  /// be silently ignored.\n  ///\n  /// The default implementation just breaks into the debugger.\n\n  virtual void exception(const std::exception &exc);\n  /// Called when a std::exception (or a subclass)\n  /// caused the thread to terminate.\n  ///\n  /// This method should not throw any exception - it would\n  /// be silently ignored.\n  ///\n  /// The default implementation just breaks into the debugger.\n\n  virtual void exception();\n  /// Called when an exception that is neither a\n  /// Poco::Exception nor a std::exception caused\n  /// the thread to terminate.\n  ///\n  /// This method should not throw any exception - it would\n  /// be silently ignored.\n  ///\n  /// The default implementation just breaks into the debugger.\n\n  static void handle(const CException &exc);\n  /// Invokes the currently registered ErrorHandler.\n\n  static void handle(const std::exception &exc);\n  /// Invokes the currently registered ErrorHandler.\n\n  static void handle();\n  /// Invokes the currently registered ErrorHandler.\n\n  static CErrorHandler *set(CErrorHandler *pHandler);\n  /// Registers the given handler as the current error handler.\n  ///\n  /// Returns the previously registered handler.\n\n  static CErrorHandler *get();\n  /// Returns a pointer to the currently registered\n  /// ErrorHandler.\n\nprotected:\n  static CErrorHandler *defaultHandler();\n  /// Returns the default ErrorHandler.\n\nprivate:\n  static CErrorHandler *_pHandler;\n  static CFastMutex _mutex;\n};\n\n//\n// inlines\n//\ninline CErrorHandler *CErrorHandler::get() { return _pHandler; }\n\n#endif // Foundation_ErrorHandler_INCLUDED\n"
  },
  {
    "path": "src/base/Event.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Event.cpp\n//\n// $Id: Event.cpp,v 1.1 2008/05/31 15:47:21 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  Event\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#include \"Event.hpp\"\n\n#if defined(POCO_OS_FAMILY_WINDOWS)\n#include \"Event_WIN32.cpp\"\n#else\n#include \"Event_POSIX.cpp\"\n#endif\n\nCEvent::CEvent(bool autoReset) : CEventImpl(autoReset) {}\n\nCEvent::~CEvent() {}\n"
  },
  {
    "path": "src/base/Event.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Event.h\n//\n// $Id: Event.h,v 1.1 2008/05/31 15:47:21 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  Event\n//\n// Definition of the Event class.\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_Event_INCLUDED\n#define Foundation_Event_INCLUDED\n\n#include \"Exception.hpp\"\n#include \"Foundation.hpp\"\n\n#if defined(POCO_OS_FAMILY_WINDOWS)\n#include \"Event_WIN32.hpp\"\n#else\n#include \"Event_POSIX.hpp\"\n#endif\n\nclass CEvent : private CEventImpl\n/// An Event is a synchronization object that\n/// allows one thread to signal one or more\n/// other threads that a certain event\n/// has happened.\n/// Usually, one thread signals an event,\n/// while one or more other threads wait\n/// for an event to become signalled.\n{\npublic:\n  CEvent(bool autoReset = true);\n  /// Creates the event. If autoReset is true,\n  /// the event is automatically reset after\n  /// a wait() successfully returns.\n\n  ~CEvent();\n  /// Destroys the event.\n\n  void set();\n  /// Signals the event. If autoReset is true,\n  /// only one thread waiting for the event\n  /// can resume execution.\n  /// If autoReset is false, all waiting threads\n  /// can resume execution.\n\n  void wait();\n  /// Waits for the event to become signalled.\n\n  void wait(long milliseconds);\n  /// Waits for the event to become signalled.\n  /// Throws a TimeoutException if the event\n  /// does not become signalled within the specified\n  /// time interval.\n\n  bool tryWait(long milliseconds);\n  /// Waits for the event to become signalled.\n  /// Returns true if the event\n  /// became signalled within the specified\n  /// time interval, false otherwise.\n\n  void reset();\n  /// Resets the event to unsignalled state.\n\nprivate:\n  CEvent(const CEvent &);\n  CEvent &operator=(const CEvent &);\n};\n\n//\n// inlines\n//\ninline void CEvent::set() { setImpl(); }\n\ninline void CEvent::wait() { waitImpl(); }\n\ninline void CEvent::wait(long milliseconds) {\n  if (!waitImpl(milliseconds))\n    throw CTimeoutException();\n}\n\ninline bool CEvent::tryWait(long milliseconds) {\n  return waitImpl(milliseconds);\n}\n\ninline void CEvent::reset() { resetImpl(); }\n\n#endif // Foundation_Event_INCLUDED\n"
  },
  {
    "path": "src/base/Event_POSIX.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Event_POSIX.cpp\n//\n// $Id: Event_POSIX.cpp,v 1.1 2008/05/31 15:47:21 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  Event\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#include \"base/Event_POSIX.hpp\"\n#include <sys/time.h>\n\nCEventImpl::CEventImpl(bool autoReset) : _auto(autoReset), _state(false) {\n  if (pthread_mutex_init(&_mutex, NULL))\n    throw CSystemException(\"cannot create event (mutex)\");\n  if (pthread_cond_init(&_cond, NULL))\n    throw CSystemException(\"cannot create event (condition)\");\n}\n\nCEventImpl::~CEventImpl() {\n  pthread_cond_destroy(&_cond);\n  pthread_mutex_destroy(&_mutex);\n}\n\nvoid CEventImpl::waitImpl() {\n  if (pthread_mutex_lock(&_mutex))\n    throw CSystemException(\"wait for event failed (lock)\");\n  while (!_state) {\n    if (pthread_cond_wait(&_cond, &_mutex)) {\n      pthread_mutex_unlock(&_mutex);\n      throw CSystemException(\"wait for event failed\");\n    }\n  }\n  if (_auto)\n    _state = false;\n  pthread_mutex_unlock(&_mutex);\n}\n\nbool CEventImpl::waitImpl(long milliseconds) {\n  int rc = 0;\n  struct timespec abstime;\n\n#if defined(__VMS)\n  struct timespec delta;\n  delta.tv_sec = milliseconds / 1000;\n  delta.tv_nsec = (milliseconds % 1000) * 1000000;\n  pthread_get_expiration_np(&delta, &abstime);\n#else\n  struct timeval tv;\n  gettimeofday(&tv, NULL);\n  abstime.tv_sec = tv.tv_sec + milliseconds / 1000;\n  abstime.tv_nsec = tv.tv_usec * 1000 + (milliseconds % 1000) * 1000000;\n  if (abstime.tv_nsec >= 1000000000) {\n    abstime.tv_nsec -= 1000000000;\n    abstime.tv_sec++;\n  }\n#endif\n\n  if (pthread_mutex_lock(&_mutex) != 0)\n    throw CSystemException(\"wait for event failed (lock)\");\n  while (!_state) {\n    if ((rc = pthread_cond_timedwait(&_cond, &_mutex, &abstime))) {\n      if (rc == ETIMEDOUT)\n        break;\n      pthread_mutex_unlock(&_mutex);\n      throw CSystemException(\"cannot wait for event\");\n    }\n  }\n  if (rc == 0 && _auto)\n    _state = false;\n  pthread_mutex_unlock(&_mutex);\n  return rc == 0;\n}\n"
  },
  {
    "path": "src/base/Event_POSIX.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Event_POSIX.h\n//\n// $Id: Event_POSIX.h,v 1.1 2008/05/31 15:47:21 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  Event\n//\n// Definition of the EventImpl class for POSIX Threads.\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_Event_POSIX_INCLUDED\n#define Foundation_Event_POSIX_INCLUDED\n\n#include \"Exception.hpp\"\n#include \"Foundation.hpp\"\n#include <errno.h>\n#include <pthread.h>\n\nclass CEventImpl {\nprotected:\n  CEventImpl(bool autoReset);\n  ~CEventImpl();\n  void setImpl();\n  void waitImpl();\n  bool waitImpl(long milliseconds);\n  void resetImpl();\n\nprivate:\n  bool _auto;\n  volatile bool _state;\n  pthread_mutex_t _mutex;\n  pthread_cond_t _cond;\n};\n\n//\n// inlines\n//\ninline void CEventImpl::setImpl() {\n  if (pthread_mutex_lock(&_mutex))\n    throw CSystemException(\"cannot signal event (lock)\");\n  _state = true;\n  if (pthread_cond_broadcast(&_cond)) {\n    pthread_mutex_unlock(&_mutex);\n    throw CSystemException(\"cannot signal event\");\n  }\n  pthread_mutex_unlock(&_mutex);\n}\n\ninline void CEventImpl::resetImpl() {\n  if (pthread_mutex_lock(&_mutex))\n    throw CSystemException(\"cannot reset event\");\n  _state = false;\n  pthread_mutex_unlock(&_mutex);\n}\n\n#endif // Foundation_Event_POSIX_INCLUDED\n"
  },
  {
    "path": "src/base/Event_WIN32.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Event_WIN32.cpp\n//\n// $Id: Event_WIN32.cpp,v 1.1 2008/05/31 15:47:21 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  Event\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#include \"Event_WIN32.hpp\"\n\nCEventImpl::CEventImpl(bool autoReset) {\n  _event = CreateEventW(NULL, autoReset ? FALSE : TRUE, FALSE, NULL);\n  if (!_event)\n    throw CSystemException(\"cannot create event\");\n}\n\nCEventImpl::~CEventImpl() { CloseHandle(_event); }\n\nvoid CEventImpl::waitImpl() {\n  switch (WaitForSingleObject(_event, INFINITE)) {\n  case WAIT_OBJECT_0:\n    return;\n  default:\n    throw CSystemException(\"wait for event failed\");\n  }\n}\n\nbool CEventImpl::waitImpl(long milliseconds) {\n  switch (WaitForSingleObject(_event, milliseconds + 1)) {\n  case WAIT_TIMEOUT:\n    return false;\n  case WAIT_OBJECT_0:\n    return true;\n  default:\n    throw CSystemException(\"wait for event failed\");\n  }\n}\n"
  },
  {
    "path": "src/base/Event_WIN32.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Event_WIN32.h\n//\n// $Id: Event_WIN32.h,v 1.1 2008/05/31 15:47:22 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  Event\n//\n// Definition of the EventImpl class for WIN32.\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_Event_WIN32_INCLUDED\n#define Foundation_Event_WIN32_INCLUDED\n\n#include \"Exception.hpp\"\n#include \"Foundation.hpp\"\n#include \"UnWindows.hpp\"\n\nclass CEventImpl {\nprotected:\n  CEventImpl(bool autoReset = false);\n  ~CEventImpl();\n  void setImpl();\n  void waitImpl();\n  bool waitImpl(long milliseconds);\n  void resetImpl();\n\nprivate:\n  HANDLE _event;\n};\n\n//\n// inlines\n//\ninline void CEventImpl::setImpl() {\n  if (!SetEvent(_event)) {\n    throw CSystemException(\"cannot signal event\");\n  }\n}\n\ninline void CEventImpl::resetImpl() {\n  if (!ResetEvent(_event)) {\n    throw CSystemException(\"cannot reset event\");\n  }\n}\n\n#endif // Foundation_Event_WIN32_INCLUDED\n"
  },
  {
    "path": "src/base/Exception.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Exception.cpp\n//\n// $Id: Exception.cpp,v 1.1 2008/05/31 15:47:22 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Core\n// Module:  Exception\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#include \"Exception.hpp\"\n#include <typeinfo>\n\nCException::CException(int code) : _pNested(0), _code(code) {}\n\nCException::CException(const std::string &msg, int code)\n    : _msg(msg), _pNested(0), _code(code) {}\n\nCException::CException(const std::string &msg, const std::string &arg, int code)\n    : _msg(msg), _pNested(0), _code(code) {\n  if (!arg.empty()) {\n    _msg.append(\": \");\n    _msg.append(arg);\n  }\n}\n\nCException::CException(const std::string &msg, const CException &nested,\n                       int code)\n    : _msg(msg), _pNested(nested.clone()), _code(code) {}\n\nCException::CException(const CException &exc)\n    : std::exception(exc), _msg(exc._msg), _code(exc._code) {\n  _pNested = exc._pNested ? exc._pNested->clone() : 0;\n}\n\nCException::~CException() throw() { delete _pNested; }\n\nCException &CException::operator=(const CException &exc) {\n  if (&exc != this) {\n    delete _pNested;\n    _msg = exc._msg;\n    _pNested = exc._pNested ? exc._pNested->clone() : 0;\n    _code = exc._code;\n  }\n  return *this;\n}\n\nconst char *CException::name() const throw() { return \"Exception\"; }\n\nconst char *CException::className() const throw() {\n  return typeid(*this).name();\n}\n\nconst char *CException::what() const throw() { return name(); }\n\nstd::string CException::displayText() const {\n  std::string txt = name();\n  if (!_msg.empty()) {\n    txt.append(\": \");\n    txt.append(_msg);\n  }\n  return txt;\n}\n\nCException *CException::clone() const { return new CException(*this); }\n\nvoid CException::rethrow() const { throw *this; }\n\nPOCO_IMPLEMENT_EXCEPTION(CLogicException, CException, \"Logic exception\")\nPOCO_IMPLEMENT_EXCEPTION(CAssertionViolationException, CLogicException,\n                         \"Assertion violation\")\nPOCO_IMPLEMENT_EXCEPTION(CNullPointerException, CLogicException, \"Null pointer\")\nPOCO_IMPLEMENT_EXCEPTION(CBugcheckException, CLogicException, \"Bugcheck\")\nPOCO_IMPLEMENT_EXCEPTION(CInvalidArgumentException, CLogicException,\n                         \"Invalid argument\")\nPOCO_IMPLEMENT_EXCEPTION(CNotImplementedException, CLogicException,\n                         \"Not implemented\")\nPOCO_IMPLEMENT_EXCEPTION(CRangeException, CLogicException, \"Out of range\")\nPOCO_IMPLEMENT_EXCEPTION(CIllegalStateException, CLogicException,\n                         \"Illegal state\")\nPOCO_IMPLEMENT_EXCEPTION(CInvalidAccessException, CLogicException,\n                         \"Invalid access\")\nPOCO_IMPLEMENT_EXCEPTION(CSignalException, CLogicException, \"Signal received\")\nPOCO_IMPLEMENT_EXCEPTION(CUnhandledException, CLogicException,\n                         \"Signal received\")\n\nPOCO_IMPLEMENT_EXCEPTION(CRuntimeException, CException, \"Runtime exception\")\nPOCO_IMPLEMENT_EXCEPTION(CNotFoundException, CRuntimeException, \"Not found\")\nPOCO_IMPLEMENT_EXCEPTION(CExistsException, CRuntimeException, \"Exists\")\nPOCO_IMPLEMENT_EXCEPTION(CTimeoutException, CRuntimeException, \"Timeout\")\nPOCO_IMPLEMENT_EXCEPTION(CSystemException, CRuntimeException,\n                         \"System exception\")\nPOCO_IMPLEMENT_EXCEPTION(CRegularExpressionException, CRuntimeException,\n                         \"Error in regular expression\")\nPOCO_IMPLEMENT_EXCEPTION(CLibraryLoadException, CRuntimeException,\n                         \"Cannot load library\")\nPOCO_IMPLEMENT_EXCEPTION(CLibraryAlreadyLoadedException, CRuntimeException,\n                         \"Library already loaded\")\nPOCO_IMPLEMENT_EXCEPTION(CNoThreadAvailableException, CRuntimeException,\n                         \"No thread available\")\nPOCO_IMPLEMENT_EXCEPTION(CPropertyNotSupportedException, CRuntimeException,\n                         \"Property not supported\")\nPOCO_IMPLEMENT_EXCEPTION(CPoolOverflowException, CRuntimeException,\n                         \"Pool overflow\")\nPOCO_IMPLEMENT_EXCEPTION(CNoPermissionException, CRuntimeException,\n                         \"No permission\")\nPOCO_IMPLEMENT_EXCEPTION(COutOfMemoryException, CRuntimeException,\n                         \"Out of memory\")\nPOCO_IMPLEMENT_EXCEPTION(CDataException, CRuntimeException, \"Data error\")\n\nPOCO_IMPLEMENT_EXCEPTION(CDataFormatException, CDataException,\n                         \"Bad data format\")\nPOCO_IMPLEMENT_EXCEPTION(CSyntaxException, CDataException, \"Syntax error\")\nPOCO_IMPLEMENT_EXCEPTION(CCircularReferenceException, CDataException,\n                         \"Circular reference\")\nPOCO_IMPLEMENT_EXCEPTION(CPathSyntaxException, CSyntaxException,\n                         \"Bad path syntax\")\nPOCO_IMPLEMENT_EXCEPTION(CIOException, CRuntimeException, \"I/O error\")\nPOCO_IMPLEMENT_EXCEPTION(CFileException, CIOException, \"File access error\")\nPOCO_IMPLEMENT_EXCEPTION(CFileExistsException, CFileException, \"File exists\")\nPOCO_IMPLEMENT_EXCEPTION(CFileNotFoundException, CFileException,\n                         \"File not found\")\nPOCO_IMPLEMENT_EXCEPTION(CPathNotFoundException, CFileException,\n                         \"Path not found\")\nPOCO_IMPLEMENT_EXCEPTION(CFileReadOnlyException, CFileException,\n                         \"File is read-only\")\nPOCO_IMPLEMENT_EXCEPTION(CFileAccessDeniedException, CFileException,\n                         \"Access to file denied\")\nPOCO_IMPLEMENT_EXCEPTION(CCreateFileException, CFileException,\n                         \"Cannot create file\")\nPOCO_IMPLEMENT_EXCEPTION(COpenFileException, CFileException, \"Cannot open file\")\nPOCO_IMPLEMENT_EXCEPTION(CWriteFileException, CFileException,\n                         \"Cannot write file\")\nPOCO_IMPLEMENT_EXCEPTION(CReadFileException, CFileException, \"Cannot read file\")\nPOCO_IMPLEMENT_EXCEPTION(CUnknownURISchemeException, CRuntimeException,\n                         \"Unknown URI scheme\")\n\nPOCO_IMPLEMENT_EXCEPTION(CApplicationException, CException,\n                         \"Application exception\")\nPOCO_IMPLEMENT_EXCEPTION(CBadCastException, CRuntimeException,\n                         \"Bad cast exception\")\n\nPOCO_IMPLEMENT_EXCEPTION(CConfigurationException, CException,\n                         \"Configuration error\");\nPOCO_IMPLEMENT_EXCEPTION(CThreadException, CException, \"Threading error\");\nPOCO_IMPLEMENT_EXCEPTION(CWin32Exception, CException, \"Win32 error\");\nPOCO_IMPLEMENT_EXCEPTION(CSDLException, CException, \"SDL error\");\nPOCO_IMPLEMENT_EXCEPTION(CGracefulException, CException,\n                         \"Graceful exit\"); /* User request to exit */\nPOCO_IMPLEMENT_EXCEPTION(CAbortException, CException,\n                         \"Abort requested\"); /* User request to abort */\n"
  },
  {
    "path": "src/base/Exception.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Exception.h\n//\n// $Id: Exception.h,v 1.1 2008/05/31 15:47:23 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Core\n// Module:  Exception\n//\n// Definition of various Poco exception classes.\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_Exception_INCLUDED\n#define Foundation_Exception_INCLUDED\n\n#include \"Foundation.hpp\"\n#include <stdexcept>\n\nclass CException : public std::exception\n/// This is the base class for all exceptions defined\n/// in the Poco class library.\n{\npublic:\n  CException(const std::string &msg, int code = 0);\n  /// Creates an exception.\n\n  CException(const std::string &msg, const std::string &arg, int code = 0);\n  /// Creates an exception.\n\n  CException(const std::string &msg, const CException &nested, int code = 0);\n  /// Creates an exception and stores a clone\n  /// of the nested exception.\n\n  CException(const CException &exc);\n  /// Copy constructor.\n\n  ~CException() throw();\n  /// Destroys the exception and deletes the nested exception.\n\n  CException &operator=(const CException &exc);\n  /// Assignment operator.\n\n  virtual const char *name() const throw();\n  /// Returns a static string describing the exception.\n\n  virtual const char *className() const throw();\n  /// Returns the name of the exception class.\n\n  virtual const char *what() const throw();\n  /// Returns a static string describing the exception.\n  ///\n  /// Same as name(), but for compatibility with std::exception.\n\n  const CException *nested() const;\n  /// Returns a pointer to the nested exception, or\n  /// null if no nested exception exists.\n\n  const std::string &message() const;\n  /// Returns the message text.\n\n  int code() const;\n  /// Returns the exception code if defined.\n\n  std::string displayText() const;\n  /// Returns a string consisting of the\n  /// message name and the message text.\n\n  virtual CException *clone() const;\n  /// Creates an exact copy of the exception.\n  ///\n  /// The copy can later be thrown again by\n  /// invoking rethrow() on it.\n\n  virtual void rethrow() const;\n  /// (Re)Throws the exception.\n  ///\n  /// This is useful for temporarily storing a\n  /// copy of an exception (see clone()), then\n  /// throwing it again.\n\nprotected:\n  CException(int code = 0);\n  /// Standard constructor.\n\nprivate:\n  std::string _msg;\n  CException *_pNested;\n  int _code;\n};\n\n//\n// inlines\n//\ninline const CException *CException::nested() const { return _pNested; }\n\ninline const std::string &CException::message() const { return _msg; }\n\ninline int CException::code() const { return _code; }\n\n//\n// Macros for quickly declaring and implementing exception classes.\n// Unfortunately, we cannot use a template here because character\n// pointers (which we need for specifying the exception name)\n// are not allowed as template arguments.\n//\n#define POCO_DECLARE_EXCEPTION(CLS, BASE)                                      \\\n  class CLS : public BASE {                                                    \\\n  public:                                                                      \\\n    CLS(int code = 0);                                                         \\\n    CLS(const std::string &msg, int code = 0);                                 \\\n    CLS(const std::string &msg, const std::string &arg, int code = 0);         \\\n    CLS(const std::string &msg, const CException &exc, int code = 0);          \\\n    CLS(const CLS &exc);                                                       \\\n    ~CLS() throw();                                                            \\\n    CLS &operator=(const CLS &exc);                                            \\\n    const char *name() const throw();                                          \\\n    const char *className() const throw();                                     \\\n    CException *clone() const;                                                 \\\n    void rethrow() const;                                                      \\\n  };\n\n#define POCO_IMPLEMENT_EXCEPTION(CLS, BASE, NAME)                              \\\n  CLS::CLS(int code) : BASE(code) {}                                           \\\n  CLS::CLS(const std::string &msg, int code) : BASE(msg, code) {}              \\\n  CLS::CLS(const std::string &msg, const std::string &arg, int code)           \\\n      : BASE(msg, arg, code) {}                                                \\\n  CLS::CLS(const std::string &msg, const CException &exc, int code)            \\\n      : BASE(msg, exc, code) {}                                                \\\n  CLS::CLS(const CLS &exc) : BASE(exc) {}                                      \\\n  CLS::~CLS() throw() {}                                                       \\\n  CLS &CLS::operator=(const CLS &exc) {                                        \\\n    BASE::operator=(exc);                                                      \\\n    return *this;                                                              \\\n  }                                                                            \\\n  const char *CLS::name() const throw() { return NAME; }                       \\\n  const char *CLS::className() const throw() { return typeid(*this).name(); }  \\\n  CException *CLS::clone() const { return new CLS(*this); }                    \\\n  void CLS::rethrow() const { throw *this; }\n\n//\n// Standard exception classes\n//\nPOCO_DECLARE_EXCEPTION(CLogicException, CException)\nPOCO_DECLARE_EXCEPTION(CAssertionViolationException, CLogicException)\nPOCO_DECLARE_EXCEPTION(CNullPointerException, CLogicException)\nPOCO_DECLARE_EXCEPTION(CBugcheckException, CLogicException)\nPOCO_DECLARE_EXCEPTION(CInvalidArgumentException, CLogicException)\nPOCO_DECLARE_EXCEPTION(CNotImplementedException, CLogicException)\nPOCO_DECLARE_EXCEPTION(CRangeException, CLogicException)\nPOCO_DECLARE_EXCEPTION(CIllegalStateException, CLogicException)\nPOCO_DECLARE_EXCEPTION(CInvalidAccessException, CLogicException)\nPOCO_DECLARE_EXCEPTION(CSignalException, CLogicException)\nPOCO_DECLARE_EXCEPTION(CUnhandledException, CLogicException)\n\nPOCO_DECLARE_EXCEPTION(CRuntimeException, CException)\nPOCO_DECLARE_EXCEPTION(CNotFoundException, CRuntimeException)\nPOCO_DECLARE_EXCEPTION(CExistsException, CRuntimeException)\nPOCO_DECLARE_EXCEPTION(CTimeoutException, CRuntimeException)\nPOCO_DECLARE_EXCEPTION(CSystemException, CRuntimeException)\nPOCO_DECLARE_EXCEPTION(CRegularExpressionException, CRuntimeException)\nPOCO_DECLARE_EXCEPTION(CLibraryLoadException, CRuntimeException)\nPOCO_DECLARE_EXCEPTION(CLibraryAlreadyLoadedException, CRuntimeException)\nPOCO_DECLARE_EXCEPTION(CNoThreadAvailableException, CRuntimeException)\nPOCO_DECLARE_EXCEPTION(CPropertyNotSupportedException, CRuntimeException)\nPOCO_DECLARE_EXCEPTION(CPoolOverflowException, CRuntimeException)\nPOCO_DECLARE_EXCEPTION(CNoPermissionException, CRuntimeException)\nPOCO_DECLARE_EXCEPTION(COutOfMemoryException, CRuntimeException)\nPOCO_DECLARE_EXCEPTION(CDataException, CRuntimeException)\n\nPOCO_DECLARE_EXCEPTION(CDataFormatException, CDataException)\nPOCO_DECLARE_EXCEPTION(CSyntaxException, CDataException)\nPOCO_DECLARE_EXCEPTION(CCircularReferenceException, CDataException)\nPOCO_DECLARE_EXCEPTION(CPathSyntaxException, CSyntaxException)\nPOCO_DECLARE_EXCEPTION(CIOException, CRuntimeException)\nPOCO_DECLARE_EXCEPTION(CFileException, CIOException)\nPOCO_DECLARE_EXCEPTION(CFileExistsException, CFileException)\nPOCO_DECLARE_EXCEPTION(CFileNotFoundException, CFileException)\nPOCO_DECLARE_EXCEPTION(CPathNotFoundException, CFileException)\nPOCO_DECLARE_EXCEPTION(CFileReadOnlyException, CFileException)\nPOCO_DECLARE_EXCEPTION(CFileAccessDeniedException, CFileException)\nPOCO_DECLARE_EXCEPTION(CCreateFileException, CFileException)\nPOCO_DECLARE_EXCEPTION(COpenFileException, CFileException)\nPOCO_DECLARE_EXCEPTION(CWriteFileException, CFileException)\nPOCO_DECLARE_EXCEPTION(CReadFileException, CFileException)\nPOCO_DECLARE_EXCEPTION(CUnknownURISchemeException, CRuntimeException)\n\nPOCO_DECLARE_EXCEPTION(CApplicationException, CException)\nPOCO_DECLARE_EXCEPTION(CBadCastException, CRuntimeException)\n\nPOCO_DECLARE_EXCEPTION(CConfigurationException, CException);\nPOCO_DECLARE_EXCEPTION(CThreadException, CException);\nPOCO_DECLARE_EXCEPTION(CWin32Exception, CException);\nPOCO_DECLARE_EXCEPTION(CSDLException, CException);\nPOCO_DECLARE_EXCEPTION(CGracefulException,\n                       CException);                  /* User request to exit */\nPOCO_DECLARE_EXCEPTION(CAbortException, CException); /* User request to abort */\n\n#endif // Foundation_Exception_INCLUDED\n"
  },
  {
    "path": "src/base/Foundation.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Foundation.h\n//\n// $Id: Foundation.h,v 1.2 2010/03/11 22:44:16 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Core\n// Module:  Foundation\n//\n// Basic definitions for the POCO Foundation library.\n// This file must be the first file included by every other Foundation\n// header file.\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_Foundation_INCLUDED\n#define Foundation_Foundation_INCLUDED\n\n//\n// Include library configuration\n//\n// CAVA #include \"Config.h\"\n\n//\n// Include platform-specific definitions\n//\n#include \"Platform.hpp\"\n#if defined(_WIN32)\n#include \"Platform_WIN32.hpp\"\n#elif defined(__VMS)\n#include \"Platform_VMS.hpp\"\n#elif defined(POCO_OS_FAMILY_UNIX)\n#include \"Platform_POSIX.hpp\"\n#endif\n\n//\n// POCO_JOIN\n//\n// The following piece of macro magic joins the two\n// arguments together, even when one of the arguments is\n// itself a macro (see 16.3.1 in C++ standard).  The key\n// is that macro expansion of macro arguments does not\n// occur in POCO_DO_JOIN2 but does in POCO_DO_JOIN.\n//\n#define POCO_JOIN(X, Y) POCO_DO_JOIN(X, Y)\n#define POCO_DO_JOIN(X, Y) POCO_DO_JOIN2(X, Y)\n#define POCO_DO_JOIN2(X, Y) X##Y\n\n//\n// Pull in basic definitions\n//\n#include \"Bugcheck.hpp\"\n#include \"Types.hpp\"\n#include <stdio.h>\n#include <string>\n\n#endif // Foundation_Foundation_INCLUDED\n"
  },
  {
    "path": "src/base/Mutex.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Mutex.cpp\n//\n// $Id: Mutex.cpp,v 1.2 2008/06/12 06:52:33 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  Mutex\n//\n// Copyright (c) 2004-2008, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#include \"Mutex.hpp\"\n#include <string.h>\n\n#if defined(POCO_OS_FAMILY_WINDOWS)\n#include \"Mutex_WIN32.cpp\"\n#else\n#include \"Mutex_POSIX.cpp\"\n#endif\n\nCMutex::CMutex() { lockName = strdup(\"anon\"); }\n\nCMutex::CMutex(const char *lName) { lockName = strdup(lName); }\n\nCMutex::~CMutex() { free(lockName); }\n\nCFastMutex::CFastMutex() { lockName = strdup(\"anon\"); }\n\nCFastMutex::CFastMutex(const char *lName) { lockName = strdup(lName); }\n\nCFastMutex::~CFastMutex() { free(lockName); }\n\nvoid CMutex::lock() {\n#if defined(DEBUG_LOCKS)\n  printf(\"        LOCK mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n  try {\n    lockImpl();\n  }\n\n  catch (CException &e) {\n    FAILURE_3(Thread,\n              \"Locking error (%s) trying to lock mutex %s from thread %s.\\n\",\n              e.message().c_str(), lockName, CURRENT_THREAD_NAME);\n  }\n\n#if defined(DEBUG_LOCKS)\n  printf(\"      LOCKED mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n}\n\nvoid CMutex::lock(long milliseconds) {\n#if defined(DEBUG_LOCKS)\n  printf(\"        LOCK mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n  try {\n    if (!tryLockImpl(milliseconds))\n      FAILURE(Timeout, \"Timeout\");\n  }\n\n  catch (CException &e) {\n    FAILURE_3(Thread,\n              \"Locking error (%s) trying to lock mutex %s from thread %s.\\n\",\n              e.message().c_str(), lockName, CURRENT_THREAD_NAME);\n  }\n\n#if defined(DEBUG_LOCKS)\n  printf(\"      LOCKED mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n}\n\nbool CMutex::tryLock() {\n  bool res;\n#if defined(DEBUG_LOCKS)\n  printf(\"    TRY LOCK mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n  try {\n    res = tryLockImpl();\n  }\n\n  catch (CException &e) {\n    FAILURE_3(Thread,\n              \"Locking error (%s) trying to lock mutex %s from thread %s.\\n\",\n              e.message().c_str(), lockName, CURRENT_THREAD_NAME);\n  }\n\n#if defined(DEBUG_LOCKS)\n  printf(\"  %s mutex %s from thread %s.   \\n\",\n         res ? \"    LOCKED\" : \"CAN'T LOCK\", lockName, CURRENT_THREAD_NAME);\n#endif\n  return res;\n}\n\nbool CMutex::tryLock(long milliseconds) {\n  bool res;\n#if defined(DEBUG_LOCKS)\n  printf(\"    TRY LOCK mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n  try {\n    res = tryLockImpl(milliseconds);\n  }\n\n  catch (CException &e) {\n    FAILURE_3(Thread,\n              \"Locking error (%s) trying to lock mutex %s from thread %s.\\n\",\n              e.message().c_str(), lockName, CURRENT_THREAD_NAME);\n  }\n\n#if defined(DEBUG_LOCKS)\n  printf(\"  %s mutex %s from thread %s.   \\n\",\n         res ? \"    LOCKED\" : \"CAN'T LOCK\", lockName, CURRENT_THREAD_NAME);\n#endif\n  return res;\n}\n\nvoid CMutex::unlock() {\n#if defined(DEBUG_LOCKS)\n  printf(\"      UNLOCK mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n  try {\n    unlockImpl();\n  }\n\n  catch (CException &e) {\n    FAILURE_3(Thread,\n              \"Locking error (%s) trying to unlock mutex %s from thread %s.\\n\",\n              e.message().c_str(), lockName, CURRENT_THREAD_NAME);\n  }\n\n#if defined(DEBUG_LOCKS)\n  printf(\"    UNLOCKED mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n}\n\nvoid CFastMutex::lock() {\n#if defined(DEBUG_LOCKS)\n  printf(\"        LOCK mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n  try {\n    lockImpl();\n  }\n\n  catch (CException &e) {\n    FAILURE_3(Thread,\n              \"Locking error (%s) trying to lock mutex %s from thread %s.\\n\",\n              e.message().c_str(), lockName, CURRENT_THREAD_NAME);\n  }\n\n#if defined(DEBUG_LOCKS)\n  printf(\"      LOCKED mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n}\n\nvoid CFastMutex::lock(long milliseconds) {\n#if defined(DEBUG_LOCKS)\n  printf(\"        LOCK mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n  try {\n    if (!tryLockImpl(milliseconds))\n      FAILURE(Timeout, \"Timeout\");\n  }\n\n  catch (CException &e) {\n    FAILURE_3(Thread,\n              \"Locking error (%s) trying to lock mutex %s from thread %s.\\n\",\n              e.message().c_str(), lockName, CURRENT_THREAD_NAME);\n  }\n\n#if defined(DEBUG_LOCKS)\n  printf(\"      LOCKED mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n}\n\nbool CFastMutex::tryLock() {\n  bool res;\n#if defined(DEBUG_LOCKS)\n  printf(\"    TRY LOCK mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n  try {\n    res = tryLockImpl();\n  }\n\n  catch (CException &e) {\n    FAILURE_3(Thread,\n              \"Locking error (%s) trying to lock mutex %s from thread %s.\\n\",\n              e.message().c_str(), lockName, CURRENT_THREAD_NAME);\n  }\n\n#if defined(DEBUG_LOCKS)\n  printf(\"  %s mutex %s from thread %s.   \\n\",\n         res ? \"    LOCKED\" : \"CAN'T LOCK\", lockName, CURRENT_THREAD_NAME);\n#endif\n  return res;\n}\n\nbool CFastMutex::tryLock(long milliseconds) {\n  bool res;\n#if defined(DEBUG_LOCKS)\n  printf(\"    TRY LOCK mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n  try {\n    res = tryLockImpl(milliseconds);\n  }\n\n  catch (CException &e) {\n    FAILURE_3(Thread,\n              \"Locking error (%s) trying to lock mutex %s from thread %s.\\n\",\n              e.message().c_str(), lockName, CURRENT_THREAD_NAME);\n  }\n\n#if defined(DEBUG_LOCKS)\n  printf(\"  %s mutex %s from thread %s.   \\n\",\n         res ? \"    LOCKED\" : \"CAN'T LOCK\", lockName, CURRENT_THREAD_NAME);\n#endif\n  return res;\n}\n\nvoid CFastMutex::unlock() {\n#if defined(DEBUG_LOCKS)\n  printf(\"      UNLOCK mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n  try {\n    unlockImpl();\n  }\n\n  catch (CException &e) {\n    FAILURE_3(Thread,\n              \"Locking error (%s) trying to unlock mutex %s from thread %s.\\n\",\n              e.message().c_str(), lockName, CURRENT_THREAD_NAME);\n  }\n\n#if defined(DEBUG_LOCKS)\n  printf(\"    UNLOCKED mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n}"
  },
  {
    "path": "src/base/Mutex.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Mutex.h\n//\n// $Id: Mutex.h,v 1.2 2008/06/12 06:52:33 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  Mutex\n//\n// Definition of the Mutex and FastMutex classes.\n//\n// Copyright (c) 2004-2008, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_Mutex_INCLUDED\n#define Foundation_Mutex_INCLUDED\n\n#if defined(NO_LOCK_TIMEOUTS)\n#define LOCK_TIMEOUT_MS\n#else\n#if !defined(LOCK_TIMEOUT_MS)\n#define LOCK_TIMEOUT_MS 5000\n#endif\n#endif\n\n// Placeholder\n#define CURRENT_THREAD_NAME \"<thread>\"\n\n#include \"../es40_debug.hpp\"\n#include \"Exception.hpp\"\n#include \"Foundation.hpp\"\n#include \"ScopedLock.hpp\"\n\n#if defined(POCO_OS_FAMILY_WINDOWS)\n#include \"Mutex_WIN32.hpp\"\n#else\n#include \"Mutex_POSIX.hpp\"\n#endif\n\nclass CMutex : private CMutexImpl\n/// A Mutex (mutual exclusion) is a synchronization\n/// mechanism used to control access to a shared resource\n/// in a concurrent (multithreaded) scenario.\n/// Mutexes are recursive, that is, the same mutex can be\n/// locked multiple times by the same thread (but, of course,\n/// not by other threads).\n/// Using the ScopedLock class is the preferred way to automatically\n/// lock and unlock a mutex.\n{\npublic:\n  typedef ::CScopedLock<CMutex> CScopedLock;\n\n  CMutex(const char *lName);\n\n  char *lockName;\n\n  CMutex();\n  /// creates the Mutex.\n\n  ~CMutex();\n  /// destroys the Mutex.\n\n  void lock();\n  /// Locks the mutex. Blocks if the mutex\n  /// is held by another thread.\n\n  void lock(long milliseconds);\n  /// Locks the mutex. Blocks up to the given number of milliseconds\n  /// if the mutex is held by another thread. Throws a TimeoutException\n  /// if the mutex can not be locked within the given timeout.\n  ///\n  /// Performance Note: On most platforms (including Windows), this member\n  /// function is implemented using a loop calling (the equivalent of) tryLock()\n  /// and Thread::sleep(). On POSIX platforms that support\n  /// pthread_mutex_timedlock(), this is used.\n\n  bool tryLock();\n  /// Tries to lock the mutex. Returns false immediately\n  /// if the mutex is already held by another thread.\n  /// Returns true if the mutex was successfully locked.\n\n  bool tryLock(long milliseconds);\n  /// Locks the mutex. Blocks up to the given number of milliseconds\n  /// if the mutex is held by another thread.\n  /// Returns true if the mutex was successfully locked.\n  ///\n  /// Performance Note: On most platforms (including Windows), this member\n  /// function is implemented using a loop calling (the equivalent of) tryLock()\n  /// and Thread::sleep(). On POSIX platforms that support\n  /// pthread_mutex_timedlock(), this is used.\n\n  void unlock();\n  /// Unlocks the mutex so that it can be acquired by\n  /// other threads.\n\nprivate:\n  CMutex(const CMutex &);\n  CMutex &operator=(const CMutex &);\n};\n\nclass CFastMutex : private CFastMutexImpl\n/// A FastMutex (mutual exclusion) is similar to a Mutex.\n/// Unlike a Mutex, however, a FastMutex is not recursive,\n/// which means that a deadlock will occur if the same\n/// thread tries to lock a mutex it has already locked again.\n/// Locking a FastMutex is faster than locking a recursive Mutex.\n/// Using the ScopedLock class is the preferred way to automatically\n/// lock and unlock a mutex.\n{\npublic:\n  typedef ::CScopedLock<CFastMutex> CScopedLock;\n\n  CFastMutex(const char *lName);\n\n  char *lockName;\n\n  CFastMutex();\n  /// creates the Mutex.\n\n  ~CFastMutex();\n  /// destroys the Mutex.\n\n  void lock();\n  /// Locks the mutex. Blocks if the mutex\n  /// is held by another thread.\n\n  void lock(long milliseconds);\n  /// Locks the mutex. Blocks up to the given number of milliseconds\n  /// if the mutex is held by another thread. Throws a TimeoutException\n  /// if the mutex can not be locked within the given timeout.\n  ///\n  /// Performance Note: On most platforms (including Windows), this member\n  /// function is implemented using a loop calling (the equivalent of) tryLock()\n  /// and Thread::sleep(). On POSIX platforms that support\n  /// pthread_mutex_timedlock(), this is used.\n\n  bool tryLock();\n  /// Tries to lock the mutex. Returns false immediately\n  /// if the mutex is already held by another thread.\n  /// Returns true if the mutex was successfully locked.\n\n  bool tryLock(long milliseconds);\n  /// Locks the mutex. Blocks up to the given number of milliseconds\n  /// if the mutex is held by another thread.\n  /// Returns true if the mutex was successfully locked.\n  ///\n  /// Performance Note: On most platforms (including Windows), this member\n  /// function is implemented using a loop calling (the equivalent of) tryLock()\n  /// and Thread::sleep(). On POSIX platforms that support\n  /// pthread_mutex_timedlock(), this is used.\n\n  void unlock();\n  /// Unlocks the mutex so that it can be acquired by\n  /// other threads.\n\nprivate:\n  CFastMutex(const CFastMutex &);\n  CFastMutex &operator=(const CFastMutex &);\n};\n\n#define MUTEX_LOCK(mutex) mutex->lock(LOCK_TIMEOUT_MS)\n#define MUTEX_READ_LOCK(mutex) mutex->readLock(LOCK_TIMEOUT_MS)\n#define MUTEX_WRITE_LOCK(mutex) mutex->writeLock(LOCK_TIMEOUT_MS)\n#define MUTEX_UNLOCK(mutex) mutex->unlock()\n#define SCOPED_M_LOCK(mutex) CMutex::CScopedLock L_##__LINE__(mutex)\n#define SCOPED_FM_LOCK(mutex) CFastMutex::CScopedLock L_##__LINE__(mutex)\n\n#endif // Foundation_Mutex_INCLUDED\n"
  },
  {
    "path": "src/base/Mutex_POSIX.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Mutex_POSIX.cpp\n//\n// $Id: Mutex_POSIX.cpp,v 1.1 2008/05/31 15:47:24 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  Mutex\n//\n// Copyright (c) 2004-2008, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#include \"Mutex_POSIX.hpp\"\n#include \"Timestamp.hpp\"\n#if !defined(POCO_NO_SYS_SELECT_H)\n#include <sys/select.h>\n#endif\n#include <sys/time.h>\n#include <unistd.h>\n\n#if defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS - 200112L) >= 0L\n#if defined(_POSIX_THREADS) && (_POSIX_THREADS - 200112L) >= 0L\n#define POCO_HAVE_MUTEX_TIMEOUT\n#endif\n#endif\n\nCMutexImpl::CMutexImpl() {\n  pthread_mutexattr_t attr;\n  pthread_mutexattr_init(&attr);\n#if defined(PTHREAD_MUTEX_RECURSIVE_NP)\n  pthread_mutexattr_settype_np(&attr, PTHREAD_MUTEX_RECURSIVE_NP);\n#else\n  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);\n#endif\n  if (pthread_mutex_init(&_mutex, &attr)) {\n    pthread_mutexattr_destroy(&attr);\n    throw CSystemException(\"cannot create mutex\");\n  }\n  pthread_mutexattr_destroy(&attr);\n}\n\nCMutexImpl::CMutexImpl(bool fast) {\n  pthread_mutexattr_t attr;\n  pthread_mutexattr_init(&attr);\n#if defined(PTHREAD_MUTEX_RECURSIVE_NP)\n  pthread_mutexattr_settype_np(&attr, fast ? PTHREAD_MUTEX_NORMAL_NP\n                                           : PTHREAD_MUTEX_RECURSIVE_NP);\n#else\n  pthread_mutexattr_settype(&attr, fast ? PTHREAD_MUTEX_NORMAL\n                                        : PTHREAD_MUTEX_RECURSIVE);\n#endif\n  if (pthread_mutex_init(&_mutex, &attr)) {\n    pthread_mutexattr_destroy(&attr);\n    throw CSystemException(\"cannot create mutex\");\n  }\n  pthread_mutexattr_destroy(&attr);\n}\n\nCMutexImpl::~CMutexImpl() { pthread_mutex_destroy(&_mutex); }\n\nbool CMutexImpl::tryLockImpl(long milliseconds) {\n#if defined(POCO_HAVE_MUTEX_TIMEOUT)\n  struct timespec abstime;\n  struct timeval tv;\n  gettimeofday(&tv, NULL);\n  abstime.tv_sec = tv.tv_sec + milliseconds / 1000;\n  abstime.tv_nsec = tv.tv_usec * 1000 + (milliseconds % 1000) * 1000000;\n  if (abstime.tv_nsec >= 1000000000) {\n    abstime.tv_nsec -= 1000000000;\n    abstime.tv_sec++;\n  }\n  int rc = pthread_mutex_timedlock(&_mutex, &abstime);\n  if (rc == 0)\n    return true;\n  else if (rc == ETIMEDOUT)\n    return false;\n  else\n    throw CSystemException(\"cannot lock mutex\");\n#else\n  const int sleepMillis = 5;\n  CTimestamp now;\n  CTimestamp::TimeDiff diff(CTimestamp::TimeDiff(milliseconds) * 1000);\n  do {\n    int rc = pthread_mutex_trylock(&_mutex);\n    if (rc == 0)\n      return true;\n    else if (rc != EBUSY)\n      throw CSystemException(\"cannot lock mutex\");\n    struct timeval tv;\n    tv.tv_sec = 0;\n    tv.tv_usec = sleepMillis * 1000;\n    select(0, NULL, NULL, NULL, &tv);\n  } while (!now.isElapsed(diff));\n  return false;\n#endif\n}\n\nCFastMutexImpl::CFastMutexImpl() : CMutexImpl(true) {}\n\nCFastMutexImpl::~CFastMutexImpl() {}\n"
  },
  {
    "path": "src/base/Mutex_POSIX.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Mutex_POSIX.h\n//\n// $Id: Mutex_POSIX.h,v 1.1 2008/05/31 15:47:24 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  Mutex\n//\n// Definition of the MutexImpl and FastMutexImpl classes for POSIX Threads.\n//\n// Copyright (c) 2004-2008, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_Mutex_POSIX_INCLUDED\n#define Foundation_Mutex_POSIX_INCLUDED\n\n#include \"Exception.hpp\"\n#include \"Foundation.hpp\"\n#include <errno.h>\n#include <pthread.h>\n\nclass CMutexImpl {\nprotected:\n  CMutexImpl();\n  CMutexImpl(bool fast);\n  ~CMutexImpl();\n  void lockImpl();\n  bool tryLockImpl();\n  bool tryLockImpl(long milliseconds);\n  void unlockImpl();\n\nprivate:\n  pthread_mutex_t _mutex;\n};\n\nclass CFastMutexImpl : public CMutexImpl {\nprotected:\n  CFastMutexImpl();\n  ~CFastMutexImpl();\n};\n\n//\n// inlines\n//\ninline void CMutexImpl::lockImpl() {\n  if (pthread_mutex_lock(&_mutex))\n    throw CSystemException(\"cannot lock mutex\");\n}\n\ninline bool CMutexImpl::tryLockImpl() {\n  int rc = pthread_mutex_trylock(&_mutex);\n  if (rc == 0)\n    return true;\n  else if (rc == EBUSY)\n    return false;\n  else\n    throw CSystemException(\"cannot lock mutex\");\n}\n\ninline void CMutexImpl::unlockImpl() {\n  if (pthread_mutex_unlock(&_mutex))\n    throw CSystemException(\"cannot unlock mutex\");\n}\n\n#endif // Foundation_Mutex_POSIX_INCLUDED\n"
  },
  {
    "path": "src/base/Mutex_WIN32.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Mutex_WIN32.cpp\n//\n// $Id: Mutex_WIN32.cpp,v 1.1 2008/05/31 15:47:24 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  Mutex\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#include \"Mutex_WIN32.hpp\"\n#include \"Timestamp.hpp\"\n\nCMutexImpl::CMutexImpl() {\n  // the fct has a boolean return value under WInnNt/2000/XP but not on Win98\n  // the return only checks if the input address of &_cs was valid, so it is\n  // safe to omit it\n  InitializeCriticalSectionAndSpinCount(&_cs, 4000);\n}\n\nCMutexImpl::~CMutexImpl() { DeleteCriticalSection(&_cs); }\n\nbool CMutexImpl::tryLockImpl(long milliseconds) {\n  const int sleepMillis = 5;\n  CTimestamp now;\n  CTimestamp::TimeDiff diff(CTimestamp::TimeDiff(milliseconds) * 1000);\n  do {\n    try {\n      if (TryEnterCriticalSection(&_cs) == TRUE)\n        return true;\n    } catch (...) {\n      throw CSystemException(\"cannot lock mutex\");\n    }\n    Sleep(sleepMillis);\n  } while (!now.isElapsed(diff));\n  return false;\n}\n"
  },
  {
    "path": "src/base/Mutex_WIN32.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Mutex_WIN32.h\n//\n// $Id: Mutex_WIN32.h,v 1.1 2008/05/31 15:47:24 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  Mutex\n//\n// Definition of the MutexImpl and FastMutexImpl classes for WIN32.\n//\n// Copyright (c) 2004-2008, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_Mutex_WIN32_INCLUDED\n#define Foundation_Mutex_WIN32_INCLUDED\n\n#include \"Exception.hpp\"\n#include \"Foundation.hpp\"\n#include \"UnWindows.hpp\"\n\nclass CMutexImpl {\nprotected:\n  CMutexImpl();\n  ~CMutexImpl();\n  void lockImpl();\n  bool tryLockImpl();\n  bool tryLockImpl(long milliseconds);\n  void unlockImpl();\n\nprivate:\n  CRITICAL_SECTION _cs;\n};\n\ntypedef CMutexImpl CFastMutexImpl;\n\n//\n// inlines\n//\ninline void CMutexImpl::lockImpl() {\n  try {\n    EnterCriticalSection(&_cs);\n  } catch (...) {\n    throw CSystemException(\"cannot lock mutex\");\n  }\n}\n\ninline bool CMutexImpl::tryLockImpl() {\n  try {\n    return TryEnterCriticalSection(&_cs) == TRUE;\n  } catch (...) {\n  }\n  throw CSystemException(\"cannot lock mutex\");\n}\n\ninline void CMutexImpl::unlockImpl() { LeaveCriticalSection(&_cs); }\n\n#endif // Foundation_Mutex_WIN32_INCLUDED\n"
  },
  {
    "path": "src/base/NumberFormatter.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// NumberFormatter.cpp\n//\n// $Id: NumberFormatter.cpp,v 1.1 2008/05/31 15:47:24 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Core\n// Module:  NumberFormatter\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#include \"NumberFormatter.hpp\"\n#include <cctype>\n#include <cinttypes>\n#include <cstdio>\n\n#include <cinttypes>\n\nstd::string CNumberFormatter::format(int value) {\n  char buffer[64];\n  std::sprintf(buffer, \"%d\", value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::format(int value, int width) {\n  poco_assert(width > 0 && width < 64);\n\n  char buffer[64];\n  std::sprintf(buffer, \"%*d\", width, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::format0(int value, int width) {\n  poco_assert(width > 0 && width < 64);\n\n  char buffer[64];\n  std::sprintf(buffer, \"%0*d\", width, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::formatHex(int value) {\n  char buffer[64];\n  std::sprintf(buffer, \"%X\", value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::formatHex(int value, int width) {\n  poco_assert(width > 0 && width < 64);\n\n  char buffer[64];\n  std::sprintf(buffer, \"%0*X\", width, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::format(unsigned value) {\n  char buffer[64];\n  std::sprintf(buffer, \"%u\", value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::format(unsigned value, int width) {\n  poco_assert(width > 0 && width < 64);\n\n  char buffer[64];\n  std::sprintf(buffer, \"%*u\", width, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::format0(unsigned int value, int width) {\n  poco_assert(width > 0 && width < 64);\n\n  char buffer[64];\n  std::sprintf(buffer, \"%0*u\", width, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::formatHex(unsigned value) {\n  char buffer[64];\n  std::sprintf(buffer, \"%X\", value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::formatHex(unsigned value, int width) {\n  poco_assert(width > 0 && width < 64);\n\n  char buffer[64];\n  std::sprintf(buffer, \"%0*X\", width, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::format(long value) {\n  char buffer[64];\n  std::sprintf(buffer, \"%ld\", value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::format(long value, int width) {\n  poco_assert(width > 0 && width < 64);\n\n  char buffer[64];\n  std::sprintf(buffer, \"%*ld\", width, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::format0(long value, int width) {\n  poco_assert(width > 0 && width < 64);\n\n  char buffer[64];\n  std::sprintf(buffer, \"%0*ld\", width, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::formatHex(long value) {\n  char buffer[64];\n  std::sprintf(buffer, \"%lX\", value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::formatHex(long value, int width) {\n  poco_assert(width > 0 && width < 64);\n\n  char buffer[64];\n  std::sprintf(buffer, \"%0*lX\", width, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::format(unsigned long value) {\n  char buffer[64];\n  std::sprintf(buffer, \"%lu\", value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::format(unsigned long value, int width) {\n  poco_assert(width > 0 && width < 64);\n\n  char buffer[64];\n  std::sprintf(buffer, \"%*lu\", width, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::format0(unsigned long value, int width) {\n  poco_assert(width > 0 && width < 64);\n\n  char buffer[64];\n  std::sprintf(buffer, \"%0*lu\", width, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::formatHex(unsigned long value) {\n  char buffer[64];\n  std::sprintf(buffer, \"%lX\", value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::formatHex(unsigned long value, int width) {\n  poco_assert(width > 0 && width < 64);\n\n  char buffer[64];\n  std::sprintf(buffer, \"%0*lX\", width, value);\n  return std::string(buffer);\n}\n\n#if defined(POCO_HAVE_INT64) && !defined(POCO_LONG_IS_64_BIT)\n\nstd::string CNumberFormatter::format(Int64 value) {\n  char buffer[64];\n  std::sprintf(buffer, \"%\" PRId64, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::format(Int64 value, int width) {\n  poco_assert(width > 0 && width < 64);\n\n  char buffer[64];\n  std::sprintf(buffer, \"%*\" PRId64, width, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::format0(Int64 value, int width) {\n  poco_assert(width > 0 && width < 64);\n\n  char buffer[64];\n  std::sprintf(buffer, \"%0*\" PRId64, width, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::formatHex(Int64 value) {\n  char buffer[64];\n  std::sprintf(buffer, \"%\" PRIX64, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::formatHex(Int64 value, int width) {\n  poco_assert(width > 0 && width < 64);\n\n  char buffer[64];\n  std::sprintf(buffer, \"%0*\" PRIX64, width, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::format(UInt64 value) {\n  char buffer[64];\n  std::sprintf(buffer, \"%\" PRIu64, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::format(UInt64 value, int width) {\n  poco_assert(width > 0 && width < 64);\n\n  char buffer[64];\n  std::sprintf(buffer, \"%*\" PRIu64, width, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::format0(UInt64 value, int width) {\n  poco_assert(width > 0 && width < 64);\n\n  char buffer[64];\n  std::sprintf(buffer, \"%0*\" PRIu64, width, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::formatHex(UInt64 value) {\n  char buffer[64];\n  std::sprintf(buffer, \"%\" PRIX64, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::formatHex(UInt64 value, int width) {\n  poco_assert(width > 0 && width < 64);\n\n  char buffer[64];\n  std::sprintf(buffer, \"%0*\" PRIX64, width, value);\n  return std::string(buffer);\n}\n\n#endif // defined(POCO_HAVE_INT64) && !defined(POCO_LONG_IS_64_BIT)\n\nstd::string CNumberFormatter::format(float value) {\n  char buffer[64];\n  std::sprintf(buffer, \"%.*g\", 10, (double)value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::format(double value) {\n  char buffer[64];\n  std::sprintf(buffer, \"%.*g\", 20, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::format(double value, int precision) {\n  poco_assert(precision >= 0 && precision < 32);\n\n  char buffer[64];\n  std::sprintf(buffer, \"%.*f\", precision, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::format(double value, int width, int precision) {\n  poco_assert(width > 0 && width < 64 && precision >= 0 && precision < width);\n\n  char buffer[64];\n  std::sprintf(buffer, \"%*.*f\", width, precision, value);\n  return std::string(buffer);\n}\n\nstd::string CNumberFormatter::format(const void *ptr) {\n  char buffer[24];\n  std::sprintf(buffer, \"%p\", ptr);\n  return std::string(buffer);\n}\n"
  },
  {
    "path": "src/base/NumberFormatter.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// NumberFormatter.h\n//\n// $Id: NumberFormatter.h,v 1.1 2008/05/31 15:47:25 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Core\n// Module:  NumberFormatter\n//\n// Definition of the NumberFormatter class.\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_NumberFormatter_INCLUDED\n#define Foundation_NumberFormatter_INCLUDED\n\n#include \"Foundation.hpp\"\n\nclass CNumberFormatter\n/// The NumberFormatter class provides static methods\n/// for formatting numeric values into strings.\n{\npublic:\n  static std::string format(int value);\n  /// Formats an integer value in decimal notation.\n\n  static std::string format(int value, int width);\n  /// Formats an integer value in decimal notation,\n  /// right justified in a field having at least\n  /// the specified width.\n\n  static std::string format0(int value, int width);\n  /// Formats an integer value in decimal notation,\n  /// right justified and zero-padded in a field\n  /// having at least the specified width.\n\n  static std::string formatHex(int value);\n  /// Formats an int value in hexadecimal notation.\n  /// The value is treated as unsigned.\n\n  static std::string formatHex(int value, int width);\n  /// Formats a int value in hexadecimal notation,\n  /// right justified and zero-padded in\n  /// a field having at least the specified width.\n  /// The value is treated as unsigned.\n\n  static std::string format(unsigned value);\n  /// Formats an unsigned int value in decimal notation.\n\n  static std::string format(unsigned value, int width);\n  /// Formats an unsigned long int in decimal notation,\n  /// right justified in a field having at least the\n  /// specified width.\n\n  static std::string format0(unsigned int value, int width);\n  /// Formats an unsigned int value in decimal notation,\n  /// right justified and zero-padded in a field having at\n  /// least the specified width.\n\n  static std::string formatHex(unsigned value);\n  /// Formats an unsigned int value in hexadecimal notation.\n\n  static std::string formatHex(unsigned value, int width);\n  /// Formats a int value in hexadecimal notation,\n  /// right justified and zero-padded in\n  /// a field having at least the specified width.\n\n  static std::string format(long value);\n  /// Formats a long value in decimal notation.\n\n  static std::string format(long value, int width);\n  /// Formats a long value in decimal notation,\n  /// right justified in a field having at least the\n  /// specified width.\n\n  static std::string format0(long value, int width);\n  /// Formats a long value in decimal notation,\n  /// right justified and zero-padded in a field\n  /// having at least the specified width.\n\n  static std::string formatHex(long value);\n  /// Formats an unsigned long value in hexadecimal notation.\n  /// The value is treated as unsigned.\n\n  static std::string formatHex(long value, int width);\n  /// Formats an unsigned long value in hexadecimal notation,\n  /// right justified and zero-padded in a field having at least the\n  /// specified width.\n  /// The value is treated as unsigned.\n\n  static std::string format(unsigned long value);\n  /// Formats an unsigned long value in decimal notation.\n\n  static std::string format(unsigned long value, int width);\n  /// Formats an unsigned long value in decimal notation,\n  /// right justified in a field having at least the specified\n  /// width.\n\n  static std::string format0(unsigned long value, int width);\n  /// Formats an unsigned long value in decimal notation,\n  /// right justified and zero-padded\n  /// in a field having at least the specified width.\n\n  static std::string formatHex(unsigned long value);\n  /// Formats an unsigned long value in hexadecimal notation.\n\n  static std::string formatHex(unsigned long value, int width);\n  /// Formats an unsigned long value in hexadecimal notation,\n  /// right justified and zero-padded in a field having at least the\n  /// specified width.\n\n#if defined(POCO_HAVE_INT64) && !defined(POCO_LONG_IS_64_BIT)\n\n  static std::string format(Int64 value);\n  /// Formats a 64-bit integer value in decimal notation.\n\n  static std::string format(Int64 value, int width);\n  /// Formats a 64-bit integer value in decimal notation,\n  /// right justified in a field having at least the specified width.\n\n  static std::string format0(Int64 value, int width);\n  /// Formats a 64-bit integer value in decimal notation,\n  /// right justified and zero-padded in a field having at least\n  /// the specified width.\n\n  static std::string formatHex(Int64 value);\n  /// Formats a 64-bit integer value in hexadecimal notation.\n  /// The value is treated as unsigned.\n\n  static std::string formatHex(Int64 value, int width);\n  /// Formats a 64-bit integer value in hexadecimal notation,\n  /// right justified and zero-padded in a field having at least\n  /// the specified width.\n  /// The value is treated as unsigned.\n\n  static std::string format(UInt64 value);\n  /// Formats an unsigned 64-bit integer value in decimal notation.\n\n  static std::string format(UInt64 value, int width);\n  /// Formats an unsigned 64-bit integer value in decimal notation,\n  /// right justified in a field having at least the specified width.\n\n  static std::string format0(UInt64 value, int width);\n  /// Formats an unsigned 64-bit integer value in decimal notation,\n  /// right justified and zero-padded in a field having at least the\n  /// specified width.\n\n  static std::string formatHex(UInt64 value);\n  /// Formats a 64-bit integer value in hexadecimal notation.\n\n  static std::string formatHex(UInt64 value, int width);\n  /// Formats a 64-bit integer value in hexadecimal notation,\n  /// right justified and zero-padded in a field having at least\n  /// the specified width.\n\n#endif // defined(POCO_HAVE_INT64) && !defined(POCO_LONG_IS_64_BIT)\n\n  static std::string format(float value);\n  /// Formats a float value in decimal floating-point notation,\n  /// according to std::printf's %g format with a precision of 8 fractional\n  /// digits.\n\n  static std::string format(double value);\n  /// Formats a double value in decimal floating-point notation,\n  /// according to std::printf's %g format with a precision of 16 fractional\n  /// digits.\n\n  static std::string format(double value, int precision);\n  /// Formats a double value in decimal floating-point notation,\n  /// according to std::printf's %f format with the given precision.\n\n  static std::string format(double value, int width, int precision);\n  /// Formats a double value in decimal floating-point notation,\n  /// right justified in a field of the specified width,\n  /// with the number of fractional digits given in precision.\n\n  static std::string format(const void *ptr);\n  /// Formats a pointer in an eight (32-bit architectures) or\n  /// sixteen (64-bit architectures) characters wide\n  /// field in hexadecimal notation.\n};\n\n#endif // Foundation_NumberFormatter_INCLUDED\n"
  },
  {
    "path": "src/base/Platform.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Platform.h\n//\n// $Id: Platform.h,v 1.1 2008/05/31 15:47:25 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Core\n// Module:  Platform\n//\n// Platform and architecture identification macros.\n//\n// NOTE: This file may be included from both C++ and C code, so it\n//       must not contain any C++ specific things.\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_Platform_INCLUDED\n#define Foundation_Platform_INCLUDED\n\n//\n// Platform Identification\n//\n#define POCO_OS_FREE_BSD 0x0001\n#define POCO_OS_AIX 0x0002\n#define POCO_OS_HPUX 0x0003\n#define POCO_OS_TRU64 0x0004\n#define POCO_OS_LINUX 0x0005\n#define POCO_OS_MAC_OS_X 0x0006\n#define POCO_OS_NET_BSD 0x0007\n#define POCO_OS_OPEN_BSD 0x0008\n#define POCO_OS_IRIX 0x0009\n#define POCO_OS_SOLARIS 0x000a\n#define POCO_OS_QNX 0x000b\n#define POCO_OS_VXWORKS 0x000c\n#define POCO_OS_CYGWIN 0x000d\n#define POCO_OS_UNKNOWN_UNIX 0x00ff\n#define POCO_OS_WINDOWS_NT 0x1001\n#define POCO_OS_WINDOWS_CE 0x1011\n#define POCO_OS_VMS 0x2001\n\n#if defined(__FreeBSD__)\n#define POCO_OS_FAMILY_UNIX 1\n#define POCO_OS_FAMILY_BSD 1\n#define POCO_OS POCO_OS_FREE_BSD\n#elif defined(_AIX) || defined(__TOS_AIX__)\n#define POCO_OS_FAMILY_UNIX 1\n#define POCO_OS POCO_OS_AIX\n#elif defined(hpux) || defined(_hpux)\n#define POCO_OS_FAMILY_UNIX 1\n#define POCO_OS POCO_OS_HPUX\n#elif defined(__digital__) || defined(__osf__)\n#define POCO_OS_FAMILY_UNIX 1\n#define POCO_OS POCO_OS_TRU64\n#elif defined(linux) || defined(__linux) || defined(__linux__) ||              \\\n    defined(__TOS_LINUX__)\n#define POCO_OS_FAMILY_UNIX 1\n#define POCO_OS POCO_OS_LINUX\n#elif defined(__APPLE__) || defined(__TOS_MACOS__)\n#define POCO_OS_FAMILY_UNIX 1\n#define POCO_OS_FAMILY_BSD 1\n#define POCO_OS POCO_OS_MAC_OS_X\n#elif defined(__NetBSD__)\n#define POCO_OS_FAMILY_UNIX 1\n#define POCO_OS_FAMILY_BSD 1\n#define POCO_OS POCO_OS_NET_BSD\n#elif defined(__OpenBSD__)\n#define POCO_OS_FAMILY_UNIX 1\n#define POCO_OS_FAMILY_BSD 1\n#define POCO_OS POCO_OS_OPEN_BSD\n#elif defined(sgi) || defined(__sgi)\n#define POCO_OS_FAMILY_UNIX 1\n#define POCO_OS POCO_OS_IRIX\n#elif defined(sun) || defined(__sun)\n#define POCO_OS_FAMILY_UNIX 1\n#define POCO_OS POCO_OS_SOLARIS\n#elif defined(__QNX__)\n#define POCO_OS_FAMILY_UNIX 1\n#define POCO_OS POCO_OS_QNX\n#elif defined(unix) || defined(__unix) || defined(__unix__)\n#define POCO_OS_FAMILY_UNIX 1\n#define POCO_OS POCO_OS_UNKNOWN_UNIX\n#elif defined(_WIN32_WCE)\n#define POCO_OS_FAMILY_WINDOWS 1\n#define POCO_OS POCO_OS_WINDOWS_CE\n#elif defined(_WIN32) || defined(_WIN64)\n#define POCO_OS_FAMILY_WINDOWS 1\n#define POCO_OS POCO_OS_WINDOWS_NT\n#elif defined(__CYGWIN__)\n#define POCO_OS_FAMILY_UNIX 1\n#define POCO_OS POCO_OS_CYGWIN\n#elif defined(__VMS)\n#define POCO_OS_FAMILY_VMS 1\n#define POCO_OS POCO_OS_VMS\n#endif\n\n//\n// Hardware Architecture and Byte Order\n//\n#define POCO_ARCH_ALPHA 0x01\n#define POCO_ARCH_IA32 0x02\n#define POCO_ARCH_IA64 0x03\n#define POCO_ARCH_MIPS 0x04\n#define POCO_ARCH_HPPA 0x05\n#define POCO_ARCH_PPC 0x06\n#define POCO_ARCH_POWER 0x07\n#define POCO_ARCH_SPARC 0x08\n#define POCO_ARCH_AMD64 0x09\n#define POCO_ARCH_ARM 0x0a\n\n#if defined(__ALPHA) || defined(__alpha) || defined(__alpha__) ||              \\\n    defined(_M_ALPHA)\n#define POCO_ARCH POCO_ARCH_ALPHA\n#define POCO_ARCH_LITTLE_ENDIAN 1\n#elif defined(i386) || defined(__i386) || defined(__i386__) || defined(_M_IX86)\n#define POCO_ARCH POCO_ARCH_IA32\n#define POCO_ARCH_LITTLE_ENDIAN 1\n#elif defined(_IA64) || defined(__IA64__) || defined(__ia64__) ||              \\\n    defined(__ia64) || defined(_M_IA64)\n#define POCO_ARCH POCO_ARCH_IA64\n#if defined(hpux) || defined(_hpux)\n#define POCO_ARCH_BIG_ENDIAN 1\n#else\n#define POCO_ARCH_LITTLE_ENDIAN 1\n#endif\n#elif defined(__x86_64__) || defined(_M_X64)\n#define POCO_ARCH POCO_ARCH_AMD64\n#define POCO_ARCH_LITTLE_ENDIAN 1\n#elif defined(__mips__) || defined(__mips) || defined(__MIPS__) ||             \\\n    defined(_M_MRX000)\n#define POCO_ARCH POCO_ARCH_MIPS\n#define POCO_ARCH_BIG_ENDIAN 1\n#elif defined(__hppa) || defined(__hppa__)\n#define POCO_ARCH POCO_ARCH_HPPA\n#define POCO_ARCH_BIG_ENDIAN 1\n#elif defined(__PPC) || defined(__POWERPC__) || defined(__powerpc) ||          \\\n    defined(__PPC__) || defined(__powerpc__) || defined(__ppc__) ||            \\\n    defined(_ARCH_PPC) || defined(_M_PPC)\n#define POCO_ARCH POCO_ARCH_PPC\n#define POCO_ARCH_BIG_ENDIAN 1\n#elif defined(_POWER) || defined(_ARCH_PWR) || defined(_ARCH_PWR2) ||          \\\n    defined(_ARCH_PWR3) || defined(_ARCH_PWR4) || defined(__THW_RS6000)\n#define POCO_ARCH POCO_ARCH_POWER\n#define POCO_ARCH_BIG_ENDIAN 1\n#elif defined(__sparc__) || defined(__sparc) || defined(sparc)\n#define POCO_ARCH POCO_ARCH_SPARC\n#define POCO_ARCH_BIG_ENDIAN 1\n#elif defined(__arm__) || defined(__arm) || defined(ARM) || defined(_ARM_) ||  \\\n    defined(__ARM__) || defined(_M_ARM)\n#define POCO_ARCH POCO_ARCH_ARM\n#if defined(__ARMEB__)\n#define POCO_ARCH_BIG_ENDIAN 1\n#else\n#define POCO_ARCH_LITTLE_ENDIAN 1\n#endif\n#endif\n\n#endif // Foundation_Platform_INCLUDED\n"
  },
  {
    "path": "src/base/Platform_POSIX.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Platform_POSIX.h\n//\n// $Id: Platform_POSIX.h,v 1.1 2008/05/31 15:47:25 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Core\n// Module:  Platform\n//\n// Platform and architecture identification macros\n// and platform-specific definitions for various POSIX platforms\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_Platform_POSIX_INCLUDED\n#define Foundation_Platform_POSIX_INCLUDED\n\n//\n// PA-RISC based HP-UX platforms have some issues...\n//\n#if defined(hpux) || defined(_hpux)\n#if defined(__hppa) || defined(__hppa__)\n#define POCO_NO_SYS_SELECT_H 1\n#if defined(__HP_aCC)\n#define POCO_NO_TEMPLATE_ICOMPARE 1\n#endif\n#endif\n#endif\n\n#endif // Foundation_Platform_POSIX_INCLUDED\n"
  },
  {
    "path": "src/base/Platform_VMS.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Platform_VMS.h\n//\n// $Id: Platform_VMS.h,v 1.1 2008/05/31 15:47:26 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Core\n// Module:  Platform\n//\n// Platform and architecture identification macros\n// and platform-specific definitions for OpenVMS.\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_Platform_VMS_INCLUDED\n#define Foundation_Platform_VMS_INCLUDED\n\n// Define the POCO_DESCRIPTOR_STRING and POCO_DESCRIPTOR_LITERAL\n// macros which we use instead of $DESCRIPTOR and $DESCRIPTOR64.\n// Our macros work with both 32bit and 64bit pointer sizes.\n#if __INITIAL_POINTER_SIZE != 64\n#define POCO_DESCRIPTOR_STRING(name, string)                                   \\\n  struct dsc$descriptor_s name = {string.size(), DSC$K_DTYPE_T, DSC$K_CLASS_S, \\\n                                  (char *)string.data()}\n#define POCO_DESCRIPTOR_LITERAL(name, string)                                  \\\n  struct dsc$descriptor_s name = {sizeof(string) - 1, DSC$K_DTYPE_T,           \\\n                                  DSC$K_CLASS_S, (char *)string}\n#else\n#define POCO_DESCRIPTOR_STRING(name, string)                                   \\\n  struct dsc64$descriptor_s name = {                                           \\\n      1,  DSC64$K_DTYPE_T, DSC64$K_CLASS_S,                                    \\\n      -1, string.size(),   (char *)string.data()}\n#define POCO_DESCRIPTOR_LITERAL(name, string)                                  \\\n  struct dsc64$descriptor_s name = {1,  DSC64$K_DTYPE_T,    DSC64$K_CLASS_S,   \\\n                                    -1, sizeof(string) - 1, (char *)string}\n#endif\n\n// No <sys/select.h> header file\n#define POCO_NO_SYS_SELECT_H\n\n#endif // Foundation_Platform_VMS_INCLUDED\n"
  },
  {
    "path": "src/base/Platform_WIN32.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Platform_WIN32.h\n//\n// $Id: Platform_WIN32.h,v 1.1 2008/05/31 15:47:26 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Core\n// Module:  Platform\n//\n// Platform and architecture identification macros\n// and platform-specific definitions for Windows.\n//\n// Copyright (c) 2004-2007, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_Platform_WIN32_INCLUDED\n#define Foundation_Platform_WIN32_INCLUDED\n\n// Verify that we're built with the multithreaded\n// versions of the runtime libraries\n#if defined(_MSC_VER) && !defined(_MT)\n#error Must compile with /MD, /MDd, /MT or /MTd\n#endif\n\n// Check debug/release settings consistency\n#if defined(NDEBUG) && defined(_DEBUG)\n#error Inconsistent build settings (check for /MD[d])\n#endif\n\n// Reduce bloat imported by \"UnWindows.h\"\n#if defined(_WIN32)\n#if !defined(_WIN32_WINNT)\n#define _WIN32_WINNT 0x0500\n#endif\n#if !defined(WIN32_LEAN_AND_MEAN) && !defined(POCO_BLOATED_WIN32)\n#define WIN32_LEAN_AND_MEAN\n#endif\n#endif\n\n// Unicode Support\n#if defined(UNICODE) && !defined(POCO_WIN32_UTF8)\n#define POCO_WIN32_UTF8\n#endif\n\n// Turn off some annoying warnings\n#if defined(_MSC_VER)\n#define _CRT_SECURE_NO_DEPRECATE 1\n//\t#pragma warning(disable:4018) // signed/unsigned comparison\n//\t#pragma warning(disable:4251) // ... needs to have dll-interface warning\n//\t#pragma warning(disable:4355) // 'this' : used in base member\n// initializer list\n#pragma warning(disable : 4996) // VC++ 8.0 deprecation warnings\n//\t#pragma warning(disable:4351) // new behavior: elements of array '...'\n// will be default initialized \t#pragma warning(disable:4675) // resolved\n// overload was found by argument-dependent lookup\n#endif\n\n//#if defined(__INTEL_COMPILER)\n//\t#pragma warning(disable:1738) // base class dllexport/dllimport\n// specification differs from that of the derived class \t#pragma\n// warning(disable:1478) // function ... was declared \"deprecated\" \t#pragma\n// warning(disable:1744) // field of class type without a DLL interface used in\n// a class with a DLL interface #endif\n\n#endif // Foundation_Platform_WIN32_INCLUDED\n"
  },
  {
    "path": "src/base/Poco.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Poco.h\n//\n// $Id: Poco.h,v 1.1 2008/05/31 15:47:26 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Core\n// Module:  Foundation\n//\n// Basic definitions for the POCO libraries.\n//\n// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_Poco_INCLUDED\n#define Foundation_Poco_INCLUDED\n\n#include \"Foundation.hpp\"\n\n#endif // Foundation_Poco_INCLUDED\n"
  },
  {
    "path": "src/base/RWLock.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// RWLock.cpp\n//\n// $Id: RWLock.cpp,v 1.3 2008/06/12 06:58:24 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  RWLock\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#include \"RWLock.hpp\"\n#include <string.h>\n\n#if defined(POCO_OS_FAMILY_WINDOWS)\n#include \"RWLock_WIN32.cpp\"\n#else\n#include \"RWLock_POSIX.cpp\"\n#endif\n\nCRWLock::CRWLock() { lockName = strdup(\"anon\"); }\n\nCRWLock::CRWLock(const char *lName) { lockName = strdup(lName); }\n\nCRWLock::~CRWLock() { free(lockName); }\n"
  },
  {
    "path": "src/base/RWLock.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// RWLock.h\n//\n// $Id: RWLock.h,v 1.1 2008/05/31 15:47:26 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  RWLock\n//\n// Definition of the RWLock class.\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_RWLock_INCLUDED\n#define Foundation_RWLock_INCLUDED\n\n#include \"../es40_debug.hpp\"\n#include \"Exception.hpp\"\n#include \"Foundation.hpp\"\n#include \"Mutex.hpp\"\n#include \"Timestamp.hpp\"\n\n#include <thread>\n\n#if defined(POCO_OS_FAMILY_WINDOWS)\n#include \"RWLock_WIN32.hpp\"\n#else\n#include \"RWLock_POSIX.hpp\"\n#endif\n\nclass CScopedRWLock;\n\nclass CRWLock : private CRWLockImpl\n/// A reader writer lock allows multiple concurrent\n/// readers or one exclusive writer.\n{\npublic:\n  typedef CScopedRWLock CScopedLock;\n\n  CRWLock(const char *lName);\n\n  void readLock(long milliseconds);\n  bool tryReadLock(long milliseconds);\n  void writeLock(long milliseconds);\n  bool tryWriteLock(long milliseconds);\n\n  char *lockName;\n\n  CRWLock();\n  /// Creates the Reader/Writer lock.\n\n  ~CRWLock();\n  /// Destroys the Reader/Writer lock.\n\n  void readLock();\n  /// Acquires a read lock. If another thread currently holds a write lock,\n  /// waits until the write lock is released.\n\n  bool tryReadLock();\n  /// Tries to acquire a read lock. Immediately returns true if successful, or\n  /// false if another thread currently holds a write lock.\n\n  void writeLock();\n  /// Acquires a write lock. If one or more other threads currently hold\n  /// locks, waits until all locks are released. The results are undefined\n  /// if the same thread already holds a read or write lock\n\n  bool tryWriteLock();\n  /// Tries to acquire a write lock. Immediately returns true if successful,\n  /// or false if one or more other threads currently hold\n  /// locks. The result is undefined if the same thread already\n  /// holds a read or write lock.\n\n  void unlock();\n  /// Releases the read or write lock.\n\nprivate:\n  CRWLock(const CRWLock &);\n  CRWLock &operator=(const CRWLock &);\n};\n\nclass CScopedRWLock\n/// A variant of ScopedLock for reader/writer locks.\n{\npublic:\n  CScopedRWLock(CRWLock *rwl, bool write = false);\n  ~CScopedRWLock();\n\nprivate:\n  CRWLock *_rwl;\n\n  CScopedRWLock();\n  CScopedRWLock(const CScopedRWLock &);\n  CScopedRWLock &operator=(const CScopedRWLock &);\n};\n\n//\n// inlines\n//\ninline void CRWLock::readLock() {\n#if defined(DEBUG_LOCKS)\n  printf(\"   READ LOCK mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n  try {\n    readLockImpl();\n  }\n\n  catch (CException &e) {\n    FAILURE_3(\n        Thread,\n        \"Locking error (%s) trying to read-lock mutex %s from thread %s.\\n\",\n        e.message().c_str(), lockName, CURRENT_THREAD_NAME);\n  }\n\n#if defined(DEBUG_LOCKS)\n  printf(\" READ LOCKED mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n}\n\ninline bool CRWLock::tryReadLock() {\n  bool res;\n#if defined(DEBUG_LOCKS)\n  printf(\" TRY RD LOCK mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n  try {\n    res = tryReadLockImpl();\n  } catch (CException &e) {\n    FAILURE_3(\n        Thread,\n        \"Locking error (%s) trying to read-lock mutex %s from thread %s.\\n\",\n        e.message().c_str(), lockName, CURRENT_THREAD_NAME);\n  }\n\n#if defined(DEBUG_LOCKS)\n  printf(\"  %s mutex %s from thread %s.   \\n\",\n         res ? \"    LOCKED\" : \"CAN'T LOCK\", lockName, CURRENT_THREAD_NAME);\n#endif\n  return res;\n}\n\ninline bool CRWLock::tryWriteLock(long milliseconds) {\n#if defined(DEBUG_LOCKS)\n  printf(\" TRY WR LOCK mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n  try {\n    CTimestamp now;\n    CTimestamp::TimeDiff diff(CTimestamp::TimeDiff(milliseconds) * 1000);\n    do {\n      if (tryWriteLock()) {\n#if defined(DEBUG_LOCKS)\n        printf(\"   WR LOCKED mutex %s from thread %s.   \\n\", lockName,\n               CURRENT_THREAD_NAME);\n#endif\n        return true;\n      }\n      std::this_thread::sleep_for(std::chrono::milliseconds(5));\n    } while (!now.isElapsed(diff));\n#if defined(DEBUG_LOCKS)\n    printf(\"CAN'T W LOCK mutex %s from thread %s.   \\n\", lockName,\n           CURRENT_THREAD_NAME);\n#endif\n    return false;\n  } catch (CException &e) {\n    FAILURE_3(\n        Thread,\n        \"Locking error (%s) trying to write-lock mutex %s from thread %s.\\n\",\n        e.message().c_str(), lockName, CURRENT_THREAD_NAME);\n  }\n}\n\ninline bool CRWLock::tryReadLock(long milliseconds) {\n#if defined(DEBUG_LOCKS)\n  printf(\" TRY RD LOCK mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n  try {\n    CTimestamp now;\n    CTimestamp::TimeDiff diff(CTimestamp::TimeDiff(milliseconds) * 1000);\n    do {\n      if (tryReadLock()) {\n#if defined(DEBUG_LOCKS)\n        printf(\"   RD LOCKED mutex %s from thread %s.   \\n\", lockName,\n               CURRENT_THREAD_NAME);\n#endif\n        return true;\n      }\n      std::this_thread::sleep_for(std::chrono::milliseconds(5));\n    } while (!now.isElapsed(diff));\n#if defined(DEBUG_LOCKS)\n    printf(\"CAN'T R LOCK mutex %s from thread %s.   \\n\", lockName,\n           CURRENT_THREAD_NAME);\n#endif\n    return false;\n  } catch (CException &e) {\n    FAILURE_3(\n        Thread,\n        \"Locking error (%s) trying to read-lock mutex %s from thread %s.\\n\",\n        e.message().c_str(), lockName, CURRENT_THREAD_NAME);\n  }\n}\n\ninline void CRWLock::writeLock(long milliseconds) {\n#if defined(DEBUG_LOCKS)\n  printf(\"  WRITE LOCK mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n  try {\n    CTimestamp now;\n    CTimestamp::TimeDiff diff(CTimestamp::TimeDiff(milliseconds) * 1000);\n    do {\n      if (tryWriteLock()) {\n#if defined(DEBUG_LOCKS)\n        printf(\"   WR LOCKED mutex %s from thread %s.   \\n\", lockName,\n               CURRENT_THREAD_NAME);\n#endif\n        return;\n      }\n      std::this_thread::sleep_for(std::chrono::milliseconds(20));\n    } while (!now.isElapsed(diff));\n    FAILURE(Timeout, \"Timeout\");\n  } catch (CException &e) {\n    FAILURE_3(\n        Thread,\n        \"Locking error (%s) trying to write-lock mutex %s from thread %s.\\n\",\n        e.message().c_str(), lockName, CURRENT_THREAD_NAME);\n  }\n}\n\ninline void CRWLock::readLock(long milliseconds) {\n#if defined(DEBUG_LOCKS)\n  printf(\"   READ LOCK mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n  try {\n    CTimestamp now;\n    CTimestamp::TimeDiff diff(CTimestamp::TimeDiff(milliseconds) * 1000);\n    do {\n      if (tryReadLock()) {\n#if defined(DEBUG_LOCKS)\n        printf(\"   RD LOCKED mutex %s from thread %s.   \\n\", lockName,\n               CURRENT_THREAD_NAME);\n#endif\n        return;\n      }\n      std::this_thread::sleep_for(std::chrono::milliseconds(5));\n    } while (!now.isElapsed(diff));\n    FAILURE(Timeout, \"Timeout\");\n  } catch (CException &e) {\n    FAILURE_3(\n        Thread,\n        \"Locking error (%s) trying to read-lock mutex %s from thread %s.\\n\",\n        e.message().c_str(), lockName, CURRENT_THREAD_NAME);\n  }\n}\n\ninline void CRWLock::writeLock() {\n#if defined(DEBUG_LOCKS)\n  printf(\"  WRITE LOCK mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n  try {\n    writeLockImpl();\n  }\n\n  catch (CException &e) {\n    FAILURE_3(\n        Thread,\n        \"Locking error (%s) trying to write-lock mutex %s from thread %s.\\n\",\n        e.message().c_str(), lockName, CURRENT_THREAD_NAME);\n  }\n\n#if defined(DEBUG_LOCKS)\n  printf(\"WRITE LOCKED mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n}\n\ninline bool CRWLock::tryWriteLock() {\n  bool res;\n#if defined(DEBUG_LOCKS)\n  printf(\" TRY WR LOCK mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n  try {\n    res = tryWriteLockImpl();\n  }\n\n  catch (CException &e) {\n    FAILURE_3(\n        Thread,\n        \"Locking error (%s) trying to write-lock mutex %s from thread %s.\\n\",\n        e.message().c_str(), lockName, CURRENT_THREAD_NAME);\n  }\n\n#if defined(DEBUG_LOCKS)\n  printf(\"  %s mutex %s from thread %s.   \\n\",\n         res ? \"    LOCKED\" : \"CAN'T LOCK\", lockName, CURRENT_THREAD_NAME);\n#endif\n  return res;\n}\n\ninline void CRWLock::unlock() {\n#if defined(DEBUG_LOCKS)\n  printf(\"      UNLOCK mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n  try {\n    unlockImpl();\n  }\n\n  catch (CException &e) {\n    FAILURE_3(Thread,\n              \"Locking error (%s) trying to unlock mutex %s from thread %s.\\n\",\n              e.message().c_str(), lockName, CURRENT_THREAD_NAME);\n  }\n\n#if defined(DEBUG_LOCKS)\n  printf(\"    UNLOCKED mutex %s from thread %s.   \\n\", lockName,\n         CURRENT_THREAD_NAME);\n#endif\n}\n\ninline CScopedRWLock::CScopedRWLock(CRWLock *rwl, bool write) : _rwl(rwl) {\n  _rwl = rwl;\n  if (write)\n    _rwl->writeLock(LOCK_TIMEOUT_MS);\n  else\n    _rwl->readLock(LOCK_TIMEOUT_MS);\n}\n\ninline CScopedRWLock::~CScopedRWLock() { _rwl->unlock(); }\n\n#define SCOPED_READ_LOCK(mutex) CRWLock::CScopedLock L_##__LINE__(mutex, false)\n#define SCOPED_WRITE_LOCK(mutex) CRWLock::CScopedLock L_##__LINE__(mutex, true)\n\n#endif // Foundation_RWLock_INCLUDED\n"
  },
  {
    "path": "src/base/RWLock_POSIX.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// RWLock_POSIX.cpp\n//\n// $Id: RWLock_POSIX.cpp,v 1.1 2008/05/31 15:47:26 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  RWLock\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#include \"RWLock_POSIX.hpp\"\n\nCRWLockImpl::CRWLockImpl() {\n  if (pthread_rwlock_init(&_rwl, NULL))\n    throw CSystemException(\"cannot create reader/writer lock\");\n}\n\nCRWLockImpl::~CRWLockImpl() { pthread_rwlock_destroy(&_rwl); }\n"
  },
  {
    "path": "src/base/RWLock_POSIX.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// RWLock_POSIX.h\n//\n// $Id: RWLock_POSIX.h,v 1.1 2008/05/31 15:47:26 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  RWLock\n//\n// Definition of the RWLockImpl class for POSIX Threads.\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_RWLock_POSIX_INCLUDED\n#define Foundation_RWLock_POSIX_INCLUDED\n\n#include \"Exception.hpp\"\n#include \"Foundation.hpp\"\n#include <errno.h>\n#include <pthread.h>\n\nclass CRWLockImpl {\nprotected:\n  CRWLockImpl();\n  ~CRWLockImpl();\n  void readLockImpl();\n  bool tryReadLockImpl();\n  void writeLockImpl();\n  bool tryWriteLockImpl();\n  void unlockImpl();\n\nprivate:\n  pthread_rwlock_t _rwl;\n};\n\n//\n// inlines\n//\ninline void CRWLockImpl::readLockImpl() {\n  if (pthread_rwlock_rdlock(&_rwl))\n    throw CSystemException(\"cannot lock reader/writer lock\");\n}\n\ninline bool CRWLockImpl::tryReadLockImpl() {\n  int rc = pthread_rwlock_tryrdlock(&_rwl);\n  if (rc == 0)\n    return true;\n  else if (rc == EBUSY)\n    return false;\n  else\n    throw CSystemException(\"cannot lock reader/writer lock\");\n}\n\ninline void CRWLockImpl::writeLockImpl() {\n  if (pthread_rwlock_wrlock(&_rwl))\n    throw CSystemException(\"cannot lock reader/writer lock\");\n}\n\ninline bool CRWLockImpl::tryWriteLockImpl() {\n  int rc = pthread_rwlock_trywrlock(&_rwl);\n  if (rc == 0)\n    return true;\n  else if (rc == EBUSY)\n    return false;\n  else\n    throw CSystemException(\"cannot lock reader/writer lock\");\n}\n\ninline void CRWLockImpl::unlockImpl() {\n  if (pthread_rwlock_unlock(&_rwl))\n    throw CSystemException(\"cannot unlock mutex\");\n}\n\n#endif // Foundation_RWLock_POSIX_INCLUDED\n"
  },
  {
    "path": "src/base/RWLock_WIN32.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// RWLock_WIN32.cpp\n//\n// $Id: RWLock_WIN32.cpp,v 1.1 2008/05/31 15:47:26 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  RWLock\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#include \"RWLock_WIN32.hpp\"\n\nCRWLockImpl::CRWLockImpl() : _readers(0), _writers(0) {\n  _mutex = CreateMutexW(NULL, FALSE, NULL);\n  if (_mutex == NULL)\n    throw CSystemException(\"cannot create reader/writer lock\");\n\n  _readEvent = CreateEventW(NULL, TRUE, TRUE, NULL);\n  if (_readEvent == NULL)\n    throw CSystemException(\"cannot create reader/writer lock\");\n\n  _writeEvent = CreateEventW(NULL, TRUE, TRUE, NULL);\n  if (_writeEvent == NULL)\n    throw CSystemException(\"cannot create reader/writer lock\");\n}\n\nCRWLockImpl::~CRWLockImpl() {\n  CloseHandle(_mutex);\n  CloseHandle(_readEvent);\n  CloseHandle(_writeEvent);\n}\n\ninline void CRWLockImpl::addWriter() {\n  switch (WaitForSingleObject(_mutex, INFINITE)) {\n  case WAIT_OBJECT_0:\n    if (++_writers == 1)\n      ResetEvent(_readEvent);\n    ReleaseMutex(_mutex);\n    break;\n  default:\n    throw CSystemException(\"cannot lock reader/writer lock\");\n  }\n}\n\ninline void CRWLockImpl::removeWriter() {\n  switch (WaitForSingleObject(_mutex, INFINITE)) {\n  case WAIT_OBJECT_0:\n    if (--_writers == 0)\n      SetEvent(_readEvent);\n    ReleaseMutex(_mutex);\n    break;\n  default:\n    throw CSystemException(\"cannot lock reader/writer lock\");\n  }\n}\n\nvoid CRWLockImpl::readLockImpl() {\n  HANDLE h[2];\n  h[0] = _mutex;\n  h[1] = _readEvent;\n  switch (WaitForMultipleObjects(2, h, TRUE, INFINITE)) {\n  case WAIT_OBJECT_0:\n  case WAIT_OBJECT_0 + 1:\n    ++_readers;\n    ResetEvent(_writeEvent);\n    ReleaseMutex(_mutex);\n    break;\n  default:\n    throw CSystemException(\"cannot lock reader/writer lock\");\n  }\n}\n\nbool CRWLockImpl::tryReadLockImpl() {\n  HANDLE h[2];\n  h[0] = _mutex;\n  h[1] = _readEvent;\n  switch (WaitForMultipleObjects(2, h, TRUE, 1)) {\n  case WAIT_OBJECT_0:\n  case WAIT_OBJECT_0 + 1:\n    ++_readers;\n    ResetEvent(_writeEvent);\n    ReleaseMutex(_mutex);\n    return true;\n  case WAIT_TIMEOUT:\n    return false;\n  default:\n    throw CSystemException(\"cannot lock reader/writer lock\");\n  }\n}\n\nvoid CRWLockImpl::writeLockImpl() {\n  addWriter();\n  HANDLE h[2];\n  h[0] = _mutex;\n  h[1] = _writeEvent;\n  switch (WaitForMultipleObjects(2, h, TRUE, INFINITE)) {\n  case WAIT_OBJECT_0:\n  case WAIT_OBJECT_0 + 1:\n    --_writers;\n    ++_readers;\n    ResetEvent(_readEvent);\n    ResetEvent(_writeEvent);\n    ReleaseMutex(_mutex);\n    break;\n  default:\n    removeWriter();\n    throw CSystemException(\"cannot lock reader/writer lock\");\n  }\n}\n\nbool CRWLockImpl::tryWriteLockImpl() {\n  addWriter();\n  HANDLE h[2];\n  h[0] = _mutex;\n  h[1] = _writeEvent;\n  switch (WaitForMultipleObjects(2, h, TRUE, 1)) {\n  case WAIT_OBJECT_0:\n  case WAIT_OBJECT_0 + 1:\n    --_writers;\n    ++_readers;\n    ResetEvent(_readEvent);\n    ResetEvent(_writeEvent);\n    ReleaseMutex(_mutex);\n    return true;\n  case WAIT_TIMEOUT:\n    removeWriter();\n    return false;\n  default:\n    removeWriter();\n    throw CSystemException(\"cannot lock reader/writer lock\");\n  }\n}\n\nvoid CRWLockImpl::unlockImpl() {\n  switch (WaitForSingleObject(_mutex, INFINITE)) {\n  case WAIT_OBJECT_0:\n    if (_writers == 0)\n      SetEvent(_readEvent);\n    if (--_readers == 0)\n      SetEvent(_writeEvent);\n    ReleaseMutex(_mutex);\n    break;\n  default:\n    throw CSystemException(\"cannot unlock reader/writer lock\");\n  }\n}\n"
  },
  {
    "path": "src/base/RWLock_WIN32.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// RWLock_WIN32.h\n//\n// $Id: RWLock_WIN32.h,v 1.1 2008/05/31 15:47:27 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  RWLock\n//\n// Definition of the RWLockImpl class for WIN32.\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_RWLock_WIN32_INCLUDED\n#define Foundation_RWLock_WIN32_INCLUDED\n\n#include \"Exception.hpp\"\n#include \"Foundation.hpp\"\n#include \"UnWindows.hpp\"\n\nclass CRWLockImpl {\nprotected:\n  CRWLockImpl();\n  ~CRWLockImpl();\n  void readLockImpl();\n  bool tryReadLockImpl();\n  void writeLockImpl();\n  bool tryWriteLockImpl();\n  void unlockImpl();\n\nprivate:\n  void addWriter();\n  void removeWriter();\n\n  HANDLE _mutex;\n  HANDLE _readEvent;\n  HANDLE _writeEvent;\n  unsigned _readers;\n  unsigned _writers;\n};\n\n#endif // Foundation_RWLock_WIN32_INCLUDED\n"
  },
  {
    "path": "src/base/RefCountedObject.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// RefCountedObject.cpp\n//\n// $Id: RefCountedObject.cpp,v 1.1 2008/05/31 15:47:27 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Core\n// Module:  RefCountedObject\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#include \"RefCountedObject.hpp\"\n#include \"Mutex.hpp\"\n\nCRefCountedObject::CRefCountedObject() : _rc(1), _rcMutex(\"rc\") {}\n\nCRefCountedObject::~CRefCountedObject() {}\n\nvoid CRefCountedObject::duplicate() const {\n  _rcMutex.lock();\n  ++_rc;\n  _rcMutex.unlock();\n}\n\nvoid CRefCountedObject::release() const {\n  _rcMutex.lock();\n  int rc = --_rc;\n  _rcMutex.unlock();\n  if (rc == 0)\n    delete this;\n}\n"
  },
  {
    "path": "src/base/RefCountedObject.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// RefCountedObject.h\n//\n// $Id: RefCountedObject.h,v 1.1 2008/05/31 15:47:27 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Core\n// Module:  RefCountedObject\n//\n// Definition of the RefCountedObject class.\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_RefCountedObject_INCLUDED\n#define Foundation_RefCountedObject_INCLUDED\n\n#include \"Foundation.hpp\"\n#include \"Mutex.hpp\"\n\nclass CRefCountedObject\n/// A base class for objects that employ\n/// reference counting based garbage collection.\n///\n/// Reference-counted objects inhibit construction\n/// by copying and assignment.\n{\npublic:\n  CRefCountedObject();\n  /// Creates the RefCountedObject.\n  /// The initial reference count is one.\n\n  void duplicate() const;\n  /// Increments the object's reference count.\n\n  void release() const;\n  /// Decrements the object's reference count\n  /// and deletes the object if the count\n  /// reaches zero.\n\n  int referenceCount() const;\n  /// Returns the reference count.\n\nprotected:\n  virtual ~CRefCountedObject();\n  /// Destroys the RefCountedObject.\n\nprivate:\n  CRefCountedObject(const CRefCountedObject &);\n  CRefCountedObject &operator=(const CRefCountedObject &);\n\n  mutable int _rc;\n  mutable CFastMutex _rcMutex;\n};\n\n//\n// inlines\n//\ninline int CRefCountedObject::referenceCount() const { return _rc; }\n\n#endif // Foundation_RefCountedObject_INCLUDED\n"
  },
  {
    "path": "src/base/ScopedLock.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// ScopedLock.h\n//\n// $Id: ScopedLock.h,v 1.1 2008/05/31 15:47:27 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  Mutex\n//\n// Definition of the ScopedLock template class.\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_ScopedLock_INCLUDED\n#define Foundation_ScopedLock_INCLUDED\n\n#include \"Foundation.hpp\"\n\n/**\n * \\brief A class that simplifies thread synchronization with a mutex or\n *fastmutex.\n *\n * The constructor accepts a Mutex and locks it.\n * The destructor unlocks the mutex.\n **/\ntemplate <class M> class CScopedLock {\npublic:\n  inline CScopedLock(M *mutex) : _mutex(mutex) {\n    _mutex->lock(LOCK_TIMEOUT_MS);\n  }\n  inline ~CScopedLock() { _mutex->unlock(); }\n\nprivate:\n  M *_mutex;\n\n  CScopedLock();\n  CScopedLock(const CScopedLock &);\n  CScopedLock &operator=(const CScopedLock &);\n};\n\n#endif // Foundation_ScopedLock_INCLUDED\n"
  },
  {
    "path": "src/base/Semaphore.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Semaphore.cpp\n//\n// $Id: Semaphore.cpp,v 1.1 2008/05/31 15:47:28 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  Semaphore\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#include \"Semaphore.hpp\"\n\n#if defined(POCO_OS_FAMILY_WINDOWS)\n#include \"Semaphore_WIN32.cpp\"\n#else\n#include \"Semaphore_POSIX.cpp\"\n#endif\n\nCSemaphore::CSemaphore(int n) : CSemaphoreImpl(n, n) {}\n\nCSemaphore::CSemaphore(int n, int max) : CSemaphoreImpl(n, max) {}\n\nCSemaphore::~CSemaphore() {}\n"
  },
  {
    "path": "src/base/Semaphore.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Semaphore.h\n//\n// $Id: Semaphore.h,v 1.1 2008/05/31 15:47:28 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  Semaphore\n//\n// Definition of the Semaphore class.\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_Semaphore_INCLUDED\n#define Foundation_Semaphore_INCLUDED\n\n#include \"Exception.hpp\"\n#include \"Foundation.hpp\"\n\n#if defined(POCO_OS_FAMILY_WINDOWS)\n#include \"Semaphore_WIN32.hpp\"\n#else\n#include \"Semaphore_POSIX.hpp\"\n#endif\n\nclass CSemaphore : private CSemaphoreImpl\n/// A Semaphore is a synchronization object with the following\n/// characteristics:\n/// A semaphore has a value that is constrained to be a non-negative\n/// integer and two atomic operations. The allowable operations are V\n/// (here called set()) and P (here called wait()). A V (set()) operation\n/// increases the value of the semaphore by one.\n/// A P (wait()) operation decreases the value of the semaphore by one,\n/// provided that can be done without violating the constraint that the\n/// value be non-negative. A P (wait()) operation that is initiated when\n/// the value of the semaphore is 0 suspends the calling thread.\n/// The calling thread may continue when the value becomes positive again.\n{\npublic:\n  CSemaphore(int n);\n  CSemaphore(int n, int max);\n  /// Creates the semaphore. The current value\n  /// of the semaphore is given in n. The\n  /// maximum value of the semaphore is given\n  /// in max.\n  /// If only n is given, it must be greater than\n  /// zero.\n  /// If both n and max are given, max must be\n  /// greater than zero, n must be greater than\n  /// or equal to zero and less than or equal\n  /// to max.\n\n  ~CSemaphore();\n  /// Destroys the semaphore.\n\n  void set();\n  /// Increments the semaphore's value by one and\n  /// thus signals the semaphore. Another thread\n  /// waiting for the semaphore will be able\n  /// to continue.\n\n  void wait();\n  /// Waits for the semaphore to become signalled.\n  /// To become signalled, a semaphore's value must\n  /// be greater than zero.\n  /// Decrements the semaphore's value by one.\n\n  void wait(long milliseconds);\n  /// Waits for the semaphore to become signalled.\n  /// To become signalled, a semaphore's value must\n  /// be greater than zero.\n  /// Throws a TimeoutException if the semaphore\n  /// does not become signalled within the specified\n  /// time interval.\n  /// Decrements the semaphore's value by one\n  /// if successful.\n\n  bool tryWait(long milliseconds);\n  /// Waits for the semaphore to become signalled.\n  /// To become signalled, a semaphore's value must\n  /// be greater than zero.\n  /// Returns true if the semaphore\n  /// became signalled within the specified\n  /// time interval, false otherwise.\n  /// Decrements the semaphore's value by one\n  /// if successful.\n\nprivate:\n  CSemaphore();\n  CSemaphore(const CSemaphore &);\n  CSemaphore &operator=(const CSemaphore &);\n};\n\n//\n// inlines\n//\ninline void CSemaphore::set() { setImpl(); }\n\ninline void CSemaphore::wait() { waitImpl(); }\n\ninline void CSemaphore::wait(long milliseconds) {\n  if (!waitImpl(milliseconds))\n    throw CTimeoutException();\n}\n\ninline bool CSemaphore::tryWait(long milliseconds) {\n  return waitImpl(milliseconds);\n}\n\n#endif // Foundation_Semaphore_INCLUDED\n"
  },
  {
    "path": "src/base/Semaphore_POSIX.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Semaphore_POSIX.cpp\n//\n// Library: Foundation\n// Package: Threading\n// Module:  Semaphore\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// SPDX-License-Identifier:\tBSL-1.0\n//\n\n#include \"Semaphore_POSIX.hpp\"\n#include <sys/time.h>\n\n//\n// Note: pthread_cond_timedwait() with CLOCK_MONOTONIC is supported\n// on Linux and QNX, as well as on Android >= 5.0 (API level 21).\n// On Android < 5.0, HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC is defined\n// to indicate availability of non-standard pthread_cond_timedwait_monotonic().\n//\n#ifndef POCO_HAVE_MONOTONIC_PTHREAD_COND_TIMEDWAIT\n#if (defined(__linux__) || defined(__QNX__)) &&                                \\\n    !(defined(__ANDROID__) &&                                                  \\\n      (defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) ||                       \\\n       __ANDROID_API__ <= 21))\n#define POCO_HAVE_MONOTONIC_PTHREAD_COND_TIMEDWAIT 1\n#endif\n#endif\n\n#ifndef POCO_HAVE_CLOCK_GETTIME\n#if (defined(_POSIX_TIMERS) && defined(CLOCK_REALTIME)) ||                     \\\n    defined(POCO_VXWORKS) || defined(__QNX__)\n#ifndef __APPLE__ // See GitHub issue #1453 - not available before Mac\n                  // OS 10.12/iOS 10\n#define POCO_HAVE_CLOCK_GETTIME\n#endif\n#endif\n#endif\n\nCSemaphoreImpl::CSemaphoreImpl(int n, int max) : _n(n), _max(max) {\n  poco_assert(n >= 0 && max > 0 && n <= max);\n\n#if defined(POCO_VXWORKS)\n  // This workaround is for VxWorks 5.x where\n  // pthread_mutex_init() won't properly initialize the mutex\n  // resulting in a subsequent freeze in pthread_mutex_destroy()\n  // if the mutex has never been used.\n  std::memset(&_mutex, 0, sizeof(_mutex));\n#endif\n  if (pthread_mutex_init(&_mutex, NULL))\n    throw CSystemException(\"cannot create semaphore (mutex)\");\n\n#if defined(POCO_HAVE_MONOTONIC_PTHREAD_COND_TIMEDWAIT)\n  pthread_condattr_t attr;\n  if (pthread_condattr_init(&attr)) {\n    pthread_mutex_destroy(&_mutex);\n    throw CSystemException(\"cannot create semaphore (condition attribute)\");\n  }\n  if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) {\n    pthread_condattr_destroy(&attr);\n    pthread_mutex_destroy(&_mutex);\n    throw CSystemException(\n        \"cannot create semaphore (condition attribute clock)\");\n  }\n  if (pthread_cond_init(&_cond, &attr)) {\n    pthread_condattr_destroy(&attr);\n    pthread_mutex_destroy(&_mutex);\n    throw CSystemException(\"cannot create semaphore (condition)\");\n  }\n  pthread_condattr_destroy(&attr);\n#else\n  if (pthread_cond_init(&_cond, NULL)) {\n    pthread_mutex_destroy(&_mutex);\n    throw CSystemException(\"cannot create semaphore (condition)\");\n  }\n#endif\n}\n\nCSemaphoreImpl::~CSemaphoreImpl() {\n  pthread_cond_destroy(&_cond);\n  pthread_mutex_destroy(&_mutex);\n}\n\nvoid CSemaphoreImpl::waitImpl() {\n  if (pthread_mutex_lock(&_mutex))\n    throw CSystemException(\"wait for semaphore failed (lock)\");\n  while (_n < 1) {\n    if (pthread_cond_wait(&_cond, &_mutex)) {\n      pthread_mutex_unlock(&_mutex);\n      throw CSystemException(\"wait for semaphore failed\");\n    }\n  }\n  --_n;\n  pthread_mutex_unlock(&_mutex);\n}\n\nbool CSemaphoreImpl::waitImpl(long milliseconds) {\n  int rc = 0;\n  struct timespec abstime;\n\n#if defined(POCO_HAVE_MONOTONIC_PTHREAD_COND_TIMEDWAIT)\n  clock_gettime(CLOCK_MONOTONIC, &abstime);\n  abstime.tv_sec += milliseconds / 1000;\n  abstime.tv_nsec += (milliseconds % 1000) * 1000000;\n  if (abstime.tv_nsec >= 1000000000) {\n    abstime.tv_nsec -= 1000000000;\n    abstime.tv_sec++;\n  }\n#elif defined(POCO_HAVE_CLOCK_GETTIME)\n  clock_gettime(CLOCK_REALTIME, &abstime);\n  abstime.tv_sec += milliseconds / 1000;\n  abstime.tv_nsec += (milliseconds % 1000) * 1000000;\n  if (abstime.tv_nsec >= 1000000000) {\n    abstime.tv_nsec -= 1000000000;\n    abstime.tv_sec++;\n  }\n#else\n  struct timeval tv;\n  gettimeofday(&tv, NULL);\n  abstime.tv_sec = tv.tv_sec + milliseconds / 1000;\n  abstime.tv_nsec = tv.tv_usec * 1000 + (milliseconds % 1000) * 1000000;\n  if (abstime.tv_nsec >= 1000000000) {\n    abstime.tv_nsec -= 1000000000;\n    abstime.tv_sec++;\n  }\n#endif\n\n  if (pthread_mutex_lock(&_mutex) != 0)\n    throw CSystemException(\"wait for semaphore failed (lock)\");\n  while (_n < 1) {\n    if ((rc = pthread_cond_timedwait(&_cond, &_mutex, &abstime))) {\n      if (rc == ETIMEDOUT)\n        break;\n      pthread_mutex_unlock(&_mutex);\n      throw CSystemException(\"cannot wait for semaphore\");\n    }\n  }\n  if (rc == 0)\n    --_n;\n  pthread_mutex_unlock(&_mutex);\n  return rc == 0;\n}\n"
  },
  {
    "path": "src/base/Semaphore_POSIX.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Semaphore_POSIX.h\n//\n// $Id: Semaphore_POSIX.h,v 1.1 2008/05/31 15:47:28 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  Semaphore\n//\n// Definition of the SemaphoreImpl class for POSIX Threads.\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_Semaphore_POSIX_INCLUDED\n#define Foundation_Semaphore_POSIX_INCLUDED\n\n#include \"Exception.hpp\"\n#include \"Foundation.hpp\"\n#include <errno.h>\n#include <pthread.h>\n\nclass CSemaphoreImpl {\nprotected:\n  CSemaphoreImpl(int n, int max);\n  ~CSemaphoreImpl();\n  void setImpl();\n  void waitImpl();\n  bool waitImpl(long milliseconds);\n\nprivate:\n  volatile int _n;\n  int _max;\n  pthread_mutex_t _mutex;\n  pthread_cond_t _cond;\n};\n\n//\n// inlines\n//\ninline void CSemaphoreImpl::setImpl() {\n  if (pthread_mutex_lock(&_mutex))\n    throw CSystemException(\"cannot signal semaphore (lock)\");\n  if (_n < _max) {\n    ++_n;\n  } else {\n    pthread_mutex_unlock(&_mutex);\n    throw CSystemException(\n        \"cannot signal semaphore: count would exceed maximum\");\n  }\n  if (pthread_cond_signal(&_cond)) {\n    pthread_mutex_unlock(&_mutex);\n    throw CSystemException(\"cannot signal semaphore\");\n  }\n  pthread_mutex_unlock(&_mutex);\n}\n\n#endif // Foundation_Semaphore_POSIX_INCLUDED\n"
  },
  {
    "path": "src/base/Semaphore_WIN32.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Semaphore_WIN32.cpp\n//\n// $Id: Semaphore_WIN32.cpp,v 1.1 2008/05/31 15:47:28 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  Semaphore\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#include \"Semaphore_WIN32.hpp\"\n\nCSemaphoreImpl::CSemaphoreImpl(int n, int max) {\n  poco_assert(n >= 0 && max > 0 && n <= max);\n\n  _sema = CreateSemaphoreW(NULL, n, max, NULL);\n  if (!_sema) {\n    throw CSystemException(\"cannot create semaphore\");\n  }\n}\n\nCSemaphoreImpl::~CSemaphoreImpl() { CloseHandle(_sema); }\n\nvoid CSemaphoreImpl::waitImpl() {\n  switch (WaitForSingleObject(_sema, INFINITE)) {\n  case WAIT_OBJECT_0:\n    return;\n  default:\n    throw CSystemException(\"wait for semaphore failed\");\n  }\n}\n\nbool CSemaphoreImpl::waitImpl(long milliseconds) {\n  switch (WaitForSingleObject(_sema, milliseconds + 1)) {\n  case WAIT_TIMEOUT:\n    return false;\n  case WAIT_OBJECT_0:\n    return true;\n  default:\n    throw CSystemException(\"wait for semaphore failed\");\n  }\n}\n"
  },
  {
    "path": "src/base/Semaphore_WIN32.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Semaphore_WIN32.h\n//\n// $Id: Semaphore_WIN32.h,v 1.1 2008/05/31 15:47:28 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Threading\n// Module:  Semaphore\n//\n// Definition of the SemaphoreImpl class for WIN32.\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_Semaphore_WIN32_INCLUDED\n#define Foundation_Semaphore_WIN32_INCLUDED\n\n#include \"Exception.hpp\"\n#include \"Foundation.hpp\"\n#include \"UnWindows.hpp\"\n\nclass CSemaphoreImpl {\nprotected:\n  CSemaphoreImpl(int n, int max);\n  ~CSemaphoreImpl();\n  void setImpl();\n  void waitImpl();\n  bool waitImpl(long milliseconds);\n\nprivate:\n  HANDLE _sema;\n};\n\n//\n// inlines\n//\ninline void CSemaphoreImpl::setImpl() {\n  if (!ReleaseSemaphore(_sema, 1, NULL)) {\n    throw CSystemException(\"cannot signal semaphore\");\n  }\n}\n\n#endif // Foundation_Semaphore_WIN32_INCLUDED\n"
  },
  {
    "path": "src/base/SingletonHolder.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// SingletonHolder.h\n//\n// $Id: SingletonHolder.h,v 1.1 2008/05/31 15:47:28 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Core\n// Module:  SingletonHolder\n//\n// Definition of the SingletonHolder template.\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_SingletonHolder_INCLUDED\n#define Foundation_SingletonHolder_INCLUDED\n\n#include \"Foundation.hpp\"\n#include \"Mutex.hpp\"\n\ntemplate <class S>\nclass CSingletonHolder\n/// This is a helper template class for managing\n/// singleton objects allocated on the heap.\n/// The class ensures proper deletion (including\n/// calling of the destructor) of singleton objects\n/// when the application that created them terminates.\n{\npublic:\n  CSingletonHolder()\n  /// Creates the SingletonHolder.\n  {\n    _pS = 0;\n  }\n  ~CSingletonHolder()\n  /// Destroys the SingletonHolder and the singleton\n  /// object that it holds.\n  {\n    delete _pS;\n  }\n  S *get()\n  /// Returns a pointer to the singleton object\n  /// hold by the SingletonHolder. The first call\n  /// to get will create the singleton.\n  {\n    CFastMutex::CScopedLock lock(&_m);\n    if (!_pS)\n      _pS = new S;\n    return _pS;\n  }\n\nprivate:\n  S *_pS;\n  CFastMutex _m;\n};\n\n#endif // Foundation_SingletonHolder_INCLUDED\n"
  },
  {
    "path": "src/base/Timestamp.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Timestamp.cpp\n//\n// $Id: Timestamp.cpp,v 1.1 2008/05/31 15:47:29 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: DateTime\n// Module:  Timestamp\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#include \"Timestamp.hpp\"\n#include \"Exception.hpp\"\n#include <algorithm>\n#if defined(POCO_OS_FAMILY_UNIX)\n#include <sys/time.h>\n#include <sys/times.h>\n#include <time.h>\n#include <unistd.h>\n#elif defined(POCO_OS_FAMILY_WINDOWS)\n#include \"UnWindows.hpp\"\n#endif\n\nCTimestamp::CTimestamp() { update(); }\n\nCTimestamp::CTimestamp(TimeVal tv) { _ts = tv; }\n\nCTimestamp::CTimestamp(const CTimestamp &other) { _ts = other._ts; }\n\nCTimestamp::~CTimestamp() {}\n\nCTimestamp &CTimestamp::operator=(const CTimestamp &other) {\n  _ts = other._ts;\n  return *this;\n}\n\nCTimestamp &CTimestamp::operator=(TimeVal tv) {\n  _ts = tv;\n  return *this;\n}\n\nvoid CTimestamp::swap(CTimestamp &timestamp) { std::swap(_ts, timestamp._ts); }\n\nCTimestamp CTimestamp::fromEpochTime(std::time_t t) {\n  return CTimestamp(TimeVal(t) * resolution());\n}\n\nCTimestamp CTimestamp::fromUtcTime(UtcTimeVal val) {\n  val -= (TimeDiff(0x01b21dd2) << 32) + 0x13814000;\n  val /= 10;\n  return CTimestamp(val);\n}\n\nvoid CTimestamp::update() {\n#if defined(POCO_OS_FAMILY_WINDOWS)\n\n  FILETIME ft;\n  GetSystemTimeAsFileTime(&ft);\n  ULARGE_INTEGER epoch; // UNIX epoch (1970-01-01 00:00:00) expressed in Windows\n                        // NT FILETIME\n  epoch.LowPart = 0xD53E8000;\n  epoch.HighPart = 0x019DB1DE;\n\n  ULARGE_INTEGER ts;\n  ts.LowPart = ft.dwLowDateTime;\n  ts.HighPart = ft.dwHighDateTime;\n  ts.QuadPart -= epoch.QuadPart;\n  _ts = ts.QuadPart / 10;\n\n#else\n\n  struct timeval tv;\n  if (gettimeofday(&tv, NULL))\n    throw CSystemException(\"cannot get time of day\");\n  _ts = TimeVal(tv.tv_sec) * resolution() + tv.tv_usec;\n\n#endif\n}\n\n#if defined(_WIN32)\n\nCTimestamp CTimestamp::fromFileTimeNP(UInt32 fileTimeLow, UInt32 fileTimeHigh) {\n  ULARGE_INTEGER epoch; // UNIX epoch (1970-01-01 00:00:00) expressed in Windows\n                        // NT FILETIME\n  epoch.LowPart = 0xD53E8000;\n  epoch.HighPart = 0x019DB1DE;\n\n  ULARGE_INTEGER ts;\n  ts.LowPart = fileTimeLow;\n  ts.HighPart = fileTimeHigh;\n  ts.QuadPart -= epoch.QuadPart;\n\n  return CTimestamp(ts.QuadPart / 10);\n}\n\nvoid CTimestamp::toFileTimeNP(UInt32 &fileTimeLow, UInt32 &fileTimeHigh) const {\n  ULARGE_INTEGER epoch; // UNIX epoch (1970-01-01 00:00:00) expressed in Windows\n                        // NT FILETIME\n  epoch.LowPart = 0xD53E8000;\n  epoch.HighPart = 0x019DB1DE;\n\n  ULARGE_INTEGER ts;\n  ts.QuadPart = _ts * 10;\n  ts.QuadPart += epoch.QuadPart;\n  fileTimeLow = ts.LowPart;\n  fileTimeHigh = ts.HighPart;\n}\n\n#endif\n"
  },
  {
    "path": "src/base/Timestamp.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Timestamp.h\n//\n// $Id: Timestamp.h,v 1.1 2008/05/31 15:47:29 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: DateTime\n// Module:  Timestamp\n//\n// Definition of the Timestamp class.\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_Timestamp_INCLUDED\n#define Foundation_Timestamp_INCLUDED\n\n#include \"Foundation.hpp\"\n#include <ctime>\n\nclass CTimestamp\n/// A Timestamp stores a monotonic time value\n/// with (theoretical) microseconds resolution.\n/// Timestamps can be compared with each other\n/// and simple arithmetics are supported.\n/// Timestamps are UTC (Coordinated Universal Time)\n/// based and thus independent of the timezone\n/// in effect on the system.\n{\npublic:\n  typedef Int64 TimeVal; /// monotonic UTC time value in microsecond resolution\n  typedef Int64\n      UtcTimeVal; /// monotonic UTC time value in 100 nanosecond resolution\n  typedef Int64 TimeDiff; /// difference between two timestamps in microseconds\n\n  CTimestamp();\n  /// Creates a timestamp with the current time.\n\n  CTimestamp(TimeVal tv);\n  /// Creates a timestamp from the given time value.\n\n  CTimestamp(const CTimestamp &other);\n  /// Copy constructor.\n\n  ~CTimestamp();\n  /// Destroys the timestamp\n\n  CTimestamp &operator=(const CTimestamp &other);\n  CTimestamp &operator=(TimeVal tv);\n\n  void swap(CTimestamp &timestamp);\n  /// Swaps the Timestamp with another one.\n\n  void update();\n  /// Updates the Timestamp with the current time.\n\n  bool operator==(const CTimestamp &ts) const;\n  bool operator!=(const CTimestamp &ts) const;\n  bool operator>(const CTimestamp &ts) const;\n  bool operator>=(const CTimestamp &ts) const;\n  bool operator<(const CTimestamp &ts) const;\n  bool operator<=(const CTimestamp &ts) const;\n\n  CTimestamp operator+(TimeDiff d) const;\n  CTimestamp operator-(TimeDiff d) const;\n  TimeDiff operator-(const CTimestamp &ts) const;\n  CTimestamp &operator+=(TimeDiff d);\n  CTimestamp &operator-=(TimeDiff d);\n\n  std::time_t epochTime() const;\n  /// Returns the timestamp expressed in time_t.\n  /// time_t base time is midnight, January 1, 1970.\n  /// Resolution is one second.\n\n  UtcTimeVal utcTime() const;\n  /// Returns the timestamp expressed in UTC-based\n  /// time. UTC base time is midnight, October 15, 1582.\n  /// Resolution is 100 nanoseconds.\n\n  TimeVal epochMicroseconds() const;\n  /// Returns the timestamp expressed in microseconds\n  /// since the Unix epoch, midnight, January 1, 1970.\n\n  TimeDiff elapsed() const;\n  /// Returns the time elapsed since the time denoted by\n  /// the timestamp. Equivalent to Timestamp() - *this.\n\n  bool isElapsed(TimeDiff interval) const;\n  /// Returns true iff the given interval has passed\n  /// since the time denoted by the timestamp.\n\n  static CTimestamp fromEpochTime(std::time_t t);\n  /// Creates a timestamp from a std::time_t.\n\n  static CTimestamp fromUtcTime(UtcTimeVal val);\n  /// Creates a timestamp from a UTC time value.\n\n  static TimeVal resolution();\n  /// Returns the resolution in units per second.\n  /// Since the timestamp has microsecond resolution,\n  /// the returned value is always 1000000.\n\n#if defined(_WIN32)\n  static CTimestamp fromFileTimeNP(UInt32 fileTimeLow, UInt32 fileTimeHigh);\n  void toFileTimeNP(UInt32 &fileTimeLow, UInt32 &fileTimeHigh) const;\n#endif\n\nprivate:\n  TimeVal _ts;\n};\n\n//\n// inlines\n//\ninline bool CTimestamp::operator==(const CTimestamp &ts) const {\n  return _ts == ts._ts;\n}\n\ninline bool CTimestamp::operator!=(const CTimestamp &ts) const {\n  return _ts != ts._ts;\n}\n\ninline bool CTimestamp::operator>(const CTimestamp &ts) const {\n  return _ts > ts._ts;\n}\n\ninline bool CTimestamp::operator>=(const CTimestamp &ts) const {\n  return _ts >= ts._ts;\n}\n\ninline bool CTimestamp::operator<(const CTimestamp &ts) const {\n  return _ts < ts._ts;\n}\n\ninline bool CTimestamp::operator<=(const CTimestamp &ts) const {\n  return _ts <= ts._ts;\n}\n\ninline CTimestamp CTimestamp::operator+(CTimestamp::TimeDiff d) const {\n  return CTimestamp(_ts + d);\n}\n\ninline CTimestamp CTimestamp::operator-(CTimestamp::TimeDiff d) const {\n  return CTimestamp(_ts - d);\n}\n\ninline CTimestamp::TimeDiff CTimestamp::operator-(const CTimestamp &ts) const {\n  return _ts - ts._ts;\n}\n\ninline CTimestamp &CTimestamp::operator+=(CTimestamp::TimeDiff d) {\n  _ts += d;\n  return *this;\n}\n\ninline CTimestamp &CTimestamp::operator-=(CTimestamp::TimeDiff d) {\n  _ts -= d;\n  return *this;\n}\n\ninline std::time_t CTimestamp::epochTime() const {\n  return std::time_t(_ts / resolution());\n}\n\ninline CTimestamp::UtcTimeVal CTimestamp::utcTime() const {\n  return _ts * 10 + (TimeDiff(0x01b21dd2) << 32) + 0x13814000;\n}\n\ninline CTimestamp::TimeVal CTimestamp::epochMicroseconds() const { return _ts; }\n\ninline CTimestamp::TimeDiff CTimestamp::elapsed() const {\n  CTimestamp now;\n  return now - *this;\n}\n\ninline bool CTimestamp::isElapsed(CTimestamp::TimeDiff interval) const {\n  CTimestamp now;\n  CTimestamp::TimeDiff diff = now - *this;\n  return diff >= interval;\n}\n\ninline CTimestamp::TimeVal CTimestamp::resolution() { return 1000000; }\n\ninline void swap(CTimestamp &s1, CTimestamp &s2) { s1.swap(s2); }\n\n#endif // Foundation_Timestamp_INCLUDED\n"
  },
  {
    "path": "src/base/Types.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// Types.h\n//\n// $Id: Types.h,v 1.1 2008/05/31 15:47:29 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Core\n// Module:  Types\n//\n// Definitions of fixed-size integer types for various platforms\n//\n// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#ifndef Foundation_Types_INCLUDED\n#define Foundation_Types_INCLUDED\n\n#include \"Foundation.hpp\"\n\n#if defined(_MSC_VER)\n//\n// Windows/Visual C++\n//\ntypedef signed char Int8;\ntypedef unsigned char UInt8;\ntypedef signed short Int16;\ntypedef unsigned short UInt16;\ntypedef signed int Int32;\ntypedef unsigned int UInt32;\ntypedef signed __int64 Int64;\ntypedef unsigned __int64 UInt64;\n#if defined(_WIN64)\n#define POCO_PTR_IS_64_BIT 1\ntypedef signed __int64 IntPtr;\ntypedef unsigned __int64 UIntPtr;\n#else\ntypedef signed long IntPtr;\ntypedef unsigned long UIntPtr;\n#endif\n#define POCO_HAVE_INT64 1\n#elif defined(__GNUC__)\n//\n// Unix/GCC\n//\ntypedef signed char Int8;\ntypedef unsigned char UInt8;\ntypedef signed short Int16;\ntypedef unsigned short UInt16;\ntypedef signed int Int32;\ntypedef unsigned int UInt32;\ntypedef signed long IntPtr;\ntypedef unsigned long UIntPtr;\n#if defined(__LP64__)\n#define POCO_PTR_IS_64_BIT 1\n#define POCO_LONG_IS_64_BIT 1\ntypedef signed long Int64;\ntypedef unsigned long UInt64;\n#else\ntypedef signed long long Int64;\ntypedef unsigned long long UInt64;\n#endif\n#define POCO_HAVE_INT64 1\n#elif defined(__DECCXX)\n//\n// Compaq C++\n//\ntypedef signed char Int8;\ntypedef unsigned char UInt8;\ntypedef signed short Int16;\ntypedef unsigned short UInt16;\ntypedef signed int Int32;\ntypedef unsigned int UInt32;\ntypedef signed __int64 Int64;\ntypedef unsigned __int64 UInt64;\n#if defined(__VMS)\n#if defined(__32BITS)\ntypedef signed long IntPtr;\ntypedef unsigned long UIntPtr;\n#else\ntypedef Int64 IntPtr;\ntypedef UInt64 UIntPtr;\n#define POCO_PTR_IS_64_BIT 1\n#endif\n#else\ntypedef signed long IntPtr;\ntypedef unsigned long UIntPtr;\n#define POCO_PTR_IS_64_BIT 1\n#define POCO_LONG_IS_64_BIT 1\n#endif\n#define POCO_HAVE_INT64 1\n#elif defined(__HP_aCC)\n//\n// HP Ansi C++\n//\ntypedef signed char Int8;\ntypedef unsigned char UInt8;\ntypedef signed short Int16;\ntypedef unsigned short UInt16;\ntypedef signed int Int32;\ntypedef unsigned int UInt32;\ntypedef signed long IntPtr;\ntypedef unsigned long UIntPtr;\n#if defined(__LP64__)\n#define POCO_PTR_IS_64_BIT 1\n#define POCO_LONG_IS_64_BIT 1\ntypedef signed long Int64;\ntypedef unsigned long UInt64;\n#else\ntypedef signed long long Int64;\ntypedef unsigned long long UInt64;\n#endif\n#define POCO_HAVE_INT64 1\n#elif defined(__SUNPRO_CC)\n//\n// SUN Forte C++\n//\ntypedef signed char Int8;\ntypedef unsigned char UInt8;\ntypedef signed short Int16;\ntypedef unsigned short UInt16;\ntypedef signed int Int32;\ntypedef unsigned int UInt32;\ntypedef signed long IntPtr;\ntypedef unsigned long UIntPtr;\n#if defined(__sparcv9)\n#define POCO_PTR_IS_64_BIT 1\n#define POCO_LONG_IS_64_BIT 1\ntypedef signed long Int64;\ntypedef unsigned long UInt64;\n#else\ntypedef signed long long Int64;\ntypedef unsigned long long UInt64;\n#endif\n#define POCO_HAVE_INT64 1\n#elif defined(__IBMCPP__)\n//\n// IBM XL C++\n//\ntypedef signed char Int8;\ntypedef unsigned char UInt8;\ntypedef signed short Int16;\ntypedef unsigned short UInt16;\ntypedef signed int Int32;\ntypedef unsigned int UInt32;\ntypedef signed long IntPtr;\ntypedef unsigned long UIntPtr;\n#if defined(__64BIT__)\n#define POCO_PTR_IS_64_BIT 1\n#define POCO_LONG_IS_64_BIT 1\ntypedef signed long Int64;\ntypedef unsigned long UInt64;\n#else\ntypedef signed long long Int64;\ntypedef unsigned long long UInt64;\n#endif\n#define POCO_HAVE_INT64 1\n#elif defined(__sgi)\n//\n// MIPSpro C++\n//\ntypedef signed char Int8;\ntypedef unsigned char UInt8;\ntypedef signed short Int16;\ntypedef unsigned short UInt16;\ntypedef signed int Int32;\ntypedef unsigned int UInt32;\ntypedef signed long IntPtr;\ntypedef unsigned long UIntPtr;\n#if _MIPS_SZLONG == 64\n#define POCO_PTR_IS_64_BIT 1\n#define POCO_LONG_IS_64_BIT 1\ntypedef signed long Int64;\ntypedef unsigned long UInt64;\n#else\ntypedef signed long long Int64;\ntypedef unsigned long long UInt64;\n#endif\n#define POCO_HAVE_INT64 1\n#endif\n\n#endif // Foundation_Types_INCLUDED\n"
  },
  {
    "path": "src/base/UnWindows.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon the Poco C++ Libraries, which is Copyright (C)\n * 2004-2006, Applied Informatics Software Engineering GmbH. and Contributors.\n */\n\n//\n// UnWindows.h\n//\n// $Id: UnWindows.h,v 1.1 2008/05/31 15:47:30 iamcamiel Exp $\n//\n// Library: Foundation\n// Package: Core\n// Module:  UnWindows\n//\n// A wrapper around the \"Poco/UnWindows.h\" header file that #undef's some\n// of the macros for function names defined by \"Poco/UnWindows.h\" that\n// are a frequent source of conflicts (e.g., GetUserName).\n//\n// Remember, that most of the WIN32 API functions come in two variants,\n// an Unicode variant (e.g., GetUserNameA) and an ASCII variant (GetUserNameW).\n// There is also a macro (GetUserName) that's either defined to be the Unicode\n// name or the ASCII name, depending on whether the UNICODE macro is #define'd\n// or not. POCO always calls the Unicode or ASCII functions directly (depending\n// on whether POCO_WIN32_UTF8 is #define'd or not), so the macros are not\n// ignored.\n//\n// These macro definitions are a frequent case of problems and naming conflicts,\n// especially for C++ programmers. Say, you define a class with a member\n// function named GetUserName. Depending on whether \"Poco/UnWindows.h\" has been\n// included by a particular translation unit or not, this might be changed to\n// GetUserNameA/GetUserNameW, or not. While, due to naming conventions used,\n// this is less of a problem in POCO, some of the users of POCO might use a\n// different naming convention where this can become a problem.\n//\n// To disable the #undef's, compile POCO with the POCO_NO_UNWINDOWS macro\n// #define'd.\n//\n// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.\n// and Contributors.\n//\n// Permission is hereby granted, free of charge, to any person or organization\n// obtaining a copy of the software and accompanying documentation covered by\n// this license (the \"Software\") to use, reproduce, display, distribute,\n// execute, and transmit the Software, and to prepare derivative works of the\n// Software, and to permit third-parties to whom the Software is furnished to\n// do so, all subject to the following:\n//\n// The copyright notices in the Software and this entire statement, including\n// the above license grant, this restriction and the following disclaimer,\n// must be included in all copies of the Software, in whole or in part, and\n// all derivative works of the Software, unless such copies or derivative\n// works are solely in the form of machine-executable object code generated by\n// a source language processor.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n// DEALINGS IN THE SOFTWARE.\n//\n\n#include <windows.h>\n\n#if !defined(POCO_NO_UNWINDOWS)\n// A list of annoying macros to #undef.\n// Feel free to extend as required.\n#undef GetBinaryType\n#undef GetShortPathName\n#undef GetLongPathName\n#undef GetEnvironmentStrings\n#undef SetEnvironmentStrings\n#undef FreeEnvironmentStrings\n#undef FormatMessage\n#undef EncryptFile\n#undef DecryptFile\n#undef CreateMutex\n#undef OpenMutex\n#undef CreateEvent\n#undef OpenEvent\n#undef CreateSemaphore\n#undef OpenSemaphore\n#undef LoadLibrary\n#undef GetModuleFileName\n#undef CreateProcess\n#undef GetCommandLine\n#undef GetEnvironmentVariable\n#undef SetEnvironmentVariable\n#undef ExpandEnvironmentStrings\n#undef OutputDebugString\n#undef FindResource\n#undef UpdateResource\n#undef FindAtom\n#undef AddAtom\n#undef GetSystemDirector\n#undef GetTempPath\n#undef GetTempFileName\n#undef SetCurrentDirectory\n#undef GetCurrentDirectory\n#undef CreateDirectory\n#undef RemoveDirectory\n#undef CreateFile\n#undef DeleteFile\n#undef SearchPath\n#undef CopyFile\n#undef MoveFile\n#undef ReplaceFile\n#undef GetComputerName\n#undef SetComputerName\n#undef GetUserName\n#undef LogonUser\n#undef GetVersion\n#undef GetObject\n#endif // POCO_NO_UNWINDOWS\n"
  },
  {
    "path": "src/config.hpp.in",
    "content": "/* Define to 1 if you have the `alarm' function. */\n#cmakedefine HAVE_ALARM\n\n/* Define to 1 if you have the <arpa/inet.h> header file. */\n#cmakedefine HAVE_ARPA_INET_H\n\n/* Define to 1 if you have the <arpa/telnet.h> header file. */\n#cmakedefine HAVE_ARPA_TELNET_H\n\n/* Define to 1 if you have the `atexit' function. */\n#cmakedefine HAVE_ATEXIT\n\n/* Define to 1 if you have the <ctype.h> header file. */\n#cmakedefine HAVE_CTYPE_H\n\n/* Define to 1 if you have the <errno.h> header file. */\n#cmakedefine HAVE_ERRNO_H\n\n/* Define to 1 if you have large file support */\n#cmakedefine HAVE_LARGE_FILES\n\n/* Define to 1 if you have large file support */\n#cmakedefine _LARGEFILE_SOURCE\n\n/* Define to 1 if you have large file support */\n#cmakedefine _LARGE_FILES\n\n/* Define to 64 if you have large file support */\n#cmakedefine _FILE_OFFSET_BITS @_FILE_OFFSET_BITS@\n\n/* Define to 1 if you have large file support */\n#cmakedefine AXPBOX_HAVE_FSEEKO @AXPBOX_HAVE_FSEEKO@\n\n/* Define to 1 if you have the <fcntl.h> header file. */\n#cmakedefine HAVE_FCNTL_H\n\n/* Define to 1 if you have the `fopen' function. */\n#cmakedefine HAVE_FOPEN\n\n/* Define to 1 if you have the `fopen64' function. */\n#cmakedefine HAVE_FOPEN64\n\n/* Define to 1 if you have the `fork' function. */\n#cmakedefine HAVE_FORK\n\n/* Define to 1 if you have the `fseek' function. */\n#cmakedefine HAVE_FSEEK\n\n/* Define to 1 if you have the `fseeko' function. */\n#cmakedefine HAVE_FSEEKO\n\n/* Define to 1 if you have the `fseeko64' function. */\n#cmakedefine HAVE_FSEEKO64\n\n/* Define to 1 if you have the `ftell' function. */\n#cmakedefine HAVE_FTELL\n\n/* Define to 1 if you have the `ftello' function. */\n#cmakedefine HAVE_FTELLO\n\n/* Define to 1 if you have the `ftello64' function. */\n#cmakedefine HAVE_FTELLO64\n\n/* Define to 1 if you have the `gmtime_s' function. */\n#cmakedefine HAVE_GMTIME_S\n\n/* Define to 1 if you have the `localtime_s' function. */\n#cmakedefine HAVE_LOCALTIME_S\n\n/* Define to 1 if you have the `inet_aton' function. */\n#cmakedefine HAVE_INET_ATON\n\n/* Define to 1 if you have the <inet.h> header file. */\n#cmakedefine HAVE_INET_H\n\n/* Define to 1 if you have the <inttypes.h> header file. */\n#cmakedefine HAVE_INTTYPES_H\n\n/* Define to 1 if you have the <in.h> header file. */\n#cmakedefine HAVE_IN_H\n\n/* Define to 1 if you have the `isblank' function. */\n#cmakedefine HAVE_ISBLANK\n\n/* Define to 1 if your system has a GNU libc compatible `malloc' function, and\n   to 0 otherwise. */\n#cmakedefine HAVE_MALLOC\n\n/* Define to 1 if you have the <malloc.h> header file. */\n#cmakedefine HAVE_MALLOC_H\n\n/* Define to 1 if you have the <memory.h> header file. */\n#cmakedefine HAVE_MEMORY_H\n\n/* Define to 1 if you have the `memset' function. */\n#cmakedefine HAVE_MEMSET\n\n/* Define to 1 if you have the <netinet/in.h> header file. */\n#cmakedefine HAVE_NETINET_IN_H\n\n/* Define to 1 if you have the `pow' function. */\n#cmakedefine HAVE_POW\n\n/* Define to 1 if you have the <process.h> header file. */\n#cmakedefine HAVE_PROCESS_H\n\n/* Define if you have POSIX threads libraries and header files. */\n#cmakedefine HAVE_PTHREAD\n\n/* Define to 1 if you have the <pthread.h> header file. */\n#cmakedefine HAVE_PTHREAD_H\n\n/* Define to 1 if your system has a GNU libc compatible `realloc' function,\n   and to 0 otherwise. */\n#cmakedefine HAVE_REALLOC\n\n/* Define to 1 if you have the `select' function. */\n#cmakedefine HAVE_SELECT\n\n/* Define to 1 if you have the <signal.h> header file. */\n#cmakedefine HAVE_SIGNAL_H\n\n/* Define to 1 if you have the `socket' function. */\n#cmakedefine HAVE_SOCKET\n\n/* Define to 1 if you have the <socket.h> header file. */\n#cmakedefine HAVE_SOCKET_H\n\n/* Define to 1 if you have the `sqrt' function. */\n#cmakedefine HAVE_SQRT\n\n/* Define to 1 if stdbool.h conforms to C99. */\n#cmakedefine HAVE_STDBOOL_H\n\n/* Define to 1 if you have the <stdint.h> header file. */\n#cmakedefine HAVE_STDINT_H\n\n/* Define to 1 if you have the <stdlib.h> header file. */\n#cmakedefine HAVE_STDLIB_H\n\n/* Define to 1 if you have the `strcasecmp' function. */\n#cmakedefine HAVE_STRCASECMP\n\n/* Define to 1 if you have the `strchr' function. */\n#cmakedefine HAVE_STRCHR\n\n/* Define to 1 if you have the `strdup' function. */\n#cmakedefine HAVE_STRDUP\n\n/* Define to 1 if you have the <stddef.h> header file. */\n#cmakedefine HAVE_STDDEF_H\n\n/* Define to 1 if you have the <strings.h> header file. */\n#cmakedefine HAVE_STRINGS_H\n\n/* Define to 1 if you have the <string.h> header file. */\n#cmakedefine HAVE_STRING_H\n\n/* Define to 1 if you have the `strncasecmp' function. */\n#cmakedefine HAVE_STRNCASECMP\n\n/* Define to 1 if you have the `strspn' function. */\n#cmakedefine HAVE_STRSPN\n\n/* Define to 1 if you have the <sys/param.h> header file. */\n#cmakedefine HAVE_SYS_PARAM_H\n\n/* Define to 1 if you have the <sys/select.h> header file. */\n#cmakedefine HAVE_SYS_SELECT_H\n\n/* Define to 1 if you have the <sys/socket.h> header file. */\n#cmakedefine HAVE_SYS_SOCKET_H\n\n/* Define to 1 if you have the <sys/stat.h> header file. */\n#cmakedefine HAVE_SYS_STAT_H\n\n/* Define to 1 if you have the <sys/time.h> header file. */\n#cmakedefine HAVE_SYS_TIME_H\n\n/* Define to 1 if you have the <sys/types.h> header file. */\n#cmakedefine HAVE_SYS_TYPES_H\n\n/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */\n#cmakedefine HAVE_SYS_WAIT_H\n\n/* Define to 1 if you have the <unistd.h> header file. */\n#cmakedefine HAVE_UNISTD_H\n\n/* Define to 1 if you have the `vfork' function. */\n#cmakedefine HAVE_VFORK\n\n/* Define to 1 if you have the <vfork.h> header file. */\n#cmakedefine HAVE_VFORK_H\n\n/* Define to 1 if you have the <windows.h> header file. */\n#cmakedefine HAVE_WINDOWS_H\n\n/* Define to 1 if you have the <winsock2.h> header file. */\n#cmakedefine HAVE_WINSOCK2_H\n\n/* Define to 1 if `fork' works. */\n#cmakedefine HAVE_WORKING_FORK\n\n/* Define to 1 if `vfork' works. */\n#cmakedefine HAVE_WORKING_VFORK\n\n/* Define to 1 if you have the <ws2tcpip.h> header file. */\n#cmakedefine HAVE_WS2TCPIP_H\n\n/* Define to 1 if the system has the type `_Bool'. */\n#cmakedefine HAVE__BOOL\n\n/* Define to 1 if you have the `_fseeki64' function. */\n#cmakedefine HAVE__FSEEKI64\n\n/* Define to 1 if you have the `_ftelli64' function. */\n#cmakedefine HAVE__FTELLI64\n\n/* Define to 1 if you have the `_strdup' function. */\n#cmakedefine HAVE__STRDUP\n\n/* Define to 1 if you have the `_stricasecmp' function. */\n#cmakedefine HAVE__STRICASECMP\n\n/* Define to 1 if you have the `_stricmp' function. */\n#cmakedefine HAVE__STRICMP\n\n/* Name of package */\n#cmakedefine PACKAGE @PACKAGE@\n\n/* Define to the address where bug reports for this package should be sent. */\n#cmakedefine PACKAGE_BUGREPORT @PACKAGE_BUGREPORT@\n\n/* Define to the full name of this package. */\n#cmakedefine PACKAGE_NAME @PACKAGE_NAME@\n\n/* Define to the full name and version of this package. */\n#cmakedefine PACKAGE_STRING @PACKAGE_STRING@\n\n/* Define to the one symbol short name of this package. */\n#cmakedefine PACKAGE_TARNAME @PACKAGE_TARNAME@\n\n/* Define to the home page for this package. */\n#cmakedefine PACKAGE_URL @PACKAGE_URL@\n\n/* Define to the version of this package. */\n#cmakedefine PACKAGE_VERSION @PACKAGE_VERSION@\n\n/* Define to the git revision of this package. */\n#cmakedefine PACKAGE_GITSHA @PACKAGE_GITSHA@\n\n\n/* Define to necessary symbol if this constant uses a non-standard name on\n   your system. */\n#cmakedefine PTHREAD_CREATE_JOINABLE @PTHREAD_CREATE_JOINABLE@\n\n/* Define as the return type of signal handlers (`int' or `void'). */\n#cmakedefine RETSIGTYPE @RETSIGTYPE@\n\n/* Define to the type of arg 1 for `select'. */\n#cmakedefine SELECT_TYPE_ARG1 @SELECT_TYPE_ARG1@\n\n/* Define to the type of args 2, 3 and 4 for `select'. */\n#cmakedefine SELECT_TYPE_ARG234 @SELECT_TYPE_ARG234@\n\n/* Define to the type of arg 5 for `select'. */\n#cmakedefine SELECT_TYPE_ARG5 @SELECT_TYPE_ARG5@\n\n/* Define to 1 if you have the ANSI C header files. */\n#cmakedefine STDC_HEADERS\n\n/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */\n#cmakedefine TIME_WITH_SYS_TIME\n\n/* Define to 1 if your <sys/time.h> declares `struct tm'. */\n#cmakedefine TM_IN_SYS_TIME\n\n/* Optional features */\n#cmakedefine HAVE_PCAP\n#cmakedefine HAVE_SDL\n#cmakedefine HAVE_X11\n\n/* Version number of package */\n#cmakedefine VERSION @PACKAGE_VERSION@\n\n/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,\n   <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the\n   #define below would cause a syntax error. */\n#cmakedefine _UINT32_T\n\n/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,\n   <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the\n   #define below would cause a syntax error. */\n#cmakedefine _UINT64_T\n\n/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,\n   <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the\n   #define below would cause a syntax error. */\n#cmakedefine _UINT8_T\n\n/* Define to empty if `const' does not conform to ANSI C. */\n#cmakedefine const\n\n/* Define to `__inline__' or `__inline' if that's what the C compiler\n   calls it, or to nothing if 'inline' is not supported under any name.  */\n#ifndef __cplusplus\n#cmakedefine inline\n#endif\n\n/* Define to the type of a signed integer type of width exactly 16 bits if\n   such a type exists and the standard includes do not define it. */\n#cmakedefine int16_t\n\n/* Define to the type of a signed integer type of width exactly 32 bits if\n   such a type exists and the standard includes do not define it. */\n#cmakedefine int32_t\n\n/* Define to the type of a signed integer type of width exactly 64 bits if\n   such a type exists and the standard includes do not define it. */\n#cmakedefine int64_t\n\n/* Define to the type of a signed integer type of width exactly 8 bits if such\n   a type exists and the standard includes do not define it. */\n#cmakedefine int8_t\n\n/* Define to rpl_malloc if the replacement function should be used. */\n#cmakedefine malloc\n\n/* Define to `int' if <sys/types.h> does not define. */\n#cmakedefine pid_t\n\n/* Define to rpl_realloc if the replacement function should be used. */\n#cmakedefine realloc\n\n/* Define to `unsigned int' if <sys/types.h> does not define. */\n#cmakedefine size_t\n\n/* Define to `int' if <sys/types.h> does not define. */\n#cmakedefine ssize_t\n\n/* Define to the type of an unsigned integer type of width exactly 16 bits if\n   such a type exists and the standard includes do not define it. */\n#cmakedefine uint16_t\n\n/* Define to the type of an unsigned integer type of width exactly 32 bits if\n   such a type exists and the standard includes do not define it. */\n#cmakedefine uint32_t\n\n/* Define to the type of an unsigned integer type of width exactly 64 bits if\n   such a type exists and the standard includes do not define it. */\n#cmakedefine uint64_t\n\n/* Define to the type of an unsigned integer type of width exactly 8 bits if\n   such a type exists and the standard includes do not define it. */\n#cmakedefine uint8_t\n\n/* Define as `fork' if `vfork' does not work. */\n#cmakedefine vfork\n\n/* Define if system is little endian */\n#cmakedefine ES40_LITTLE_ENDIAN\n\n/* Define if system is big endian */\n#cmakedefine ES40_BIG_ENDIAN\n"
  },
  {
    "path": "src/config_debug.hpp",
    "content": "// This is config_debug.h\n//\n// This file contains the debug configuration options.\n// This file was generated by configure_1.sh\n//\n// $Id: config_debug.h,v 1.5 2010/03/11 22:44:13 iamcamiel Exp $\n\n// Define to 1 if you want to show the cycle counter\n#define HIDE_COUNTER 1\n\n// Define to 1 if you want to show estimate speed\n#undef MIPS_ESTIMATE\n\n// Define to 1 if you want to show memory map\n#undef DUMP_MEMMAP\n\n// Define to 1 if you want to check for overlapping of memory ranges\n#define CHECK_MEM_RANGES 1\n\n// Define to 1 if you want to use the new floating-point implementation\n#undef HAVE_NEW_FP\n\n// Define to 1 if you want to enable VGA debugging\n#undef DEBUG_VGA\n\n// Define to 1 if you want to enable Serial Port debugging\n#undef DEBUG_SERIAL\n\n// Define to 1 if you want to enable IDE General debugging\n#undef DEBUG_IDE\n\n// Define to 1 if you want to enable IDE Busmaster debugging\n#undef DEBUG_IDE_BUSMASTER\n\n// Define to 1 if you want to enable IDE Command debugging\n#undef DEBUG_IDE_COMMAND\n\n// Define to 1 if you want to enable IDE CMD debugging\n#undef DEBUG_IDE_CMD\n\n// Define to 1 if you want to enable IDE DMA debugging\n#undef DEBUG_IDE_DMA\n\n// Define to 1 if you want to enable IDE Interrupt debugging\n#undef DEBUG_IDE_INTERRUPT\n\n// Define to 1 if you want to enable IDE Command Register debugging\n#undef DEBUG_IDE_REG_COMMAND\n\n// Define to 1 if you want to enable IDE Control Register debugging\n#undef DEBUG_IDE_REG_CONTROL\n\n// Define to 1 if you want to enable IDE ATAPI Packet debugging\n#undef DEBUG_IDE_PACKET\n\n// Define to 1 if you want to enable IDE Thread debugging\n#undef DEBUG_IDE_THREADS\n\n// Define to 1 if you want to enable IDE Mutexes debugging\n#undef DEBUG_IDE_LOCKS\n\n// Define to 1 if you want to enable IDE Multiple debugging\n#undef DEBUG_IDE_MULTIPLE\n\n// Define to 1 if you want to enable Floating Point conversions debugging\n#undef DEBUG_FP_CONVERSION\n\n// Define to 1 if you want to enable Floating Point load/store debugging\n#undef DEBUG_FP_LOADSTORE\n\n// Define to 1 if you want to enable General NIC debugging\n#undef DEBUG_NIC\n\n// Define to 1 if you want to enable NIC Filter debugging\n#undef DEBUG_NIC_FILTER\n\n// Define to 1 if you want to enable NIC Serial ROM debugging\n#undef DEBUG_NIC_SROM\n\n// Define to 1 if you want to enable unknown memory access debugging\n#undef DEBUG_UNKMEM\n\n// Define to 1 if you want to enable PCI debugging\n#undef DEBUG_PCI\n\n// Define to 1 if you want to enable Translationbuffer debugging\n#undef DEBUG_TB\n\n// Define to 1 if you want to enable I/O Port Access debugging\n#undef DEBUG_PORTACCESS\n\n// Define to 1 if you want to enable Keyboard debugging\n#undef DEBUG_KBD\n\n// Define to 1 if you want to enable Programmable Interrupt Controller (PIC)\n// debugging\n#undef DEBUG_PIC\n\n// Define to 1 if you want to enable Printer port debugging\n#undef DEBUG_LPT\n\n// Define to 1 if you want to enable USB Controller debugging\n#undef DEBUG_USB\n\n// Define to 1 if you want to enable SCSI Device debugging\n#undef DEBUG_SCSI\n\n// Define to 1 if you want to enable Symbios SCSI Controller debugging\n#undef DEBUG_SYM\n\n// Define to 1 if you want to enable Symbios Registers debugging\n#undef DEBUG_SYM_REGS\n\n// Define to 1 if you want to enable Symbios SCRIPTS Execution debugging\n#undef DEBUG_SYM_SCRIPTS\n\n// Define to 1 if you want to enable DMA Controller debugging\n#undef DEBUG_DMA\n\n// Define to 1 if you want to enable backtrace on SIGSEGV debugging\n#undef DEBUG_BACKTRACE\n\n// Define to 1 if you want to enable mutex debugging\n#undef DEBUG_LOCKS\n\n// Define to 1 if you want to enable SDL Key translation debugging\n#undef DEBUG_SDL_KEY\n"
  },
  {
    "path": "src/cpu_arith.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n/* comparison */\n#define DO_CMPEQ RCV = (RAV == RBV) ? 1 : 0;\n#define DO_CMPLT RCV = ((s64)RAV < (s64)RBV) ? 1 : 0;\n#define DO_CMPLE RCV = ((s64)RAV <= (s64)RBV) ? 1 : 0;\n\n/* addition */\n#define DO_ADDQ RCV = RAV + RBV;\n#define DO_S4ADDQ RCV = (RAV * 4) + RBV;\n#define DO_S8ADDQ RCV = (RAV * 8) + RBV;\n\n#define DO_ADDQ_V                                                              \\\n  {                                                                            \\\n    u64 rav = RAV;                                                             \\\n    u64 rbv = RBV;                                                             \\\n    RCV = rav + rbv;                                                           \\\n                                                                               \\\n    /* test for integer overflow */                                            \\\n    if (((~rav ^ rbv) & (rav ^ RCV)) & Q_SIGN) {                               \\\n      ARITH_TRAP_I(TRAP_IOV, RC);                                              \\\n      printf(\"ADDQ_V %016\" PRIu64 \"x + %016\" PRIu64 \"x = %016\" PRIu64          \\\n             \"x + TRAP.\\n\",                                                    \\\n             rav, rbv, RCV);                                                   \\\n    }                                                                          \\\n  }\n\n#define DO_ADDL RCV = sext_u64_32(RAV + RBV);\n#define DO_S4ADDL RCV = sext_u64_32((RAV * 4) + RBV);\n#define DO_S8ADDL RCV = sext_u64_32((RAV * 8) + RBV);\n\n#define DO_ADDL_V                                                              \\\n  {                                                                            \\\n    u64 rav = RAV;                                                             \\\n    u64 rbv = RBV;                                                             \\\n    RCV = sext_u64_32(rav + rbv);                                              \\\n                                                                               \\\n    /* test for integer overflow */                                            \\\n    if (((~rav ^ rbv) & (rav ^ RCV)) & L_SIGN) {                               \\\n      ARITH_TRAP_I(TRAP_IOV, RC);                                              \\\n      printf(\"ADDL_V %016\" PRIu64 \"x + %016\" PRIu64 \"x = %016\" PRIu64          \\\n             \"x + TRAP.\\n\",                                                    \\\n             rav, rbv, RCV);                                                   \\\n    }                                                                          \\\n  }\n\n#define DO_CTLZ                                                                \\\n  temp_64 = 0;                                                                 \\\n  temp_64_2 = RBV;                                                             \\\n  for (i = 63; i >= 0; i--)                                                    \\\n    if ((temp_64_2 >> i) & 1)                                                  \\\n      break;                                                                   \\\n    else                                                                       \\\n      temp_64++;                                                               \\\n  RCV = temp_64;\n\n#define DO_CTPOP                                                               \\\n  temp_64 = 0;                                                                 \\\n  temp_64_2 = RBV;                                                             \\\n  for (i = 0; i < 64; i++)                                                     \\\n    if ((temp_64_2 >> i) & 1)                                                  \\\n      temp_64++;                                                               \\\n  RCV = temp_64;\n\n#define DO_CTTZ                                                                \\\n  temp_64 = 0;                                                                 \\\n  temp_64_2 = RBV;                                                             \\\n  for (i = 0; i < 64; i++)                                                     \\\n    if ((temp_64_2 >> i) & 1)                                                  \\\n      break;                                                                   \\\n    else                                                                       \\\n      temp_64++;                                                               \\\n  RCV = temp_64;\n\n#define DO_CMPULT RCV = ((u64)RAV < (u64)RBV) ? 1 : 0;\n#define DO_CMPULE RCV = ((u64)RAV <= (u64)RBV) ? 1 : 0;\n\n/* multiplication */\n#define DO_MULL RCV = sext_u64_32(sext_u64_32(RAV) * sext_u64_32(RBV));\n\n#define DO_MULL_V                                                              \\\n  {                                                                            \\\n    u64 rav = RAV;                                                             \\\n    u64 rbv = RBV;                                                             \\\n    u64 sr = sext_u64_32(rav) * sext_u64_32(rbv);                              \\\n    RCV = sext_u64_32(sr);                                                     \\\n    if ((RCV ^ sr) & U64(0xffffffff00000000)) {                                \\\n      ARITH_TRAP_I(TRAP_IOV, RC);                                              \\\n      printf(\"MULL_V %016\" PRIu64 \"x * %016\" PRIu64 \"x = %016\" PRIu64          \\\n             \"x + TRAP.\\n\",                                                    \\\n             rav, rbv, RCV);                                                   \\\n    }                                                                          \\\n  }\n\n#define DO_MULQ RCV = RAV * RBV;\n\n#define DO_MULQ_V                                                              \\\n  {                                                                            \\\n    u64 rav = RAV;                                                             \\\n    u64 rbv = RBV;                                                             \\\n    u64 t64;                                                                   \\\n    RCV = uemul64(rav, rbv, &t64);                                             \\\n    if (Q_GETSIGN(rav))                                                        \\\n      t64 -= rbv;                                                              \\\n    if (Q_GETSIGN(rbv))                                                        \\\n      t64 -= rav;                                                              \\\n    if (Q_GETSIGN(RCV) ? (t64 != X64_QUAD) : (t64 != 0)) {                     \\\n      ARITH_TRAP_I(TRAP_IOV, RC);                                              \\\n      printf(\"MULQ_V %016\" PRIu64 \"x * %016\" PRIu64 \"x = %016\" PRIu64          \\\n             \"x + TRAP.\\n\",                                                    \\\n             rav, rbv, RCV);                                                   \\\n    }                                                                          \\\n  }\n\n#define DO_UMULH uemul64(RAV, RBV, &RCV);\n\n/* subtraction */\n#define DO_SUBQ RCV = RAV - RBV;\n#define DO_S4SUBQ RCV = (RAV * 4) - RBV;\n#define DO_S8SUBQ RCV = (RAV * 8) - RBV;\n\n#define DO_SUBQ_V                                                              \\\n  {                                                                            \\\n    u64 rav = RAV;                                                             \\\n    u64 rbv = RBV;                                                             \\\n    RCV = rav - rbv;                                                           \\\n                                                                               \\\n    /* test for integer overflow */                                            \\\n    if (((rav ^ rbv) & (rav ^ RCV)) & Q_SIGN) {                                \\\n      ARITH_TRAP_I(TRAP_IOV, RC);                                              \\\n      printf(\"SUBQ_V %016\" PRIu64 \"x - %016\" PRIu64 \"x = %016\" PRIu64          \\\n             \"x + TRAP.\\n\",                                                    \\\n             rav, rbv, RCV);                                                   \\\n    }                                                                          \\\n  }\n\n#define DO_SUBL RCV = sext_u64_32(RAV - RBV);\n#define DO_S4SUBL RCV = sext_u64_32((RAV * 4) - RBV);\n#define DO_S8SUBL RCV = sext_u64_32((RAV * 8) - RBV);\n\n#define DO_SUBL_V                                                              \\\n  {                                                                            \\\n    u64 rav = RAV;                                                             \\\n    u64 rbv = RBV;                                                             \\\n    RCV = sext_u64_32(rav - rbv);                                              \\\n                                                                               \\\n    /* test for integer overflow */                                            \\\n    if (((rav ^ rbv) & (rav ^ RCV)) & L_SIGN) {                                \\\n      ARITH_TRAP_I(TRAP_IOV, RC);                                              \\\n      printf(\"SUBL_V %016\" PRIu64 \"x - %016\" PRIu64 \"x = %016\" PRIu64          \\\n             \"x + TRAP.\\n\",                                                    \\\n             rav, rbv, RCV);                                                   \\\n    }                                                                          \\\n  }\n"
  },
  {
    "path": "src/cpu_bwx.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#define DO_CMPBGE                                                              \\\n  state.r[REG_3] =                                                             \\\n      (((u8)(state.r[REG_1] & 0xff) >= (u8)(V_2 & 0xff)) ? 1 : 0) |            \\\n      (((u8)((state.r[REG_1] >> 8) & 0xff) >= (u8)((V_2 >> 8) & 0xff)) ? 2     \\\n                                                                       : 0) |  \\\n      (((u8)((state.r[REG_1] >> 16) & 0xff) >= (u8)((V_2 >> 16) & 0xff))       \\\n           ? 4                                                                 \\\n           : 0) |                                                              \\\n      (((u8)((state.r[REG_1] >> 24) & 0xff) >= (u8)((V_2 >> 24) & 0xff))       \\\n           ? 8                                                                 \\\n           : 0) |                                                              \\\n      (((u8)((state.r[REG_1] >> 32) & 0xff) >= (u8)((V_2 >> 32) & 0xff))       \\\n           ? 16                                                                \\\n           : 0) |                                                              \\\n      (((u8)((state.r[REG_1] >> 40) & 0xff) >= (u8)((V_2 >> 40) & 0xff))       \\\n           ? 32                                                                \\\n           : 0) |                                                              \\\n      (((u8)((state.r[REG_1] >> 48) & 0xff) >= (u8)((V_2 >> 48) & 0xff))       \\\n           ? 64                                                                \\\n           : 0) |                                                              \\\n      (((u8)((state.r[REG_1] >> 56) & 0xff) >= (u8)((V_2 >> 56) & 0xff)) ? 128 \\\n                                                                         : 0);\n\n#define DO_EXTBL                                                               \\\n  state.r[REG_3] = (state.r[REG_1] >> ((V_2 & 7) * 8)) & X64_BYTE;\n#define DO_EXTWL                                                               \\\n  state.r[REG_3] = (state.r[REG_1] >> ((V_2 & 7) * 8)) & X64_WORD;\n#define DO_EXTLL                                                               \\\n  state.r[REG_3] = (state.r[REG_1] >> ((V_2 & 7) * 8)) & X64_LONG;\n#define DO_EXTQL state.r[REG_3] = (state.r[REG_1] >> ((V_2 & 7) * 8));\n#define DO_EXTWH                                                               \\\n  state.r[REG_3] = (state.r[REG_1] << ((64 - ((V_2 & 7) * 8)) & 63)) & X64_WORD;\n#define DO_EXTLH                                                               \\\n  state.r[REG_3] = (state.r[REG_1] << ((64 - ((V_2 & 7) * 8)) & 63)) & X64_LONG;\n#define DO_EXTQH                                                               \\\n  state.r[REG_3] = (state.r[REG_1] << ((64 - ((V_2 & 7) * 8)) & 63)) & X64_QUAD;\n\n#define DO_INSBL                                                               \\\n  state.r[REG_3] = (state.r[REG_1] & X64_BYTE) << ((V_2 & 7) * 8);\n#define DO_INSWL                                                               \\\n  state.r[REG_3] = (state.r[REG_1] & X64_WORD) << ((V_2 & 7) * 8);\n#define DO_INSLL                                                               \\\n  state.r[REG_3] = (state.r[REG_1] & X64_LONG) << ((V_2 & 7) * 8);\n#define DO_INSQL state.r[REG_3] = (state.r[REG_1]) << ((V_2 & 7) * 8);\n#define DO_INSWH                                                               \\\n  state.r[REG_3] =                                                             \\\n      (V_2 & 7)                                                                \\\n          ? ((state.r[REG_1] & X64_WORD) >> ((64 - ((V_2 & 7) * 8)) & 63))     \\\n          : 0;\n#define DO_INSLH                                                               \\\n  state.r[REG_3] =                                                             \\\n      (V_2 & 7)                                                                \\\n          ? ((state.r[REG_1] & X64_LONG) >> ((64 - ((V_2 & 7) * 8)) & 63))     \\\n          : 0;\n#define DO_INSQH                                                               \\\n  state.r[REG_3] =                                                             \\\n      (V_2 & 7)                                                                \\\n          ? ((state.r[REG_1] & X64_QUAD) >> ((64 - ((V_2 & 7) * 8)) & 63))     \\\n          : 0;\n\n#define DO_MSKBL                                                               \\\n  state.r[REG_3] = state.r[REG_1] & ~(X64_BYTE << ((V_2 & 7) * 8));\n#define DO_MSKWL                                                               \\\n  state.r[REG_3] = state.r[REG_1] & ~(X64_WORD << ((V_2 & 7) * 8));\n#define DO_MSKLL                                                               \\\n  state.r[REG_3] = state.r[REG_1] & ~(X64_LONG << ((V_2 & 7) * 8));\n#define DO_MSKQL                                                               \\\n  state.r[REG_3] = state.r[REG_1] & ~(X64_QUAD << ((V_2 & 7) * 8));\n#define DO_MSKWH                                                               \\\n  state.r[REG_3] =                                                             \\\n      (V_2 & 7)                                                                \\\n          ? (state.r[REG_1] & ~(X64_WORD >> ((64 - ((V_2 & 7) * 8)) & 63)))    \\\n          : state.r[REG_1];\n#define DO_MSKLH                                                               \\\n  state.r[REG_3] =                                                             \\\n      (V_2 & 7)                                                                \\\n          ? (state.r[REG_1] & ~(X64_LONG >> ((64 - ((V_2 & 7) * 8)) & 63)))    \\\n          : state.r[REG_1];\n#define DO_MSKQH                                                               \\\n  state.r[REG_3] =                                                             \\\n      (V_2 & 7)                                                                \\\n          ? (state.r[REG_1] & ~(X64_QUAD >> ((64 - ((V_2 & 7) * 8)) & 63)))    \\\n          : state.r[REG_1];\n\n#define DO_SEXTB state.r[REG_3] = sext_u64_8(V_2);\n#define DO_SEXTW state.r[REG_3] = sext_u64_16(V_2);\n\n#define DO_ZAP                                                                 \\\n  state.r[REG_3] =                                                             \\\n      state.r[REG_1] &                                                         \\\n      (((V_2 & 1) ? 0 : U64(0xff)) | ((V_2 & 2) ? 0 : U64(0xff00)) |           \\\n       ((V_2 & 4) ? 0 : U64(0xff0000)) | ((V_2 & 8) ? 0 : U64(0xff000000)) |   \\\n       ((V_2 & 16) ? 0 : U64(0xff00000000)) |                                  \\\n       ((V_2 & 32) ? 0 : U64(0xff0000000000)) |                                \\\n       ((V_2 & 64) ? 0 : U64(0xff000000000000)) |                              \\\n       ((V_2 & 128) ? 0 : U64(0xff00000000000000)));\n\n#define DO_ZAPNOT                                                              \\\n  state.r[REG_3] =                                                             \\\n      state.r[REG_1] &                                                         \\\n      (((V_2 & 1) ? U64(0xff) : 0) | ((V_2 & 2) ? U64(0xff00) : 0) |           \\\n       ((V_2 & 4) ? U64(0xff0000) : 0) | ((V_2 & 8) ? U64(0xff000000) : 0) |   \\\n       ((V_2 & 16) ? U64(0xff00000000) : 0) |                                  \\\n       ((V_2 & 32) ? U64(0xff0000000000) : 0) |                                \\\n       ((V_2 & 64) ? U64(0xff000000000000) : 0) |                              \\\n       ((V_2 & 128) ? U64(0xff00000000000000) : 0));\n"
  },
  {
    "path": "src/cpu_control.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#define DO_BEQ                                                                 \\\n  if (!state.r[REG_1])                                                         \\\n    add_pc(DISP_21 * 4);\n\n#define DO_BGE                                                                 \\\n  if ((s64)state.r[REG_1] >= 0)                                                \\\n    add_pc(DISP_21 * 4);\n\n#define DO_BGT                                                                 \\\n  if ((s64)state.r[REG_1] > 0)                                                 \\\n    add_pc(DISP_21 * 4);\n\n#define DO_BLBC                                                                \\\n  if (!(state.r[REG_1] & 1))                                                   \\\n    add_pc(DISP_21 * 4);\n\n#define DO_BLBS                                                                \\\n  if (state.r[REG_1] & 1)                                                      \\\n    add_pc(DISP_21 * 4);\n\n#define DO_BLE                                                                 \\\n  if ((s64)state.r[REG_1] <= 0)                                                \\\n    add_pc(DISP_21 * 4);\n\n#define DO_BLT                                                                 \\\n  if ((s64)state.r[REG_1] < 0)                                                 \\\n    add_pc(DISP_21 * 4);\n\n#define DO_BNE                                                                 \\\n  if (state.r[REG_1])                                                          \\\n    add_pc(DISP_21 * 4);\n\n#define DO_BR                                                                  \\\n  {                                                                            \\\n    state.r[REG_1] = state.pc & ~U64(0x3);                                     \\\n    add_pc(DISP_21 * 4);                                                       \\\n  }\n\n#define DO_BSR DO_BR\n\n#define DO_JMP                                                                 \\\n  {                                                                            \\\n    temp_64 = state.r[REG_2] & ~U64(0x3);                                      \\\n    state.r[REG_1] = state.pc & ~U64(0x3);                                     \\\n    set_pc(temp_64 | (state.pc & 3));                                          \\\n  }\n\n// JSR, RET and JSR_COROUTINE is really JMP, just with different prediction\n// bits.\n"
  },
  {
    "path": "src/cpu_debug.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if defined(IDB)\nextern const char *PAL_NAME[];\nextern const char *IPR_NAME[];\n\nextern char dbg_string[1000];\n#if !defined(LS_MASTER) && !defined(LS_SLAVE)\nextern char *dbg_strptr;\n#endif\nvoid handle_debug_string(char *s);\n\n#define TRC_(down, up, x, y)                                                   \\\n  if (bTrace)                                                                  \\\n    trc->trace(this, state.current_pc, state.pc, down, up, x, y);\n\n#define TRC(down, up)                                                          \\\n  if (bTrace)                                                                  \\\n    trc->trace(this, state.current_pc, state.pc, down, up, (char *)0, 0);\n\n#define TRC_BR                                                                 \\\n  if (bTrace)                                                                  \\\n    trc->trace_br(this, state.current_pc, state.pc);\n\n#define GO_PAL(offset)                                                         \\\n  {                                                                            \\\n    if (bDisassemble) {                                                        \\\n      sprintf(dbg_strptr, \" ==> PAL %x!\\n\", offset);                           \\\n      dbg_strptr += strlen(dbg_strptr);                                        \\\n    }                                                                          \\\n    handle_debug_string(dbg_string);                                           \\\n    state.exc_addr = state.current_pc;                                         \\\n    set_pc(state.pal_base | offset | 1);                                       \\\n    if ((offset == DTBM_SINGLE || offset == ITB_MISS) && bTrace)               \\\n      trc->set_waitfor(this, state.exc_addr & ~U64(0x3));                      \\\n    else                                                                       \\\n      TRC_(true, false, \"GO_PAL %04x\", offset);                                \\\n  }\n\n#else\n#define TRC_(down, up, x, y) ;\n#define TRC(down, up) ;\n#define TRC_BR ;\n\n#define GO_PAL(offset)                                                         \\\n  {                                                                            \\\n    state.exc_addr = state.current_pc;                                         \\\n    set_pc(state.pal_base | offset | 1);                                       \\\n  }\n#endif\n#if defined(IDB)\n#define DEBUG_XX                                                               \\\n  if (trc->get_fnc_name(this, state.current_pc & ~U64(0x3), &funcname)) {      \\\n    if (bListing && !strcmp(funcname, \"\")) {                                   \\\n      printf(\"%08\" PRIx64 \": \\\"%s\\\"\\n\", state.current_pc,                         \\\n             cSystem->PtrToMem(state.current_pc));                             \\\n      state.pc = (state.current_pc +                                           \\\n                  strlen(cSystem->PtrToMem(state.current_pc)) + 4) &           \\\n                 ~U64(0x3);                                                    \\\n      while (state.pc < 0x600000 && cSystem->ReadMem(state.pc, 32, this) == 0) \\\n        state.pc += 4;                                                         \\\n      return;                                                                  \\\n    } else if (bListing && !strcmp(funcname, \"!SKIP\")) {                       \\\n      while (state.pc < 0x600000 && cSystem->ReadMem(state.pc, 32, this) == 0) \\\n        state.pc += 4;                                                         \\\n      return;                                                                  \\\n    } else if (bListing && !strncmp(funcname, \"!CHAR-\", 6)) {                  \\\n      u64 xx_upto;                                                             \\\n      int xx_result;                                                           \\\n      xx_result = sscanf(&(funcname[6]), \"%\" PRIx64 \"\", &xx_upto);                \\\n      if (xx_result == 1) {                                                    \\\n        state.pc = state.current_pc;                                           \\\n        while (state.pc < xx_upto) {                                           \\\n          printf(\"%08\" PRIx64 \": \\\"%s\\\"\\n\", state.pc,                             \\\n                 cSystem->PtrToMem(state.pc));                                 \\\n          state.pc += strlen(cSystem->PtrToMem(state.pc));                     \\\n          while (state.pc < xx_upto &&                                         \\\n                 cSystem->ReadMem(state.pc, 8, this) == 0)                     \\\n            state.pc++;                                                        \\\n        }                                                                      \\\n        return;                                                                \\\n      }                                                                        \\\n    } else if (bListing && !strncmp(funcname, \"!LCHAR-\", 7)) {                 \\\n      char stringval[300];                                                     \\\n      int stringlen;                                                           \\\n      u64 xx_upto;                                                             \\\n      int xx_result;                                                           \\\n      xx_result = sscanf(&(funcname[7]), \"%\" PRIx64 \"\", &xx_upto);                \\\n      if (xx_result == 1) {                                                    \\\n        state.pc = state.current_pc;                                           \\\n        while (state.pc < xx_upto) {                                           \\\n          stringlen = (int)cSystem->ReadMem(state.pc++, 8, this);              \\\n          memset(stringval, 0, 300);                                           \\\n          strncpy(stringval, cSystem->PtrToMem(state.pc), stringlen);          \\\n          printf(\"%08\" PRIx64 \": \\\"%s\\\"\\n\", state.pc - 1, stringval);             \\\n          state.pc += stringlen;                                               \\\n          while (state.pc < xx_upto &&                                         \\\n                 cSystem->ReadMem(state.pc, 8, this) == 0)                     \\\n            state.pc++;                                                        \\\n        }                                                                      \\\n        return;                                                                \\\n      }                                                                        \\\n    } else if (bListing && !strncmp(funcname, \"!X64-\", 5)) {                   \\\n      printf(\"\\n%s:\\n\", &(funcname[5]));                                       \\\n      state.pc = state.current_pc;                                             \\\n      while ((state.pc == state.current_pc) ||                                 \\\n             !trc->get_fnc_name(this, state.pc, &funcname)) {                  \\\n        printf(\"%08\" PRIx64 \": %016\" PRIx64 \"\\n\", state.pc,                          \\\n               cSystem->ReadMem(state.pc, 64, this));                          \\\n        state.pc += 8;                                                         \\\n      }                                                                        \\\n      return;                                                                  \\\n    } else if (bListing && !strncmp(funcname, \"!X32-\", 5)) {                   \\\n      printf(\"\\n%s:\\n\", &(funcname[5]));                                       \\\n      state.pc = state.current_pc;                                             \\\n      while ((state.pc == state.current_pc) ||                                 \\\n             !trc->get_fnc_name(this, state.pc, &funcname)) {                  \\\n        printf(\"%08\" PRIx64 \": %08\" PRIx64 \"\\n\", state.pc,                           \\\n               cSystem->ReadMem(state.pc, 32, this));                          \\\n        state.pc += 4;                                                         \\\n      }                                                                        \\\n      return;                                                                  \\\n    } else if (!strncmp(funcname, \":\", 1)) {                                   \\\n      sprintf(dbg_strptr, \"%s:\\n\", funcname);                                  \\\n      dbg_strptr += strlen(dbg_strptr);                                        \\\n    } else {                                                                   \\\n      sprintf(dbg_strptr, \"\\n%s:\\n\", funcname);                                \\\n      dbg_strptr += strlen(dbg_strptr);                                        \\\n    }                                                                          \\\n  }                                                                            \\\n  sprintf(dbg_strptr, bListing ? \"%08\" PRIx64 \": \" : \"%016\" PRIx64 \"\",               \\\n          state.current_pc);                                                   \\\n  dbg_strptr += strlen(dbg_strptr);                                            \\\n  if (!bListing)                                                               \\\n    sprintf(dbg_strptr, \"(%08\" PRIx64 \"): \", current_pc_physical);                \\\n  else {                                                                       \\\n    sprintf(dbg_strptr, \"%08x %c%c%c%c: \", ins, printable((char)(ins)),        \\\n            printable((char)(ins >> 8)), printable((char)(ins >> 16)),         \\\n            printable((char)(ins >> 24)));                                     \\\n  }                                                                            \\\n  dbg_strptr += strlen(dbg_strptr);\n\n#define UNKNOWN1                                                               \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX                                                                   \\\n  }                                                                            \\\n  sprintf(dbg_strptr, \"Unknown opcode: %02x   \", opcode);                      \\\n  dbg_strptr += strlen(dbg_strptr);                                            \\\n  handle_debug_string(dbg_string);                                             \\\n  return;\n\n#define UNKNOWN2                                                               \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX                                                                   \\\n  }                                                                            \\\n  sprintf(dbg_strptr, \"Unknown opcode: %02x.%02x   \", opcode, function);       \\\n  dbg_strptr += strlen(dbg_strptr);                                            \\\n  handle_debug_string(dbg_string);                                             \\\n  return;\n\n#define POST_X64(a)                                                            \\\n  if (bDisassemble) {                                                          \\\n    if (!bListing) {                                                           \\\n      sprintf(dbg_strptr, \" ==> %\" PRIx64 \"\", a);                                 \\\n      dbg_strptr += strlen(dbg_strptr);                                        \\\n    }                                                                          \\\n  }\n\n#define PRE_PAL(mnemonic)                                                      \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX;                                                                  \\\n    if (function < 0x40 || (function > 0x7f && function < 0xc0))               \\\n      sprintf(dbg_strptr, #mnemonic \" %s\", PAL_NAME[function]);                \\\n    else                                                                       \\\n      sprintf(dbg_strptr, #mnemonic \" ?%x?\", function);                        \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n  }\n\n#define POST_PAL TRC(1, 0);\n\n#define PRE_BR(mnemonic)                                                       \\\n  if (bDisassemble) {                                                          \\\n    u64 dbg_x = (state.current_pc + 4 + (DISP_21 * 4)) & ~U64(0x3);            \\\n    DEBUG_XX sprintf(dbg_strptr, #mnemonic \" r%d, \", REG_1 & 31);              \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    if (trc->get_fnc_name(this, dbg_x, &funcname))                             \\\n      sprintf(dbg_strptr, \"%s\", funcname);                                     \\\n    else                                                                       \\\n      sprintf(dbg_strptr, \"%\" PRIx64 \"\", dbg_x);                                  \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n  }\n\n#define POST_BR TRC_BR;\n\n#define PRE_COND(mnemonic)                                                     \\\n  if (bDisassemble) {                                                          \\\n    u64 dbg_x = (state.current_pc + 4 + (DISP_21 * 4)) & ~U64(0x3);            \\\n    DEBUG_XX sprintf(dbg_strptr, #mnemonic \" r%d, \", REG_1 & 31);              \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    if (trc->get_fnc_name(this, dbg_x, &funcname))                             \\\n      sprintf(dbg_strptr, \"%s\", funcname);                                     \\\n    else                                                                       \\\n      sprintf(dbg_strptr, \"%\" PRIx64 \"\", dbg_x);                                  \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    if (!bListing) {                                                           \\\n      sprintf(dbg_strptr, \": (%\" PRIx64 \")\", state.r[REG_1]);                     \\\n      dbg_strptr += strlen(dbg_strptr);                                        \\\n    }                                                                          \\\n  }\n\n#define POST_COND TRC_BR;\n\n#define PRE_FCOND(mnemonic)                                                    \\\n  if (bDisassemble) {                                                          \\\n    u64 dbg_x = (state.current_pc + 4 + (DISP_21 * 4)) & ~U64(0x3);            \\\n    DEBUG_XX sprintf(dbg_strptr, #mnemonic \" f%d, \", FREG_1);                  \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    if (trc->get_fnc_name(this, dbg_x, &funcname))                             \\\n      sprintf(dbg_strptr, \"%s\", funcname);                                     \\\n    else                                                                       \\\n      sprintf(dbg_strptr, \"%\" PRIx64 \"\", dbg_x);                                  \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    if (!bListing) {                                                           \\\n      sprintf(dbg_strptr, \": (%\" PRIx64 \")\", state.f[FREG_1]);                    \\\n      dbg_strptr += strlen(dbg_strptr);                                        \\\n    }                                                                          \\\n  }\n\n#define POST_FCOND TRC_BR;\n\n#define PRE_BSR(mnemonic)                                                      \\\n  if (bDisassemble) {                                                          \\\n    u64 dbg_x = (state.current_pc + 4 + (DISP_21 * 4)) & ~U64(0x3);            \\\n    DEBUG_XX sprintf(dbg_strptr, #mnemonic \" r%d, \", REG_1 & 31);              \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    if (trc->get_fnc_name(this, dbg_x, &funcname))                             \\\n      sprintf(dbg_strptr, \"%s\", funcname);                                     \\\n    else                                                                       \\\n      sprintf(dbg_strptr, \"%\" PRIx64 \"\", dbg_x);                                  \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n  }\n\n#define POST_BSR                                                               \\\n  if (REG_1 == 31) {                                                           \\\n    TRC(0, 1);                                                                 \\\n  } else {                                                                     \\\n    TRC(1, 1);                                                                 \\\n  }\n\n#define PRE_JMP(mnemonic)                                                      \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX sprintf(dbg_strptr, #mnemonic \" r%d, r%d\", REG_1 & 31,            \\\n                     REG_2 & 31);                                              \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    if (!bListing) {                                                           \\\n      sprintf(dbg_strptr, \": (%\" PRIx64 \")\", state.r[REG_2]);                     \\\n      dbg_strptr += strlen(dbg_strptr);                                        \\\n    }                                                                          \\\n  }\n\n#define POST_JMP                                                               \\\n  if (REG_1 == 31) {                                                           \\\n    TRC(0, 1);                                                                 \\\n  } else {                                                                     \\\n    TRC(1, 1);                                                                 \\\n  }\n\n#define PRE_RET(mnemonic)                                                      \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX sprintf(dbg_strptr, #mnemonic \" r%d\", REG_2 & 31);                \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    if (!bListing) {                                                           \\\n      sprintf(dbg_strptr, \": (%\" PRIx64 \")\", state.r[REG_2]);                     \\\n      dbg_strptr += strlen(dbg_strptr);                                        \\\n    }                                                                          \\\n  }\n\n#define POST_RET TRC(0, 1);\n\n#define PRE_MFPR(mnemonic)                                                     \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX;                                                                  \\\n    sprintf(dbg_strptr, #mnemonic \" r%d, %s\", REG_1 & 31, IPR_NAME[function]); \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n  }\n\n#define POST_MFPR POST_X64(state.r[REG_1]);\n\n#define PRE_MTPR(mnemonic)                                                     \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX;                                                                  \\\n    sprintf(dbg_strptr, #mnemonic \" r%d, %s\", REG_2 & 31, IPR_NAME[function]); \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n  }\n\n#define POST_MTPR POST_X64(state.r[REG_2]);\n\n#define PRE_NOP(mnemonic)                                                      \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX;                                                                  \\\n    sprintf(dbg_strptr, #mnemonic \"\");                                         \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n  }\n\n#define POST_NOP ;\n\n#define PRE_MEM(mnemonic)                                                      \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX;                                                                  \\\n    sprintf(dbg_strptr, #mnemonic \" r%d, %04xH(r%d)\", REG_1 & 31,              \\\n            (u32)DISP_16, REG_2 & 31);                                         \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    if (!bListing) {                                                           \\\n      sprintf(dbg_strptr, \": (%\" PRIx64 \")\", state.r[REG_2]);                     \\\n      dbg_strptr += strlen(dbg_strptr);                                        \\\n    }                                                                          \\\n  }\n\n#define POST_MEM POST_X64(state.r[REG_1]);\n\n#define PRE_R12_R3(mnemonic)                                                   \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX;                                                                  \\\n    sprintf(dbg_strptr, #mnemonic \" r%d, \", REG_1 & 31);                       \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    if (ins & 0x1000)                                                          \\\n      sprintf(dbg_strptr, \"%02\" PRIx64 \"H\", V_2);                              \\\n    else                                                                       \\\n      sprintf(dbg_strptr, \"r%d\", REG_2 & 31);                                  \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    sprintf(dbg_strptr, \", r%d\", REG_3 & 31);                                  \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    if (!bListing) {                                                           \\\n      sprintf(dbg_strptr, \": (%\" PRIx64 \",%\" PRIx64 \")\", state.r[REG_1], V_2);       \\\n      dbg_strptr += strlen(dbg_strptr);                                        \\\n    }                                                                          \\\n  }\n\n#define POST_R12_R3 POST_X64(state.r[REG_3]);\n\n// Pre-debugging macro for floating-point instructions that have Fa and Fb\n\n// as input and Fc as output.\n#define PRE_F12_F3(mnemonic)                                                   \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX;                                                                  \\\n    sprintf(dbg_strptr, #mnemonic \" f%d, f%d, f%d\", FREG_1, FREG_2, FREG_3);   \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    if (!bListing) {                                                           \\\n      sprintf(dbg_strptr, \": (%\" PRIx64 \",%\" PRIx64 \")\", state.f[FREG_1],            \\\n              state.f[FREG_2]);                                                \\\n      dbg_strptr += strlen(dbg_strptr);                                        \\\n    }                                                                          \\\n  }\n\n// Post-debugging macro for floating-point instructions that have Fa and Fb\n// as input and Fc as output.\n#define POST_F12_F3 POST_X64(state.f[FREG_3]);\n\n#define PRE_R1_F3(mnemonic)                                                    \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX;                                                                  \\\n    sprintf(dbg_strptr, #mnemonic \" r%d, f%d \", REG_1 & 31, FREG_3);           \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    if (!bListing) {                                                           \\\n      sprintf(dbg_strptr, \": (%\" PRIx64 \")\", state.r[REG_1]);                     \\\n      dbg_strptr += strlen(dbg_strptr);                                        \\\n    }                                                                          \\\n  }\n\n#define POST_R1_F3 POST_X64(state.f[FREG_3]);\n\n#define PRE_F1_R3(mnemonic)                                                    \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX;                                                                  \\\n    sprintf(dbg_strptr, #mnemonic \" f%d, r%d \", FREG_1, REG_3 & 31);           \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    if (!bListing) {                                                           \\\n      sprintf(dbg_strptr, \": (%\" PRIx64 \")\", state.f[FREG_1]);                    \\\n      dbg_strptr += strlen(dbg_strptr);                                        \\\n    }                                                                          \\\n  }\n\n#define POST_F1_R3 POST_X64(state.r[REG_3]);\n\n#define PRE_X_F1(mnemonic)                                                     \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX;                                                                  \\\n    sprintf(dbg_strptr, #mnemonic \" f%d \", FREG_1 & 31);                       \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n  }\n\n#define POST_X_F1 POST_X64(state.f[FREG_1]);\n\n#define PRE_R2_R3(mnemonic)                                                    \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX;                                                                  \\\n    sprintf(dbg_strptr, #mnemonic \" \");                                        \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    if (ins & 0x1000)                                                          \\\n      sprintf(dbg_strptr, \"%02\" PRIx64 \"H\", V_2);                              \\\n    else                                                                       \\\n      sprintf(dbg_strptr, \"r%d\", REG_2 & 31);                                  \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    sprintf(dbg_strptr, \", r%d\", REG_3 & 31);                                  \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    if (!bListing) {                                                           \\\n      sprintf(dbg_strptr, \": (%\" PRIx64 \")\", V_2);                                \\\n      dbg_strptr += strlen(dbg_strptr);                                        \\\n    }                                                                          \\\n  }\n\n#define POST_R2_R3 POST_X64(state.r[REG_3]);\n\n#define PRE_X_R1(mnemonic)                                                     \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX;                                                                  \\\n    sprintf(dbg_strptr, #mnemonic \" r%d\", REG_1 & 31);                         \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n  }\n\n#define POST_X_R1 POST_X64(state.r[REG_1]);\n\n#define PRE_X_R3(mnemonic)                                                     \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX;                                                                  \\\n    sprintf(dbg_strptr, #mnemonic \" r%d\", REG_3 & 31);                         \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n  }\n\n#define POST_X_R3 POST_X64(state.r[REG_3]);\n\n#define PRE_HW_LD(mnemonic)                                                    \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX;                                                                  \\\n    sprintf(dbg_strptr, #mnemonic);                                            \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    switch (function & ~1) {                                                   \\\n    case 0:                                                                    \\\n      sprintf(dbg_strptr, \"/Phys\");                                            \\\n      break;                                                                   \\\n    case 2:                                                                    \\\n      sprintf(dbg_strptr, \"/Phys/Lock\");                                       \\\n      break;                                                                   \\\n    case 4:                                                                    \\\n      sprintf(dbg_strptr, \"/Vpte\");                                            \\\n      break;                                                                   \\\n    case 10:                                                                   \\\n      sprintf(dbg_strptr, \"/Chk\");                                             \\\n      break;                                                                   \\\n    case 12:                                                                   \\\n      sprintf(dbg_strptr, \"/Alt\");                                             \\\n      break;                                                                   \\\n    case 14:                                                                   \\\n      sprintf(dbg_strptr, \"/Alt/Chk\");                                         \\\n      break;                                                                   \\\n    }                                                                          \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    sprintf(dbg_strptr, \" r%d, %04xH(r%d)\", REG_1 & 31, (u32)DISP_12,          \\\n            REG_2 & 31);                                                       \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    if (!bListing) {                                                           \\\n      sprintf(dbg_strptr, \": (%\" PRIx64 \")\", state.r[REG_2]);                     \\\n      dbg_strptr += strlen(dbg_strptr);                                        \\\n    }                                                                          \\\n  }\n\n#define POST_HW_LD POST_X64(state.r[REG_1]);\n\n#define PRE_HW_ST(mnemonic)                                                    \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX;                                                                  \\\n    sprintf(dbg_strptr, #mnemonic);                                            \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    switch (function & ~1) {                                                   \\\n    case 0:                                                                    \\\n      sprintf(dbg_strptr, \"/Phys\");                                            \\\n      break;                                                                   \\\n    case 2:                                                                    \\\n      sprintf(dbg_strptr, \"/Phys/Cond\");                                       \\\n      break;                                                                   \\\n    case 12:                                                                   \\\n      sprintf(dbg_strptr, \"/Alt\");                                             \\\n      break;                                                                   \\\n    }                                                                          \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    sprintf(dbg_strptr, \" r%d, %04xH(r%d)\", REG_1 & 31, (u32)DISP_12,          \\\n            REG_2 & 31);                                                       \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    if (!bListing) {                                                           \\\n      sprintf(dbg_strptr, \": (%\" PRIx64 \")\", state.r[REG_2]);                     \\\n      dbg_strptr += strlen(dbg_strptr);                                        \\\n    }                                                                          \\\n  }\n\n#define POST_HW_ST POST_X64(state.r[REG_1]);\n\n// Pre-debugging macro for floating-point load/store instructions.\n#define PRE_FMEM(mnemonic)                                                     \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX;                                                                  \\\n    sprintf(dbg_strptr, #mnemonic \" f%d, %04xH(r%d)\", FREG_1, (u32)DISP_16,    \\\n            REG_2 & 31);                                                       \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    if (!bListing) {                                                           \\\n      sprintf(dbg_strptr, \": (%\" PRIx64 \")\", state.r[REG_2]);                     \\\n      dbg_strptr += strlen(dbg_strptr);                                        \\\n    }                                                                          \\\n  }\n\n// Post-debugging macro for floating-point load/store instructions.\n#define POST_FMEM POST_X64(state.f[FREG_1]);\n\n// Pre-debugging macro for floating-point instructions that have Fb as input\n\n// And Fc as output.\n#define PRE_F2_F3(mnemonic)                                                    \\\n  if (bDisassemble) {                                                          \\\n    DEBUG_XX;                                                                  \\\n    sprintf(dbg_strptr, #mnemonic \" f%d, f%d\", FREG_2, FREG_3);                \\\n    dbg_strptr += strlen(dbg_strptr);                                          \\\n    if (!bListing) {                                                           \\\n      sprintf(dbg_strptr, \": (%\" PRIx64 \")\", state.f[FREG_2]);                    \\\n      dbg_strptr += strlen(dbg_strptr);                                        \\\n    }                                                                          \\\n  }\n\n// Post-debugging macro for floating-point instructions that have Fb as input\n// And Fc as output.\n#define POST_F2_F3 POST_X64(state.f[FREG_3]);\n\n#else\n#ifndef NDEBUG\n#define UNKNOWN1                                                               \\\n  printf(\"Unknown opcode: %02x   \\n\", opcode);                                 \\\n  return;\n\n#define UNKNOWN2                                                               \\\n  printf(\"Unknown opcode: %02x.%02x   \\n\", opcode, function);                  \\\n  return;\n#else\n#define UNKNOWN1 return;\n#define UNKNOWN2 return;\n#endif\n#endif\n#if defined(IDB)\n\n// Debugging version of the OP macro:\n// Execute the DO_<mnemonic> macro for an instruction, along with disassembling\n\n// the instruction if needed.\n#define OP(mnemonic, format)                                                   \\\n  PRE_##format(mnemonic);                                                      \\\n  if (!bListing) {                                                             \\\n    DO_##mnemonic;                                                             \\\n  }                                                                            \\\n  POST_##format;                                                               \\\n  handle_debug_string(dbg_string);                                             \\\n  return;\n\n// Execute a function rather than a DO_<mnemonic> macro for an instruction\n#define OP_FNC(mnemonic, format)                                               \\\n  PRE_##format(mnemonic);                                                      \\\n  if (!bListing) {                                                             \\\n    mnemonic();                                                                \\\n  }                                                                            \\\n  POST_##format;                                                               \\\n  handle_debug_string(dbg_string);                                             \\\n  return;\n\n#else // defined(IDB)\n\n// Non-debugging version of the OP macro:\n\n// Execute the DO_<mnemonic> macro for an instruction.\n#define OP(mnemonic, format)                                                   \\\n  DO_##mnemonic;                                                               \\\n  return;\n\n// Execute a function rather than a DO_<mnemonic> macro for an instruction\n#define OP_FNC(mnemonic, format)                                               \\\n  mnemonic();                                                                  \\\n  return;\n#endif // defined(IDB)\n"
  },
  {
    "path": "src/cpu_defs.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n/* Copyright notice from Simh/alpha/alpha_fpi.c and alpha_fpv.c:\n\n   Copyright (c) 2003-2006, Robert M Supnik\n\n   Permission is hereby granted, free of charge, to any person obtaining a\n   copy of this software and associated documentation files (the \"Software\"),\n   to deal in the Software without restriction, including without limitation\n   the rights to use, copy, modify, merge, publish, distribute, sublicense,\n   and/or sell copies of the Software, and to permit persons to whom the\n   Software is furnished to do so, subject to the following conditions:\n\n   The above copyright notice and this permission notice shall be included in\n   all copies or substantial portions of the Software.\n\n   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\n   ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n   Except as contained in this notice, the name of Robert M Supnik shall not be\n   used in advertising or otherwise to promote the sale, use or other dealings\n   in this Software without prior written authorization from Robert M Supnik.\n*/\n\n#if !defined(__CPU_DEFS__)\n#define __CPU_DEFS__\n\n/* Instruction formats */\n#define I_V_OP 26 /* opcode */\n#define I_M_OP 0x3F\n#define I_OP (I_M_OP << I_V_OP)\n#define I_V_RA 21 /* Ra */\n#define I_M_RA 0x1F\n#define I_V_RB 16 /* Rb */\n#define I_M_RB 0x1F\n#define I_V_FTRP 13 /* floating trap mode */\n#define I_M_FTRP 0x7\n#define I_FTRP (I_M_FTRP << I_V_FTRP)\n#define I_F_VAXRSV 0x4800 /* VAX reserved */\n#define I_FTRP_V 0x2000   /* /V trap */\n#define I_FTRP_U 0x2000   /* /U trap */\n#define I_FTRP_S 0x8000   /* /S trap */\n#define I_FTRP_SUI 0xE000 /* /SUI trap */\n#define I_FTRP_SVI 0xE000 /* /SVI trap */\n#define I_V_FRND 11       /* floating round mode */\n#define I_M_FRND 0x3\n#define I_FRND (I_M_FRND << I_V_FRND)\n#define I_FRND_C 0 /* chopped */\n#define I_FRND_M 1 /* to minus inf */\n#define I_FRND_N 2 /* normal */\n#define I_FRND_D 3 /* dynamic */\n#define I_FRND_P 3 /* in FPCR: plus inf */\n#define I_V_FSRC 9 /* floating source */\n#define I_M_FSRC 0x3\n#define I_FSRC (I_M_FSRC << I_V_FSRC)\n#define I_FSRC_X 0x0200 /* data type X */\n#define I_V_FFNC 5      /* floating function */\n#define I_M_FFNC 0x3F\n#define I_V_LIT8 13 /* integer 8b literal */\n#define I_M_LIT8 0xFF\n#define I_V_ILIT 12 /* literal flag */\n#define I_ILIT (1u << I_V_ILIT)\n#define I_V_IFNC 5 /* integer function */\n#define I_M_IFNC 0x3F\n#define I_V_RC 0 /* Rc */\n#define I_M_RC 0x1F\n#define I_V_MDSP 0 /* memory displacement */\n#define I_M_MDSP 0xFFFF\n#define I_V_BDSP 0\n#define I_M_BDSP 0x1FFFFF /* branch displacement */\n#define I_V_PALOP 0\n#define I_M_PALOP 0x3FFFFFF /* PAL subopcode */\n#define I_GETOP(x) (((x) >> I_V_OP) & I_M_OP)\n#define I_GETRA(x) (((x) >> I_V_RA) & I_M_RA)\n#define I_GETRB(x) (((x) >> I_V_RB) & I_M_RB)\n#define I_GETLIT8(x) (((x) >> I_V_LIT8) & I_M_LIT8)\n#define I_GETIFNC(x) (((x) >> I_V_IFNC) & I_M_IFNC)\n#define I_GETFRND(x) (((x) >> I_V_FRND) & I_M_FRND)\n#define I_GETFFNC(x) (((x) >> I_V_FFNC) & I_M_FFNC)\n#define I_GETRC(x) (((x) >> I_V_RC) & I_M_RC)\n#define I_GETMDSP(x) (((x) >> I_V_MDSP) & I_M_MDSP)\n#define I_GETBDSP(x) (((x) >> I_V_BDSP) & I_M_BDSP)\n#define I_GETPAL(x) (((x) >> I_V_PALOP) & I_M_PALOP)\n\n/* Floating point types */\n#define DT_F 0 /* type F */\n#define DT_G 1 /* type G */\n#define DT_S 0 /* type S */\n#define DT_T 1 /* type T */\n\n/* Floating point memory format (VAX F) */\n#define F_V_SIGN 15\n#define F_SIGN (1u << F_V_SIGN)\n#define F_V_EXP 7\n#define F_M_EXP 0xFF\n#define F_BIAS 0x80\n#define F_EXP (F_M_EXP << F_V_EXP)\n#define F_V_FRAC 29\n#define F_GETEXP(x) (((x) >> F_V_EXP) & F_M_EXP)\n#define SWAP_VAXF(x) ((((x) >> 16) & 0xFFFF) | (((x)&0xFFFF) << 16))\n\n/* Floating point memory format (VAX G) */\n#define G_V_SIGN 15\n#define G_SIGN (1u << F_V_SIGN)\n#define G_V_EXP 4\n#define G_M_EXP 0x7FF\n#define G_BIAS 0x400\n#define G_EXP (G_M_EXP << G_V_EXP)\n#define G_GETEXP(x) (((x) >> G_V_EXP) & G_M_EXP)\n#define SWAP_VAXG(x)                                                           \\\n  ((((x)&U64(0x000000000000FFFF)) << 48) |                                     \\\n   (((x)&U64(0x00000000FFFF0000)) << 16) |                                     \\\n   (((x) >> 16) & U64(0x00000000FFFF0000)) |                                   \\\n   (((x) >> 48) & U64(0x000000000000FFFF)))\n\n/* Floating memory format (IEEE S) */\n#define S_V_SIGN 31\n#define S_SIGN (1u << S_V_SIGN)\n#define S_V_EXP 23\n#define S_M_EXP 0xFF\n#define S_BIAS 0x7F\n#define S_NAN 0xFF\n#define S_EXP (S_M_EXP << S_V_EXP)\n#define S_V_FRAC 29\n#define S_GETEXP(x) (((x) >> S_V_EXP) & S_M_EXP)\n\n/* Floating point memory format (IEEE T) */\n#define T_V_SIGN 63\n#define T_SIGN U64(0x8000000000000000)\n#define T_V_EXP 52\n#define T_M_EXP 0x7FF\n#define T_BIAS 0x3FF\n#define T_NAN 0x7FF\n#define T_EXP U64(0x7FF0000000000000)\n#define T_FRAC U64(0x000FFFFFFFFFFFFF)\n#define T_GETEXP(x) (((u32)((x) >> T_V_EXP)) & T_M_EXP)\n\n/* Floating point register format (all except VAX D) */\n#define FPR_V_SIGN 63\n#define FPR_SIGN U64(0x8000000000000000)\n#define FPR_V_EXP 52\n#define FPR_M_EXP 0x7FF\n#define FPR_NAN 0x7FF\n#define FPR_EXP U64(0x7FF0000000000000)\n#define FPR_HB U64(0x0010000000000000)\n#define FPR_FRAC U64(0x000FFFFFFFFFFFFF)\n#define FPR_GUARD (UF_V_NM - FPR_V_EXP)\n#define FPR_GETSIGN(x) (((u32)((x) >> FPR_V_SIGN)) & 1)\n#define FPR_GETEXP(x) (((u32)((x) >> FPR_V_EXP)) & FPR_M_EXP)\n#define FPR_GETFRAC(x) ((x)&FPR_FRAC)\n#define FP_TRUE U64(0x4000000000000000) /* 0.5/2.0 in reg */\n\n/* Floating point register format (VAX D) */\n#define FDR_V_SIGN 63\n#define FDR_SIGN U64(0x8000000000000000)\n#define FDR_V_EXP 55\n#define FDR_M_EXP 0xFF\n#define FDR_EXP U64(0x7F80000000000000)\n#define FDR_HB U64(0x0080000000000000)\n#define FDR_FRAC U64(0x007FFFFFFFFFFFFF)\n#define FDR_GUARD (UF_V_NM - FDR_V_EXP)\n#define FDR_GETSIGN(x) (((u32)((x) >> FDR_V_SIGN)) & 1)\n#define FDR_GETEXP(x) (((u32)((x) >> FDR_V_EXP)) & FDR_M_EXP)\n#define FDR_GETFRAC(x) ((x)&FDR_FRAC)\n#define D_BIAS 0x80\n\n/* Unpacked floating point number */\nstruct ufp {\n  u32 sign;\n  s32 exp;\n  u64 frac;\n};\n\ntypedef struct ufp UFP;\n\n#define UF_V_NM 63\n#define UF_NM U64(0x8000000000000000) /* normalized */\n\n/* Bit patterns */\n#define X64_BYTE U64(0xff)\n#define X64_WORD U64(0xffff)\n#define X64_LONG U64(0xffffffff)\n#define X64_QUAD U64(0xffffffffffffffff)\n#define B_SIGN U64(0x80)\n#define W_SIGN U64(0x8000)\n#define L_SIGN U64(0x80000000)\n#define Q_SIGN U64(0x8000000000000000)\n#define Q_GETSIGN(x) (((x) >> 63) & 1)\n\n/* IEEE control register (left 32b only) */\n#define FPCR_SUM U64(0x8000000000000000)  /* summary */\n#define FPCR_INED U64(0x4000000000000000) /* inexact disable */\n#define FPCR_UNFD U64(0x2000000000000000) /* underflow disable */\n#define FPCR_UNDZ U64(0x1000000000000000) /* underflow to 0 */\n#define FPCR_V_RMOD 58                    /* rounding mode */\n#define FPCR_M_RMOD 0x3\n#define FPCR_IOV U64(0x0200000000000000)  /* integer overflow */\n#define FPCR_INE U64(0x0100000000000000)  /* inexact */\n#define FPCR_UNF U64(0x0080000000000000)  /* underflow */\n#define FPCR_OVF U64(0x0040000000000000)  /* overflow */\n#define FPCR_DZE U64(0x0020000000000000)  /* div by zero */\n#define FPCR_INV U64(0x0010000000000000)  /* invalid operation */\n#define FPCR_OVFD U64(0x0008000000000000) /* overflow disable */\n#define FPCR_DZED U64(0x0004000000000000) /* div by zero disable */\n#define FPCR_INVD U64(0x0002000000000000) /* invalid op disable */\n#define FPCR_DNZ U64(0x0001000000000000)  /* denormal to zero */\n#define FPCR_DNOD U64(0x0000800000000000) /* denormal disable */\n#define FPCR_RAZ U64(0x00007FFF00000000)  /* zero */\n#define FPCR_ERR                                                               \\\n  (FPCR_IOV | FPCR_INE | FPCR_UNF | FPCR_OVF | FPCR_DZE | FPCR_INV)\n#define FPCR_GETFRND(x) (((x) >> FPCR_V_RMOD) & FPCR_M_RMOD)\n#define NEG_Q(x) ((~(x) + 1) & X64_QUAD)\n#define ABS_Q(x) (((x)&Q_SIGN) ? NEG_Q(x) : (x))\n\n/* IEEE */\n#define UFT_ZERO 0   /* unpacked: zero */\n#define UFT_FIN 1    /* finite */\n#define UFT_DENORM 2 /* denormal */\n#define UFT_INF 3    /* infinity */\n#define UFT_NAN 4    /* not a number */\n\n#define Q_FINITE(x) ((x) <= UFT_FIN) /* finite */\n#define Q_SUI(x) (((x)&I_FTRP) == I_FTRP_SVI)\n\n/* 64b * 64b unsigned multiply */\ninline u64 uemul64(u64 a, u64 b, u64 *hi) {\n  u64 ahi;\n\n  u64 alo;\n\n  u64 bhi;\n\n  u64 blo;\n\n  u64 rhi;\n\n  u64 rmid1;\n\n  u64 rmid2;\n\n  u64 rlo;\n\n  ahi = (a >> 32) & X64_LONG;\n  alo = a & X64_LONG;\n  bhi = (b >> 32) & X64_LONG;\n  blo = b & X64_LONG;\n  rhi = ahi * bhi;\n  rmid1 = ahi * blo;\n  rmid2 = alo * bhi;\n  rlo = alo * blo;\n  rhi = rhi + ((rmid1 >> 32) & X64_LONG) + ((rmid2 >> 32) & X64_LONG);\n  rmid1 = (rmid1 << 32) & X64_QUAD;\n  rmid2 = (rmid2 << 32) & X64_QUAD;\n  rlo = (rlo + rmid1) & X64_QUAD;\n  if (rlo < rmid1)\n    rhi = rhi + 1;\n  rlo = (rlo + rmid2) & X64_QUAD;\n  if (rlo < rmid2)\n    rhi = rhi + 1;\n  if (hi)\n    *hi = rhi & X64_QUAD;\n  return rlo;\n}\n\n/* 64b / 64b unsigned fraction divide */\ninline u64 ufdiv64(u64 dvd, u64 dvr, u32 prec, u32 *sticky) {\n  u64 quo;\n  u32 i;\n\n  quo = 0;                              /* clear quotient */\n  for (i = 0; (i < prec) && dvd; i++) { /* divide loop */\n    quo = quo << 1;                     /* shift quo */\n    if (dvd >= dvr) {                   /* div step ok? */\n      dvd = dvd - dvr;                  /* subtract */\n      quo = quo + 1;\n    } /* quo bit = 1 */\n\n    dvd = dvd << 1;\n  } /* shift divd */\n\n  quo = quo << (UF_V_NM - i + 1); /* shift quo */\n  if (sticky)\n    *sticky = (dvd ? 1 : 0); /* set sticky bit */\n  return quo;                /* return quotient */\n}\n\n/* Fraction square root routine - code from SoftFloat */\ninline u64 fsqrt64(u64 asig, s32 exp) {\n  static const u32 sqrtOdd[] = {0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F,\n                                0x0236, 0x02E0, 0x039C, 0x0468, 0x0545, 0x0631,\n                                0x072B, 0x0832, 0x0946, 0x0A67};\n  static const u32 sqrtEven[] = {0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429,\n                                 0x0356, 0x029E, 0x0200, 0x0179, 0x0109, 0x00AF,\n                                 0x0068, 0x0034, 0x0012, 0x0002};\n\n  u64 zsig;\n  u64 remh;\n  u64 reml;\n  u64 t;\n  u32 index;\n  u32 z;\n  u32 a;\n  u32 sticky = 0;\n\n  /* Calculate an approximation to the square root of the 32-bit significand\n   given by 'a'.  Considered as an integer, 'a' must be at least 2^31.  If bit 0\n   of 'exp' (the least significant bit) is 1, the integer returned approximates\n   2^31*sqrt('a'/2^31), where 'a' is considered an integer.  If bit 0 of 'exp'\n   is 0, the integer returned approximates 2^31*sqrt('a'/2^30).  In either\n   case, the approximation returned lies strictly within +/-2 of the exact\n   value. */\n  a = (u32)(asig >> 32);                     /* high order frac */\n  index = (a >> 27) & 0xF;                   /* bits<30:27> */\n  if (exp & 1) {                             /* odd exp? */\n    z = 0x4000 + (a >> 17) - sqrtOdd[index]; /* initial guess */\n    z = ((a / z) << 14) + (z << 15);         /* Newton iteration */\n    a = a >> 1;\n  } else {\n    z = 0x8000 + (a >> 17) - sqrtEven[index]; /* initial guess */\n    z = (a / z) + z;                          /* Newton iteration */\n    z = (z >= 0x20000) ? 0xFFFF8000 : (z << 15);\n    if (z <= a)\n      z = (a >> 1) | 0x80000000;\n  }\n\n  zsig = (((((u64)a) << 31) / ((u64)z)) + (z >> 1)) & X64_LONG;\n\n  /* Calculate the final answer in two steps.  First, do one iteration of\n   Newton's approximation.  The divide-by-2 is accomplished by clever\n   positioning of the operands.  Then, check the bits just below the\n   (double precision) rounding bit to see if they are close to zero\n   (that is, the rounding bits are close to midpoint).  If so, make\n   sure that the result^2 is <below> the input operand */\n  asig = asig >> ((exp & 1) ? 3 : 2); /* leave 2b guard */\n  zsig =\n      ufdiv64(asig, zsig << 32, 64, NULL) + (zsig << 30); /* Newton iteration */\n  if ((zsig & 0x1FF) <= 5) {                              /* close to even? */\n    remh = uemul64(zsig, zsig, &reml);                    /* result^2 */\n    remh = (asig - remh - (reml ? 1 : 0)) & X64_QUAD;     /* arg - result^2 */\n    reml = NEG_Q(reml);\n    while (Q_GETSIGN(remh) != 0) {      /* if arg < result^2 */\n      zsig = (zsig - 1) & X64_QUAD;     /* decr result */\n      t = ((zsig << 1) & X64_QUAD) | 1; /* incr result^2 */\n      reml = (reml + t) & X64_QUAD;     /* and retest */\n      remh = (remh + (zsig >> 63) + ((reml < t) ? 1 : 0)) & X64_QUAD;\n    }\n\n    if ((remh | reml) != 0)\n      sticky = 1;\n  } /* not exact? */\n\n  zsig = (zsig << 1) | sticky; /* left justify result */\n  return zsig;\n}\n\n// INTERRUPT VECTORS\n#define DTBM_DOUBLE_3 U64(0x100)\n#define DTBM_DOUBLE_4 U64(0x180)\n#define FEN U64(0x200)\n#define UNALIGN U64(0x280)\n#define DTBM_SINGLE U64(0x300)\n#define DFAULT U64(0x380)\n#define OPCDEC U64(0x400)\n#define IACV U64(0x480)\n#define MCHK U64(0x500)\n#define ITB_MISS U64(0x580)\n#define ARITH U64(0x600)\n#define INTERRUPT U64(0x680)\n#define MT_FPCR U64(0x700)\n#define RESET U64(0x780)\n\n/** Chip ID (EV68CB pass 4) [HRM p 5-16]; actual value derived from SRM-code */\n#define CPU_CHIP_ID 0x21\n\n/** Major CPU type (EV68CB) [ARM pp D-1..3] */\n#define CPU_TYPE_MAJOR 12\n\n/** Minor CPU type (pass 4) [ARM pp D-1..3] */\n#define CPU_TYPE_MINOR 6\n\n/** Implementation version [HRM p 2-38; ARM p D-5] */\n#define CPU_IMPLVER 2\n\n/** Architecture mask [HRM p 2-38; ARM p D-4]; FIX not implemented */\n#define CPU_AMASK U64(0x1305)\n#define DISP_12 (sext_u64_12(ins))\n#define DISP_13 (sext_u64_13(ins))\n#define DISP_16 (sext_u64_16(ins))\n#define DISP_21 (sext_u64_21(ins))\n\n#define DATA_PHYS_NT(addr, flags)                                              \\\n  if (virt2phys(addr, &phys_address, flags, NULL, ins))                        \\\n    return;\n\n#define ALIGN_PHYS(a) (phys_address & ~((u64)((a)-1)))\n\n/* Increase memory access page alignment checking to 8KB instead of\n   4KB, 8KB minimum on AXP. Potentially should be dynamic in future,\n   resolves OpenVMS installation problems. Source:\n   https://www.openvmshobbyist.com/forum/viewthread.php?forum_id=161&thread_id=2801\n\n   https://github.com/gdwnldsKSC/es40/commit/dad191fb2f279164122654aba6da53acc1040d97\n*/\n\n#define DATA_PHYS(addr, flags, align)                                          \\\n  if ((addr) & (align)) {                                                      \\\n    u64 a1 = (addr);                                                           \\\n    u64 a2 = (addr) + (align);                                                 \\\n    if ((a1 ^ a2) & ~U64(0x1fff)) /* 8K page boundary crossed*/                \\\n    {                                                                          \\\n      state.fault_va = addr;                                                   \\\n      state.exc_sum = ((REG_1 &0x1f) << 8);                                    \\\n      state.mm_stat = (I_GETOP(ins) << 4) | ((flags & ACCESS_WRITE) ? 1 : 0);  \\\n      printf(\"unaligned addess %d, %d -> trap! \",flags,align);                 \\\n      printf(\"exc_sum = 0x%04\" PRId64 \"x, fault_va = 0x%016\" PRId64            \\\n          \"x, mm_stat = 0x%03\" PRId64 \"x.\\n\",state.exc_sum, state.fault_va,    \\\n          state.mm_stat);                                                      \\\n      GO_PAL(UNALIGN);                                                         \\\n      return;                                                                  \\\n    }                                                                          \\\n  }                                                                            \\\n  DATA_PHYS_NT(addr, flags) // use the define above instead of duplicating\n\n/**\n * Normal variant of read action\n * In reality, these would generate an alignment trap, and the exception\n * handler would put things straight. Instead, to speed things up, we'll\n * just perform the read as requested using the unaligned address.\n **/\n#if defined(IDB)\n#define LLR last_read_loc = phys_address\n#define LWR last_write_loc = phys_address\n#else\n#define LLR\n#define LWR\n#endif\n\n#define READ_PHYS(size)                                                        \\\n  cSystem->ReadMem(phys_address, size, this);                                  \\\n  LLR\n\n#define READ_VIRT(va, size, dest)                                              \\\n  pbc = false;                                                                 \\\n  DATA_PHYS(va, ACCESS_READ, (size / 8) - 1);                                  \\\n  LLR;                                                                         \\\n  if (pbc) {                                                                   \\\n    dest = 0;                                                                  \\\n    for (int ii = 0; ii < (size / 8); ii++) {                                  \\\n      DATA_PHYS(va + ii, ACCESS_READ, 0);                                      \\\n      dest |= (cSystem->ReadMem(phys_address, 8, this) << (ii * 8));           \\\n    }                                                                          \\\n  } else {                                                                     \\\n    dest = cSystem->ReadMem(phys_address, size, this);                         \\\n  }\n\n#define READ_VIRT_LOCK(va, size, dest)                                         \\\n  pbc = false;                                                                 \\\n  DATA_PHYS(va, ACCESS_READ, (size / 8) - 1);                                  \\\n  LLR;                                                                         \\\n  cSystem->cpu_lock(state.iProcNum, phys_address);                             \\\n  if (pbc) {                                                                   \\\n    dest = 0;                                                                  \\\n    for (int ii = 0; ii < (size / 8); ii++) {                                  \\\n      DATA_PHYS(va + ii, ACCESS_READ, 0);                                      \\\n      dest |= (cSystem->ReadMem(phys_address, 8, this) << (ii * 8));           \\\n    }                                                                          \\\n  } else {                                                                     \\\n    dest = cSystem->ReadMem(phys_address, size, this);                         \\\n  }\n\n#define READ_VIRT_F(va, size, dest, f)                                         \\\n  pbc = false;                                                                 \\\n  DATA_PHYS(va, ACCESS_READ, (size / 8) - 1);                                  \\\n  LLR;                                                                         \\\n  if (pbc) {                                                                   \\\n    u64 aa = 0;                                                                \\\n    for (int ii = 0; ii < (size / 8); ii++) {                                  \\\n      DATA_PHYS(va + ii, ACCESS_READ, 0);                                      \\\n      aa |= (cSystem->ReadMem(phys_address, 8, this) << (ii * 8));             \\\n    }                                                                          \\\n    dest = f(aa);                                                              \\\n  } else {                                                                     \\\n    dest = f(cSystem->ReadMem(phys_address, size, this));                      \\\n  }\n\n#define READ_VIRT_LOCK_F(va, size, dest, f)                                    \\\n  pbc = false;                                                                 \\\n  DATA_PHYS(va, ACCESS_READ, (size / 8) - 1);                                  \\\n  LLR;                                                                         \\\n  cSystem->cpu_lock(state.iProcNum, phys_address);                             \\\n  if (pbc) {                                                                   \\\n    u64 aa = 0;                                                                \\\n    for (int ii = 0; ii < (size / 8); ii++) {                                  \\\n      DATA_PHYS(va + ii, ACCESS_READ, 0);                                      \\\n      aa |= (cSystem->ReadMem(phys_address, 8, this) << (ii * 8));             \\\n    }                                                                          \\\n    dest = f(aa);                                                              \\\n  } else {                                                                     \\\n    dest = f(cSystem->ReadMem(phys_address, size, this));                      \\\n  }\n\n/**\n * Normal variant of write action\n * In reality, these would generate an alignment trap, and the exception\n * handler would put things straight. Instead, to speed things up, we'll\n * just perform the write as requested using the unaligned address.\n **/\n#define WRITE_PHYS(data, size)                                                 \\\n  cSystem->WriteMem(phys_address, size, data, this);                           \\\n  LWR\n\n#define WRITE_VIRT(va, size, src)                                              \\\n  pbc = false;                                                                 \\\n  DATA_PHYS(va, ACCESS_WRITE, (size / 8) - 1);                                 \\\n  LWR;                                                                         \\\n  if (pbc) {                                                                   \\\n    u64 aa = src;                                                              \\\n    for (int ii = 0; ii < (size / 8); ii++) {                                  \\\n      DATA_PHYS(va + ii, ACCESS_WRITE, 0);                                     \\\n      cSystem->WriteMem(phys_address, 8, aa, this);                            \\\n      aa >>= 8;                                                                \\\n    }                                                                          \\\n  } else {                                                                     \\\n    cSystem->WriteMem(phys_address, size, src, this);                          \\\n  }\n\n/**\n * NO-TRAP (NT) variants of read action.\n * This is used for HW_LD, where alignment traps are\n * inhibited. We'll align the adress and read using the aligned\n * address.\n **/\n#define READ_PHYS_NT(size)                                                     \\\n  cSystem->ReadMem(ALIGN_PHYS((size) / 8), size, this);                        \\\n  LLR;\n\n/**\n * NO-TRAP (NT) variants of write action.\n * This is used for HW_ST, where alignment traps are\n * inhibited. We'll align the adress and write using the aligned\n * address.\n **/\n#if defined(IDB)\n#define WRITE_PHYS_NT(data, size)                                              \\\n  cSystem->WriteMem(ALIGN_PHYS((size) / 8), size, data, this);                 \\\n  LWR\n#else\n#define WRITE_PHYS_NT(data, size)                                              \\\n  cSystem->WriteMem(ALIGN_PHYS((size) / 8), size, data, this)\n#endif\n\n#define REG_1 RREG(I_GETRA(ins))\n#define REG_2 RREG(I_GETRB(ins))\n#define REG_3 RREG(I_GETRC(ins))\n#define FREG_1 (I_GETRA(ins))\n#define FREG_2 (I_GETRB(ins))\n#define FREG_3 (I_GETRC(ins))\n#define RA REG_1\n#define RAV state.r[RA]\n#define RB REG_2\n#define RBV ((ins & 0x1000) ? ((ins >> 13) & 0xff) : state.r[RB])\n#define V_2 RBV\n#define RC REG_3\n#define RCV state.r[RC]\n\n#define ACCESS_READ 0\n#define ACCESS_WRITE 1\n#define ACCESS_EXEC 2\n#define ACCESS_MODE 3\n#define NO_CHECK 4\n#define VPTE 8\n#define FAKE 16\n#define ALT 32\n#define RECUR 128\n#define PROBE 256\n#define PROBEW 512\n\n#define FPSTART                                                                \\\n  if (state.fpen == 0) /* flt point disabled? */                               \\\n  {                                                                            \\\n    GO_PAL(FEN); /* set trap */                                                \\\n    break;       /* and stop current instruction */                            \\\n  }                                                                            \\\n  state.exc_sum = 0;\n\n/* Traps - corresponds to arithmetic trap summary register */\n#define TRAP_SWC U64(0x01) /* software completion */\n#define TRAP_INV U64(0x02) /* invalid operand */\n#define TRAP_DZE U64(0x04) /* divide by zero */\n#define TRAP_OVF U64(0x08) /* overflow */\n#define TRAP_UNF U64(0x10) /* underflow */\n#define TRAP_INE U64(0x20) /* inexact */\n#define TRAP_IOV U64(0x40) /* integer overflow */\n\n#define TRAP_INT U64(0x80) /* exception register is integer reg */\n\n#define ARITH_TRAP(flags, reg)                                                 \\\n  {                                                                            \\\n    state.exc_sum |= flags;             /* cause of trap */                    \\\n    state.exc_sum |= (reg & 0x1f) << 8; /* destination register */             \\\n    GO_PAL(ARITH);                      /* trap */                             \\\n  }\n\n#define ARITH_TRAP_I(flags, reg)                                               \\\n  {                                                                            \\\n    state.exc_sum = 0;                                                         \\\n    ARITH_TRAP(TRAP_INT | flags, reg)                                          \\\n  }\n\n#define SPE_0_MASK U64(0x0000ffffc0000000)  /* <47:30> */\n#define SPE_0_MATCH U64(0x0000ffff80000000) /* <47:31> */\n#define SPE_0_MAP U64(0x000000003fffffff)   /* <29:0>  */\n\n#define SPE_1_MASK U64(0x0000fe0000000000)  /* <47:41> */\n#define SPE_1_MATCH U64(0x0000fc0000000000) /* <47:42> */\n#define SPE_1_MAP U64(0x000001ffffffffff)   /* <40:0>  */\n#define SPE_1_TEST U64(0x0000010000000000)  /* <40>    */\n#define SPE_1_ADD U64(0x00000e0000000000)   /* <43:41> */\n\n#define SPE_2_MASK U64(0x0000c00000000000)  /* <47:46> */\n#define SPE_2_MATCH U64(0x0000800000000000) /* <47>    */\n#define SPE_2_MAP U64(0x00000fffffffffff)   /* <43:0>  */\n#endif\n"
  },
  {
    "path": "src/cpu_fp_branch.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if defined(HAVE_NEW_FP)\n#define DO_FBEQ                                                                \\\n  FPSTART;                                                                     \\\n  if ((state.f[FREG_1] & ~FPR_SIGN) == 0) /* +0 or - 0? */                     \\\n    add_pc(DISP_21 * 4);\n\n#define DO_FBGE                                                                \\\n  FPSTART;                                                                     \\\n  if (state.f[FREG_1] <= FPR_SIGN) /* +0 to + n? */                            \\\n    add_pc(DISP_21 * 4);\n\n#define DO_FBGT                                                                \\\n  FPSTART;                                                                     \\\n  if (!(state.f[FREG_1] & FPR_SIGN) && (state.f[FREG_1] != 0))                 \\\n                                                                               \\\n    /* not - and not 0? */                                                     \\\n    add_pc(DISP_21 * 4);\n\n#define DO_FBLE                                                                \\\n  FPSTART;                                                                     \\\n  if ((state.f[FREG_1] & FPR_SIGN) || (state.f[FREG_1] == 0))                  \\\n                                                                               \\\n    /* - or 0? */                                                              \\\n    add_pc(DISP_21 * 4);\n\n#define DO_FBLT                                                                \\\n  FPSTART;                                                                     \\\n  if (state.f[FREG_1] > FPR_SIGN) /* -0 to -n? */                              \\\n    add_pc(DISP_21 * 4);\n\n#define DO_FBNE                                                                \\\n  FPSTART;                                                                     \\\n  if ((state.f[FREG_1] & ~FPR_SIGN) != 0) /* not +0 or -0? */                  \\\n    add_pc(DISP_21 * 4);\n\n#else\n#define DO_FBEQ                                                                \\\n  FPSTART;                                                                     \\\n  if (state.f[FREG_1] == U64(0x0000000000000000) ||                            \\\n      state.f[FREG_1] == U64(0x8000000000000000))                              \\\n    add_pc(DISP_21 * 4);\n#define DO_FBGE                                                                \\\n  FPSTART;                                                                     \\\n  if (!(state.f[FREG_1] & U64(0x8000000000000000)) ||                          \\\n      state.f[FREG_1] == U64(0x8000000000000000))                              \\\n    add_pc(DISP_21 * 4);\n#define DO_FBGT                                                                \\\n  FPSTART;                                                                     \\\n  if (!(state.f[FREG_1] & U64(0x8000000000000000)) &&                          \\\n      state.f[FREG_1] != U64(0x0000000000000000))                              \\\n    add_pc(DISP_21 * 4);\n#define DO_FBLE                                                                \\\n  FPSTART;                                                                     \\\n  if ((state.f[FREG_1] & U64(0x8000000000000000)) ||                           \\\n      state.f[FREG_1] == U64(0x0000000000000000))                              \\\n    add_pc(DISP_21 * 4);\n#define DO_FBLT                                                                \\\n  FPSTART;                                                                     \\\n  if ((state.f[FREG_1] & U64(0x8000000000000000)) &&                           \\\n      state.f[FREG_1] != U64(0x8000000000000000))                              \\\n    add_pc(DISP_21 * 4);\n#define DO_FBNE                                                                \\\n  FPSTART;                                                                     \\\n  if (state.f[FREG_1] != U64(0x0000000000000000) &&                            \\\n      state.f[FREG_1] != U64(0x8000000000000000))                              \\\n    add_pc(DISP_21 * 4);\n#endif\n"
  },
  {
    "path": "src/cpu_fp_memory.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if defined(HAVE_NEW_FP)\n#define DO_LDF                                                                 \\\n  FPSTART;                                                                     \\\n  if (FREG_1 != 31) {                                                          \\\n    READ_VIRT_F(state.r[REG_2] + DISP_16, 32, state.f[FREG_1], vax_ldf);       \\\n  }\n\n#define DO_LDG                                                                 \\\n  FPSTART;                                                                     \\\n  if (FREG_1 != 31) {                                                          \\\n    READ_VIRT_F(state.r[REG_2] + DISP_16, 64, state.f[FREG_1], vax_ldg);       \\\n  }\n\n#define DO_LDS                                                                 \\\n  FPSTART;                                                                     \\\n  if (FREG_1 != 31) {                                                          \\\n    READ_VIRT_F(state.r[REG_2] + DISP_16, 32, state.f[FREG_1], ieee_lds);      \\\n  }\n\n#define DO_LDT                                                                 \\\n  FPSTART;                                                                     \\\n  if (FREG_1 != 31) {                                                          \\\n    READ_VIRT(state.r[REG_2] + DISP_16, 64, state.f[FREG_1]);                  \\\n  }\n\n#define DO_STF                                                                 \\\n  FPSTART;                                                                     \\\n  WRITE_VIRT(state.r[REG_2] + DISP_16, 32, vax_stf(state.f[FREG_1]));\n\n#define DO_STG                                                                 \\\n  FPSTART;                                                                     \\\n  WRITE_VIRT(state.r[REG_2] + DISP_16, 64, vax_stg(state.f[FREG_1]));\n\n#define DO_STS                                                                 \\\n  FPSTART;                                                                     \\\n  WRITE_VIRT(state.r[REG_2] + DISP_16, 32, ieee_sts(state.f[FREG_1]));\n\n#define DO_STT                                                                 \\\n  FPSTART;                                                                     \\\n  WRITE_VIRT(state.r[REG_2] + DISP_16, 64, state.f[FREG_1]);\n\n#else\n#define DO_LDF                                                                 \\\n  FPSTART;                                                                     \\\n  if (FREG_1 != 31) {                                                          \\\n    READ_VIRT_F(state.r[REG_2] + DISP_16, 32, state.f[FREG_1], load_f);        \\\n  }\n\n#define DO_LDG                                                                 \\\n  FPSTART;                                                                     \\\n  if (FREG_1 != 31) {                                                          \\\n    READ_VIRT_F(state.r[REG_2] + DISP_16, 64, state.f[FREG_1], load_g);        \\\n  }\n\n#define DO_LDS                                                                 \\\n  FPSTART;                                                                     \\\n  if (FREG_1 != 31) {                                                          \\\n    READ_VIRT_F(state.r[REG_2] + DISP_16, 32, state.f[FREG_1], load_s);        \\\n  }\n\n#define DO_LDT                                                                 \\\n  FPSTART;                                                                     \\\n  if (FREG_1 != 31) {                                                          \\\n    READ_VIRT(state.r[REG_2] + DISP_16, 64, state.f[FREG_1]);                  \\\n  }\n\n#define DO_STF                                                                 \\\n  FPSTART;                                                                     \\\n  WRITE_VIRT(state.r[REG_2] + DISP_16, 32, store_f(state.f[FREG_1]));\n\n#define DO_STG                                                                 \\\n  FPSTART;                                                                     \\\n  WRITE_VIRT(state.r[REG_2] + DISP_16, 64, store_g(state.f[FREG_1]));\n\n#define DO_STS                                                                 \\\n  FPSTART;                                                                     \\\n  WRITE_VIRT(state.r[REG_2] + DISP_16, 32, store_s(state.f[FREG_1]));\n\n#define DO_STT                                                                 \\\n  FPSTART;                                                                     \\\n  WRITE_VIRT(state.r[REG_2] + DISP_16, 64, state.f[FREG_1]);\n#endif\n"
  },
  {
    "path": "src/cpu_fp_operate.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if defined(HAVE_NEW_FP)\n\n/* copy sign */\n#define DO_CPYS                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] =                                                            \\\n      (state.f[FREG_1] & FPR_SIGN) | (state.f[FREG_2] & ~FPR_SIGN);\n\n#define DO_CPYSN                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = ((state.f[FREG_1] & FPR_SIGN) ^ FPR_SIGN) |                \\\n                    (state.f[FREG_2] & ~FPR_SIGN);\n\n#define DO_CPYSE                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = (state.f[FREG_1] & (FPR_SIGN | FPR_EXP)) |                 \\\n                    (state.f[FREG_2] & ~(FPR_SIGN | FPR_EXP));\n\n/* conditional move */\n#define DO_FCMOVEQ                                                             \\\n  FPSTART;                                                                     \\\n  if ((state.f[FREG_1] & ~FPR_SIGN) == 0)                                      \\\n    state.f[FREG_3] = state.f[FREG_2];\n\n#define DO_FCMOVGE                                                             \\\n  FPSTART;                                                                     \\\n  if (state.f[FREG_1] <= FPR_SIGN)                                             \\\n    state.f[FREG_3] = state.f[FREG_2];\n\n#define DO_FCMOVGT                                                             \\\n  FPSTART;                                                                     \\\n  if (!FPR_GETSIGN(state.f[FREG_1]) && (state.f[FREG_1] != 0))                 \\\n    state.f[FREG_3] = state.f[FREG_2];\n\n#define DO_FCMOVLE                                                             \\\n  FPSTART;                                                                     \\\n  if (FPR_GETSIGN(state.f[FREG_1]) || (state.f[FREG_1] == 0))                  \\\n    state.f[FREG_3] = state.f[FREG_2];\n\n#define DO_FCMOVLT                                                             \\\n  FPSTART;                                                                     \\\n  if (state.f[FREG_1] > FPR_SIGN)                                              \\\n    state.f[FREG_3] = state.f[FREG_2];\n\n#define DO_FCMOVNE                                                             \\\n  FPSTART;                                                                     \\\n  if ((state.f[FREG_1] & ~FPR_SIGN) != 0)                                      \\\n    state.f[FREG_3] = state.f[FREG_2];\n\n/* floating-point control register */\n#define DO_MF_FPCR                                                             \\\n  FPSTART;                                                                     \\\n  state.f[FREG_1] = state.fpcr;\n\n#define DO_MT_FPCR                                                             \\\n  FPSTART;                                                                     \\\n  state.fpcr = state.f[FREG_1] & U64(0x7fff800000000000);                      \\\n  if (state.fpcr & U64(0x03f0000000000000))                                    \\\n    state.fpcr |= U64(0x8000000000000000); /* SUM */\n\n/* add */\n#define DO_ADDG                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = vax_fadd(state.f[FREG_1], state.f[FREG_2], ins, DT_G, 0);\n\n#define DO_ADDF                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = vax_fadd(state.f[FREG_1], state.f[FREG_2], ins, DT_F, 0);\n\n#define DO_ADDT                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = ieee_fadd(state.f[FREG_1], state.f[FREG_2], ins, DT_T, 0);\n\n#define DO_ADDS                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = ieee_fadd(state.f[FREG_1], state.f[FREG_2], ins, DT_S, 0);\n\n/* subtract */\n#define DO_SUBG                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = vax_fadd(state.f[FREG_1], state.f[FREG_2], ins, DT_G, 1);\n\n#define DO_SUBF                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = vax_fadd(state.f[FREG_1], state.f[FREG_2], ins, DT_F, 1);\n\n#define DO_SUBT                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = ieee_fadd(state.f[FREG_1], state.f[FREG_2], ins, DT_T, 1);\n\n#define DO_SUBS                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = ieee_fadd(state.f[FREG_1], state.f[FREG_2], ins, DT_S, 1);\n\n/* comparison */\n#define DO_CMPGEQ                                                              \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] =                                                            \\\n      (vax_fcmp(state.f[FREG_1], state.f[FREG_2], ins) == 0) ? FP_TRUE : 0;\n\n#define DO_CMPGLE                                                              \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] =                                                            \\\n      (vax_fcmp(state.f[FREG_1], state.f[FREG_2], ins) <= 0) ? FP_TRUE : 0;\n\n#define DO_CMPGLT                                                              \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] =                                                            \\\n      (vax_fcmp(state.f[FREG_1], state.f[FREG_2], ins) < 0) ? FP_TRUE : 0;\n\n#define DO_CMPTEQ                                                              \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = (ieee_fcmp(state.f[FREG_1], state.f[FREG_2], ins, 0) == 0) \\\n                        ? FP_TRUE                                              \\\n                        : 0;\n\n#define DO_CMPTLE                                                              \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = (ieee_fcmp(state.f[FREG_1], state.f[FREG_2], ins, 1) <= 0) \\\n                        ? FP_TRUE                                              \\\n                        : 0;\n\n#define DO_CMPTLT                                                              \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] =                                                            \\\n      (ieee_fcmp(state.f[FREG_1], state.f[FREG_2], ins, 1) < 0) ? FP_TRUE : 0;\n\n#define DO_CMPTUN                                                              \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = ((ieee_unpack(state.f[FREG_1], &ufp1, ins) == UFT_NAN) ||  \\\n                     (ieee_unpack(state.f[FREG_2], &ufp2, ins) == UFT_NAN))    \\\n                        ? FP_TRUE                                              \\\n                        : 0;\n\n/* format conversions */\n#define DO_CVTQL                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = ((state.f[FREG_2] & 0xC0000000) << 32) |                   \\\n                    ((state.f[FREG_2] & 0x3FFFFFFF) << 29);                    \\\n  if (FPR_GETSIGN(state.f[FREG_2])                                             \\\n          ? (state.f[FREG_2] < U64(0xFFFFFFFF80000000))                        \\\n          : (state.f[FREG_2] > U64(0x000000007FFFFFFF))) {                     \\\n    if (ins & I_FTRP_V)                                                        \\\n      vax_trap(TRAP_IOV, ins);                                                 \\\n  }\n\n#define DO_CVTLQ                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = sext_u64_32(((state.f[FREG_2] >> 32) & 0xC0000000) |       \\\n                                ((state.f[FREG_2] >> 29) & 0x3FFFFFFF));\n\n#define DO_CVTGQ                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = vax_cvtfi(state.f[FREG_2], ins);\n\n#define DO_CVTQG                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = vax_cvtif(state.f[FREG_2], ins, DT_G);\n\n#define DO_CVTQF                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = vax_cvtif(state.f[FREG_2], ins, DT_F);\n\n#define DO_CVTTQ                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = ieee_cvtfi(state.f[FREG_2], ins);\n\n#define DO_CVTQT                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = ieee_cvtif(state.f[FREG_2], ins, DT_T);\n\n#define DO_CVTQS                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = ieee_cvtif(state.f[FREG_2], ins, DT_S);\n\n#define DO_CVTGD                                                               \\\n  FPSTART;                                                                     \\\n  vax_unpack(state.f[FREG_2], &ufp2, ins);                                     \\\n  state.f[FREG_3] = vax_rpack_d(&ufp2, ins);\n\n#define DO_CVTDG                                                               \\\n  FPSTART;                                                                     \\\n  vax_unpack_d(state.f[FREG_2], &ufp2, ins);                                   \\\n  state.f[FREG_3] = vax_rpack(&ufp2, ins, DT_G);\n\n#define DO_CVTGF                                                               \\\n  FPSTART;                                                                     \\\n  vax_unpack(state.f[FREG_2], &ufp2, ins);                                     \\\n  state.f[FREG_3] = vax_rpack(&ufp2, ins, DT_F);\n\n#define DO_CVTST                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = ieee_cvtst(state.f[FREG_2], ins);\n\n#define DO_CVTTS                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = ieee_cvtts(state.f[FREG_2], ins);\n\n/* float <-> integer register moves */\n#define DO_FTOIS                                                               \\\n  FPSTART;                                                                     \\\n  state.r[REG_3] = ieee_sts(state.f[FREG_1]);\n\n#define DO_FTOIT                                                               \\\n  FPSTART;                                                                     \\\n  state.r[REG_3] = state.f[FREG_1];\n\n#define DO_ITOFT                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = state.r[REG_1];\n\n#define DO_ITOFS                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = ieee_lds((u32)state.r[REG_1]);\n\n#define DO_ITOFF                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = vax_ldf(SWAP_VAXF((u32)state.r[REG_1]));\n\n/* Multiply */\n#define DO_MULG                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = vax_fmul(state.f[FREG_1], state.f[FREG_2], ins, DT_G);\n\n#define DO_MULF                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = vax_fmul(state.f[FREG_1], state.f[FREG_2], ins, DT_F);\n\n#define DO_MULT                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = ieee_fmul(state.f[FREG_1], state.f[FREG_2], ins, DT_T);\n\n#define DO_MULS                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = ieee_fmul(state.f[FREG_1], state.f[FREG_2], ins, DT_S);\n\n/* Divide */\n#define DO_DIVG                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = vax_fdiv(state.f[FREG_1], state.f[FREG_2], ins, DT_G);\n\n#define DO_DIVF                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = vax_fdiv(state.f[FREG_1], state.f[FREG_2], ins, DT_F);\n\n#define DO_DIVT                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = ieee_fdiv(state.f[FREG_1], state.f[FREG_2], ins, DT_T);\n\n#define DO_DIVS                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = ieee_fdiv(state.f[FREG_1], state.f[FREG_2], ins, DT_S);\n\n/* Square-root */\n#define DO_SQRTG                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = vax_sqrt(state.f[FREG_2], ins, DT_G);\n\n#define DO_SQRTF                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = vax_sqrt(state.f[FREG_2], ins, DT_F);\n\n#define DO_SQRTT                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = ieee_sqrt(state.f[FREG_2], ins, DT_T);\n\n#define DO_SQRTS                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = ieee_sqrt(state.f[FREG_2], ins, DT_S);\n\n#else\n#define DO_CPYS                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = (state.f[FREG_1] & U64(0x8000000000000000)) |              \\\n                    (state.f[FREG_2] & U64(0x7fffffffffffffff));\n\n#define DO_CPYSN                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] =                                                            \\\n      (state.f[FREG_1] & U64(0x8000000000000000) ^ U64(0x8000000000000000)) |  \\\n      (state.f[FREG_2] & U64(0x7fffffffffffffff));\n\n#define DO_CPYSE                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = (state.f[FREG_1] & U64(0xfff0000000000000)) |              \\\n                    (state.f[FREG_2] & U64(0x000fffffffffffff));\n\n#define DO_CVTQL                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = ((state.f[FREG_2] & U64(0x00000000c0000000)) << 32) |      \\\n                    ((state.f[FREG_2] & U64(0x000000003fffffff)) << 29);\n\n#define DO_CVTLQ                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] =                                                            \\\n      sext_u64_32(((state.f[FREG_2] >> 32) & U64(0x00000000c0000000)) |        \\\n                  ((state.f[FREG_2] >> 29) & U64(0x000000003fffffff)));\n\n#define DO_FCMOVEQ                                                             \\\n  FPSTART;                                                                     \\\n  if (state.f[FREG_1] == U64(0x0000000000000000) ||                            \\\n      state.f[FREG_1] == U64(0x8000000000000000))                              \\\n    state.f[FREG_3] = state.f[FREG_2];\n#define DO_FCMOVGE                                                             \\\n  FPSTART;                                                                     \\\n  if (!(state.f[FREG_1] & U64(0x8000000000000000)) ||                          \\\n      state.f[FREG_1] == U64(0x8000000000000000))                              \\\n    state.f[FREG_3] = state.f[FREG_2];\n#define DO_FCMOVGT                                                             \\\n  FPSTART;                                                                     \\\n  if (!(state.f[FREG_1] & U64(0x8000000000000000)) &&                          \\\n      state.f[FREG_1] != U64(0x0000000000000000))                              \\\n    state.f[FREG_3] = state.f[FREG_2];\n#define DO_FCMOVLE                                                             \\\n  FPSTART;                                                                     \\\n  if ((state.f[FREG_1] & U64(0x8000000000000000)) ||                           \\\n      state.f[FREG_1] == U64(0x0000000000000000))                              \\\n    state.f[FREG_3] = state.f[FREG_2];\n#define DO_FCMOVLT                                                             \\\n  FPSTART;                                                                     \\\n  if ((state.f[FREG_1] & U64(0x8000000000000000)) &&                           \\\n      state.f[FREG_1] != U64(0x8000000000000000))                              \\\n    state.f[FREG_3] = state.f[FREG_2];\n#define DO_FCMOVNE                                                             \\\n  FPSTART;                                                                     \\\n  if (state.f[FREG_1] != U64(0x0000000000000000) &&                            \\\n      state.f[FREG_1] != U64(0x8000000000000000))                              \\\n    state.f[FREG_3] = state.f[FREG_2];\n\n#define DO_MF_FPCR                                                             \\\n  FPSTART;                                                                     \\\n  state.f[FREG_1] = state.fpcr;\n#define DO_MT_FPCR                                                             \\\n  FPSTART;                                                                     \\\n  state.fpcr = state.f[FREG_1];\n\n#define DO_ADDG                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2g(g2host(state.f[FREG_1]) + g2host(state.f[FREG_2]));\n#define DO_ADDF                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2f(f2host(state.f[FREG_1]) + f2host(state.f[FREG_2]));\n#define DO_ADDT                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2t(t2host(state.f[FREG_1]) + t2host(state.f[FREG_2]));\n#define DO_ADDS                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2s(s2host(state.f[FREG_1]) + s2host(state.f[FREG_2]));\n\n#define DO_SUBG                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2g(g2host(state.f[FREG_1]) - g2host(state.f[FREG_2]));\n#define DO_SUBF                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2f(f2host(state.f[FREG_1]) - f2host(state.f[FREG_2]));\n#define DO_SUBT                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2t(t2host(state.f[FREG_1]) - t2host(state.f[FREG_2]));\n#define DO_SUBS                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2s(s2host(state.f[FREG_1]) - s2host(state.f[FREG_2]));\n\n#define DO_CMPGEQ                                                              \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = (g2host(state.f[FREG_1]) == g2host(state.f[FREG_2]))       \\\n                        ? U64(0x4000000000000000)                              \\\n                        : 0;\n#define DO_CMPGLE                                                              \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = (g2host(state.f[FREG_1]) <= g2host(state.f[FREG_2]))       \\\n                        ? U64(0x4000000000000000)                              \\\n                        : 0;\n#define DO_CMPGLT                                                              \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = (g2host(state.f[FREG_1]) < g2host(state.f[FREG_2]))        \\\n                        ? U64(0x4000000000000000)                              \\\n                        : 0;\n\n#define DO_CMPTEQ                                                              \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = (t2host(state.f[FREG_1]) == t2host(state.f[FREG_2]))       \\\n                        ? U64(0x4000000000000000)                              \\\n                        : 0;\n#define DO_CMPTLE                                                              \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = (t2host(state.f[FREG_1]) <= t2host(state.f[FREG_2]))       \\\n                        ? U64(0x4000000000000000)                              \\\n                        : 0;\n#define DO_CMPTLT                                                              \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = (t2host(state.f[FREG_1]) < t2host(state.f[FREG_2]))        \\\n                        ? U64(0x4000000000000000)                              \\\n                        : 0;\n#define DO_CMPTUN                                                              \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = (i_isnan(state.f[FREG_1]) || i_isnan(state.f[FREG_2]))     \\\n                        ? U64(0x4000000000000000)                              \\\n                        : 0;\n\n#define DO_CVTGQ                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = (u64)((s64)g2host(state.f[FREG_2]));\n#define DO_CVTQG                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2g((double)((s64)state.f[FREG_2]));\n#define DO_CVTQF                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2f((double)((s64)state.f[FREG_2]));\n\n#define DO_CVTTQ                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = (u64)((s64)t2host(state.f[FREG_2]));\n#define DO_CVTQT                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2t((double)((s64)state.f[FREG_2]));\n#define DO_CVTQS                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2s((double)((s64)state.f[FREG_2]));\n#define DO_CVTGD                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2d(g2host(state.f[FREG_2]));\n#define DO_CVTDG                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2g(d2host(state.f[FREG_2]));\n#define DO_CVTGF                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2f(g2host(state.f[FREG_2]));\n\n#define DO_FTOIS                                                               \\\n  FPSTART;                                                                     \\\n  temp_64 = state.f[FREG_1];                                                   \\\n  state.r[REG_3] =                                                             \\\n      (temp_64 & U64(0x000000003fffffff)) |                                    \\\n      ((temp_64 & U64(0xc000000000000000)) >> 32) |                            \\\n      (((temp_64 & U64(0x8000000000000000)) >> 31) * U64(0xffffffff));\n\n#define DO_FTOIT                                                               \\\n  FPSTART;                                                                     \\\n  state.r[REG_3] = state.f[FREG_1];\n#define DO_ITOFT                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = state.r[REG_1];\n#define DO_ITOFS                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = load_s((u32)state.r[REG_1]);\n#define DO_ITOFF                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = itof_f(state.r[REG_1]);\n\n#define DO_MULG                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2g(g2host(state.f[FREG_1]) * g2host(state.f[FREG_2]));\n#define DO_MULF                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2f(f2host(state.f[FREG_1]) * f2host(state.f[FREG_2]));\n#define DO_MULT                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2t(t2host(state.f[FREG_1]) * t2host(state.f[FREG_2]));\n#define DO_MULS                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2s(s2host(state.f[FREG_1]) * s2host(state.f[FREG_2]));\n\n#define DO_DIVG                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2g(g2host(state.f[FREG_1]) / g2host(state.f[FREG_2]));\n#define DO_DIVF                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2f(f2host(state.f[FREG_1]) / f2host(state.f[FREG_2]));\n#define DO_DIVT                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2t(t2host(state.f[FREG_1]) / t2host(state.f[FREG_2]));\n#define DO_DIVS                                                                \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2s(s2host(state.f[FREG_1]) / s2host(state.f[FREG_2]));\n\n#define DO_SQRTG                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2g(sqrt(g2host(state.f[FREG_2])));\n#define DO_SQRTF                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2f(sqrt(f2host(state.f[FREG_2])));\n#define DO_SQRTT                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2t(sqrt(t2host(state.f[FREG_2])));\n#define DO_SQRTS                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2s(sqrt(s2host(state.f[FREG_2])));\n\n#define DO_CVTST                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2t(s2host(state.f[FREG_2]));\n#define DO_CVTTS                                                               \\\n  FPSTART;                                                                     \\\n  state.f[FREG_3] = host2s(t2host(state.f[FREG_2]));\n#endif\n"
  },
  {
    "path": "src/cpu_logical.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#define DO_AND state.r[REG_3] = state.r[REG_1] & V_2;\n#define DO_BIC state.r[REG_3] = state.r[REG_1] & ~V_2;\n#define DO_BIS state.r[REG_3] = state.r[REG_1] | V_2;\n#define DO_EQV state.r[REG_3] = state.r[REG_1] ^ ~V_2;\n#define DO_ORNOT state.r[REG_3] = state.r[REG_1] | ~V_2;\n#define DO_XOR state.r[REG_3] = state.r[REG_1] ^ V_2;\n\n#define DO_CMOVEQ                                                              \\\n  if (!state.r[REG_1])                                                         \\\n    state.r[REG_3] = V_2;\n#define DO_CMOVGE                                                              \\\n  if ((s64)state.r[REG_1] >= 0)                                                \\\n    state.r[REG_3] = V_2;\n#define DO_CMOVGT                                                              \\\n  if ((s64)state.r[REG_1] > 0)                                                 \\\n    state.r[REG_3] = V_2;\n#define DO_CMOVLBC                                                             \\\n  if (!(state.r[REG_1] & U64(0x1)))                                            \\\n    state.r[REG_3] = V_2;\n#define DO_CMOVLBS                                                             \\\n  if (state.r[REG_1] & U64(0x1))                                               \\\n    state.r[REG_3] = V_2;\n#define DO_CMOVLE                                                              \\\n  if ((s64)state.r[REG_1] <= 0)                                                \\\n    state.r[REG_3] = V_2;\n#define DO_CMOVLT                                                              \\\n  if ((s64)state.r[REG_1] < 0)                                                 \\\n    state.r[REG_3] = V_2;\n#define DO_CMOVNE                                                              \\\n  if (state.r[REG_1])                                                          \\\n    state.r[REG_3] = V_2;\n\n#define DO_SLL state.r[REG_3] = state.r[REG_1] << (V_2 & 63);\n#define DO_SRA                                                                 \\\n  state.r[REG_3] =                                                             \\\n      (V_2 & 63)                                                               \\\n          ? ((state.r[REG_1] >> (V_2 & 63)) |                                  \\\n             ((state.r[REG_1] >> 63) ? (X64_QUAD << (64 - (V_2 & 63))) : 0))   \\\n          : state.r[REG_1];\n#define DO_SRL state.r[REG_3] = state.r[REG_1] >> (V_2 & 63);\n"
  },
  {
    "path": "src/cpu_memory.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#define DO_LDA state.r[REG_1] = state.r[REG_2] + DISP_16;\n\n#define DO_LDAH state.r[REG_1] = state.r[REG_2] + (DISP_16 << 16);\n\n#define DO_LDBU READ_VIRT(state.r[REG_2] + DISP_16, 8, state.r[REG_1]);\n\n#define DO_LDL                                                                 \\\n  READ_VIRT_F(state.r[REG_2] + DISP_16, 32, state.r[REG_1], sext_u64_32);\n\n#define DO_LDL_L                                                               \\\n  READ_VIRT_LOCK_F(state.r[REG_2] + DISP_16, 32, state.r[REG_1], sext_u64_32);\n\n#define DO_LDQ READ_VIRT(state.r[REG_2] + DISP_16, 64, state.r[REG_1]);\n\n#define DO_LDQ_L READ_VIRT_LOCK(state.r[REG_2] + DISP_16, 64, state.r[REG_1]);\n\n#define DO_LDQ_U                                                               \\\n  READ_VIRT((state.r[REG_2] + DISP_16) & ~U64(0x7), 64, state.r[REG_1]);\n\n#define DO_LDWU READ_VIRT(state.r[REG_2] + DISP_16, 16, state.r[REG_1]);\n\n#define DO_STB WRITE_VIRT(state.r[REG_2] + DISP_16, 8, state.r[REG_1]);\n\n#define DO_STL WRITE_VIRT(state.r[REG_2] + DISP_16, 32, state.r[REG_1]);\n\n#define DO_STL_C                                                               \\\n  if (cSystem->cpu_unlock(state.iProcNum)) {                                   \\\n    WRITE_VIRT(state.r[REG_2] + DISP_16, 32, state.r[REG_1]);                  \\\n    state.r[REG_1] = 1;                                                        \\\n  } else                                                                       \\\n    state.r[REG_1] = 0;\n\n#define DO_STQ WRITE_VIRT(state.r[REG_2] + DISP_16, 64, state.r[REG_1]);\n\n#define DO_STQ_C                                                               \\\n  if (cSystem->cpu_unlock(state.iProcNum)) {                                   \\\n    WRITE_VIRT(state.r[REG_2] + DISP_16, 64, state.r[REG_1]);                  \\\n    state.r[REG_1] = 1;                                                        \\\n  } else                                                                       \\\n    state.r[REG_1] = 0;\n\n#define DO_STQ_U                                                               \\\n  WRITE_VIRT((state.r[REG_2] + DISP_16) & ~U64(0x07), 64, state.r[REG_1]);\n\n#define DO_STW WRITE_VIRT(state.r[REG_2] + DISP_16, 16, state.r[REG_1]);\n"
  },
  {
    "path": "src/cpu_misc.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#define DO_AMASK state.r[REG_3] = V_2 & ~CPU_AMASK;\n\n#define DO_CALL_PAL                                                            \\\n  if (((function < 0x40) && ((state.cm != 0))) ||                              \\\n      ((function > 0x3f) && (function < 0x80)) || (function > 0xbf)) {         \\\n    UNKNOWN2                                                                   \\\n  } else {                                                                     \\\n    if (state.pal_vms) {                                                       \\\n      switch (function) {                                                      \\\n      case 0x01: /* CFLUSH */                                                  \\\n        vmspal_call_cflush();                                                  \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x02: /* DRAINA */                                                  \\\n        vmspal_call_draina();                                                  \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x03: /* LDQP */                                                    \\\n        vmspal_call_ldqp();                                                    \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x04: /* STQP */                                                    \\\n        vmspal_call_stqp();                                                    \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x05: /* SWPCTX */                                                  \\\n        vmspal_call_swpctx();                                                  \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x06: /* MFPR_ASN */                                                \\\n        vmspal_call_mfpr_asn();                                                \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x07: /* MTPR_ASTEN */                                              \\\n        vmspal_call_mtpr_asten();                                              \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x08: /* MTPR_ASTSR */                                              \\\n        vmspal_call_mtpr_astsr();                                              \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x09: /* CSERVE */                                                  \\\n        vmspal_call_cserve();                                                  \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x0b: /* MFPR_FEN */                                                \\\n        vmspal_call_mfpr_fen();                                                \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x0c: /* MTPR_FEN */                                                \\\n        vmspal_call_mtpr_fen();                                                \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x0e: /* MFPR_IPL */                                                \\\n        vmspal_call_mfpr_ipl();                                                \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x0f: /* MTPR_IPL */                                                \\\n        vmspal_call_mtpr_ipl();                                                \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x10: /* MFPR_MCES */                                               \\\n        vmspal_call_mfpr_mces();                                               \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x11: /* MTPR_MCES */                                               \\\n        vmspal_call_mtpr_mces();                                               \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x12: /* MFPR_PCBB */                                               \\\n        vmspal_call_mfpr_pcbb();                                               \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x13: /* MFPR_PRBR */                                               \\\n        vmspal_call_mfpr_prbr();                                               \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x14: /* MTPR_PRBR */                                               \\\n        vmspal_call_mtpr_prbr();                                               \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x15: /* MFPR_PTBR */                                               \\\n        vmspal_call_mfpr_ptbr();                                               \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x16: /* MFPR_SCBB */                                               \\\n        vmspal_call_mfpr_scbb();                                               \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x17: /* MTPR_SCBB */                                               \\\n        vmspal_call_mtpr_scbb();                                               \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x18: /* MTPR_SIRR */                                               \\\n        vmspal_call_mtpr_sirr();                                               \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x19: /* MFPR_SISR */                                               \\\n        vmspal_call_mfpr_sisr();                                               \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x1a: /* MFPR_TBCHK */                                              \\\n        vmspal_call_mfpr_tbchk();                                              \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x1b: /* MTPR_TBIA */                                               \\\n        vmspal_call_mtpr_tbia();                                               \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x1c: /* MTPR_TBIAP */                                              \\\n        vmspal_call_mtpr_tbiap();                                              \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x1d: /* MTPR_TBIS */                                               \\\n        vmspal_call_mtpr_tbis();                                               \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x1e: /* MFPR_ESP */                                                \\\n        vmspal_call_mfpr_esp();                                                \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x1f: /* MTPR_ESP */                                                \\\n        vmspal_call_mtpr_esp();                                                \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x20: /* MFPR_SSP */                                                \\\n        vmspal_call_mfpr_ssp();                                                \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x21: /* MTPR_SSP */                                                \\\n        vmspal_call_mtpr_ssp();                                                \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x22: /* MFPR_USP */                                                \\\n        vmspal_call_mfpr_usp();                                                \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x23: /* MTPR_USP */                                                \\\n        vmspal_call_mtpr_usp();                                                \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x24: /* MTPR_TBISD */                                              \\\n        vmspal_call_mtpr_tbisd();                                              \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x25: /* MTPR_TBISI */                                              \\\n        vmspal_call_mtpr_tbisi();                                              \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x26: /* MFPR_ASTEN */                                              \\\n        vmspal_call_mfpr_asten();                                              \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x27: /* MFPR_ASTSR */                                              \\\n        vmspal_call_mfpr_astsr();                                              \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x29: /* MFPR_VPTB */                                               \\\n        vmspal_call_mfpr_vptb();                                               \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x2e: /* MTPR_DATFX */                                              \\\n        vmspal_call_mtpr_datfx();                                              \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x3f: /* MFPR_WHAMI */                                              \\\n        vmspal_call_mfpr_whami();                                              \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x86: /* IMB */                                                     \\\n        vmspal_call_imb();                                                     \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x8f: /* PROBER */                                                  \\\n        vmspal_call_prober();                                                  \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x90: /* PROBEW */                                                  \\\n        vmspal_call_probew();                                                  \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x91: /* RD_PS */                                                   \\\n        vmspal_call_rd_ps();                                                   \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x92: /* REI */                                                     \\\n        vmspal_call_rei();                                                     \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x9b: /* SWASTEN */                                                 \\\n        vmspal_call_swasten();                                                 \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x9c: /* WR_PS_SW */                                                \\\n        vmspal_call_wr_ps_sw();                                                \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x9d: /* RSCC */                                                    \\\n        vmspal_call_rscc();                                                    \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x9e: /* READ_UNQ */                                                \\\n        vmspal_call_read_unq();                                                \\\n        break;                                                                 \\\n                                                                               \\\n      case 0x9f: /* WRITE_UNQ */                                               \\\n        vmspal_call_write_unq();                                               \\\n        break;                                                                 \\\n                                                                               \\\n      default:                                                                 \\\n        state.r[32 + 23] = state.pc;                                           \\\n        set_pc(state.pal_base | (1 << 13) | ((function & 0x80) << 5) |         \\\n               ((function & 0x3f) << 6) | 1);                                  \\\n        TRC(true, false)                                                       \\\n      }                                                                        \\\n    } else {                                                                   \\\n      state.r[32 + 23] = state.pc;                                             \\\n      set_pc(state.pal_base | (1 << 13) | ((function & 0x80) << 5) |           \\\n             ((function & 0x3f) << 6) | 1);                                    \\\n      TRC(true, false)                                                         \\\n    }                                                                          \\\n  }\n\n#define DO_IMPLVER state.r[REG_3] = CPU_IMPLVER;\n\n#define DO_RPCC                                                                \\\n  state.r[REG_1] = ((u64)state.cc_offset) << 32 | (state.cc & U64(0xffffffff));\n\n// The following ops have no function right now (at least, not until multiple\n// CPU's are supported).\n#define DO_TRAPB ;\n#define DO_EXCB ;\n#define DO_MB ;\n#define DO_WMB ;\n#define DO_FETCH ;\n#define DO_FETCH_M ;\n#define DO_ECB ;\n#define DO_WH64 ;\n#define DO_WH64EN ;\n"
  },
  {
    "path": "src/cpu_mvi.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#define DO_MINUB8                                                              \\\n  temp_64 = 0;                                                                 \\\n  temp_64_1 = state.r[REG_1];                                                  \\\n  temp_64_2 = V_2;                                                             \\\n  for (i = 0; i < 64; i += 8) {                                                \\\n    if ((u8)((temp_64_1 >> i) & X64_BYTE) > (u8)((temp_64_2 >> i) & X64_BYTE)) \\\n      temp_64 |= (((temp_64_2 >> i) & X64_BYTE) << i);                         \\\n    else                                                                       \\\n      temp_64 |= (((temp_64_1 >> i) & X64_BYTE) << i);                         \\\n  }                                                                            \\\n  state.r[REG_3] = temp_64;\n\n#define DO_MINSB8                                                              \\\n  temp_64 = 0;                                                                 \\\n  temp_64_1 = state.r[REG_1];                                                  \\\n  temp_64_2 = V_2;                                                             \\\n  for (i = 0; i < 64; i += 8) {                                                \\\n    if ((s8)((temp_64_1 >> i) & X64_BYTE) > (s8)((temp_64_2 >> i) & X64_BYTE)) \\\n      temp_64 |= (((temp_64_2 >> i) & X64_BYTE) << i);                         \\\n    else                                                                       \\\n      temp_64 |= (((temp_64_1 >> i) & X64_BYTE) << i);                         \\\n  }                                                                            \\\n  state.r[REG_3] = temp_64;\n\n#define DO_MINUW4                                                              \\\n  temp_64 = 0;                                                                 \\\n  temp_64_1 = state.r[REG_1];                                                  \\\n  temp_64_2 = V_2;                                                             \\\n  for (i = 0; i < 64; i += 16) {                                               \\\n    if ((u16)((temp_64_1 >> i) & X64_WORD) >                                   \\\n        (u16)((temp_64_2 >> i) & X64_WORD))                                    \\\n      temp_64 |= (((temp_64_2 >> i) & X64_WORD) << i);                         \\\n    else                                                                       \\\n      temp_64 |= (((temp_64_1 >> i) & X64_WORD) << i);                         \\\n  }                                                                            \\\n  state.r[REG_3] = temp_64;\n\n#define DO_MINSW4                                                              \\\n  temp_64 = 0;                                                                 \\\n  temp_64_1 = state.r[REG_1];                                                  \\\n  temp_64_2 = V_2;                                                             \\\n  for (i = 0; i < 64; i += 16) {                                               \\\n    if ((s16)((temp_64_1 >> i) & X64_WORD) >                                   \\\n        (s16)((temp_64_2 >> i) & X64_WORD))                                    \\\n      temp_64 |= (((temp_64_2 >> i) & X64_WORD) << i);                         \\\n    else                                                                       \\\n      temp_64 |= (((temp_64_1 >> i) & X64_WORD) << i);                         \\\n  }                                                                            \\\n  state.r[REG_3] = temp_64;\n\n#define DO_MAXUB8                                                              \\\n  temp_64 = 0;                                                                 \\\n  temp_64_1 = state.r[REG_1];                                                  \\\n  temp_64_2 = V_2;                                                             \\\n  for (i = 0; i < 64; i += 8) {                                                \\\n    if ((u8)((temp_64_1 >> i) & X64_BYTE) > (u8)((temp_64_2 >> i) & X64_BYTE)) \\\n      temp_64 |= (((temp_64_1 >> i) & X64_BYTE) << i);                         \\\n    else                                                                       \\\n      temp_64 |= (((temp_64_2 >> i) & X64_BYTE) << i);                         \\\n  }                                                                            \\\n  state.r[REG_3] = temp_64;\n\n#define DO_MAXSB8                                                              \\\n  temp_64 = 0;                                                                 \\\n  temp_64_1 = state.r[REG_1];                                                  \\\n  temp_64_2 = V_2;                                                             \\\n  for (i = 0; i < 64; i += 8) {                                                \\\n    if ((s8)((temp_64_1 >> i) & X64_BYTE) > (s8)((temp_64_2 >> i) & X64_BYTE)) \\\n      temp_64 |= (((temp_64_1 >> i) & X64_BYTE) << i);                         \\\n    else                                                                       \\\n      temp_64 |= (((temp_64_2 >> i) & X64_BYTE) << i);                         \\\n  }                                                                            \\\n  state.r[REG_3] = temp_64;\n\n#define DO_MAXUW4                                                              \\\n  temp_64 = 0;                                                                 \\\n  temp_64_1 = state.r[REG_1];                                                  \\\n  temp_64_2 = V_2;                                                             \\\n  for (i = 0; i < 64; i += 16) {                                               \\\n    if ((u16)((temp_64_1 >> i) & X64_WORD) >                                   \\\n        (u16)((temp_64_2 >> i) & X64_WORD))                                    \\\n      temp_64 |= (((temp_64_1 >> i) & X64_WORD) << i);                         \\\n    else                                                                       \\\n      temp_64 |= (((temp_64_2 >> i) & X64_WORD) << i);                         \\\n  }                                                                            \\\n  state.r[REG_3] = temp_64;\n\n#define DO_MAXSW4                                                              \\\n  temp_64 = 0;                                                                 \\\n  temp_64_1 = state.r[REG_1];                                                  \\\n  temp_64_2 = V_2;                                                             \\\n  for (i = 0; i < 64; i += 16) {                                               \\\n    if ((s16)((temp_64_1 >> i) & X64_WORD) >                                   \\\n        (s16)((temp_64_2 >> i) & X64_WORD))                                    \\\n      temp_64 |= (((temp_64_1 >> i) & X64_WORD) << i);                         \\\n    else                                                                       \\\n      temp_64 |= (((temp_64_2 >> i) & X64_WORD) << i);                         \\\n  }                                                                            \\\n  state.r[REG_3] = temp_64;\n\n#define DO_PERR                                                                \\\n  temp_64 = 0;                                                                 \\\n  temp_64_1 = state.r[REG_1];                                                  \\\n  temp_64_2 = V_2;                                                             \\\n  for (i = 0; i < 64; i += 8) {                                                \\\n    if ((s8)((temp_64_1 >> i) & X64_BYTE) > (s8)((temp_64_2 >> i) & X64_BYTE)) \\\n      temp_64 |= ((u64)((s8)((temp_64_1 >> i) & X64_BYTE) -                    \\\n                        (s8)((temp_64_2 >> i) & X64_BYTE))                     \\\n                  << i);                                                       \\\n    else                                                                       \\\n      temp_64 |= ((u64)((s8)((temp_64_2 >> i) & X64_BYTE) -                    \\\n                        (s8)((temp_64_1 >> i) & X64_BYTE))                     \\\n                  << i);                                                       \\\n  }                                                                            \\\n  state.r[REG_3] = temp_64;\n\n#define DO_PKLB                                                                \\\n  temp_64_2 = V_2;                                                             \\\n  state.r[REG_3] = (temp_64_2 & U64(0x00000000000000ff)) |                     \\\n                   ((temp_64_2 & U64(0x000000ff00000000)) >> 24);\n\n#define DO_PKWB                                                                \\\n  temp_64_2 = V_2;                                                             \\\n  state.r[REG_3] = (temp_64_2 & U64(0x00000000000000ff)) |                     \\\n                   ((temp_64_2 & U64(0x0000000000ff0000)) >> 8) |              \\\n                   ((temp_64_2 & U64(0x000000ff00000000)) >> 16) |             \\\n                   ((temp_64_2 & U64(0x00ff000000000000)) >> 24);\n\n#define DO_UNPKBL                                                              \\\n  temp_64_2 = V_2;                                                             \\\n  state.r[REG_3] =                                                             \\\n      (temp_64_2 & U64(0x000000ff)) | ((temp_64_2 & U64(0x0000ff00)) << 24);\n\n#define DO_UNPKBW                                                              \\\n  temp_64_2 = V_2;                                                             \\\n  state.r[REG_3] = (temp_64_2 & U64(0x000000ff)) |                             \\\n                   ((temp_64_2 & U64(0x0000ff00)) << 8) |                      \\\n                   ((temp_64_2 & U64(0x00ff0000)) << 16) |                     \\\n                   ((temp_64_2 & U64(0xff000000)) << 24);\n"
  },
  {
    "path": "src/cpu_pal.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#define DO_HW_MFPR                                                             \\\n  if ((function & 0xc0) == 0x40) { /* PCTX */                                  \\\n    state.r[REG_1] = ((u64)state.asn << 39) | ((u64)state.astrr << 9) |        \\\n                     ((u64)state.aster << 5) |                                 \\\n                     (state.fpen ? U64(0x1) << 2 : 0) |                        \\\n                     (state.ppcen ? U64(0x1) << 1 : 0);                        \\\n  } else {                                                                     \\\n    switch (function) {                                                        \\\n    case 0x05: /* PMPC     */                                                  \\\n      state.r[REG_1] = state.pmpc;                                             \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x06: /* EXC_ADDR */                                                  \\\n      state.r[REG_1] = state.exc_addr;                                         \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x07: /* IVA_FORM */                                                  \\\n      state.r[REG_1] = va_form(state.exc_addr, true);                          \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x08: /* IER_CM   */                                                  \\\n    case 0x09: /* CM       */                                                  \\\n    case 0x0a: /* IER      */                                                  \\\n    case 0x0b: /* IER_CM   */                                                  \\\n      state.r[REG_1] = (((u64)state.eien) << 33) | (((u64)state.slen) << 32) | \\\n                       (((u64)state.cren) << 31) | (((u64)state.pcen) << 29) | \\\n                       (((u64)state.sien) << 13) |                             \\\n                       (((u64)state.asten) << 13) | (((u64)state.cm) << 3);    \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x0c: /* SIRR */                                                      \\\n      state.r[REG_1] = ((u64)state.sir) << 13;                                 \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x0d: /* ISUM */                                                      \\\n      state.r[REG_1] =                                                         \\\n          (((u64)(state.eir & state.eien)) << 33) |                            \\\n          (((u64)(state.slr & state.slen)) << 32) |                            \\\n          (((u64)(state.crr & state.cren)) << 31) |                            \\\n          (((u64)(state.pcr & state.pcen)) << 29) |                            \\\n          (((u64)(state.sir & state.sien)) << 13) |                            \\\n          (((u64)(((U64(0x1) << (state.cm + 1)) - 1) & state.aster &           \\\n                  state.astrr & (state.asten * 0x3)))                          \\\n           << 3) |                                                             \\\n          (((u64)(((U64(0x1) << (state.cm + 1)) - 1) & state.aster &           \\\n                  state.astrr & (state.asten * 0xc)))                          \\\n           << 7);                                                              \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x0f: /* EXC_SUM */                                                   \\\n      state.r[REG_1] = state.exc_sum;                                          \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x10: /* PAL_BASE */                                                  \\\n      state.r[REG_1] = state.pal_base;                                         \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x11: /* i_ctl */                                                     \\\n      state.r[REG_1] =                                                         \\\n          state.i_ctl_other | (((u64)CPU_CHIP_ID) << 24) |                     \\\n          (u64)state.i_ctl_vptb | (((u64)state.i_ctl_va_mode) << 15) |         \\\n          (state.hwe ? U64(0x1) << 12 : 0) | (state.sde ? U64(0x1) << 7 : 0) | \\\n          (((u64)state.i_ctl_spe) << 3);                                       \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x14: /* PCTR_CTL */                                                  \\\n      state.r[REG_1] = state.pctr_ctl;                                         \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x16: /* I_STAT */                                                    \\\n      state.r[REG_1] = state.i_stat;                                           \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x27: /* MM_STAT */                                                   \\\n      state.r[REG_1] = state.mm_stat;                                          \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x2a: /* DC_STAT */                                                   \\\n      state.r[REG_1] = state.dc_stat;                                          \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x2b: /* C_DATA */                                                    \\\n      state.r[REG_1] = 0;                                                      \\\n      break;                                                                   \\\n                                                                               \\\n    case 0xc0: /* CC */                                                        \\\n      state.r[REG_1] =                                                         \\\n          (((u64)state.cc_offset) << 32) | (state.cc & U64(0xffffffff));       \\\n      break;                                                                   \\\n                                                                               \\\n    case 0xc2: /* VA */                                                        \\\n      state.r[REG_1] = state.fault_va;                                         \\\n      break;                                                                   \\\n                                                                               \\\n    case 0xc3: /* VA_FORM */                                                   \\\n      state.r[REG_1] = va_form(state.fault_va, false);                         \\\n      break;                                                                   \\\n                                                                               \\\n    default:                                                                   \\\n      UNKNOWN2;                                                                \\\n    }                                                                          \\\n  }\n\n#define DO_HW_MTPR                                                             \\\n  if ((function & 0xc0) == 0x40) {                                             \\\n    if (function & 1)                                                          \\\n      state.asn = (int)(state.r[REG_2] >> 39) & 0xff;                          \\\n    if (function & 2) {                                                        \\\n      state.aster = (int)(state.r[REG_2] >> 5) & 0xf;                          \\\n      state.check_int = true;                                                  \\\n    }                                                                          \\\n    if (function & 4) {                                                        \\\n      state.astrr = (int)(state.r[REG_2] >> 9) & 0xf;                          \\\n      state.check_int = true;                                                  \\\n    }                                                                          \\\n    if (function & 8)                                                          \\\n      state.ppcen = (int)(state.r[REG_2] >> 1) & 1;                            \\\n    if (function & 16)                                                         \\\n      state.fpen = (int)(state.r[REG_2] >> 2) & 1;                             \\\n  } else {                                                                     \\\n    switch (function) {                                                        \\\n    case 0x00: /* ITB_TAG */                                                   \\\n      state.last_tb_virt = state.r[REG_2];                                     \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x01: /* ITB_PTE */                                                   \\\n      add_tb_i(state.last_tb_virt, state.r[REG_2]);                            \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x02: /* ITB_IAP */                                                   \\\n      tbiap(ACCESS_EXEC);                                                      \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x03: /* ITB_IA */                                                    \\\n      tbia(ACCESS_EXEC);                                                       \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x04: /* ITB_IS */                                                    \\\n      tbis(state.r[REG_2], ACCESS_EXEC);                                       \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x09: /* CM */                                                        \\\n      state.cm = (int)(state.r[REG_2] >> 3) & 3;                               \\\n      state.check_int = true;                                                  \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x0b: /* IER_CM */                                                    \\\n      state.cm = (int)(state.r[REG_2] >> 3) & 3;                               \\\n      state.check_int = true;                                                  \\\n                                                                               \\\n    case 0x0a: /* IER */                                                       \\\n      state.asten = (int)(state.r[REG_2] >> 13) & 1;                           \\\n      state.sien = (int)(state.r[REG_2] >> 13) & 0xfffe;                       \\\n      state.pcen = (int)(state.r[REG_2] >> 29) & 3;                            \\\n      state.cren = (int)(state.r[REG_2] >> 31) & 1;                            \\\n      state.slen = (int)(state.r[REG_2] >> 32) & 1;                            \\\n      state.eien = (int)(state.r[REG_2] >> 33) & 0x3f;                         \\\n      state.check_int = true;                                                  \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x0c: /* SIRR */                                                      \\\n      state.sir = (int)(state.r[REG_2] >> 13) & 0xfffe;                        \\\n      state.check_int = true;                                                  \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x0e: /* HW_INT_CLR */                                                \\\n      state.pcr &= ~((state.r[REG_2] >> 29) & U64(0x3));                       \\\n      state.crr &= ~((state.r[REG_2] >> 31) & U64(0x1));                       \\\n      state.slr &= ~((state.r[REG_2] >> 32) & U64(0x1));                       \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x10: /* PAL_BASE */                                                  \\\n      set_PAL_BASE(state.r[REG_2] & U64(0x00000fffffff8000));                  \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x11: /* i_ctl */                                                     \\\n      state.i_ctl_other = state.r[REG_2] & U64(0x00000000007e2f67);            \\\n      state.i_ctl_vptb =                                                       \\\n          sext_u64_48(state.r[REG_2] & U64(0x0000ffffc0000000));               \\\n      state.i_ctl_spe = (int)(state.r[REG_2] >> 3) & 3;                        \\\n      state.sde = (state.r[REG_2] >> 7) & 1;                                   \\\n      state.hwe = (state.r[REG_2] >> 12) & 1;                                  \\\n      state.i_ctl_va_mode = (int)(state.r[REG_2] >> 15) & 3;                   \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x12: /* ic_flush_asm */                                              \\\n      flush_icache_asm();                                                      \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x13: /* IC_FLUSH */                                                  \\\n      flush_icache();                                                          \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x14: /* PCTR_CTL */                                                  \\\n      state.pctr_ctl = state.r[REG_2] & U64(0xffffffffffffffdf);               \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x15: /* CLR_MAP */                                                   \\\n    case 0x17: /* SLEEP   */                                                   \\\n    case 0x27: /* MM_STAT */                                                   \\\n    case 0x2b: /* C_DATA  */                                                   \\\n    case 0x2c: /* C_SHIFT */                                                   \\\n    case 0x2d: /* M_FIX */                                                     \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x16:                         /* I_STAT */                            \\\n      state.i_stat &= ~state.r[REG_2]; /* W1C */                               \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x20: /* DTB_TAG0 */                                                  \\\n      state.last_tb_virt = state.r[REG_2];                                     \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x21: /* DTB_PTE0 */                                                  \\\n      add_tb_d(state.last_tb_virt, state.r[REG_2]);                            \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x24: /* DTB_IS0 */                                                   \\\n      tbis(state.r[REG_2], ACCESS_READ);                                       \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x25: /* DTB_ASN0 */                                                  \\\n      state.asn0 = (int)(state.r[REG_2] >> 56);                                \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x26: /* DTB_ALTMODE */                                               \\\n      state.alt_cm = (int)(state.r[REG_2] & 3);                                \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x28: /* M_CTL */                                                     \\\n      state.smc = (int)(state.r[REG_2] >> 4) & 3;                              \\\n      state.m_ctl_spe = (int)(state.r[REG_2] >> 1) & 7;                        \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x29: /* DC_CTL */                                                    \\\n      state.dc_ctl = state.r[REG_2];                                           \\\n      break;                                                                   \\\n                                                                               \\\n    case 0x2a: /* DC_STAT */                                                   \\\n      state.dc_stat &= ~state.r[REG_2];                                        \\\n      break;                                                                   \\\n                                                                               \\\n    case 0xa0: /* DTB_TAG1 */                                                  \\\n      state.last_tb_virt = state.r[REG_2];                                     \\\n      break;                                                                   \\\n                                                                               \\\n    case 0xa1: /* DTB_PTE1 */                                                  \\\n      add_tb_d(state.last_tb_virt, state.r[REG_2]);                            \\\n      break;                                                                   \\\n                                                                               \\\n    case 0xa2: /* DTB_IAP */                                                   \\\n      tbiap(ACCESS_READ);                                                      \\\n      break;                                                                   \\\n                                                                               \\\n    case 0xa3: /* DTB_IA */                                                    \\\n      tbia(ACCESS_READ);                                                       \\\n      break;                                                                   \\\n                                                                               \\\n    case 0xa4: /* DTB_IS1 */                                                   \\\n      tbis(state.r[REG_2], ACCESS_READ);                                       \\\n      break;                                                                   \\\n                                                                               \\\n    case 0xa5: /* DTB_ASN1 */                                                  \\\n      state.asn1 = (int)(state.r[REG_2] >> 56);                                \\\n      break;                                                                   \\\n                                                                               \\\n    case 0xc0: /* CC */                                                        \\\n      state.cc_offset = (u32)(state.r[REG_2] >> 32);                           \\\n      break;                                                                   \\\n                                                                               \\\n    case 0xc1: /* CC_CTL */                                                    \\\n      state.cc_ena = (state.r[REG_2] >> 32) & 1;                               \\\n      state.cc = (u32)(state.r[REG_2] & U64(0xfffffff0));                      \\\n      break;                                                                   \\\n                                                                               \\\n    case 0xc4: /* VA_CTL */                                                    \\\n      state.va_ctl_vptb =                                                      \\\n          sext_u64_48(state.r[REG_2] & U64(0x0000ffffc0000000));               \\\n      state.va_ctl_va_mode = (int)(state.r[REG_2] >> 1) & 3;                   \\\n      break;                                                                   \\\n                                                                               \\\n    default:                                                                   \\\n      UNKNOWN2;                                                                \\\n    }                                                                          \\\n  }\n\n#define DO_HW_RET set_pc(state.r[REG_2])\n#define DO_HW_LDL                                                              \\\n  switch (function) {                                                          \\\n  case 0: /* longword physical */                                              \\\n    phys_address = state.r[REG_2] + DISP_12;                                   \\\n    state.r[REG_1] = READ_PHYS_NT(32);                                         \\\n    break;                                                                     \\\n                                                                               \\\n  case 2: /* longword physical locked */                                       \\\n    phys_address = state.r[REG_2] + DISP_12;                                   \\\n    cSystem->cpu_lock(state.iProcNum, phys_address);                           \\\n    state.r[REG_1] = READ_PHYS_NT(32);                                         \\\n    break;                                                                     \\\n                                                                               \\\n  case 4: /* longword virtual vpte                 chk   alt    vpte */        \\\n    DATA_PHYS_NT(state.r[REG_2] + DISP_12, ACCESS_READ | NO_CHECK | VPTE);     \\\n    state.r[REG_1] = READ_PHYS_NT(32);                                         \\\n    break;                                                                     \\\n                                                                               \\\n  case 8: /* longword virtual */                                               \\\n    DATA_PHYS_NT(state.r[REG_2] + DISP_12, ACCESS_READ | NO_CHECK);            \\\n    state.r[REG_1] = READ_PHYS_NT(32);                                         \\\n    break;                                                                     \\\n                                                                               \\\n  case 10: /* longword virtual check */                                        \\\n    DATA_PHYS_NT(state.r[REG_2] + DISP_12, ACCESS_READ);                       \\\n    state.r[REG_1] = READ_PHYS_NT(32);                                         \\\n    break;                                                                     \\\n                                                                               \\\n  case 12: /* longword virtual alt */                                          \\\n    DATA_PHYS_NT(state.r[REG_2] + DISP_12, ACCESS_READ | NO_CHECK | ALT);      \\\n    state.r[REG_1] = READ_PHYS_NT(32);                                         \\\n    break;                                                                     \\\n                                                                               \\\n  case 14: /* longword virtual alt check */                                    \\\n    DATA_PHYS_NT(state.r[REG_2] + DISP_12, ACCESS_READ | ALT);                 \\\n    state.r[REG_1] = READ_PHYS_NT(32);                                         \\\n    break;                                                                     \\\n                                                                               \\\n  default:                                                                     \\\n    UNKNOWN2;                                                                  \\\n  }\n\n#define DO_HW_LDQ                                                              \\\n  switch (function) {                                                          \\\n  case 1: /* quadword physical */                                              \\\n    phys_address = state.r[REG_2] + DISP_12;                                   \\\n    state.r[REG_1] = READ_PHYS_NT(64);                                         \\\n    break;                                                                     \\\n                                                                               \\\n  case 3: /* quadword physical locked */                                       \\\n    phys_address = state.r[REG_2] + DISP_12;                                   \\\n    cSystem->cpu_lock(state.iProcNum, phys_address);                           \\\n    state.r[REG_1] = READ_PHYS_NT(64);                                         \\\n    break;                                                                     \\\n                                                                               \\\n  case 5: /* quadword virtual vpte                 chk   alt    vpte */        \\\n    DATA_PHYS_NT(state.r[REG_2] + DISP_12, ACCESS_READ | NO_CHECK | VPTE);     \\\n    state.r[REG_1] = READ_PHYS_NT(64);                                         \\\n    break;                                                                     \\\n                                                                               \\\n  case 9: /* quadword virtual */                                               \\\n    DATA_PHYS_NT(state.r[REG_2] + DISP_12, ACCESS_READ | NO_CHECK);            \\\n    state.r[REG_1] = READ_PHYS_NT(64);                                         \\\n    break;                                                                     \\\n                                                                               \\\n  case 11: /* quadword virtual check */                                        \\\n    DATA_PHYS_NT(state.r[REG_2] + DISP_12, ACCESS_READ);                       \\\n    state.r[REG_1] = READ_PHYS_NT(64);                                         \\\n    break;                                                                     \\\n                                                                               \\\n  case 13: /* quadword virtual alt */                                          \\\n    DATA_PHYS_NT(state.r[REG_2] + DISP_12, ACCESS_READ | NO_CHECK | ALT);      \\\n    state.r[REG_1] = READ_PHYS_NT(64);                                         \\\n    break;                                                                     \\\n                                                                               \\\n  case 15: /* quadword virtual alt check */                                    \\\n    DATA_PHYS_NT(state.r[REG_2] + DISP_12, ACCESS_READ | ALT);                 \\\n    state.r[REG_1] = READ_PHYS_NT(64);                                         \\\n    break;                                                                     \\\n                                                                               \\\n  default:                                                                     \\\n    UNKNOWN2;                                                                  \\\n  }\n\n#define DO_HW_STL                                                              \\\n  switch (function) {                                                          \\\n  case 0: /* longword physical */                                              \\\n    phys_address = state.r[REG_2] + DISP_12;                                   \\\n    WRITE_PHYS_NT(state.r[REG_1], 32);                                         \\\n    break;                                                                     \\\n                                                                               \\\n  case 2: /* longword physical conditional */                                  \\\n    if (cSystem->cpu_unlock(state.iProcNum)) {                                 \\\n      phys_address = state.r[REG_2] + DISP_12;                                 \\\n      WRITE_PHYS_NT(state.r[REG_1], 32);                                       \\\n      state.r[REG_1] = 1;                                                      \\\n    } else                                                                     \\\n      state.r[REG_1] = 0;                                                      \\\n    break;                                                                     \\\n                                                                               \\\n  case 4: /* longword virtual                      chk   alt    vpte */        \\\n    DATA_PHYS_NT(state.r[REG_2] + DISP_12, ACCESS_READ | NO_CHECK);            \\\n    WRITE_PHYS_NT(state.r[REG_1], 32);                                         \\\n    break;                                                                     \\\n                                                                               \\\n  case 12: /* longword virtual alt */                                          \\\n    DATA_PHYS_NT(state.r[REG_2] + DISP_12, ACCESS_READ | NO_CHECK | ALT);      \\\n    WRITE_PHYS_NT(state.r[REG_1], 32);                                         \\\n    break;                                                                     \\\n                                                                               \\\n  default:                                                                     \\\n    UNKNOWN2;                                                                  \\\n  }\n\n#define DO_HW_STQ                                                              \\\n  switch (function) {                                                          \\\n  case 1: /* quadword physical */                                              \\\n    phys_address = state.r[REG_2] + DISP_12;                                   \\\n    WRITE_PHYS_NT(state.r[REG_1], 64);                                         \\\n    break;                                                                     \\\n                                                                               \\\n  case 3: /* quadword physical conditional */                                  \\\n    if (cSystem->cpu_unlock(state.iProcNum)) {                                 \\\n      phys_address = state.r[REG_2] + DISP_12;                                 \\\n      WRITE_PHYS_NT(state.r[REG_1], 64);                                       \\\n      state.r[REG_1] = 1;                                                      \\\n    } else                                                                     \\\n      state.r[REG_1] = 0;                                                      \\\n    break;                                                                     \\\n                                                                               \\\n  case 5: /* quadword virtual                      chk    alt    vpte */       \\\n    DATA_PHYS_NT(state.r[REG_2] + DISP_12, ACCESS_READ | NO_CHECK);            \\\n    WRITE_PHYS_NT(state.r[REG_1], 64);                                         \\\n    break;                                                                     \\\n                                                                               \\\n  case 13: /* quadword virtual alt */                                          \\\n    DATA_PHYS_NT(state.r[REG_2] + DISP_12, ACCESS_READ | NO_CHECK | ALT);      \\\n    WRITE_PHYS_NT(state.r[REG_1], 64);                                         \\\n    break;                                                                     \\\n                                                                               \\\n  default:                                                                     \\\n    UNKNOWN2;                                                                  \\\n  }\n"
  },
  {
    "path": "src/cpu_vax.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#define DO_RC                                                                  \\\n  state.r[REG_1] = state.bIntrFlag ? 1 : 0;                                    \\\n  state.bIntrFlag = false;\n\n#define DO_RS                                                                  \\\n  state.r[REG_1] = state.bIntrFlag ? 1 : 0;                                    \\\n  state.bIntrFlag = true;\n"
  },
  {
    "path": "src/datatypes.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_DATATYPES_H)\n#define INCLUDED_DATATYPES_H\n\n#if defined(HAVE_STDINT_H)\n#include <cstdint>\n#endif\n\n#if defined(HAVE_INTTYPES_H)\n#include <cinttypes>\n#endif\n\n#if defined(_WIN32) && !defined(__GNUWIN32__)\n\n#define U64(a) a##ui64\n\n#else // defined(_WIN32)\n\n#define U64(a)  UINT64_C(a)\n\n#endif // defined(_WIN32)\n\ntypedef uint8_t u8;\ntypedef uint16_t u16;\ntypedef uint32_t u32;\ntypedef uint64_t u64;\n\ntypedef int8_t s8;\ntypedef int16_t s16;\ntypedef int32_t s32;\ntypedef int64_t s64;\n\ntypedef u8 u_int8_t;\ntypedef u16 u_int16_t;\ntypedef u32 u_int32_t;\ntypedef u64 u_int64_t;\n\n#define HAVE_U_INT8_T 1\n#define HAVE_INT8_T 1\n#define HAVE_U_INT16_T 1\n#define HAVE_INT16_T 1\n#define HAVE_U_INT32_T 1\n#define HAVE_INT32_T 1\n#define HAVE_U_INT64_T 1\n#define HAVE_INT64_T 1\n\n/**\n * Sign-extend an 8-bit value to 64 bits.\n **/\ninline u64 sext_u64_8(u64 a) {\n#if defined(ES40_BIG_ENDIAN)\n  return (((a)&U64(0x0000000000000080)) ? ((a) | U64(0xffffffffffffff00))\n                                        : ((a) & U64(0x00000000000000ff)));\n#else\n  // Optimised implementation for LE machines of this hotpath inline\n  // function. The implementation above compiles to three opcodes but\n  // the following compiles to just one movsx? opcode.\n  auto aa = static_cast<s64>(*reinterpret_cast<s8*>(&a));\n  return *reinterpret_cast<u64*>(&aa);\n#endif\n}\n\n/**\n * Sign-extend a 12-bit value to 64 bits.\n **/\ninline u64 sext_u64_12(u64 a) {\n  return (((a)&U64(0x0000000000000800)) ? ((a) | U64(0xfffffffffffff000))\n                                        : ((a) & U64(0x0000000000000fff)));\n}\n\n/**\n * Sign-extend a 13-bit value to 64 bits.\n **/\ninline u64 sext_u64_13(u64 a) {\n  return (((a)&U64(0x0000000000001000)) ? ((a) | U64(0xffffffffffffe000))\n                                        : ((a) & U64(0x0000000000001fff)));\n}\n\n/**\n * Sign-extend an 16-bit value to 64 bits.\n **/\ninline u64 sext_u64_16(u64 a) {\n#if defined(ES40_BIG_ENDIAN)\n  return (((a)&U64(0x0000000000008000)) ? ((a) | U64(0xffffffffffff0000))\n                                        : ((a) & U64(0x000000000000ffff)));\n#else\n  // Optimised implementation for LE machines of this hotpath inline\n  // function. The implementation above compiles to three opcodes but\n  // the following compiles to just one movsx? opcode.\n  auto aa = static_cast<s64>(*reinterpret_cast<s16*>(&a));\n  return *reinterpret_cast<u64*>(&aa);\n#endif\n}\n\n/**\n * Sign-extend a 21-bit value to 64 bits.\n **/\ninline u64 sext_u64_21(u64 a) {\n  return (((a)&U64(0x0000000000100000)) ? ((a) | U64(0xffffffffffe00000))\n                                        : ((a) & U64(0x00000000001fffff)));\n}\n\n/**\n * Sign-extend a 32-bit value to 64 bits.\n **/\ninline u64 sext_u64_32(u64 a) {\n#if defined(ES40_BIG_ENDIAN)\n  return (((a)&U64(0x0000000080000000)) ? ((a) | U64(0xffffffff00000000))\n                                        : ((a) & U64(0x00000000ffffffff)));\n#else\n  // Optimised implementation for LE machines of this hotpath inline\n  // function. The implementation above compiles to three opcodes but\n  // the following compiles to just one movsx? opcode.\n  auto aa = static_cast<s64>(*reinterpret_cast<s32*>(&a));\n  return *reinterpret_cast<u64*>(&aa);\n#endif\n}\n\n/**\n * Sign-extend a 48-bit value to 64 bits.\n **/\ninline u64 sext_u64_48(u64 a) {\n  return (((a)&U64(0x0000800000000000)) ? ((a) | U64(0xffff000000000000))\n                                        : ((a) & U64(0x0000ffffffffffff)));\n}\n\ninline bool test_bit_64(u64 x, int bit) {\n  return (x & (U64(0x1) << bit)) ? true : false;\n}\n\n/**\n * Sign-extend a 24-bit value to 32 bits.\n **/\ninline u32 sext_u32_24(u32 a) {\n  return (((a)&0x00800000) ? ((a) | 0xff000000) : ((a)&0x00ffffff));\n}\n#endif // INCLUDED_DATATYPES_H\n"
  },
  {
    "path": "src/es40-cfg.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"StdAfx.hpp\"\n\n// C++ includes\n#include <algorithm>\n#include <fstream>\n#include <iostream>\n#include <sstream>\n#include <string>\n#include <vector>\n\n#if defined(HAVE_PCAP)\n#include <pcap.h>\n#endif\n\nusing namespace std;\n\n// Question classes\n\n#include \"FreeTextQuestion.hpp\"\n#include \"MultipleChoiceQuestion.hpp\"\n#include \"NumberQuestion.hpp\"\n#include \"Question.hpp\"\n#include \"ShrinkingChoiceQuestion.hpp\"\n\n/**\n * Add disks for a controller to the configuration file.\n *\n * \\param disk_q: A ShrinkingChoiceQuestion that contains\n *                all allowed disk names for this controller,\n *                and a special answer \"none\" with a value\n *                of \"\".\n * \\param os:     Output stream for the configuration file.\n **/\nvoid add_disks(ShrinkingChoiceQuestion *disk_q, ostream *os) {\n  /* Loop until there are no more disks to be added.\n   */\n  for (;;) {\n    /* If disk_q has only one answer left, this is the\n     * \"none\" answer. This controller can contain no\n     * more disks.\n     */\n    if (disk_q->countAnswers() == 1)\n      break;\n\n    /* If the answer value is \"\", the answer \"none\"\n     * was given. Stop adding disks to this controller.\n     */\n    if (disk_q->ask() == \"\")\n      break;\n\n    /* Find out if this should be using:\n     *   - a disk image file\n     *   - a raw device\n     *   - a RAM DISK\n     */\n    MultipleChoiceQuestion type_q;\n    type_q.setQuestion(\"How should \" + disk_q->getAnswer() + \" be emulated?\");\n    type_q.setDefault(\"file\");\n    type_q.setExplanation(\"Disks can be emulated in several ways.\");\n    type_q.addAnswer(\"file\", \"file\",\n                     \"The disk uses a disk image on the host system's disk.\");\n    type_q.addAnswer(\"device\", \"device\",\n                     \"The disk uses one of the host system's raw disks.\");\n    type_q.addAnswer(\"ramdisk\", \"ramdisk\",\n                     \"The disk stores it's data in RAM. Volatile.\");\n\n    *os << \"    \" << disk_q->getAnswer() << \" = \" << type_q.ask() << \"\\n\";\n    *os << \"    {\\n\";\n\n    if (type_q.getAnswer() == \"file\" || type_q.getAnswer() == \"device\") {\n      /* For a file or device, we need to know what\n       * file or device to use.\n       */\n      FreeTextQuestion img_q;\n      img_q.setQuestion(\"What \" + type_q.getAnswer() + \" should \" +\n                        disk_q->getAnswer() + \" use?\");\n      img_q.setExplanation(\"Enter the path to the \" + type_q.getAnswer() +\n                           \" to use for this disk.\");\n      *os << \"      \" << type_q.getAnswer() << \" = \\\"\" << img_q.ask()\n          << \"\\\";\\n\";\n    }\n\n    if (type_q.getAnswer() == \"file\") {\n      /* For a file, we need to know whether to create\n       * it when it doesn't exist or not.\n       */\n      MultipleChoiceQuestion create_q;\n      create_q.setQuestion(\n          \"If the file doesn't exist, do you want us to create it?\");\n      create_q.setExplanation(\n          \"The file will be created the first time the emulator runs.\");\n      create_q.addAnswer(\"no\", \"no\", \"Don't create this file\");\n      create_q.addAnswer(\"yes\", \"yes\", \"Create this file\");\n      if (create_q.getAnswer() == \"yes\") {\n        /* If we should create the file, we need to\n         * know it's size.\n         */\n        MultipleChoiceQuestion unit_q;\n        unit_q.setQuestion(\n            \"What unit do you want to use to specify the disk size?\");\n        unit_q.setExplanation(\n            \"This is needed to create the file if it doesn't exist.\");\n        unit_q.addAnswer(\"KB\", \"K\", \"Kilobytes\");\n        unit_q.addAnswer(\"MB\", \"M\", \"Megabytes\");\n        unit_q.addAnswer(\"GB\", \"G\", \"Gigabytes\");\n        unit_q.setDefault(\"MB\");\n        unit_q.ask();\n        NumberQuestion size_q;\n        size_q.setQuestion(\"How many \" + unit_q.getAnswer() +\n                           \"Bytes should the disk be?\");\n        size_q.setExplanation(\n            \"This is needed to create the file if it doesn't exist.\");\n        size_q.setRange(1, 1024);\n        size_q.setDefault(\"10\");\n        size_q.ask();\n        *os << \"      autocreate_size = \\\"\" << size_q.getAnswer()\n            << unit_q.getAnswer() << \"\\\";\\n\";\n      }\n    }\n\n    if (type_q.getAnswer() == \"ramdisk\") {\n      /* For a RAM DISK, we need to know what\n       * size it should be.\n       */\n      MultipleChoiceQuestion unit_q;\n      unit_q.setQuestion(\n          \"What unit do you want to use to specify the disk size?\");\n      unit_q.setExplanation(\"This is needed to create the RAMDISK.\");\n      unit_q.addAnswer(\"KB\", \"K\", \"Kilobytes\");\n      unit_q.addAnswer(\"MB\", \"M\", \"Megabytes\");\n      unit_q.addAnswer(\"GB\", \"G\", \"Gigabytes\");\n      unit_q.setDefault(\"MB\");\n      unit_q.ask();\n      NumberQuestion size_q;\n      size_q.setQuestion(\"How many \" + unit_q.getAnswer() +\n                         \"Bytes should the disk be?\");\n      size_q.setExplanation(\"This is needed to create the RAMDISK.\");\n      size_q.setRange(1, 1024);\n      size_q.setDefault(\"10\");\n      size_q.ask();\n      *os << \"      size = \\\"\" << size_q.getAnswer() << unit_q.getAnswer()\n          << \"\\\";\\n\";\n    }\n\n    /* We need to know whether to emulate this as\n     * a cd-rom, or as a hard-disk.\n     */\n    MultipleChoiceQuestion cdrom_q;\n    cdrom_q.setQuestion(\"Should \" + disk_q->getAnswer() +\n                        \" be a disk or a cd-rom device?\");\n    cdrom_q.setExplanation(\"Do you want the OS to see this \" +\n                           type_q.getAnswer() +\n                           \" as a hard-disk, or as a cd-rom?\");\n    cdrom_q.addAnswer(\"disk\", \"false\", \"Hard-disk\");\n    cdrom_q.addAnswer(\"cd-rom\", \"true\", \"CD-ROM drive\");\n    cdrom_q.setDefault(\"disk\");\n\n    /* We also need to know whether this is a\n     * writeable or a read-only device.\n     */\n    MultipleChoiceQuestion ro_q;\n    ro_q.setQuestion(\"Should \" + disk_q->getAnswer() + \" be a read-only disk?\");\n    ro_q.setExplanation(\"You might want to write-protect this disk.\");\n    ro_q.addAnswer(\"no\", \"false\", \"writeable\");\n    ro_q.addAnswer(\"yes\", \"true\", \"read-only\");\n    ro_q.setDefault(\"no\");\n\n    if (cdrom_q.ask() == \"true\") {\n      /* CD-ROMs are always read-only.\n       */\n      ro_q.setAnswer(\"true\");\n    } else if (type_q.getAnswer() == \"ramdisk\") {\n      /* Read-only RAM DISKs don't make any sense.\n       */\n      ro_q.setAnswer(\"false\");\n    } else {\n      /* Otherwise, ask.\n       */\n      ro_q.ask();\n    }\n\n    *os << \"      cdrom = \" << cdrom_q.getAnswer() << \";\\n\";\n    *os << \"      read_only = \" << ro_q.getAnswer() << \";\\n\";\n\n    /* The user can define a custom model\n     * number for the device.\n     */\n    FreeTextQuestion ft_q;\n    ft_q.setQuestion(\"Would you like to set a disk model number?\");\n    ft_q.setExplanation(\"Leave blank to choose the default.\");\n    if (ft_q.ask() != \"\")\n      *os << \"      model_number = \\\"\" << ft_q.getAnswer() << \"\\\";\\n\";\n\n    /* The user can define a custom revision\n     * number for the device.\n     */\n    ft_q.setQuestion(\"Would you like to set a revision number?\");\n    if (ft_q.ask() != \"\")\n      *os << \"      rev_number = \\\"\" << ft_q.getAnswer() << \"\\\";\\n\";\n\n    /* The user can define a custom serial\n     * number for the device.\n     */\n    ft_q.setQuestion(\"Would you like to set a serial number?\");\n    if (ft_q.ask() != \"\")\n      *os << \"      serial_number = \\\"\" << ft_q.getAnswer() << \"\\\";\\n\";\n\n    *os << \"    }\\n\\n\";\n  }\n}\n\n/**\n * Entry point for configuration.\n **/\nint main_cfg(int argc, char *argv[]) {\n  /* Explanation\n   */\n  printf(\"We are now going to set up an initial configuration file for the \"\n         \"Emulator.\\n\");\n  printf(\"This file will be saved as es40.cfg in the current directory.\\n\\n\");\n  printf(\n      \"For more detailed information to the current question, answer '?'.\\n\");\n\n  /* Open es40.cfg for writing.\n   */\n  filebuf fb;\n  fb.open(\"es40.cfg\", ios::out);\n  ostream os(&fb);\n\n  /* **************************** *\n   * GUI Choice                   *\n   * **************************** */\n\n  MultipleChoiceQuestion gui_q;\n\n  gui_q.setQuestion(\"Do you want to have a GUI?\");\n  gui_q.setExplanation(\n      \"You need a GUI if you want to use an emulated graphics card. You don't \"\n      \"need this for most OS'es. If you don't need this, we recomment that you \"\n      \"answer 'none' to this question.\");\n  gui_q.setDefault(\"none\");\n  gui_q.addAnswer(\"none\", \"\", \"No GUI. Graphics cards are not supported.\");\n\n#if defined(HAVE_SDL)\n  gui_q.addAnswer(\"SDL\", \"sdl\",\n                  \"Simple Directmedia Layer. Preferred GUI mechanism.\");\n#endif\n#if defined(HAVE_X11)\n  gui_q.addAnswer(\"X11\", \"X11\", \"Unix X-Windows GUI support.\");\n#endif\n#if defined(_WIN32)\n  gui_q.addAnswer(\"win32\", \"win32\", \"Windows 32 GUI support.\");\n#endif\n\n  if (gui_q.countAnswers() == 1) {\n    /* The only valid answer is \"none\".\n     */\n    cout << \"\\nSorry, the GUI is not available! (no SDL, win32 or X11 support \"\n            \"found).\\n\";\n    gui_q.setAnswer(\"\");\n  } else {\n    /* Ask what GUI to use?\n     */\n    gui_q.ask();\n  }\n\n  if (gui_q.getAnswer() != \"\") {\n    /* Yes, we have a GUI.\n     */\n    os << \"gui = \" << gui_q.getAnswer() << \"\\n\";\n    os << \"{\\n\";\n    os << \"}\\n\\n\";\n  }\n\n  /* **************************** *\n   * Memory Size                  *\n   * **************************** */\n\n  MultipleChoiceQuestion mem_q;\n\n  mem_q.setQuestion(\"How much RAM memory do you want to emulate?\");\n  mem_q.setExplanation(\"Your system should have enough free memory to emulate \"\n                       \"the amount you choose here.\");\n  mem_q.setDefault(\"256M\");\n\n  /* Add memory sizes from 32 MB to 8 GB\n   * (25 to 34 bits).\n   */\n  for (int i = 25; i < 34; i++) {\n    string a;\n    int j = i;\n    if (i < 30) {\n      /* Megabyte-range.\n       */\n      j -= 20;\n      a = \"M\";\n    } else {\n      /* Gigabyte range.\n       */\n      j -= 30;\n      a = \"G\";\n    }\n    mem_q.addAnswer(i2s(1 << j) + a, i2s(i),\n                    i2s(1 << j) + a + \"Bytes of memory.\");\n  }\n\n  os << \"sys0 = tsunami\\n\";\n  os << \"{\\n\";\n  os << \"  memory.bits = \" << mem_q.ask() << \";\\n\";\n\n  /* **************************** *\n   * ROM Files                    *\n   * **************************** */\n\n  FreeTextQuestion rom_q;\n  rom_q.setQuestion(\"Where can the SRM ROM image be found?\");\n  rom_q.setExplanation(\"This file is required.\");\n#if defined(_WIN32)\n  rom_q.setDefault(\"rom\\\\cl67srmrom.exe\");\n#elif defined(__VMS)\n  rom_q.setDefault(\"[.ROM]CL67SRMROM.EXE\");\n#else\n  rom_q.setDefault(\"rom/cl67srmrom.exe\");\n#endif\n\n  os << \"  rom.srm = \\\"\" << rom_q.ask() << \"\\\";\\n\";\n\n  rom_q.setQuestion(\"Where should the decompressed ROM image be saved?\");\n  rom_q.setExplanation(\n      \"This file will be created the first time the emulator runs.\");\n#if defined(_WIN32)\n  rom_q.setDefault(\"rom\\\\decompressed.rom\");\n#elif defined(__VMS)\n  rom_q.setDefault(\"[.ROM]DECOMPRESSED.ROM\");\n#else\n  rom_q.setDefault(\"rom/decompressed.rom\");\n#endif\n\n  os << \"  rom.decompressed = \\\"\" << rom_q.ask() << \"\\\";\\n\";\n\n  rom_q.setQuestion(\"Where should the Flash ROM image be saved?\");\n#if defined(_WIN32)\n  rom_q.setDefault(\"rom\\\\flash.rom\");\n#elif defined(__VMS)\n  rom_q.setDefault(\"[.ROM]FLASH.ROM\");\n#else\n  rom_q.setDefault(\"rom/flash.rom\");\n#endif\n\n  os << \"  rom.flash = \\\"\" << rom_q.ask() << \"\\\";\\n\";\n\n  rom_q.setQuestion(\"Where should the DPR EEPROM image be saved?\");\n#if defined(_WIN32)\n  rom_q.setDefault(\"rom\\\\dpr.rom\");\n#elif defined(__VMS)\n  rom_q.setDefault(\"[.ROM]DPR.ROM\");\n#else\n  rom_q.setDefault(\"rom/dpr.rom\");\n#endif\n\n  os << \"  rom.dpr = \\\"\" << rom_q.ask() << \"\\\";\\n\\n\";\n\n  /* **************************** *\n   * CPU's                        *\n   * **************************** */\n\n  NumberQuestion cpu_q;\n\n  cpu_q.setQuestion(\"How many CPU's do you want in the system?\");\n  cpu_q.setRange(1, 4);\n  cpu_q.setDefault(\"1\");\n  cpu_q.setExplanation(\n      \"The normal value for the number of CPU's is 1. More CPU's are very \"\n      \"experimental, and currently doesn't work.\");\n\n  cpu_q.ask();\n\n  MultipleChoiceQuestion icache_q;\n\n  icache_q.setQuestion(\"Do you want the ICACHE on the CPU's enabled?\");\n  icache_q.setExplanation(\n      \"The ICACHE makes the CPU emulation more accurate, but also slows down \"\n      \"the emulator. Decent operating systems shouldn't depend on this.\");\n  icache_q.setDefault(\"no\");\n  icache_q.addAnswer(\"yes\", \"true\",\n                     \"ICACHE enabled. Performance hit, but may be necessary \"\n                     \"for some software.\");\n  icache_q.addAnswer(\n      \"no\", \"false\",\n      \"ICACHE disabled. Better performance, but may not always work.\");\n\n  icache_q.ask();\n\n  MultipleChoiceQuestion skip_memtest_hack_q;\n\n  skip_memtest_hack_q.setQuestion(\"Do you want to skip memtest on SRM start?\");\n  skip_memtest_hack_q.setExplanation(\n      \"This makes startup significantly faster, but may not work with some \"\n      \"versions of the firmware.\");\n  skip_memtest_hack_q.setDefault(\"no\");\n  skip_memtest_hack_q.addAnswer(\n      \"yes\", \"true\",\n      \"Skip memtest hack enabled. CPU detects the instruction pointer where \"\n      \"the memtest starts and skips it.\");\n  skip_memtest_hack_q.addAnswer(\"no\", \"false\",\n                                \"Skip memtest hack disabled. Firmware checks \"\n                                \"all available memory on startup.\");\n\n  skip_memtest_hack_q.ask();\n\n  NumberQuestion mhz_q;\n\n  mhz_q.setQuestion(\"What should the reported speed of the CPU's be in MHz?\");\n  mhz_q.setExplanation(\"This only changes the CPU speed reported to the OS; \"\n                       \"not the speed of the emulation.\");\n  mhz_q.setRange(10, 1250);\n  mhz_q.setDefault(\"800\");\n\n  mhz_q.ask();\n\n  for (int i = 0; i < cpu_q.getNum(); i++) {\n    /* Repeat the CPU configuration for each\n     * CPU. Differing CPU specs are not supported.\n     */\n    os << \"  cpu\" << i << \" = ev68cb\\n\";\n    os << \"  {\\n\";\n    os << \"    speed = \" << mhz_q.getAnswer() << \"M;\\n\";\n    os << \"    icache = \" << icache_q.getAnswer() << \";\\n\";\n    os << \"    skip_memtest_hack = \" << skip_memtest_hack_q.getAnswer()\n       << \";\\n\";\n    os << \"  }\\n\\n\";\n  }\n\n  /* **************************** *\n   * Serial Ports                 *\n   * **************************** */\n\n  /* There are two serial ports (0 and 1).\n   */\n  for (int i = 0; i < 2; i++) {\n    NumberQuestion port_q;\n    port_q.setQuestion(\"What telnet port should serial \" + i2s(i) + \" listen?\");\n    port_q.setRange(1, 65535);\n    /* The default ports are 21264 and 21265.\n     */\n    port_q.setDefault(i2s(21264 + i));\n    port_q.setExplanation(\"You will telnet to this port to establish a \"\n                          \"connection with emulated serial port \" +\n                          i2s(i) + \".\");\n\n    port_q.ask();\n\n    FreeTextQuestion exec_q;\n    exec_q.setQuestion(\n        \"What program should be started automatically for serial \" + i2s(i) +\n        \"?\");\n#if defined(_WIN32)\n    /* On windows, default to\n     * C:\\Program Files\\Putty\\Putty.exe\n     */\n    exec_q.setDefault(\"C:\\\\Program Files\\\\Putty\\\\Putty.exe\");\n#else\n    /* On other OS'es, default to\n     * putty\n     */\n    exec_q.setDefault(\"putty\");\n#endif\n    exec_q.setExplanation(\"Enter the path to a program to start this to create \"\n                          \"an automatic connection with the serial port. Set \"\n                          \"to 'none' to establish the connection manually.\");\n\n    exec_q.ask();\n    FreeTextQuestion arg_q;\n\n    /* If none was answered, we don't need to\n     * ask for arguments.\n     */\n    if (exec_q.getAnswer() != \"none\") {\n      arg_q.setQuestion(\"What arguments should the program use to connect to \"\n                        \"the serial port?\");\n      arg_q.setExplanation(\"Enter the arguments the program needs.\");\n      /* This is the argument format for PuTTy.\n       */\n      arg_q.setDefault(\"telnet://localhost:\" + port_q.getAnswer());\n\n      arg_q.ask();\n    }\n\n    os << \"  serial\" << i << \" = serial\\n\";\n    os << \"  {\\n\";\n    os << \"    port = \" << port_q.getAnswer() << \";\\n\";\n    if (exec_q.getAnswer() != \"none\") {\n#if defined(_WIN32)\n      /* Quote the program path/name in \"\",\n       * as it may contain spaces.\n       */\n      os << \"    action = \\\"\\\"\\\"\" << exec_q.getAnswer() << \"\\\"\\\" \"\n         << arg_q.getAnswer() << \"\\\";\\n\";\n#else\n      os << \"    action = \\\"\" << exec_q.getAnswer() << \" \" << arg_q.getAnswer()\n         << \"\\\";\\n\";\n#endif\n    }\n    os << \"  }\\n\\n\";\n  }\n\n  /* **************************** *\n   * Floppy Disks                *\n   * **************************** */\n\n  MultipleChoiceQuestion fdc_q;\n\n  fdc_q.setQuestion(\"Do you want a floppy controller in your system?\");\n  fdc_q.setExplanation(\n      \"You need a floppy controller if you want to add floppy drives.\");\n  fdc_q.setDefault(\"no\");\n  fdc_q.addAnswer(\"yes\", \"fdc\", \"FDC present.\");\n  fdc_q.addAnswer(\"no\", \"\", \"FDC not present.\");\n\n  if (fdc_q.ask() != \"\") {\n    /* Use a ShrinkingChoiceQuestion; once\n     * a disk position has been used, it\n     * can't be used again.\n     */\n    ShrinkingChoiceQuestion fd_q;\n    fd_q.setQuestion(\"Do you want to add any disks to the Floppy controller?\");\n    fd_q.setDefault(\"none\");\n    fd_q.setExplanation(\"Here, you can add floppy drives to your system.\");\n    fd_q.addAnswer(\"none\", \"\", \"stop adding disks\");\n    fd_q.addAnswer(\"0\", \"disk0.0\", \"A:\");\n    fd_q.addAnswer(\"1\", \"disk0.1\", \"B:\");\n\n    os << \"  fdc0 = floppy\\n\";\n    os << \"  {\\n\";\n    /* Ask what disks to add.\n     */\n    add_disks(&fd_q, &os);\n    os << \"  }\\n\\n\";\n  }\n\n  /* **************************** *\n   * ALi IDE Disks                *\n   * **************************** */\n\n  /* Use a ShrinkingChoiceQuestion; once\n   * a disk position has been used, it\n   * can't be used again.\n   */\n  ShrinkingChoiceQuestion ide_q;\n  ide_q.setQuestion(\"Do you want to add any disks to the IDE controller?\");\n  ide_q.setDefault(\"none\");\n  ide_q.setExplanation(\"The IDE controller is mandatory. You can skip this, \"\n                       \"and set up a SCSI controller, too.\");\n  ide_q.addAnswer(\"none\", \"\", \"stop adding disks\");\n  ide_q.addAnswer(\"0.0\", \"disk0.0\", \"primary master\");\n  ide_q.addAnswer(\"0.1\", \"disk0.1\", \"primary slave\");\n  ide_q.addAnswer(\"1.0\", \"disk1.0\", \"secondary master\");\n  ide_q.addAnswer(\"1.1\", \"disk1.1\", \"secondary slave\");\n\n  os << \"  pci0.15 = ali_ide\\n\";\n  os << \"  {\\n\";\n  /* Ask what disks to add.\n   */\n  add_disks(&ide_q, &os);\n  os << \"  }\\n\\n\";\n\n  /* **************************** *\n   * VGA Card                     *\n   * **************************** */\n\n  /* Use a ShrinkingChoiceQuestion. Once a\n   * card is using a specific PCI slot, it\n   * can't be used by another card.\n   */\n  ShrinkingChoiceQuestion pci_q;\n\n  /* Only add the PCI bus 0 slots, as the\n   * VGA card is only supported on hose 0.\n   */\n  for (int i = 1; i < 5; i++) {\n    pci_q.addAnswer(\"0.\" + i2s(i), \"pci0.\" + i2s(i), \"Bus 0, Slot \" + i2s(i));\n  }\n  pci_q.setExplanation(\"Only free PCI slots are listed.\");\n\n  MultipleChoiceQuestion vga_q;\n\n  if (gui_q.getAnswer() != \"\") {\n    vga_q.setQuestion(\n        \"What (if any) VGA card do you wish to add to the system?\");\n    vga_q.setExplanation(\n        \"Functionality of the different cards is pretty much the same; some \"\n        \"OS'es seem to have a preference, though.\");\n    vga_q.setDefault(\"Cirrus\");\n    vga_q.addAnswer(\"none\", \"\", \"No graphics card\");\n    vga_q.addAnswer(\"Cirrus\", \"cirrus\", \"Cirrus CL-GD something\");\n    vga_q.addAnswer(\"S3\", \"s3\", \"S3 Trio 64\");\n#if defined(HAVE_RADEON)\n    /* Radeon support is optional, and currently\n     * unreleased, because the specs are only\n     * available under an NDA with AMD. Once AMD\n     * has publicly released the Radeon 7500 (RV200)\n     * specs, the emulated Radeon card will be\n     * released.\n     */\n    vga_q.addAnswer(\"Radeon\", \"radeon\", \"Radeon 7500\");\n#endif\n\n    vga_q.ask();\n  }\n\n  if (vga_q.getAnswer() != \"\") {\n    pci_q.setQuestion(\"What PCI slot should the \" + vga_q.getAnswer() +\n                      \" card be on?\");\n    pci_q.setDefault(\"0.1\");\n\n    rom_q.setQuestion(\"Where can the VGA BIOS ROM image be found?\");\n    rom_q.setExplanation(\"This file is required.\");\n#if defined(_WIN32)\n    rom_q.setDefault(\"rom\\\\vgabios-0.6a.bin\");\n#elif defined(__VMS)\n    rom_q.setDefault(\"[.ROM]VGABIOS_0_6A.BIN\");\n#else\n    rom_q.setDefault(\"rom/vgabios-0.6a.bin\");\n#endif\n\n    os << \"  \" << pci_q.ask() << \" = \" << vga_q.getAnswer() << \"\\n\";\n    os << \"  {\\n\";\n    os << \"    rom = \\\"\" << rom_q.ask() << \"\\\";\\n\";\n    os << \"  }\\n\\n\";\n  }\n\n  /* **************************** *\n   * Free Form PCI Cards          *\n   * **************************** */\n\n  /* Add the PCI bus 1 slots. All non-VGA\n   * PCI cards can be on either hose 0 or\n   * hose 1.\n   */\n  for (int i = 1; i < 7; i++) {\n    pci_q.addAnswer(\"1.\" + i2s(i), \"pci1.\" + i2s(i), \"Bus 1, Slot \" + i2s(i));\n  }\n\n  MultipleChoiceQuestion card_q;\n\n  card_q.setQuestion(\"Would you like to add another PCI card to the system?\");\n  card_q.setDefault(\"none\");\n  card_q.setExplanation(\"Choose what PCI card you'd like to add. Choose none \"\n                        \"if you have no more cards to add.\");\n  card_q.addAnswer(\"none\", \"\", \"No more cards to add\");\n#if defined(HAVE_PCAP)\n  card_q.addAnswer(\"nic\", \"dec21143\", \"DEC 21143 Network Interface (1 max)\");\n#endif\n  card_q.addAnswer(\"scsi\", \"sym53c810\",\n                   \"Symbios 53C810 narrow SCSI controller\");\n  card_q.addAnswer(\n      \"wide scsi\", \"sym53c895\",\n      \"Symbios 53C895 wide SCSI controller (doesn't work with OpenVMS)\");\n\n  /* Loop until there are no more PCI\n   * cards to add.\n   */\n  for (;;) {\n    /* If there are no more free PCI slots,\n     * stop adding PCI cards.\n     */\n    if (pci_q.countAnswers() == 0)\n      break;\n\n    /* Default to the first available free\n     * PCI slot.\n     */\n    pci_q.setDefault(pci_q.getFirstChoice());\n\n    /* If this answer has been answered with\n     * \"none\", stop adding PCI cards.\n     */\n    if (card_q.ask() == \"\")\n      break;\n\n    /* Determine where to put this card.\n     */\n    pci_q.setQuestion(\"In what PCI slot would you like to put the \" +\n                      card_q.getAnswer() + \" card?\");\n    os << \"  \" << pci_q.ask() << \" = \" << card_q.getAnswer() << \"\\n\";\n    os << \"  {\\n\";\n\n    if (card_q.getAnswer() == \"dec21143\") {\n      /* Due to limitations in our network\n       * emulation, only one NIC is allowed.\n       * Remove it from the list of choices.\n       */\n      card_q.dropChoice(\"nic\");\n\n#if defined(HAVE_PCAP)\n      MultipleChoiceQuestion if_q;\n      if_q.setQuestion(\"What host network interface should we connect to \"\n                       \"(answer ? for a list)?\");\n      if_q.setExplanation(\"Choose 'list' to get a list at run-time.\");\n      if_q.addAnswer(\"list\", \"\", \"Get a list at run-time\");\n\n      /* Get a list of network interfaces and\n       * add them to the list.\n       */\n      pcap_if_t *alldevs;\n      pcap_if_t *d;\n      char errbuf[PCAP_ERRBUF_SIZE];\n\n      if (pcap_findalldevs(&alldevs, errbuf) == -1) {\n        /* No devices to add.\n         */\n        printf(\"Error in pcap_findalldevs_ex: %s\", errbuf);\n      } else {\n        int i = 1;\n        for (d = alldevs; d; d = d->next) {\n          // if_q.addAnswer(i2s(i),d->name, string(d->name) + \"(\" +\n          // string(d->description) + \")\");\n          if_q.addAnswer(i2s(i), d->name, d->name);\n          i++;\n        }\n      }\n\n      if (if_q.ask() != \"\")\n        os << \"    adapter = \\\"\" << if_q.getAnswer() << \"\\\";\\n\";\n\n      FreeTextQuestion mac_q;\n      mac_q.setQuestion(\"What should the NIC's MAC address be?\");\n      mac_q.setExplanation(\"This should be unique on your network.\");\n      mac_q.setDefault(\"08-00-2B-E5-40-00\");\n      os << \"    mac = \\\"\" << mac_q.ask() << \"\\\";\\n\";\n#endif\n    } else if (card_q.getAnswer() == \"sym53c810\") {\n      /* Use a ShrinkingChoiceQuestion; once\n       * a disk position has been used, it\n       * can't be used again.\n       */\n      ShrinkingChoiceQuestion disk_q;\n      disk_q.setQuestion(\n          \"Do you want to add any disks to the Sym53C810 controller?\");\n      disk_q.setDefault(\"none\");\n      disk_q.setExplanation(\n          \"Add disks. Select 'none' if you have no more disks to add.\");\n      disk_q.addAnswer(\"none\", \"\", \"stop adding disks\");\n      /* The narrow SCSI controller supports\n       * devices at targets 0..6.\n       */\n      for (int i = 0; i < 7; i++) {\n        disk_q.addAnswer(i2s(i), \"disk0.\" + i2s(i), \"Target \" + i2s(i));\n      }\n      /* Ask what disks to add.\n       */\n      add_disks(&disk_q, &os);\n    } else if (card_q.getAnswer() == \"sym53c895\") {\n      /* Use a ShrinkingChoiceQuestion; once\n       * a disk position has been used, it\n       * can't be used again.\n       */\n      ShrinkingChoiceQuestion disk_q;\n      disk_q.setQuestion(\n          \"Do you want to add any disks to the Sym53C895 controller?\");\n      disk_q.setDefault(\"none\");\n      disk_q.setExplanation(\n          \"Add disks. Select 'none' if you have no more disks to add.\");\n      disk_q.addAnswer(\"none\", \"\", \"stop adding disks\");\n      /* The wide SCSI controller supports\n       * devices at targets 0..6 and 8..15.\n       */\n      for (int i = 0; i < 16; i++) {\n        if (i != 7)\n          disk_q.addAnswer(i2s(i), \"disk0.\" + i2s(i), \"Target \" + i2s(i));\n      }\n      /* Ask what disks to add.\n       */\n      add_disks(&disk_q, &os);\n    }\n    os << \"  }\\n\\n\";\n  }\n\n  MultipleChoiceQuestion mouse_q;\n  mouse_q.setQuestion(\"Would you like to emulate the mouse?\");\n  mouse_q.setExplanation(\"The mouse is not really working yet... :-(\");\n  mouse_q.addAnswer(\"no\", \"false\", \"Disable the mouse\");\n  mouse_q.addAnswer(\"yes\", \"true\", \"Enable the mouse\");\n  mouse_q.setDefault(\"no\");\n\n  MultipleChoiceQuestion vgacons_q;\n  vgacons_q.setQuestion(\"Where would you like console output to go?\");\n  vgacons_q.setExplanation(\"This is the SRM console option\");\n  vgacons_q.addAnswer(\"serial\", \"false\", \"Console on serial port 0\");\n  vgacons_q.addAnswer(\"graphics\", \"true\", \"Console on graphics controller\");\n  vgacons_q.setDefault(\"graphics\");\n\n  if (vga_q.getAnswer() != \"\") {\n    /* If a VGA card is present, ask about\n     * the mouse and the console.\n     */\n    mouse_q.ask();\n    vgacons_q.ask();\n  } else {\n    /* No VGA card present, mouse support\n     * is disabled, and the console goes\n     * to serial port 0.\n     */\n    mouse_q.setAnswer(\"false\");\n    vgacons_q.setAnswer(\"false\");\n  }\n\n  FreeTextQuestion lpt_q;\n  lpt_q.setQuestion(\"Where would you like printer output to go?\");\n  lpt_q.setExplanation(\"Output from the printer port will be saved to this \"\n                       \"file. Leave blank if not wanted.\");\n  lpt_q.ask();\n\n  os << \"  pci0.7 = ali\\n\";\n  os << \"  {\\n\";\n  os << \"    mouse.enabled = \" << mouse_q.getAnswer() << \";\\n\";\n  os << \"    vga_console = \" << vgacons_q.getAnswer() << \";\\n\";\n  if (lpt_q.getAnswer() != \"\")\n    os << \"    lpt.outfile = \\\"\" << lpt_q.getAnswer() << \"\\\"\\n\";\n  os << \"  }\\n\\n\";\n\n  /* The USB device is a fixed part, and\n   * currently not configurable.\n   */\n  os << \"  pci0.19 = ali_usb\\n\";\n  os << \"  {\\n\";\n  os << \"  }\\n\";\n\n  os << \"}\\n\";\n\n  /* Close es40.cfg.\n   */\n  fb.close();\n\n  /* All is well.\n   */\n  return 0;\n}\n"
  },
  {
    "path": "src/es40_debug.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n   This file is based upon GXemul.\n *\n *  Copyright (C) 2004-2007  Anders Gavare.  All rights reserved.\n *\n *  Redistribution and use in source and binary forms, with or without\n *  modification, are permitted provided that the following conditions are met:\n *\n *  1. Redistributions of source code must retain the above copyright\n *     notice, this list of conditions and the following disclaimer.\n *  2. Redistributions in binary form must reproduce the above copyright\n *     notice, this list of conditions and the following disclaimer in the\n *     documentation and/or other materials provided with the distribution.\n *  3. The name of the author may not be used to endorse or promote products\n *     derived from this software without specific prior written permission.\n *\n *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n *  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n *  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n *  SUCH DAMAGE.\n */\n\n/*****************************************************************************\n *\n *  NOTE:  debug(), fatal(), and debug_indentation() are not re-entrant.\n *         The global variable quiet_mode can be used to suppress the output\n *         of debug(), but not the output of fatal().\n *\n *****************************************************************************/\n#include \"StdAfx.hpp\"\n\n// int verbose = 0;\nint quiet_mode = 0;\n\nstatic int debug_indent = 0;\nstatic int debug_currently_at_start_of_line = 1;\n\n/*\n *  va_debug():\n *\n *  Used internally by debug() and fatal().\n */\nstatic void va_debug(va_list argp, char *fmt) {\n  char buf[DEBUG_BUFSIZE + 1];\n  char *s;\n  int i;\n\n  buf[0] = buf[DEBUG_BUFSIZE] = 0;\n\n  // vsnprintf(buf, DEBUG_BUFSIZE, fmt, argp);\n  sprintf(buf, fmt, argp);\n\n  s = buf;\n  while (*s) {\n    if (debug_currently_at_start_of_line) {\n      for (i = 0; i < debug_indent; i++)\n        printf(\" \");\n    }\n\n    printf(\"%c\", *s);\n\n    debug_currently_at_start_of_line = 0;\n    if (*s == '\\n' || *s == '\\r')\n      debug_currently_at_start_of_line = 1;\n    s++;\n  }\n}\n\n/*\n *  debug_indentation():\n *\n *  Modify the debug indentation.\n */\nvoid debug_indentation(int diff) {\n  debug_indent += diff;\n  if (debug_indent < 0)\n    fprintf(stderr, \"WARNING: debug_indent less than 0!\\n\");\n}\n\n/*\n *  debug():\n *\n *  Debug output (ignored if quiet_mode is set).\n */\nvoid debug(char *fmt, ...) {\n  va_list argp;\n\n  if (quiet_mode)\n    return;\n\n  va_start(argp, fmt);\n  va_debug(argp, fmt);\n  va_end(argp);\n}\n\n/*\n *  fatal():\n *\n *  Fatal works like debug(), but doesn't care about the quiet_mode\n *  setting.\n */\nvoid fatal(char *fmt, ...) {\n  va_list argp;\n\n  va_start(argp, fmt);\n  va_debug(argp, fmt);\n  va_end(argp);\n}\n"
  },
  {
    "path": "src/es40_debug.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n *\n * Parts of this file based upon GXemul, which is Copyright (C) 2004-2007\n * Anders Gavare.  All rights reserved.\n */\n\n#include <stdarg.h>\n\n#if !defined(INCLUDED_DEBUG_H)\n#define INCLUDED_DEBUG_H\n\n#define DEBUG_BUFSIZE 1024\n#define FAILMSG_BUFSIZE 8000\n#define DEBUG_INDENTATION 4\n\n#ifdef HAVE___FUNCTION__\n#define FAILURE(cls, error_msg)                                                \\\n  {                                                                            \\\n    char where_msg[FAILMSG_BUFSIZE];;                                                       \\\n    sprintf(where_msg, \"%s, line %i, function '%s'\", __FILE__, __LINE__,       \\\n            __FUNCTION__);                                                     \\\n    throw C##cls##Exception(error_msg, where_msg);                             \\\n  }\n\n#else\n#define FAILURE(cls, error_msg)                                                \\\n  {                                                                            \\\n    char where_msg[FAILMSG_BUFSIZE];                                           \\\n    sprintf(where_msg, \"%s, line %i\", __FILE__, __LINE__);                     \\\n    throw C##cls##Exception(error_msg, where_msg);                             \\\n  }\n#endif /*  !HAVE___FUNCTION__  */\n\n#define FAILURE_1(cls, error_msg, a)                                           \\\n  {                                                                            \\\n    char what_msg[FAILMSG_BUFSIZE];                                            \\\n    sprintf(what_msg, error_msg, a);                                           \\\n    FAILURE(cls, what_msg);                                                    \\\n  }\n\n#define FAILURE_2(cls, error_msg, a, b)                                        \\\n  {                                                                            \\\n    char what_msg[FAILMSG_BUFSIZE];                                            \\\n    sprintf(what_msg, error_msg, a, b);                                        \\\n    FAILURE(cls, what_msg);                                                    \\\n  }\n\n#define FAILURE_3(cls, error_msg, a, b, c)                                     \\\n  {                                                                            \\\n    char what_msg[FAILMSG_BUFSIZE];                                            \\\n    sprintf(what_msg, error_msg, a, b, c);                                     \\\n    FAILURE(cls, what_msg);                                                    \\\n  }\n\n#define FAILURE_4(cls, error_msg, a, b, c, d)                                  \\\n  {                                                                            \\\n    char what_msg[FAILMSG_BUFSIZE];                                            \\\n    sprintf(what_msg, error_msg, a, b, c, d);                                  \\\n    FAILURE(cls, what_msg);                                                    \\\n  }\n\n#define FAILURE_5(cls, error_msg, a, b, c, d, e)                               \\\n  {                                                                            \\\n    char what_msg[FAILMSG_BUFSIZE];                                            \\\n    sprintf(what_msg, error_msg, a, b, c, d, e);                               \\\n    FAILURE(cls, what_msg);                                                    \\\n  }\n\n#define FAILURE_6(cls, error_msg, a, b, c, d, e, f)                            \\\n  {                                                                            \\\n    char what_msg[FAILMSG_BUFSIZE];                                            \\\n    sprintf(what_msg, error_msg, a, b, c, d, e, f);                            \\\n    FAILURE(cls, what_msg);                                                    \\\n  }\n\n#define CHECK_ALLOCATION(ptr)                                                  \\\n  {                                                                            \\\n    if ((ptr) == NULL)                                                         \\\n      FAILURE(OutOfMemory, \"Out of memory\");                                   \\\n  }\n\n#define CHECK_REALLOCATION(dst, src, type)                                     \\\n  {                                                                            \\\n    type *rea_x;                                                               \\\n    rea_x = (type *)src;                                                       \\\n    if ((rea_x) == NULL) {                                                     \\\n      FAILURE(OutOfMemory, \"Out of memory\");                                   \\\n    } else {                                                                   \\\n      dst = rea_x;                                                             \\\n    }                                                                          \\\n  }\n\nvoid debug_indentation(int diff);\nvoid debug(char *fmt, ...);\nvoid fatal(char *fmt, ...);\n#endif\n"
  },
  {
    "path": "src/es40_endian.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_ENDIAN_H)\n#define INCLUDED_ENDIAN_H\n\n#if !defined(ES40_LITTLE_ENDIAN) && !defined(ES40_BIG_ENDIAN)\n#if defined(_WIN32) || defined(__VMS)\n#define ES40_LITTLE_ENDIAN\n#else // defined (_WIN32) || defined(__VMS)\n#include <sys/param.h>\n\n#if !defined(__BYTE_ORDER) && defined(BYTE_ORDER)\n#define __BYTE_ORDER BYTE_ORDER\n#if !defined(__BIG_ENDIAN) && defined(BIG_ENDIAN)\n#define __BIG_ENDIAN BIG_ENDIAN\n#endif\n#if !defined(__LITTLE_ENDIAN) && defined(LITTLE_ENDIAN)\n#define __LITTLE_ENDIAN LITTLE_ENDIAN\n#endif\n#endif\n#if (defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN)) || defined(sparc)\n#define ES40_BIG_ENDIAN\n#else // assume little endian\n#define ES40_LITTLE_ENDIAN\n#endif\n#endif // defined (_WIN32) || defined(__VMS)\n#endif // !defined(ES40_LITTLE_ENDIAN) && !defined(ES40_BIG_ENDIAN)\n#define swap_64(x)                                                             \\\n  ((((x)&U64(0x00000000000000ff)) << 56) |                                     \\\n   (((x)&U64(0x000000000000ff00)) << 40) |                                     \\\n   (((x)&U64(0x0000000000ff0000)) << 24) |                                     \\\n   (((x)&U64(0x00000000ff000000)) << 8) |                                      \\\n   (((x)&U64(0x000000ff00000000)) >> 8) |                                      \\\n   (((x)&U64(0x0000ff0000000000)) >> 24) |                                     \\\n   (((x)&U64(0x00ff000000000000)) >> 40) |                                     \\\n   (((x)&U64(0xff00000000000000)) >> 56))\n#define swap_32(x)                                                             \\\n  ((((x)&0x000000ff) << 24) | (((x)&0x0000ff00) << 8) |                        \\\n   (((x)&0x00ff0000) >> 8) | (((x)&0xff000000) >> 24))\n#define swap_16(x) ((((x)&0x00ff) << 8) | (((x)&0xff00) >> 8))\n#define swap_8(x) ((x)&0xff)\n#if defined(ES40_BIG_ENDIAN)\n#define endian_64(x) swap_64(x)\n#define endian_32(x) swap_32(x)\n#define endian_16(x) swap_16(x)\n#define endian_8(x) swap_8(x)\n#else // defined(ES40_BIG_ENDIAN)\n#define endian_64(x) (x)\n#define endian_32(x) ((x)&0xffffffff)\n#define endian_16(x) ((x)&0xffff)\n#define endian_8(x) ((x)&0xff)\n#endif // defined(ES40_BIG_ENDIAN)\ninline u64 endian_bits(u64 x, int numbits) {\n  switch (numbits) {\n  case 64:\n    return endian_64(x);\n  case 32:\n    return endian_32(x);\n  case 16:\n    return endian_16(x);\n  case 8:\n    return endian_8(x);\n  default:\n    FAILURE(InvalidArgument, \"Weird numbits in endian_bits\");\n  }\n}\n#endif // INCLUDED_ENDIAN_H\n"
  },
  {
    "path": "src/es40_float.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include <math.h>\n\n//#define DEBUG_FP_CONVERSION 1\n//#define DEBUG_FP_LOADSTORE 1\n#define FLOAT_IS_IEEE 1\n\n/**\n * VAX (G or F) floating point to host conversion.\n * Converts the register-form of F and G foating point values to a double.\n **/\ninline double f2host(u64 val) {\n  int s = (val & U64(0x8000000000000000)) ? 1 : 0;\n  int e = (int)((val & U64(0x7ff0000000000000)) >> 52);\n  s64 f = (val & U64(0x000fffffffffffff));\n  f |= U64(0x0010000000000000);\n\n  double res;\n\n  if (e == 0)\n    res = 0.0;\n  else\n    res = (s ? -1.0 : 1.0) * pow((double)2.0, e - 1024) *\n          ((double)f / (double)(s64)U64(0x0020000000000000));\n\n#if defined(DEBUG_FP_CONVERSION)\n  printf(\"f/g->host: %016\" PRIx64 \" -> %f   \\n\", val, res);\n#endif\n  return res;\n}\n\n#define g2host f2host\n\n/**\n * VAX (D) floating point to host conversion.\n * Converts the register-form of D foating point values to a double.\n **/\ninline double d2host(u64 val) {\n  int s = (val & U64(0x8000000000000000)) ? 1 : 0;\n  int e = (int)((val & U64(0x7f80000000000000)) >> 55);\n  s64 f = (val & U64(0x007fffffffffffff));\n  f |= U64(0x0080000000000000);\n\n  double res;\n\n  if (e == 0)\n    res = 0.0;\n  else\n    res = (s ? -1.0 : 1.0) * pow((double)2.0, e - 128) *\n          ((double)f / (double)(s64)U64(0x0100000000000000));\n\n#if defined(DEBUG_FP_CONVERSION)\n  printf(\"d->host: %016\" PRIx64 \" -> %f   \\n\", val, res);\n#endif\n  return res;\n}\n\n/**\n * IEEE (S or T) floating point to host conversion.\n * Converts the register-form of S and T foating point values to a double.\n **/\ninline double s2host(u64 val) {\n  double res;\n\n#if defined(FLOAT_IS_IEEE)\n  if (sizeof(double) == 8) {\n    union s2h_conv {\n      u64 a;\n      double b;\n    } f_ieee;\n    f_ieee.a = val;\n    res = f_ieee.b;\n  } else\n#endif\n  {\n    int s = (val & U64(0x8000000000000000)) ? 1 : 0;\n    int e = (int)((val & U64(0x7ff0000000000000)) >> 52);\n    s64 f = (val & U64(0x000fffffffffffff));\n\n    if (e == 2047) {\n      if (f)\n        res = (s ? -0.0 : 0.0) / 0.0; // NaN\n      else\n        res = (s ? -1.0 : 1.0) / 0.0; // +/- Inf\n    } else if (e == 0) {\n      if (f)\n        res = (s ? -1.0 : 1.0) *\n              ldexp((double)f / (double)((s64)U64(0x10000000000000)), -1022);\n      else\n        res = (s ? -1.0 : 1.0) * 0.0;\n    } else {\n      res = (s ? -1.0 : 1.0) *\n            ldexp(1.0 + ((double)f / (double)((s64)U64(0x0010000000000000))),\n                  e - 1023);\n    }\n  }\n\n#if defined(DEBUG_FP_CONVERSION)\n  printf(\"s/t->host: %016\" PRIx64 \" -> %f   \\n\", val, res);\n#endif\n  return res;\n}\n\n#define t2host s2host\n\n/**\n * Check IEEE floating point value for NaN.\n **/\ninline bool i_isnan(u64 val) {\n  int e = (int)((val & U64(0x7ff0000000000000)) >> 52);\n  s64 f = (val & U64(0x000fffffffffffff));\n\n  return (e == 2047) && f;\n}\n\n/**\n * Host to VAX F floating point conversion.\n * Converts a double to the register-form of F foating point values.\n **/\ninline u64 host2f(double val) {\n  double fr;\n  double v = val;\n  int s = (v < 0.0) ? 1 : 0;\n  if (s)\n    v *= -1.0;\n\n  int e = (int)(log((double)v) / log((double)2.0));\n  bool exp_down = true;\n\n  if (val == 0.0)\n    return 0;\n\n  fr = v / pow((double)2.0, e);\n\n  while ((fr >= 1.0 && e < 127) || e < -127) {\n    e++;\n    exp_down = false;\n    fr = v / pow((double)2.0, e);\n  }\n\n  while (((fr < 0.5 && e > -127) || e > 127) && exp_down) {\n    e--;\n    fr = v / pow((double)2.0, e);\n  }\n\n  e += 1024;\n\n  u64 f = (u64)(fr * (double)U64(0x0020000000000000) + 0.5);\n\n  f = (s ? U64(0x8000000000000000) : 0) |\n      (((u64)e << 52) & U64(0x7ff0000000000000)) |\n      (f & U64(0x000fffffe0000000));\n\n#if defined(DEBUG_FP_CONVERSION)\n  printf(\"host->f: %f -> %016\" PRIx64 \"   \\n\", val, f);\n#endif\n  return f;\n}\n\n/**\n * Host to VAX G floating point conversion.\n * Converts a double to the register-form of G foating point values.\n **/\ninline u64 host2g(double val) {\n  double fr;\n  double v = val;\n  int s = (v < 0.0) ? 1 : 0;\n  if (s)\n    v *= -1.0;\n\n  int e = (int)(log((double)v) / log((double)2.0));\n  bool exp_down = true;\n\n  if (val == 0.0)\n    return 0;\n\n  fr = v / pow((double)2.0, e);\n\n  while ((fr >= 1.0 && e < 1023) || e < -1023) {\n    e++;\n    exp_down = false;\n    fr = v / pow((double)2.0, e);\n  }\n\n  while (((fr < 0.5 && e > -1023) || e > 1023) && exp_down) {\n    e--;\n    fr = v / pow((double)2.0, e);\n  }\n\n  e += 1024;\n\n  u64 f = (u64)(fr * (double)U64(0x0020000000000000) + 0.5);\n\n  f = (s ? U64(0x8000000000000000) : 0) |\n      (((u64)e << 52) & U64(0x7ff0000000000000)) |\n      (f & U64(0x000fffffffffffff));\n\n#if defined(DEBUG_FP_CONVERSION)\n  printf(\"host->g: %f -> %016\" PRIx64 \"   \\n\", val, f);\n#endif\n  return f;\n}\n\n/**\n * Host to VAX D floating point conversion.\n * Converts a double to the register-form of D foating point values.\n **/\ninline u64 host2d(double val) {\n  double fr;\n  double v = val;\n  int s = (v < 0.0) ? 1 : 0;\n  if (s)\n    v *= -1.0;\n\n  int e = (int)(log((double)v) / log((double)2.0));\n  bool exp_down = true;\n\n  if (val == 0.0)\n    return 0;\n\n  fr = v / pow((double)2.0, e);\n\n  while ((fr >= 1.0 && e < 127) || e < -127) {\n    e++;\n    exp_down = false;\n    fr = v / pow((double)2.0, e);\n  }\n\n  while (((fr < 0.5 && e > -127) || e > 127) && exp_down) {\n    e--;\n    fr = v / pow((double)2.0, e);\n  }\n\n  e += 128;\n\n  u64 f = (u64)(fr * (double)U64(0x0100000000000000) + 0.5);\n\n  f = (s ? U64(0x8000000000000000) : 0) |\n      (((u64)e << 55) & U64(0x7f80000000000000)) |\n      (f & U64(0x007fffffffffffff));\n\n#if defined(DEBUG_FP_CONVERSION)\n  printf(\"host->d: %f -> %016\" PRIx64 \"   \\n\", val, f);\n#endif\n  return f;\n}\n\n/**\n * Map an 8-bit IEEE (S) exponent to an 11-bit IEEE (T) exponent.\n **/\ninline u32 map_s(u32 val) {\n  if (val == 0)\n    return 0;\n  else if (val == 0xff)\n    return 0x7ff;\n  else if (val & 0x80)\n    return (val & 0x7f) | 0x400;\n  else\n    return (val & 0x7f) | 0x380;\n}\n\n/**\n * Host to 32-bit IEEE (S) floating point conversion.\n * Converts a double to the register-form of S foating point values.\n **/\ninline u64 host2s(double val) {\n  u64 f;\n  int s;\n  int e;\n#if defined(FLOAT_IS_IEEE)\n  if (sizeof(float) == 4) {\n    union h2s_conv {\n      u32 a;\n      float b;\n    } f_ieee;\n    f_ieee.b = (float)val;\n    s = (f_ieee.a >> 31) & 1;\n    e = (f_ieee.a >> 23) & 0xff;\n    f = (u64)(f_ieee.a >> 0 & 0x7fffff) << 29;\n  } else\n#endif\n  {\n    double v = val;\n    s = (v < 0.0) ? 1 : 0;\n    if (s)\n      v *= -1.0;\n    e = (int)(log((double)v) / log((double)2.0));\n\n    double fr;\n    bool exp_down = true;\n\n    if (val == 0.0)\n      return 0;\n\n    fr = v / pow((double)2.0, e);\n\n    while ((fr >= 2.0 && e < 127) || e < -127) {\n      e++;\n      exp_down = false;\n      fr = v / pow((double)2.0, e);\n    }\n\n    while (((fr < 1.0 && e > -127) || e > 127) && exp_down) {\n      e--;\n      fr = v / pow((double)2.0, e);\n    }\n\n    e += 255;\n\n    if (e == 0)\n      fr = v / pow((double)2.0, -126);\n\n    f = (u64)(fr * (double)U64(0x0010000000000000) + 0.5);\n  }\n\n  e = map_s(e);\n\n  f = (s ? U64(0x800000000000000) : 0) |\n      (((u64)e << 52) & U64(0x7ff0000000000000)) |\n      (f & U64(0x000fffffe0000000));\n\n#if defined(DEBUG_FP_CONVERSION)\n  printf(\"host->s: %f -> %016\" PRIx64 \"   \\n\", val, f);\n#endif\n  return f;\n}\n\n/**\n * Host to 64-bit IEEE (T) floating point conversion.\n * Converts a double to the register-form of T foating point values.\n **/\ninline u64 host2t(double val) {\n  u64 f;\n#if defined(FLOAT_IS_IEEE)\n  if (sizeof(double) == 8) {\n    union h2t_conv {\n      u64 a;\n      double b;\n    } f_ieee;\n    f_ieee.b = val;\n    f = f_ieee.a;\n  } else\n#endif\n  {\n    double v = val;\n    int s = (v < 0.0) ? 1 : 0;\n    if (s)\n      v *= -1.0;\n\n    int e = (int)(log((double)v) / log((double)2.0));\n    double fr;\n    bool exp_down = true;\n\n    if (val == 0.0)\n      return 0;\n\n    fr = v / pow((double)2.0, e);\n\n    while ((fr >= 2.0 && e < 1023) || e < -1023) {\n      e++;\n      exp_down = false;\n      fr = v / pow((double)2.0, e);\n    }\n\n    while (((fr < 1.0 && e > -1023) || e > 1023) && exp_down) {\n      e--;\n      fr = v / pow((double)2.0, e);\n    }\n\n    e += 1023;\n\n    if (e == 0)\n      fr = v / pow((double)2.0, -1022);\n\n    f = (u64)(fr * (double)U64(0x0010000000000000) + 0.5);\n\n    f = (s ? U64(0x800000000000000) : 0) |\n        (((u64)e << 52) & U64(0x7ff0000000000000)) |\n        (f & U64(0x000fffffffffffff));\n  }\n\n#if defined(DEBUG_FP_CONVERSION)\n  printf(\"host->t: %f -> %016\" PRIx64 \"   \\n\", val, f);\n#endif\n  return f;\n}\n\n/**\n * Perform the VAX-byte ordering swap + the SEF mapping necessary to store\n * 32-bit VAX (F) floating point values to memory.\n **/\ninline u32 store_f(u64 val) {\n  u64 retval = (val & U64(0x00001fffe0000000)) >>\n               13; /* frac.lo          : 29..44 --> 16..31 */\n  retval |= (val & U64(0xc000000000000000)) >>\n            48; /* exp.hi + sign    : 62..63 --> 14..15 */\n  retval |= (val & U64(0x07ffe00000000000)) >>\n            45; /* frac.hi + exp.lo : 45..58 -->  0..13 */\n\n#if defined(DEBUG_FP_LOADSTORE)\n  printf(\"f->mem: %016\" PRIx64 \" -> %08x   \\n\", val, retval);\n#endif\n  return (u32)retval;\n}\n\n/**\n * Perform the VAX-byte ordering swap necessary to store 64-bit VAX (G)\n * floating point values to memory.\n **/\ninline u64 store_g(u64 val) {\n  u64 retval = (val >> 48) & U64(0x000000000000ffff);\n  retval |= (val >> 16) & U64(0x00000000ffff0000);\n  retval |= (val << 48) & U64(0xffff000000000000);\n  retval |= (val << 16) & U64(0x0000ffff00000000);\n\n#if defined(DEBUG_FP_LOADSTORE)\n  printf(\"g->mem: %016\" PRIx64 \" -> %016\" PRIx64 \"   \\n\", val, retval);\n#endif\n  return retval;\n}\n\n/**\n * Perform the VAX-byte ordering swap + the SEF mapping necessary to load\n * 32-bit VAX (F) floating point values from memory.\n **/\ninline u64 load_f(u32 val) {\n  u64 retval = (u64)(val & 0xffff0000)\n               << 13; /* frac.lo          : 16..31 --> 29..44 */\n  retval |= (u64)(val & 0x0000c000)\n            << 48; /* exp.hi + sign    : 14..15 --> 62..63 */\n  retval |= (u64)(val & 0x00003fff)\n            << 45; /* frac.hi + exp.lo :  0..13 --> 45..58 */\n  if (((val & 0x00004000) == 0) && ((val & 0x00003f80) != 0))\n    retval |= U64(0x3800000000000000); /* exp.mid */\n\n#if defined(DEBUG_FP_LOADSTORE)\n  printf(\"mem->f: %08x -> %016\" PRIx64 \"   \\n\", val, retval);\n#endif\n  return retval;\n}\n\n/**\n * Perform the SEF mapping necessary to load\n * 32-bit VAX (F) floating point values from an integer register.\n **/\ninline u64 itof_f(u64 val) {\n  u64 retval = (val & U64(0x3fffffff))\n               << 29; /* frac + exp.lo  :  0..29 --> 29..58 */\n  retval |= (val & U64(0xc0000000))\n            << 32; /* exp.hi + sign : 30..31 --> 62..63 */\n  if (((val & U64(0x40000000)) == 0) && ((val & U64(0x3f800000)) != 0))\n    retval |= U64(0x3800000000000000); /* exp.mid */\n\n#if defined(DEBUG_FP_LOADSTORE)\n  printf(\"reg->f: %08x -> %016\" PRIx64 \"   \\n\", val, retval);\n#endif\n  return retval;\n}\n\n/**\n * Perform the VAX-byte ordering swap necessary to load 64-bit VAX (G)\n * floating point values from memory.\n **/\ninline u64 load_g(u64 val) {\n  u64 retval = (val & U64(0x000000000000ffff)) << 48;\n  retval |= (val & U64(0x00000000ffff0000)) << 16;\n  retval |= (val & U64(0x0000ffff00000000)) >> 16;\n  retval |= (val & U64(0xffff000000000000)) >> 48;\n\n#if defined(DEBUG_FP_LOADSTORE)\n  printf(\"mem->g: %016\" PRIx64 \" -> %016\" PRIx64 \"   \\n\", val, retval);\n#endif\n  return retval;\n}\n\n/**\n * Perform the the SEF mapping necessary to load 32-bit IEEE (S)\n * floating point values from memory.\n **/\ninline u64 load_s(u32 val) {\n  return ((val & U64(0x80000000)) << 32)          // sign\n         | ((u64)map_s((val >> 23) & 0xff) << 52) // exp\n         | ((val & U64(0x7fffff)) << 29);\n}\n\n/**\n * Perform the the SEF mapping necessary to store 32-bit IEEE (S)\n * floating point values to memory.\n **/\ninline u32 store_s(u64 val) {\n  return ((u32)(val >> 32) & 0xc0000000) | ((u32)(val >> 29) & 0x3fffffff);\n}\n"
  },
  {
    "path": "src/gui/gui.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n *  This file is based upon Bochs.\n *\n *  Copyright (C) 2002  MandrakeSoft S.A.\n *\n *    MandrakeSoft S.A.\n *    43, rue d'Aboukir\n *    75002 Paris - France\n *    http://www.linux-mandrake.com/\n *    http://www.mandrakesoft.com/\n *\n *  This library is free software; you can redistribute it and/or\n *  modify it under the terms of the GNU Lesser General Public\n *  License as published by the Free Software Foundation; either\n *  version 2 of the License, or (at your option) any later version.\n *\n *  This library is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n *  Lesser General Public License for more details.\n *\n *  You should have received a copy of the GNU Lesser General Public\n *  License along with this library; if not, write to the Free Software\n *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA\n */\n\n//#define DEBUG_LOCKS\n//#define NO_LOCK_TIMEOUTS\n\n#include \"../StdAfx.hpp\"\n\n#include <signal.h>\n\n#include \"gui.hpp\"\n\nbx_gui_c *bx_gui = NULL;\n\n#define BX_KEY_UNKNOWN 0x7fffffff\n#define N_USER_KEYS 36\n\ntypedef struct {\n  const char *key;\n  u32 symbol;\n} user_key_t;\n\nstatic user_key_t user_keys[N_USER_KEYS] = {\n    {\"f1\", BX_KEY_F1},           {\"f2\", BX_KEY_F2},\n    {\"f3\", BX_KEY_F3},           {\"f4\", BX_KEY_F4},\n    {\"f5\", BX_KEY_F5},           {\"f6\", BX_KEY_F6},\n    {\"f7\", BX_KEY_F7},           {\"f8\", BX_KEY_F8},\n    {\"f9\", BX_KEY_F9},           {\"f10\", BX_KEY_F10},\n    {\"f11\", BX_KEY_F11},         {\"f12\", BX_KEY_F12},\n    {\"alt\", BX_KEY_ALT_L},       {\"bksl\", BX_KEY_BACKSLASH},\n    {\"bksp\", BX_KEY_BACKSPACE},  {\"ctrl\", BX_KEY_CTRL_L},\n    {\"del\", BX_KEY_DELETE},      {\"down\", BX_KEY_DOWN},\n    {\"end\", BX_KEY_END},         {\"enter\", BX_KEY_ENTER},\n    {\"esc\", BX_KEY_ESC},         {\"home\", BX_KEY_HOME},\n    {\"ins\", BX_KEY_INSERT},      {\"left\", BX_KEY_LEFT},\n    {\"menu\", BX_KEY_MENU},       {\"minus\", BX_KEY_MINUS},\n    {\"pgdwn\", BX_KEY_PAGE_DOWN}, {\"pgup\", BX_KEY_PAGE_UP},\n    {\"plus\", BX_KEY_KP_ADD},     {\"right\", BX_KEY_RIGHT},\n    {\"shift\", BX_KEY_SHIFT_L},   {\"space\", BX_KEY_SPACE},\n    {\"tab\", BX_KEY_TAB},         {\"up\", BX_KEY_UP},\n    {\"win\", BX_KEY_WIN_L},       {\"print\", BX_KEY_PRINT}};\n\nbx_gui_c::bx_gui_c(void) {\n  framebuffer = NULL;\n  guiMutex = new CMutex(\"gui-lock\");\n}\n\nbx_gui_c::~bx_gui_c() {\n  if (framebuffer != NULL) {\n    delete[] framebuffer;\n  }\n}\n\nvoid bx_gui_c::init(unsigned tilewidth, unsigned tileheight) {\n  new_gfx_api = 0;\n  host_xres = 640;\n  host_yres = 480;\n  host_bpp = 8;\n\n  specific_init(tilewidth, tileheight);\n\n  charmap_updated = 0;\n\n  if (!new_gfx_api && (framebuffer == NULL)) {\n    framebuffer = new u8[BX_MAX_XRES * BX_MAX_YRES * 4];\n  }\n}\n\nvoid bx_gui_c::cleanup(void) {}\nu32 get_user_key(char *key) {\n  int i = 0;\n\n  while (i < N_USER_KEYS) {\n    if (!strcmp(key, user_keys[i].key))\n      return user_keys[i].symbol;\n    i++;\n  }\n\n  return BX_KEY_UNKNOWN;\n}\n\nvoid bx_gui_c::mouse_enabled_changed(bool val) {\n\n  // This is only called when SIM->get_init_done is 1.  Note that VAL\n  // is the new value of mouse_enabled, which may not match the old\n  // value which is still in SIM->get_param_bool(BXPN_MOUSE_ENABLED)->get().\n  bx_gui->mouse_enabled_changed_specific(val);\n}\n\nvoid bx_gui_c::init_signal_handlers() {\n#if BX_GUI_SIGHANDLER\n  if (bx_gui_sighandler) {\n    u32 mask = bx_gui->get_sighandler_mask();\n    for (u32 sig = 0; sig < 32; sig++) {\n      if (mask & (1 << sig))\n        signal(sig, bx_signal_handler);\n    }\n  }\n#endif\n}\n\nvoid bx_gui_c::set_text_charmap(u8 *fbuffer) {\n  memcpy(&bx_gui->vga_charmap, fbuffer, 0x2000);\n  for (unsigned i = 0; i < 256; i++)\n    bx_gui->char_changed[i] = 1;\n  bx_gui->charmap_updated = 1;\n}\n\nvoid bx_gui_c::set_text_charbyte(u16 address, u8 data) {\n  bx_gui->vga_charmap[address] = data;\n  bx_gui->char_changed[address >> 5] = 1;\n  bx_gui->charmap_updated = 1;\n}\n\nvoid bx_gui_c::beep_on(float frequency) {\n  BX_INFO((\"GUI Beep ON (frequency=%.2f)\", frequency));\n}\n\nvoid bx_gui_c::beep_off() { BX_INFO((\"GUI Beep OFF\")); }\n\nvoid bx_gui_c::get_capabilities(u16 *xres, u16 *yres, u16 *bpp) {\n  *xres = 1024;\n  *yres = 768;\n  *bpp = 32;\n}\n\nbx_svga_tileinfo_t *bx_gui_c::graphics_tile_info(bx_svga_tileinfo_t *info) {\n  if (!info) {\n    info = (bx_svga_tileinfo_t *)malloc(sizeof(bx_svga_tileinfo_t));\n    if (!info) {\n      return NULL;\n    }\n  }\n\n  host_pitch = host_xres * ((host_bpp + 1) >> 3);\n\n  info->bpp = host_bpp;\n  info->pitch = host_pitch;\n  switch (info->bpp) {\n  case 15:\n    info->red_shift = 15;\n    info->green_shift = 10;\n    info->blue_shift = 5;\n    info->red_mask = 0x7c00;\n    info->green_mask = 0x03e0;\n    info->blue_mask = 0x001f;\n    break;\n\n  case 16:\n    info->red_shift = 16;\n    info->green_shift = 11;\n    info->blue_shift = 5;\n    info->red_mask = 0xf800;\n    info->green_mask = 0x07e0;\n    info->blue_mask = 0x001f;\n    break;\n\n  case 24:\n  case 32:\n    info->red_shift = 24;\n    info->green_shift = 16;\n    info->blue_shift = 8;\n    info->red_mask = 0xff0000;\n    info->green_mask = 0x00ff00;\n    info->blue_mask = 0x0000ff;\n    break;\n  }\n\n  info->is_indexed = (host_bpp == 8);\n#ifdef BX_LITTLE_ENDIAN\n  info->is_little_endian = 1;\n#else\n  info->is_little_endian = 0;\n#endif\n  return info;\n}\n\nu8 *bx_gui_c::graphics_tile_get(unsigned x0, unsigned y0, unsigned *w,\n                                unsigned *h) {\n  if (x0 + X_TILESIZE > host_xres) {\n    *w = host_xres - x0;\n  } else {\n    *w = X_TILESIZE;\n  }\n\n  if (y0 + Y_TILESIZE > host_yres) {\n    *h = host_yres - y0;\n  } else {\n    *h = Y_TILESIZE;\n  }\n\n  return (u8 *)framebuffer + y0 * host_pitch + x0 * ((host_bpp + 1) >> 3);\n}\n\nvoid bx_gui_c::graphics_tile_update_in_place(unsigned x0, unsigned y0,\n                                             unsigned w, unsigned h) {\n  u8 tile[X_TILESIZE * Y_TILESIZE * 4];\n  u8 *tile_ptr;\n  u8 *fb_ptr;\n  u16 xc;\n  u16 yc;\n  u16 fb_pitch;\n  u16 tile_pitch;\n  u8 r;\n  u8 diffx;\n  u8 diffy;\n\n  diffx = (x0 % X_TILESIZE);\n  diffy = (y0 % Y_TILESIZE);\n  if (diffx > 0) {\n    x0 -= diffx;\n    w += diffx;\n  }\n\n  if (diffy > 0) {\n    y0 -= diffy;\n    h += diffy;\n  }\n\n  fb_pitch = host_pitch;\n  tile_pitch = X_TILESIZE * ((host_bpp + 1) >> 3);\n  for (yc = y0; yc < (y0 + h); yc += Y_TILESIZE) {\n    for (xc = x0; xc < (x0 + w); xc += X_TILESIZE) {\n      fb_ptr = framebuffer + (yc * fb_pitch + xc * ((host_bpp + 1) >> 3));\n      tile_ptr = &tile[0];\n      for (r = 0; r < h; r++) {\n        memcpy(tile_ptr, fb_ptr, tile_pitch);\n        fb_ptr += fb_pitch;\n        tile_ptr += tile_pitch;\n      }\n\n      graphics_tile_update(tile, xc, yc);\n    }\n  }\n}\n\nvoid bx_gui_c::lock() { MUTEX_LOCK(guiMutex); }\n\nvoid bx_gui_c::unlock() { MUTEX_UNLOCK(guiMutex); }\n"
  },
  {
    "path": "src/gui/gui.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n *  This file is based upon Bochs.\n *\n *  Copyright (C) 2002  MandrakeSoft S.A.\n *\n *    MandrakeSoft S.A.\n *    43, rue d'Aboukir\n *    75002 Paris - France\n *    http://www.linux-mandrake.com/\n *    http://www.mandrakesoft.com/\n *\n *  This library is free software; you can redistribute it and/or\n *  modify it under the terms of the GNU Lesser General Public\n *  License as published by the Free Software Foundation; either\n *  version 2 of the License, or (at your option) any later version.\n *\n *  This library is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n *  Lesser General Public License for more details.\n *\n *  You should have received a copy of the GNU Lesser General Public\n *  License along with this library; if not, write to the Free Software\n *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA\n */\n\n#ifndef __GUI_H__\n#define __GUI_H__\n\n#define BX_DEBUG(a)                                                            \\\n  {                                                                            \\\n    printf a;                                                                  \\\n    printf(\"   \\n\");                                                           \\\n  }\n#define BX_INFO(a) BX_DEBUG(a)\n#define BX_PANIC(a) BX_DEBUG(a)\n#define BX_ERROR(a) BX_DEBUG(a)\n#include \"vga.hpp\"\n\n/// VGA mode information for GUI\ntypedef struct {\n  u16 start_address;\n  u8 cs_start;\n  u8 cs_end;\n  u16 line_offset;\n  u16 line_compare;\n  u8 h_panning;\n  u8 v_panning;\n  bool line_graphics;\n  bool split_hpanning;\n} bx_vga_tminfo_t;\n\n/// VGA tile information for GUI\ntypedef struct {\n  u16 bpp, pitch;\n  u8 red_shift, green_shift, blue_shift;\n  u8 is_indexed, is_little_endian;\n  unsigned long red_mask, green_mask, blue_mask;\n} bx_svga_tileinfo_t;\n\nextern class bx_gui_c *bx_gui;\n\n/**\n * \\brief Abstract base class for GUI implementations.\n **/\nclass bx_gui_c {\npublic:\n  bx_gui_c(void);\n  virtual ~bx_gui_c();\n  virtual void specific_init(unsigned x_tilesize, unsigned y_tilesize) = 0;\n  virtual void text_update(u8 *old_text, u8 *new_text, unsigned long cursor_x,\n                           unsigned long cursor_y, bx_vga_tminfo_t tm_info,\n                           unsigned rows) = 0;\n  virtual void graphics_tile_update(u8 *snapshot, unsigned x, unsigned y) = 0;\n  virtual bx_svga_tileinfo_t *graphics_tile_info(bx_svga_tileinfo_t *info);\n  virtual u8 *graphics_tile_get(unsigned x, unsigned y, unsigned *w,\n                                unsigned *h);\n  virtual void graphics_tile_update_in_place(unsigned x, unsigned y, unsigned w,\n                                             unsigned h);\n  virtual void handle_events(void) = 0;\n  virtual void flush(void) = 0;\n  virtual void clear_screen(void) = 0;\n  virtual bool palette_change(unsigned index, unsigned red, unsigned green,\n                              unsigned blue) = 0;\n  virtual void dimension_update(unsigned x, unsigned y, unsigned fheight = 0,\n                                unsigned fwidth = 0, unsigned bpp = 8) = 0;\n  virtual void mouse_enabled_changed_specific(bool val) = 0;\n  virtual void exit(void) = 0;\n\n  virtual u32 get_sighandler_mask() { return 0; }\n  virtual void sighandler(int sig) {}\n  virtual void beep_on(float frequency);\n  virtual void beep_off();\n  virtual void get_capabilities(u16 *xres, u16 *yres, u16 *bpp);\n\n  static void key_event(u32 key);\n  static void set_text_charmap(u8 *fbuffer);\n  static void set_text_charbyte(u16 address, u8 data);\n\n  void init(unsigned x_tilesize, unsigned y_tilesize);\n  void cleanup(void);\n  static void mouse_enabled_changed(bool val);\n  static void init_signal_handlers();\n\n  void lock();\n  void unlock();\n\nprotected:\n  CMutex *guiMutex;\n  static s32 make_text_snapshot(char **snapshot, u32 *length);\n\n  //  static void toggle_mouse_enable(void);\n  unsigned char vga_charmap[0x2000];\n  bool charmap_updated;\n  bool char_changed[256];\n  bool new_gfx_api;\n  u16 host_xres;\n  u16 host_yres;\n  u16 host_pitch;\n  u8 host_bpp;\n  u8 *framebuffer;\n};\n\n#define BX_KEY_PRESSED 0x00000000\n#define BX_KEY_RELEASED 0x80000000\n\n#define BX_KEY_UNHANDLED 0x10000000\n\n#define BX_KEY_CTRL_L 0\n#define BX_KEY_SHIFT_L 1\n\n#define BX_KEY_F1 2\n#define BX_KEY_F2 3\n#define BX_KEY_F3 4\n#define BX_KEY_F4 5\n#define BX_KEY_F5 6\n#define BX_KEY_F6 7\n#define BX_KEY_F7 8\n#define BX_KEY_F8 9\n#define BX_KEY_F9 10\n#define BX_KEY_F10 11\n#define BX_KEY_F11 12\n#define BX_KEY_F12 13\n\n#define BX_KEY_CTRL_R 14\n#define BX_KEY_SHIFT_R 15\n#define BX_KEY_CAPS_LOCK 16\n#define BX_KEY_NUM_LOCK 17\n#define BX_KEY_ALT_L 18\n#define BX_KEY_ALT_R 19\n\n#define BX_KEY_A 20\n#define BX_KEY_B 21\n#define BX_KEY_C 22\n#define BX_KEY_D 23\n#define BX_KEY_E 24\n#define BX_KEY_F 25\n#define BX_KEY_G 26\n#define BX_KEY_H 27\n#define BX_KEY_I 28\n#define BX_KEY_J 29\n#define BX_KEY_K 30\n#define BX_KEY_L 31\n#define BX_KEY_M 32\n#define BX_KEY_N 33\n#define BX_KEY_O 34\n#define BX_KEY_P 35\n#define BX_KEY_Q 36\n#define BX_KEY_R 37\n#define BX_KEY_S 38\n#define BX_KEY_T 39\n#define BX_KEY_U 40\n#define BX_KEY_V 41\n#define BX_KEY_W 42\n#define BX_KEY_X 43\n#define BX_KEY_Y 44\n#define BX_KEY_Z 45\n\n#define BX_KEY_0 46\n#define BX_KEY_1 47\n#define BX_KEY_2 48\n#define BX_KEY_3 49\n#define BX_KEY_4 50\n#define BX_KEY_5 51\n#define BX_KEY_6 52\n#define BX_KEY_7 53\n#define BX_KEY_8 54\n#define BX_KEY_9 55\n\n#define BX_KEY_ESC 56\n\n#define BX_KEY_SPACE 57\n#define BX_KEY_SINGLE_QUOTE 58\n#define BX_KEY_COMMA 59\n#define BX_KEY_PERIOD 60\n#define BX_KEY_SLASH 61\n\n#define BX_KEY_SEMICOLON 62\n#define BX_KEY_EQUALS 63\n\n#define BX_KEY_LEFT_BRACKET 64\n#define BX_KEY_BACKSLASH 65\n#define BX_KEY_RIGHT_BRACKET 66\n#define BX_KEY_MINUS 67\n#define BX_KEY_GRAVE 68\n\n#define BX_KEY_BACKSPACE 69\n#define BX_KEY_ENTER 70\n#define BX_KEY_TAB 71\n\n#define BX_KEY_LEFT_BACKSLASH 72\n#define BX_KEY_PRINT 73\n#define BX_KEY_SCRL_LOCK 74\n#define BX_KEY_PAUSE 75\n\n#define BX_KEY_INSERT 76\n#define BX_KEY_DELETE 77\n#define BX_KEY_HOME 78\n#define BX_KEY_END 79\n#define BX_KEY_PAGE_UP 80\n#define BX_KEY_PAGE_DOWN 81\n\n#define BX_KEY_KP_ADD 82\n#define BX_KEY_KP_SUBTRACT 83\n#define BX_KEY_KP_END 84\n#define BX_KEY_KP_DOWN 85\n#define BX_KEY_KP_PAGE_DOWN 86\n#define BX_KEY_KP_LEFT 87\n#define BX_KEY_KP_RIGHT 88\n#define BX_KEY_KP_HOME 89\n#define BX_KEY_KP_UP 90\n#define BX_KEY_KP_PAGE_UP 91\n#define BX_KEY_KP_INSERT 92\n#define BX_KEY_KP_DELETE 93\n#define BX_KEY_KP_5 94\n\n#define BX_KEY_UP 95\n#define BX_KEY_DOWN 96\n#define BX_KEY_LEFT 97\n#define BX_KEY_RIGHT 98\n\n#define BX_KEY_KP_ENTER 99\n#define BX_KEY_KP_MULTIPLY 100\n#define BX_KEY_KP_DIVIDE 101\n\n#define BX_KEY_WIN_L 102\n#define BX_KEY_WIN_R 103\n#define BX_KEY_MENU 104\n\n#define BX_KEY_ALT_SYSREQ 105\n#define BX_KEY_CTRL_BREAK 106\n\n#define BX_KEY_INT_BACK 107\n#define BX_KEY_INT_FORWARD 108\n#define BX_KEY_INT_STOP 109\n#define BX_KEY_INT_MAIL 110\n#define BX_KEY_INT_SEARCH 111\n#define BX_KEY_INT_FAV 112\n#define BX_KEY_INT_HOME 113\n\n#define BX_KEY_POWER_MYCOMP 114\n#define BX_KEY_POWER_CALC 115\n#define BX_KEY_POWER_SLEEP 116\n#define BX_KEY_POWER_POWER 117\n#define BX_KEY_POWER_WAKE 118\n\n#define BX_KEY_NBKEYS 119\n\n// If you add BX_KEYs Please update\n// - BX_KEY_NBKEYS\n// - the scancodes table in the file iodev/scancodes.cc\n// - the bx_key_symbol table in the file gui/keymap.cc\n\n/////////////// GUI plugin support\n// Define macro to supply gui plugin code.  This macro is called once in GUI to\n// supply the plugin initialization methods.  Since it is nearly identical for\n// each gui module, the macro is easier to maintain than pasting the same code\n// in each one.\n//\n// Each gui should declare a class pointer called \"theGui\" which is derived\n// from bx_gui_c, before calling this macro.  For example, the SDL port\n// says:\n\n//   static bx_sdl_gui_c *theGui;\n#define IMPLEMENT_GUI_PLUGIN_CODE(gui_name)                                    \\\n  int lib##gui_name##_LTX_plugin_init(CConfigurator *cfg) {                    \\\n    printf(\"%%GUI-I-INS: Installing %s module as the ES40 GUI\\n\", #gui_name);  \\\n    theGui = new bx_##gui_name##_gui_c(cfg);                                   \\\n    bx_gui = theGui;                                                           \\\n    return (0); /* Success */                                                  \\\n  }                                                                            \\\n                                                                               \\\n  void lib##gui_name##_LTX_plugin_fini(void) {}\n#endif\n"
  },
  {
    "path": "src/gui/gui_win32_font.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n *  This file is based upon Bochs.\n *\n *  Copyright (C) 2002  MandrakeSoft S.A.\n *\n *    MandrakeSoft S.A.\n *    43, rue d'Aboukir\n *    75002 Paris - France\n *    http://www.linux-mandrake.com/\n *    http://www.mandrakesoft.com/\n *\n *  This library is free software; you can redistribute it and/or\n *  modify it under the terms of the GNU Lesser General Public\n *  License as published by the Free Software Foundation; either\n *  version 2 of the License, or (at your option) any later version.\n *\n *  This library is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n *  Lesser General Public License for more details.\n *\n *  You should have received a copy of the GNU Lesser General Public\n *  License along with this library; if not, write to the Free Software\n *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA\n */\n\ntypedef struct {\n  unsigned char data[16];\n} bx_fontcharbitmap_t;\n\nstatic const bx_fontcharbitmap_t bx_vgafont[256] = {\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xa5, 0x99, 0x81, 0x81, 0x7e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xdb, 0xe7, 0xff, 0xff, 0x7e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x36, 0x7f, 0x7f, 0x7f, 0x7f, 0x3e, 0x1c, 0x08,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x3e, 0x7f, 0x3e, 0x1c, 0x08, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff,\n      0xff, 0xff, 0xff, 0xff}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff,\n      0xff, 0xff, 0xff, 0xff}},\n    {{0x00, 0x00, 0x78, 0x60, 0x70, 0x58, 0x1e, 0x33, 0x33, 0x33, 0x33, 0x1e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0xfc, 0xcc, 0xfc, 0x0c, 0x0c, 0x0c, 0x0c, 0x0e, 0x0f, 0x07,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0xfe, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xe6, 0xe7, 0x67,\n      0x03, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7f, 0x7c, 0x78, 0x70, 0x60, 0x40,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0xfe, 0xdb, 0xdb, 0xdb, 0xde, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x3e, 0x63, 0x06, 0x1c, 0x36, 0x63, 0x63, 0x36, 0x1c, 0x30, 0x63,\n      0x3e, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x7f, 0x7f,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x7f, 0x30, 0x18, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x7f, 0x06, 0x0c, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x7f, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x36, 0x7f, 0x36, 0x14, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x1c, 0x3e, 0x3e, 0x7f, 0x7f, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x3e, 0x3e, 0x1c, 0x1c, 0x08, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x36, 0x36, 0x7f, 0x36, 0x36, 0x36, 0x7f, 0x36, 0x36,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x18, 0x18, 0x3e, 0x63, 0x43, 0x03, 0x3e, 0x60, 0x60, 0x61, 0x63, 0x3e,\n      0x18, 0x18, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x43, 0x63, 0x30, 0x18, 0x0c, 0x06, 0x63, 0x61,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x1c, 0x36, 0x36, 0x1c, 0x6e, 0x3b, 0x33, 0x33, 0x33, 0x6e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x0c, 0x0c, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18,\n      0x0c, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x40, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x01,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x1c, 0x36, 0x63, 0x63, 0x6b, 0x6b, 0x63, 0x63, 0x36, 0x1c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x18, 0x1c, 0x1e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x3e, 0x63, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x63, 0x7f,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x3e, 0x63, 0x60, 0x60, 0x3c, 0x60, 0x60, 0x60, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x30, 0x38, 0x3c, 0x36, 0x33, 0x7f, 0x30, 0x30, 0x30, 0x78,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x7f, 0x03, 0x03, 0x03, 0x3f, 0x60, 0x60, 0x60, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x1c, 0x06, 0x03, 0x03, 0x3f, 0x63, 0x63, 0x63, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x7f, 0x63, 0x60, 0x60, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x60, 0x30, 0x1e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x3e, 0x63, 0x63, 0x30, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x7b, 0x7b, 0x7b, 0x3b, 0x03, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x3f, 0x66, 0x66, 0x66, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3f,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x03, 0x03, 0x43, 0x66, 0x3c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x1f, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x36, 0x1f,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16, 0x06, 0x46, 0x66, 0x7f,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16, 0x06, 0x06, 0x06, 0x0f,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x7b, 0x63, 0x63, 0x66, 0x5c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x63,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x33, 0x33, 0x1e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x67, 0x66, 0x66, 0x36, 0x1e, 0x1e, 0x36, 0x66, 0x66, 0x67,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x0f, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7f,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x63, 0x77, 0x7f, 0x7f, 0x6b, 0x63, 0x63, 0x63, 0x63, 0x63,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x63, 0x67, 0x6f, 0x7f, 0x7b, 0x73, 0x63, 0x63, 0x63, 0x63,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x3f, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x06, 0x06, 0x06, 0x0f,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x6b, 0x7b, 0x3e,\n      0x30, 0x70, 0x00, 0x00}},\n    {{0x00, 0x00, 0x3f, 0x66, 0x66, 0x66, 0x3e, 0x36, 0x66, 0x66, 0x66, 0x67,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x3e, 0x63, 0x63, 0x06, 0x1c, 0x30, 0x60, 0x63, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, 0x1c, 0x08,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x6b, 0x6b, 0x6b, 0x7f, 0x77, 0x36,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x63, 0x63, 0x36, 0x3e, 0x1c, 0x1c, 0x3e, 0x36, 0x63, 0x63,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x7f, 0x63, 0x61, 0x30, 0x18, 0x0c, 0x06, 0x43, 0x63, 0x7f,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0x60, 0x40,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x08, 0x1c, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0xff, 0x00, 0x00}},\n    {{0x0c, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x07, 0x06, 0x06, 0x1e, 0x36, 0x66, 0x66, 0x66, 0x66, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x03, 0x03, 0x03, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x38, 0x30, 0x30, 0x3c, 0x36, 0x33, 0x33, 0x33, 0x33, 0x6e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x1c, 0x36, 0x26, 0x06, 0x0f, 0x06, 0x06, 0x06, 0x06, 0x0f,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3e,\n      0x30, 0x33, 0x1e, 0x00}},\n    {{0x00, 0x00, 0x07, 0x06, 0x06, 0x36, 0x6e, 0x66, 0x66, 0x66, 0x66, 0x67,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x18, 0x18, 0x00, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x60, 0x60, 0x00, 0x70, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,\n      0x66, 0x66, 0x3c, 0x00}},\n    {{0x00, 0x00, 0x07, 0x06, 0x06, 0x66, 0x36, 0x1e, 0x1e, 0x36, 0x66, 0x67,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x7f, 0x6b, 0x6b, 0x6b, 0x6b, 0x63,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3e,\n      0x06, 0x06, 0x0f, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3e,\n      0x30, 0x30, 0x78, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x6e, 0x66, 0x06, 0x06, 0x06, 0x0f,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x06, 0x1c, 0x30, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x08, 0x0c, 0x0c, 0x3f, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x6b, 0x6b, 0x6b, 0x7f, 0x36,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x36, 0x1c, 0x1c, 0x1c, 0x36, 0x63,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7e,\n      0x60, 0x30, 0x1f, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x33, 0x18, 0x0c, 0x06, 0x63, 0x7f,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x6e, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x63, 0x7f, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x03, 0x43, 0x66, 0x3c, 0x30,\n      0x60, 0x3e, 0x00, 0x00}},\n    {{0x00, 0x00, 0x33, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x30, 0x18, 0x0c, 0x00, 0x3e, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x08, 0x1c, 0x36, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x33, 0x00, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x06, 0x0c, 0x18, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x1c, 0x36, 0x1c, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x06, 0x06, 0x66, 0x3c, 0x30, 0x60,\n      0x3c, 0x00, 0x00, 0x00}},\n    {{0x00, 0x08, 0x1c, 0x36, 0x00, 0x3e, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x63, 0x00, 0x00, 0x3e, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x06, 0x0c, 0x18, 0x00, 0x3e, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x66, 0x00, 0x00, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x18, 0x3c, 0x66, 0x00, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x06, 0x0c, 0x18, 0x00, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x63, 0x00, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x1c, 0x36, 0x1c, 0x00, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x18, 0x0c, 0x06, 0x00, 0x7f, 0x66, 0x06, 0x3e, 0x06, 0x06, 0x66, 0x7f,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x6e, 0x6c, 0x7e, 0x1b, 0x1b, 0x76,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x7c, 0x36, 0x33, 0x33, 0x7f, 0x33, 0x33, 0x33, 0x33, 0x73,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x08, 0x1c, 0x36, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x63, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x06, 0x0c, 0x18, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x0c, 0x1e, 0x33, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x06, 0x0c, 0x18, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x63, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7e,\n      0x60, 0x30, 0x1e, 0x00}},\n    {{0x00, 0x63, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x63, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x18, 0x18, 0x3c, 0x66, 0x06, 0x06, 0x06, 0x66, 0x3c, 0x18, 0x18,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x1c, 0x36, 0x26, 0x06, 0x0f, 0x06, 0x06, 0x06, 0x06, 0x67, 0x3f,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x18, 0x18,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x1f, 0x33, 0x33, 0x1f, 0x23, 0x33, 0x7b, 0x33, 0x33, 0x33, 0x63,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x70, 0xd8, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18,\n      0x1b, 0x0e, 0x00, 0x00}},\n    {{0x00, 0x18, 0x0c, 0x06, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x30, 0x18, 0x0c, 0x00, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x18, 0x0c, 0x06, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x18, 0x0c, 0x06, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x6e, 0x3b, 0x00, 0x3b, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x6e, 0x3b, 0x00, 0x63, 0x67, 0x6f, 0x7f, 0x7b, 0x73, 0x63, 0x63, 0x63,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x3c, 0x36, 0x36, 0x7c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x1c, 0x36, 0x36, 0x1c, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x0c, 0x0c, 0x00, 0x0c, 0x0c, 0x06, 0x03, 0x63, 0x63, 0x3e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x60, 0x60, 0x60, 0x60, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x03, 0x03, 0x43, 0x63, 0x33, 0x18, 0x0c, 0x06, 0x3b, 0x61, 0x30,\n      0x18, 0x7c, 0x00, 0x00}},\n    {{0x00, 0x03, 0x03, 0x43, 0x63, 0x33, 0x18, 0x0c, 0x66, 0x73, 0x79, 0x7c,\n      0x60, 0x60, 0x00, 0x00}},\n    {{0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x36, 0x1b, 0x36, 0x6c, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x36, 0x6c, 0x36, 0x1b, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22,\n      0x88, 0x22, 0x88, 0x22}},\n    {{0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55,\n      0xaa, 0x55, 0xaa, 0x55}},\n    {{0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee,\n      0xbb, 0xee, 0xbb, 0xee}},\n    {{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n      0x18, 0x18, 0x18, 0x18}},\n    {{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,\n      0x18, 0x18, 0x18, 0x18}},\n    {{0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,\n      0x18, 0x18, 0x18, 0x18}},\n    {{0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x6c, 0x6c, 0x6c, 0x6c,\n      0x6c, 0x6c, 0x6c, 0x6c}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x6c, 0x6c, 0x6c, 0x6c,\n      0x6c, 0x6c, 0x6c, 0x6c}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,\n      0x18, 0x18, 0x18, 0x18}},\n    {{0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x60, 0x6f, 0x6c, 0x6c, 0x6c, 0x6c,\n      0x6c, 0x6c, 0x6c, 0x6c}},\n    {{0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,\n      0x6c, 0x6c, 0x6c, 0x6c}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x60, 0x6f, 0x6c, 0x6c, 0x6c, 0x6c,\n      0x6c, 0x6c, 0x6c, 0x6c}},\n    {{0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x60, 0x7f, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x7f, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18,\n      0x18, 0x18, 0x18, 0x18}},\n    {{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18,\n      0x18, 0x18, 0x18, 0x18}},\n    {{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18,\n      0x18, 0x18, 0x18, 0x18}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18,\n      0x18, 0x18, 0x18, 0x18}},\n    {{0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18,\n      0x18, 0x18, 0x18, 0x18}},\n    {{0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0x6c, 0x6c, 0x6c, 0x6c,\n      0x6c, 0x6c, 0x6c, 0x6c}},\n    {{0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0x0c, 0xfc, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0c, 0xec, 0x6c, 0x6c, 0x6c, 0x6c,\n      0x6c, 0x6c, 0x6c, 0x6c}},\n    {{0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xef, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xef, 0x6c, 0x6c, 0x6c, 0x6c,\n      0x6c, 0x6c, 0x6c, 0x6c}},\n    {{0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0x0c, 0xec, 0x6c, 0x6c, 0x6c, 0x6c,\n      0x6c, 0x6c, 0x6c, 0x6c}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xef, 0x00, 0xef, 0x6c, 0x6c, 0x6c, 0x6c,\n      0x6c, 0x6c, 0x6c, 0x6c}},\n    {{0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xff, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18,\n      0x18, 0x18, 0x18, 0x18}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x6c, 0x6c, 0x6c, 0x6c,\n      0x6c, 0x6c, 0x6c, 0x6c}},\n    {{0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xfc, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18,\n      0x18, 0x18, 0x18, 0x18}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x6c, 0x6c, 0x6c, 0x6c,\n      0x6c, 0x6c, 0x6c, 0x6c}},\n    {{0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xff, 0x6c, 0x6c, 0x6c, 0x6c,\n      0x6c, 0x6c, 0x6c, 0x6c}},\n    {{0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18,\n      0x18, 0x18, 0x18, 0x18}},\n    {{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18,\n      0x18, 0x18, 0x18, 0x18}},\n    {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n      0xff, 0xff, 0xff, 0xff}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,\n      0xff, 0xff, 0xff, 0xff}},\n    {{0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,\n      0x0f, 0x0f, 0x0f, 0x0f}},\n    {{0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,\n      0xf0, 0xf0, 0xf0, 0xf0}},\n    {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x1b, 0x1b, 0x3b, 0x6e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x1e, 0x33, 0x33, 0x33, 0x1b, 0x33, 0x63, 0x63, 0x63, 0x33,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x7f, 0x63, 0x63, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x7f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x7f, 0x63, 0x06, 0x0c, 0x18, 0x0c, 0x06, 0x63, 0x7f,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x0e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x06,\n      0x03, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x36, 0x1c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x1c, 0x36, 0x63, 0x63, 0x63, 0x36, 0x36, 0x36, 0x36, 0x77,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x78, 0x0c, 0x18, 0x30, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x3c,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0xc0, 0x60, 0x7e, 0xdb, 0xdb, 0xcf, 0x7e, 0x06, 0x03,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x38, 0x0c, 0x06, 0x06, 0x3e, 0x06, 0x06, 0x06, 0x0c, 0x38,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x70, 0xd8, 0xd8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n      0x18, 0x18, 0x18, 0x18}},\n    {{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1b, 0x1b, 0x1b, 0x0e,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x00, 0x6e, 0x3b, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x1c, 0x36, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x37, 0x36, 0x36, 0x3c, 0x38,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x1b, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x0e, 0x1b, 0x0c, 0x06, 0x13, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n    {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n      0x00, 0x00, 0x00, 0x00}},\n};\n"
  },
  {
    "path": "src/gui/gui_x11.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n *  This file is based upon Bochs.\n *\n *  Copyright (C) 2002  MandrakeSoft S.A.\n *\n *    MandrakeSoft S.A.\n *    43, rue d'Aboukir\n *    75002 Paris - France\n *    http://www.linux-mandrake.com/\n *    http://www.mandrakesoft.com/\n *\n *  This library is free software; you can redistribute it and/or\n *  modify it under the terms of the GNU Lesser General Public\n *  License as published by the Free Software Foundation; either\n *  version 2 of the License, or (at your option) any later version.\n *\n *  This library is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n *  Lesser General Public License for more details.\n *\n *  You should have received a copy of the GNU Lesser General Public\n *  License along with this library; if not, write to the Free Software\n *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA\n\n */\n\n#define XK_PUBLISHING\n#define XK_TECHNICAL\n\n#include \"../StdAfx.hpp\"\n\n#if defined(HAVE_X11)\n#include \"../Configurator.hpp\"\n#include \"../Keyboard.hpp\"\n#include \"../VGA.hpp\"\n#include \"gui.hpp\"\n#include \"keymap.hpp\"\n\nextern \"C\" {\n#include <X11/Xatom.h>\n#include <X11/Xlib.h>\n#include <X11/Xos.h>\n#include <X11/Xutil.h>\n#include <X11/keysym.h>\n}\n#include \"gui_win32_font.hpp\"\n\nclass bx_x11_gui_c : public bx_gui_c {\npublic:\n  bx_x11_gui_c(CConfigurator *cfg) {\n    myCfg = cfg;\n    bx_keymap = new bx_keymap_c(cfg);\n  };\n\n  virtual void specific_init(unsigned x_tilesize, unsigned y_tilesize);\n  virtual void text_update(u8 *old_text, u8 *new_text, unsigned long cursor_x,\n                           unsigned long cursor_y, bx_vga_tminfo_t tm_info,\n                           unsigned rows);\n  virtual void graphics_tile_update(u8 *snapshot, unsigned x, unsigned y);\n  virtual void handle_events(void);\n  virtual void flush(void);\n  virtual void clear_screen(void);\n  virtual bool palette_change(unsigned index, unsigned red, unsigned green,\n                              unsigned blue);\n  virtual void dimension_update(unsigned x, unsigned y, unsigned fheight = 0,\n                                unsigned fwidth = 0, unsigned bpp = 8);\n  virtual void mouse_enabled_changed_specific(bool val);\n  virtual void exit(void);\n  virtual bx_svga_tileinfo_t *graphics_tile_info(bx_svga_tileinfo_t *info);\n  virtual u8 *graphics_tile_get(unsigned x, unsigned y, unsigned *w,\n                                unsigned *h);\n  virtual void graphics_tile_update_in_place(unsigned x, unsigned y, unsigned w,\n                                             unsigned h);\n  virtual void get_capabilities(u16 *xres, u16 *yres, u16 *bpp);\n\nprivate:\n  CConfigurator *myCfg;\n};\n\n// declare one instance of the gui object and call macro to insert the\n// plugin code\nstatic bx_x11_gui_c *theGui = NULL;\nIMPLEMENT_GUI_PLUGIN_CODE(x11)\n#define MAX_MAPPED_STRING_LENGTH 10\n\n/* These are used as arguments to nearly every Xlib routine, so it saves\n * routine arguments to declare them global.  If there were\n * additional source files, they would be declared extern there. */\nDisplay *bx_x_display;\nint bx_x_screen_num;\nstatic Visual *default_visual;\nstatic Colormap default_cmap;\nstatic unsigned long white_pixel = 0, black_pixel = 0;\n\nstatic char *progname; /* name this program was invoked by */\n\nstatic unsigned int text_rows = 25, text_cols = 80;\nstatic u8 h_panning = 0, v_panning = 0;\nstatic u16 line_compare = 1023;\n\nstatic Window win;\nstatic GC gc, gc_inv;\nstatic unsigned font_width, font_height;\nstatic unsigned dimension_x = 0, dimension_y = 0;\nstatic unsigned vga_bpp = 8;\n\nstatic XImage *ximage = NULL;\nstatic unsigned imDepth, imWide, imBPP;\n\n// current cursor coordinates\nstatic int prev_x = -1, prev_y = -1;\nstatic int current_x = -1, current_y = -1, current_z = 0;\nstatic unsigned mouse_button_state = 0;\nstatic bool CTRL_pressed = 0;\n\nstatic unsigned prev_cursor_x = 0;\nstatic unsigned prev_cursor_y = 0;\n\nstatic int warp_home_x = 200;\nstatic int warp_home_y = 200;\nstatic int mouse_enable_x = 0;\nstatic int mouse_enable_y = 0;\nstatic int warp_dx = 0;\nstatic int warp_dy = 0;\n\nstatic void warp_cursor(int dx, int dy);\nstatic void disable_cursor();\nstatic void enable_cursor();\n\nstatic u32 convertStringToXKeysym(const char *string);\n\nstatic bool x_init_done = false;\n\nstatic Pixmap vgafont[256];\n\nstatic void send_keyboard_mouse_status(void);\n\nstatic bool x_keymapping;\nstatic bool x_private_colormap;\n\nu32 ascii_to_key_event[0x5f] = {\n    //  !\"#$%&'\n    BX_KEY_SPACE, BX_KEY_1, BX_KEY_SINGLE_QUOTE, BX_KEY_3, BX_KEY_4, BX_KEY_5,\n    BX_KEY_7, BX_KEY_SINGLE_QUOTE,\n\n    // ()*+,-./\n    BX_KEY_9, BX_KEY_0, BX_KEY_8, BX_KEY_EQUALS, BX_KEY_COMMA, BX_KEY_MINUS,\n    BX_KEY_PERIOD, BX_KEY_SLASH,\n\n    // 01234567\n    BX_KEY_0, BX_KEY_1, BX_KEY_2, BX_KEY_3, BX_KEY_4, BX_KEY_5, BX_KEY_6,\n    BX_KEY_7,\n\n    // 89:;<=>?\n    BX_KEY_8, BX_KEY_9, BX_KEY_SEMICOLON, BX_KEY_SEMICOLON, BX_KEY_COMMA,\n    BX_KEY_EQUALS, BX_KEY_PERIOD, BX_KEY_SLASH,\n\n    // @ABCDEFG\n    BX_KEY_2, BX_KEY_A, BX_KEY_B, BX_KEY_C, BX_KEY_D, BX_KEY_E, BX_KEY_F,\n    BX_KEY_G,\n\n    // HIJKLMNO\n    BX_KEY_H, BX_KEY_I, BX_KEY_J, BX_KEY_K, BX_KEY_L, BX_KEY_M, BX_KEY_N,\n    BX_KEY_O,\n\n    // PQRSTUVW\n    BX_KEY_P, BX_KEY_Q, BX_KEY_R, BX_KEY_S, BX_KEY_T, BX_KEY_U, BX_KEY_V,\n    BX_KEY_W,\n\n    // XYZ[\\]^_\n    BX_KEY_X, BX_KEY_Y, BX_KEY_Z, BX_KEY_LEFT_BRACKET, BX_KEY_BACKSLASH,\n    BX_KEY_RIGHT_BRACKET, BX_KEY_6, BX_KEY_MINUS,\n\n    // `abcdefg\n    BX_KEY_GRAVE, BX_KEY_A, BX_KEY_B, BX_KEY_C, BX_KEY_D, BX_KEY_E, BX_KEY_F,\n    BX_KEY_G,\n\n    // hijklmno\n    BX_KEY_H, BX_KEY_I, BX_KEY_J, BX_KEY_K, BX_KEY_L, BX_KEY_M, BX_KEY_N,\n    BX_KEY_O,\n\n    // pqrstuvw\n    BX_KEY_P, BX_KEY_Q, BX_KEY_R, BX_KEY_S, BX_KEY_T, BX_KEY_U, BX_KEY_V,\n    BX_KEY_W,\n\n    // xyz{|}~\n    BX_KEY_X, BX_KEY_Y, BX_KEY_Z, BX_KEY_LEFT_BRACKET, BX_KEY_BACKSLASH,\n    BX_KEY_RIGHT_BRACKET, BX_KEY_GRAVE};\n\nextern u8 graphics_snapshot[32 * 1024];\n\nstatic void create_internal_vga_font(void);\nstatic void xkeypress(KeySym keysym, int press_release);\n\n// extern \"C\" void select_visual(void);\n#define ROUNDUP(nbytes, pad) ((((nbytes) + ((pad)-1)) / (pad)) * ((pad) >> 3))\n#define MAX_VGA_COLORS 256\n\nunsigned long col_vals[MAX_VGA_COLORS]; // 256 VGA colors\nunsigned curr_foreground, curr_background;\n\nstatic unsigned x_tilesize, y_tilesize;\n\n// BxEvent *x11_notify_callback (void *unused, BxEvent *event);\n// bxevent_handler old_callback = NULL;\n// void *old_callback_arg = NULL;\n\n// Try to allocate NCOLORS at once in the colormap provided.  If it can\n// be done, return true.  If not, return false.  (In either case, free\n// up the color cells so that we don't add to the problem!)  This is used\n// to determine whether Bochs should use a private colormap even when the\n\n// user did not specify it.\nstatic bool test_alloc_colors(Colormap cmap, u32 n_tries) {\n  XColor color;\n  unsigned long pixel[MAX_VGA_COLORS];\n  bool pixel_valid[MAX_VGA_COLORS];\n  u32 n_allocated = 0;\n  u32 i;\n  color.flags = DoRed | DoGreen | DoBlue;\n  for (i = 0; i < n_tries; i++) {\n\n    // choose weird color values that are unlikely to already be in the\n    // colormap.\n    color.red = ((i + 41) % MAX_VGA_COLORS) << 8;\n    color.green = ((i + 42) % MAX_VGA_COLORS) << 8;\n    color.blue = ((i + 43) % MAX_VGA_COLORS) << 8;\n    pixel_valid[i] = false;\n    if (XAllocColor(bx_x_display, cmap, &color)) {\n      pixel[i] = color.pixel;\n      pixel_valid[i] = true;\n      n_allocated++;\n    }\n  }\n\n  BX_INFO((\"test_alloc_colors: %d colors available out of %d colors tried\",\n           n_allocated, n_tries));\n\n  // now free them all\n  for (i = 0; i < n_tries; i++) {\n    if (pixel_valid[i])\n      XFreeColors(bx_x_display, cmap, &pixel[i], 1, 0);\n  }\n\n  return (n_allocated == n_tries);\n}\n\nvoid bx_x11_gui_c::specific_init(unsigned tilewidth, unsigned tileheight) {\n  unsigned i;\n  int x;\n  int y;                         /* window position */\n  unsigned int border_width = 4; /* four pixels */\n  const char *window_name = \"ES40 Emulator\";\n  const char *icon_name = \"ES40\";\n  XSizeHints size_hints;\n  char *display_name = NULL;\n\n  /* create GC for text and drawing */\n  unsigned long valuemask = 0; /* ignore XGCvalues and use defaults */\n  XGCValues values;\n  int default_depth;\n  XEvent report;\n  XSetWindowAttributes win_attr;\n  unsigned long plane_masks_return[1];\n  XColor color;\n\n  x_tilesize = tilewidth;\n  y_tilesize = tileheight;\n\n  /* connect to X server */\n  if ((bx_x_display = XOpenDisplay(display_name)) == NULL && progname != nullptr) {\n    BX_PANIC((\"%s: cannot connect to X server %s\", progname,\n              XDisplayName(display_name)));\n  }\n\n  /* get screen size from display structure macro */\n  bx_x_screen_num = DefaultScreen(bx_x_display);\n\n  /* Note that in a real application, x and y would default to 0\n   * but would be settable from the command line or resource database.\n   */\n  x = y = 0;\n\n  // Temporary values so we can create the window\n  font_width = 8;\n  font_height = 16;\n\n  dimension_x = text_cols * font_width;\n  dimension_y = text_rows * font_height;\n\n  /* create opaque window */\n  win = XCreateSimpleWindow(bx_x_display,\n                            RootWindow(bx_x_display, bx_x_screen_num), x, y,\n                            dimension_x, dimension_y, border_width,\n                            BlackPixel(bx_x_display, bx_x_screen_num),\n                            BlackPixel(bx_x_display, bx_x_screen_num));\n\n  // (attempt to) enable backing store\n  win_attr.save_under = 1;\n  win_attr.backing_store = Always;\n  XChangeWindowAttributes(bx_x_display, win, CWSaveUnder | CWBackingStore,\n                          &win_attr);\n\n  default_depth = DefaultDepth(bx_x_display, bx_x_screen_num);\n  default_visual = DefaultVisual(bx_x_display, bx_x_screen_num);\n\n  x_private_colormap = myCfg->get_bool_value(\"private_colormap\", true);\n  if (!x_private_colormap) {\n\n    // if (!SIM->get_param_bool(BXPN_PRIVATE_COLORMAP)->get()) {\n    default_cmap = DefaultColormap(bx_x_display, bx_x_screen_num);\n\n    // try to use default colormap.  If not enough colors are available,\n    // then switch to private colormap despite the user setting.  There\n    // are too many cases when no colors are available and ES40 Emulator\n    // simply draws everything in black on black.\n    if (!test_alloc_colors(default_cmap, 16)) {\n      printf(\"xxx: I can't allocate 16 colors\\n\");\n      x_private_colormap = true;\n    }\n\n    col_vals[0] = BlackPixel(bx_x_display, bx_x_screen_num);\n    col_vals[15] = WhitePixel(bx_x_display, bx_x_screen_num);\n    for (i = 1; i < MAX_VGA_COLORS; i++) {\n      if (i == 15)\n        continue;\n      col_vals[i] = col_vals[0];\n    }\n  }\n\n  if (x_private_colormap) {\n\n    // if (SIM->get_param_bool(BXPN_PRIVATE_COLORMAP)->get()) {\n    default_cmap =\n        XCreateColormap(bx_x_display, DefaultRootWindow(bx_x_display),\n                        default_visual, AllocNone);\n    if (XAllocColorCells(bx_x_display, default_cmap, False, plane_masks_return,\n                         0, col_vals, MAX_VGA_COLORS) == 0) {\n      BX_PANIC((\"XAllocColorCells returns error. Maybe your screen does not \"\n                \"support a private colormap?\"));\n    }\n\n    win_attr.colormap = default_cmap;\n    XChangeWindowAttributes(bx_x_display, win, CWColormap, &win_attr);\n\n    color.flags = DoRed | DoGreen | DoBlue;\n\n    for (i = 0; i < MAX_VGA_COLORS; i++) {\n      color.pixel = i;\n      if (i == 15) {\n        color.red = 0xffff;\n        color.green = 0xffff;\n        color.blue = 0xffff;\n      } else {\n        color.red = 0;\n        color.green = 0;\n        color.blue = 0;\n      }\n\n      XStoreColor(bx_x_display, default_cmap, &color);\n    }\n  }\n\n  // convenience variables which hold the black & white color indeces\n  black_pixel = col_vals[0];\n  white_pixel = col_vals[15];\n\n  BX_INFO((\"font %u wide x %u high, display depth = %d\", (unsigned)font_width,\n           (unsigned)font_height, default_depth));\n\n  // select_visual();\n\n  /* Set size hints for window manager.  The window manager may\n   * override these settings.  Note that in a real\n   * application if size or position were set by the user\n   * the flags would be UPosition and USize, and these would\n   * override the window manager's preferences for this window.\n   */\n\n  /* x, y, width, and height hints are now taken from\n   * the actual settings of the window when mapped. Note\n   * that PPosition and PSize must be specified anyway.\n   */\n  size_hints.flags = PPosition | PSize | PMinSize | PMaxSize;\n  size_hints.max_width = size_hints.min_width = dimension_x;\n  size_hints.max_height = size_hints.min_height = dimension_y;\n  {\n    XWMHints wm_hints;\n    XClassHint class_hints;\n\n    /* format of the window name and icon name\n     * arguments has changed in R4\n     */\n    XTextProperty windowName;\n\n    /* format of the window name and icon name\n     * arguments has changed in R4\n     */\n    XTextProperty iconName;\n\n    /* These calls store window_name and icon_name into\n     * XTextProperty structures and set their other\n     * fields properly. */\n    if (XStringListToTextProperty((char **)&window_name, 1, &windowName) == 0 && progname != nullptr) {\n      BX_PANIC((\"%s: structure allocation for windowName failed.\", progname));\n    }\n\n    if (XStringListToTextProperty((char **)&icon_name, 1, &iconName) == 0 && progname != nullptr) {\n      BX_PANIC((\"%s: structure allocation for iconName failed.\", progname));\n    }\n\n    wm_hints.initial_state = NormalState;\n    wm_hints.input = True;\n    class_hints.res_name = progname;\n    class_hints.res_class = (char *)\"ES40 Emulator\";\n\n    XSetWMProperties(bx_x_display, win, &windowName, &iconName, NULL /*argv*/,\n                     0 /*argc*/, &size_hints, &wm_hints, &class_hints);\n    XFree(windowName.value);\n    XFree(iconName.value);\n\n    Atom wm_delete = XInternAtom(bx_x_display, \"WM_DELETE_WINDOW\", 1);\n    XSetWMProtocols(bx_x_display, win, &wm_delete, 1);\n  }\n\n  /* Select event types wanted */\n  XSelectInput(bx_x_display, win,\n               ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask |\n                   ButtonReleaseMask | StructureNotifyMask | PointerMotionMask |\n                   EnterWindowMask | LeaveWindowMask);\n\n  /* Create default Graphics Context */\n  gc = XCreateGC(bx_x_display, win, valuemask, &values);\n  gc_inv = XCreateGC(bx_x_display, win, valuemask, &values);\n\n  XSetState(bx_x_display, gc, white_pixel, black_pixel, GXcopy, AllPlanes);\n\n  XSetState(bx_x_display, gc_inv, black_pixel, white_pixel, GXinvert,\n            AllPlanes);\n\n  /* Display window */\n  XMapWindow(bx_x_display, win);\n  XSync(bx_x_display, /* no discard */ 0);\n\n  BX_DEBUG((\"waiting for MapNotify\"));\n  while (1) {\n    XNextEvent(bx_x_display, &report);\n    if (report.type == MapNotify)\n      break;\n  }\n\n  BX_DEBUG((\"MapNotify found.\"));\n\n  // Create the VGA font\n  create_internal_vga_font();\n  {\n    char *imagedata;\n\n    ximage = XCreateImage(bx_x_display, default_visual,\n                          default_depth,          // depth of image (bitplanes)\n                          ZPixmap, 0,             // offset\n                          NULL,                   // malloc() space after\n                          x_tilesize, y_tilesize, // x & y size of image\n                          32,                     // # bits of padding\n                          0); // bytes_per_line, let X11 calculate\n    if (!ximage)\n      BX_PANIC((\"vga: couldn't XCreateImage()\"));\n\n    imDepth = default_depth;\n    imWide = ximage->bytes_per_line;\n    imBPP = ximage->bits_per_pixel;\n\n    imagedata = (char *)malloc((size_t)(ximage->bytes_per_line * y_tilesize));\n    if (!imagedata)\n      BX_PANIC((\"imagedata: malloc returned error\"));\n\n    ximage->data = imagedata;\n\n    if (imBPP < imDepth) {\n      BX_PANIC((\"vga_x: bits_per_pixel < depth ?\"));\n    }\n\n    x_init_done = true;\n  }\n\n  curr_background = 0;\n  XSetBackground(bx_x_display, gc, col_vals[curr_background]);\n  curr_foreground = 1;\n  XSetForeground(bx_x_display, gc, col_vals[curr_foreground]);\n\n  // XGrabPointer( bx_x_display, win, True, 0, GrabModeAsync, GrabModeAsync,\n  //  win, None, CurrentTime );\n  XFlush(bx_x_display);\n\n  // loads keymap for x11\n  x_keymapping = myCfg->get_bool_value(\"keyboard.use_mapping\", false);\n  if (x_keymapping) {\n\n    // if (SIM->get_param_bool(BXPN_KBD_USEMAPPING)->get()) {\n    bx_keymap->loadKeymap(convertStringToXKeysym);\n  }\n\n  new_gfx_api = 1;\n}\n\n// This is called whenever the mouse_enabled parameter changes.  It\n// can change because of a gui event such as clicking on the mouse-enable\n// bitmap or pressing the middle button, or from the configuration interface.\n\n// In all those cases, setting the parameter value will get you here.\nvoid bx_x11_gui_c::mouse_enabled_changed_specific(bool val) {\n  BX_DEBUG((\"mouse_enabled=%d, x11 specific code\", val ? 1 : 0));\n  if (val) {\n    BX_INFO((\"[x] Mouse on\"));\n    mouse_enable_x = current_x;\n    mouse_enable_y = current_y;\n    disable_cursor();\n\n    // Move the cursor to a 'safe' place\n    warp_cursor(warp_home_x - current_x, warp_home_y - current_y);\n  } else {\n    BX_INFO((\"[x] Mouse off\"));\n    enable_cursor();\n    warp_cursor(mouse_enable_x - current_x, mouse_enable_y - current_y);\n  }\n}\n\n/**\n * Create a bitmap for VGA font data\n **/\nvoid create_internal_vga_font(void) {\n\n  // Default values\n  font_width = 8;\n  font_height = 16;\n\n  for (int i = 0; i < 256; i++) {\n    vgafont[i] = XCreateBitmapFromData(bx_x_display, win,\n                                       (const char *)bx_vgafont[i].data,\n                                       font_width, font_height);\n    if (vgafont[i] == None)\n      BX_PANIC((\"Can't create vga font [%d]\", i));\n  }\n}\n\nvoid bx_x11_gui_c::handle_events(void) {\n  XEvent report;\n  XKeyEvent *key_event;\n  KeySym keysym;\n  XComposeStatus compose;\n  char buffer[MAX_MAPPED_STRING_LENGTH];\n  int bufsize = MAX_MAPPED_STRING_LENGTH;\n  int charcount;\n  bool mouse_update;\n  int y;\n  int height;\n\n  XPointerMovedEvent *pointer_event;\n  XEnterWindowEvent *enter_event;\n  XLeaveWindowEvent *leave_event;\n  XButtonEvent *button_event;\n  XExposeEvent *expose_event;\n\n  // current_x = -1;\n  // current_y = -1;\n  mouse_update = 0;\n\n  while (XPending(bx_x_display) > 0) {\n    XNextEvent(bx_x_display, &report);\n    current_z = 0;\n    switch (report.type) {\n    case Expose:\n      expose_event = &report.xexpose;\n\n      /* Adjust y.*/\n      y = expose_event->y;\n      height = expose_event->height;\n      if (y < 0) {\n        height += y;\n        y = 0;\n      }\n\n      theVGA->redraw_area((unsigned)expose_event->x, y,\n                          (unsigned)expose_event->width, height);\n\n      break;\n\n    case ConfigureNotify:\n      BX_DEBUG((\"ConfigureNotify Xevent\"));\n      break;\n\n    case ButtonPress:\n      button_event = (XButtonEvent *)&report;\n      BX_DEBUG((\"xxx: buttonpress\"));\n      current_x = button_event->x;\n      current_y = button_event->y;\n      mouse_update = 1;\n      BX_DEBUG((\"xxx:   x,y=(%d,%d)\", current_x, current_y));\n      switch (button_event->button) {\n      case Button1:\n        mouse_button_state |= 0x01;\n        send_keyboard_mouse_status();\n        mouse_update = 0;\n        break;\n\n      case Button2:\n        if (CTRL_pressed) {\n\n          //            toggle_mouse_enable();\n        } else {\n          mouse_button_state |= 0x04;\n          send_keyboard_mouse_status();\n          mouse_update = 0;\n        }\n        break;\n\n      case Button3:\n        mouse_button_state |= 0x02;\n        send_keyboard_mouse_status();\n        mouse_update = 0;\n        break;\n      }\n      break;\n\n    case ButtonRelease:\n      button_event = (XButtonEvent *)&report;\n      current_x = button_event->x;\n      current_y = button_event->y;\n      mouse_update = 1;\n      switch (button_event->button) {\n      case Button1:\n        mouse_button_state &= ~0x01;\n        send_keyboard_mouse_status();\n        mouse_update = 0;\n        break;\n\n      case Button2:\n        mouse_button_state &= ~0x04;\n        send_keyboard_mouse_status();\n        mouse_update = 0;\n        break;\n\n      case Button3:\n        mouse_button_state &= ~0x02;\n        send_keyboard_mouse_status();\n        mouse_update = 0;\n        break;\n\n      case Button4:\n        current_z = 1;\n        send_keyboard_mouse_status();\n        mouse_update = 0;\n        break;\n\n      case Button5:\n        current_z = -1;\n        send_keyboard_mouse_status();\n        mouse_update = 0;\n        break;\n      }\n      break;\n\n    case KeyPress:\n      key_event = (XKeyEvent *)&report;\n      charcount = XLookupString(key_event, buffer, bufsize, &keysym, &compose);\n      xkeypress(keysym, 0);\n      break;\n\n    case KeyRelease:\n      key_event = (XKeyEvent *)&report;\n      charcount = XLookupString(key_event, buffer, bufsize, &keysym, &compose);\n      xkeypress(keysym, 1);\n      break;\n\n    case MotionNotify:\n      pointer_event = (XPointerMovedEvent *)&report;\n      current_x = pointer_event->x;\n      current_y = pointer_event->y;\n      mouse_update = 1;\n      break;\n\n    case EnterNotify:\n      enter_event = (XEnterWindowEvent *)&report;\n      prev_x = current_x = enter_event->x;\n      prev_y = current_y = enter_event->y;\n      break;\n\n    case LeaveNotify:\n      leave_event = (XLeaveWindowEvent *)&report;\n      prev_x = current_x = -1;\n      prev_y = current_y = -1;\n      break;\n\n    case MapNotify:\n\n      /* screen needs redraw, since X would have tossed previous\n       * requests before window mapped\n       */\n\n      // retval = 1;\n      break;\n\n    case ClientMessage:\n      if (!strcmp(XGetAtomName(bx_x_display, report.xclient.message_type),\n                  \"WM_PROTOCOLS\")) {\n        FAILURE(Graceful, \"Emulator stopped from X\");\n\n        // bx_stop_simulation();\n      }\n      break;\n\n    default:\n\n      // (mch) Ignore...\n      BX_DEBUG((\"XXX: default Xevent type\"));\n\n      /* all events selected by StructureNotifyMask are thrown away here,\n       * since nothing is done with them */\n      break;\n    } /* end switch */\n  }   /* end while */\n\n  if (mouse_update) {\n    BX_DEBUG((\"handle_events(): send mouse status\"));\n    send_keyboard_mouse_status();\n  }\n}\n\nvoid send_keyboard_mouse_status(void) {\n  BX_DEBUG(\n      (\"XXX: prev=(%d,%d) curr=(%d,%d)\", prev_x, prev_y, current_x, current_y));\n\n  if (((prev_x != -1) && (current_x != -1) && (prev_y != -1) &&\n       (current_y != -1)) ||\n      (current_z != 0)) {\n    int dx;\n\n    int dy;\n\n    int dz;\n\n    // (mch) consider warping here\n    dx = current_x - prev_x - warp_dx;\n    dy = -(current_y - prev_y - warp_dy);\n    dz = current_z;\n    warp_cursor(warp_home_x - current_x, warp_home_y - current_y);\n\n    // DEV_mouse_motion_ext (dx, dy, dz, mouse_button_state);\n    prev_x = current_x;\n    prev_y = current_y;\n  } else {\n    if ((current_x != -1) && (current_y != -1)) {\n      prev_x = current_x;\n      prev_y = current_y;\n    } else {\n      prev_x = current_x = -1;\n      prev_y = current_y = -1;\n    }\n  }\n}\n\nvoid bx_x11_gui_c::flush(void) {\n  if (bx_x_display)\n    XFlush(bx_x_display);\n}\n\nvoid xkeypress(KeySym keysym, int press_release) {\n  u32 key_event;\n\n  if ((keysym == XK_Control_L) || (keysym == XK_Control_R)) {\n    CTRL_pressed = !press_release;\n  }\n\n  /* Old (no mapping) behavior */\n  if (!x_keymapping) {\n\n    // if (!SIM->get_param_bool(BXPN_KBD_USEMAPPING)->get()) {\n    // this depends on the fact that the X11 keysyms which\n    // correspond to the ascii characters space .. tilde\n    // are in consequtive order.\n    if ((keysym >= XK_space) && (keysym <= XK_asciitilde)) {\n      key_event = ascii_to_key_event[keysym - XK_space];\n    } else {\n      switch (keysym) {\n      case XK_KP_1:\n#ifdef XK_KP_End\n\n      case XK_KP_End:\n#endif\n        key_event = BX_KEY_KP_END;\n        break;\n\n      case XK_KP_2:\n#ifdef XK_KP_Down\n\n      case XK_KP_Down:\n#endif\n        key_event = BX_KEY_KP_DOWN;\n        break;\n\n      case XK_KP_3:\n#ifdef XK_KP_Page_Down\n\n      case XK_KP_Page_Down:\n#endif\n        key_event = BX_KEY_KP_PAGE_DOWN;\n        break;\n\n      case XK_KP_4:\n#ifdef XK_KP_Left\n\n      case XK_KP_Left:\n#endif\n        key_event = BX_KEY_KP_LEFT;\n        break;\n\n      case XK_KP_5:\n#ifdef XK_KP_Begin\n\n      case XK_KP_Begin:\n#endif\n        key_event = BX_KEY_KP_5;\n        break;\n\n      case XK_KP_6:\n#ifdef XK_KP_Right\n\n      case XK_KP_Right:\n#endif\n        key_event = BX_KEY_KP_RIGHT;\n        break;\n\n      case XK_KP_7:\n#ifdef XK_KP_Home\n\n      case XK_KP_Home:\n#endif\n        key_event = BX_KEY_KP_HOME;\n        break;\n\n      case XK_KP_8:\n#ifdef XK_KP_Up\n\n      case XK_KP_Up:\n#endif\n        key_event = BX_KEY_KP_UP;\n        break;\n\n      case XK_KP_9:\n#ifdef XK_KP_Page_Up\n\n      case XK_KP_Page_Up:\n#endif\n        key_event = BX_KEY_KP_PAGE_UP;\n        break;\n\n      case XK_KP_0:\n#ifdef XK_KP_Insert\n\n      case XK_KP_Insert:\n#endif\n        key_event = BX_KEY_KP_INSERT;\n        break;\n\n      case XK_KP_Decimal:\n#ifdef XK_KP_Delete\n\n      case XK_KP_Delete:\n#endif\n        key_event = BX_KEY_KP_DELETE;\n        break;\n\n#ifdef XK_KP_Enter\n\n      case XK_KP_Enter:\n        key_event = BX_KEY_KP_ENTER;\n        break;\n#endif\n\n      case XK_KP_Subtract:\n        key_event = BX_KEY_KP_SUBTRACT;\n        break;\n\n      case XK_KP_Add:\n        key_event = BX_KEY_KP_ADD;\n        break;\n\n      case XK_KP_Multiply:\n        key_event = BX_KEY_KP_MULTIPLY;\n        break;\n\n      case XK_KP_Divide:\n        key_event = BX_KEY_KP_DIVIDE;\n        break;\n\n      case XK_Up:\n        key_event = BX_KEY_UP;\n        break;\n\n      case XK_Down:\n        key_event = BX_KEY_DOWN;\n        break;\n\n      case XK_Left:\n        key_event = BX_KEY_LEFT;\n        break;\n\n      case XK_Right:\n        key_event = BX_KEY_RIGHT;\n        break;\n\n      case XK_Delete:\n        key_event = BX_KEY_DELETE;\n        break;\n\n      case XK_BackSpace:\n        key_event = BX_KEY_BACKSPACE;\n        break;\n\n      case XK_Tab:\n        key_event = BX_KEY_TAB;\n        break;\n#ifdef XK_ISO_Left_Tab\n\n      case XK_ISO_Left_Tab:\n        key_event = BX_KEY_TAB;\n        break;\n#endif\n\n      case XK_Return:\n        key_event = BX_KEY_ENTER;\n        break;\n\n      case XK_Escape:\n        key_event = BX_KEY_ESC;\n        break;\n\n      case XK_F1:\n        key_event = BX_KEY_F1;\n        break;\n\n      case XK_F2:\n        key_event = BX_KEY_F2;\n        break;\n\n      case XK_F3:\n        key_event = BX_KEY_F3;\n        break;\n\n      case XK_F4:\n        key_event = BX_KEY_F4;\n        break;\n\n      case XK_F5:\n        key_event = BX_KEY_F5;\n        break;\n\n      case XK_F6:\n        key_event = BX_KEY_F6;\n        break;\n\n      case XK_F7:\n        key_event = BX_KEY_F7;\n        break;\n\n      case XK_F8:\n        key_event = BX_KEY_F8;\n        break;\n\n      case XK_F9:\n        key_event = BX_KEY_F9;\n        break;\n\n      case XK_F10:\n        key_event = BX_KEY_F10;\n        break;\n\n      case XK_F11:\n        key_event = BX_KEY_F11;\n        break;\n\n      case XK_F12:\n        key_event = BX_KEY_F12;\n        break;\n\n      case XK_Control_L:\n        key_event = BX_KEY_CTRL_L;\n        break;\n#ifdef XK_Control_R\n\n      case XK_Control_R:\n        key_event = BX_KEY_CTRL_R;\n        break;\n#endif\n\n      case XK_Shift_L:\n        key_event = BX_KEY_SHIFT_L;\n        break;\n\n      case XK_Shift_R:\n        key_event = BX_KEY_SHIFT_R;\n        break;\n\n      case XK_Alt_L:\n        key_event = BX_KEY_ALT_L;\n        break;\n#ifdef XK_Alt_R\n\n      case XK_Alt_R:\n        key_event = BX_KEY_ALT_R;\n        break;\n#endif\n\n      case XK_Caps_Lock:\n        key_event = BX_KEY_CAPS_LOCK;\n        break;\n\n      case XK_Num_Lock:\n        key_event = BX_KEY_NUM_LOCK;\n        break;\n#ifdef XK_Scroll_Lock\n\n      case XK_Scroll_Lock:\n        key_event = BX_KEY_SCRL_LOCK;\n        break;\n#endif\n#ifdef XK_Print\n\n      case XK_Print:\n        key_event = BX_KEY_PRINT;\n        break;\n#endif\n#ifdef XK_Pause\n\n      case XK_Pause:\n        key_event = BX_KEY_PAUSE;\n        break;\n#endif\n\n      case XK_Insert:\n        key_event = BX_KEY_INSERT;\n        break;\n\n      case XK_Home:\n        key_event = BX_KEY_HOME;\n        break;\n\n      case XK_End:\n        key_event = BX_KEY_END;\n        break;\n\n      case XK_Page_Up:\n        key_event = BX_KEY_PAGE_UP;\n        break;\n\n      case XK_Page_Down:\n        key_event = BX_KEY_PAGE_DOWN;\n        break;\n\n      default:\n        BX_ERROR((\"xkeypress(): keysym %x unhandled!\", (unsigned)keysym));\n        return;\n        break;\n      }\n    }\n  } else {\n\n    /* use mapping */\n    BXKeyEntry *entry = bx_keymap->findHostKey(keysym);\n    if (!entry) {\n      BX_ERROR((\"xkeypress(): keysym %x unhandled!\", (unsigned)keysym));\n      return;\n    }\n\n    key_event = entry->baseKey;\n  }\n\n  if (press_release)\n    key_event |= BX_KEY_RELEASED;\n\n  theKeyboard->gen_scancode(key_event);\n}\n\nvoid bx_x11_gui_c::clear_screen(void) {\n  XClearArea(bx_x_display, win, 0, 0, dimension_x, dimension_y, 0);\n}\n\nvoid bx_x11_gui_c::text_update(u8 *old_text, u8 *new_text,\n                               unsigned long cursor_x, unsigned long cursor_y,\n                               bx_vga_tminfo_t tm_info, unsigned nrows) {\n  u8 *old_line;\n\n  u8 *new_line;\n\n  u8 *text_base;\n  u8 cChar;\n  unsigned int curs;\n  unsigned int hchars;\n  unsigned int i;\n  unsigned int j;\n  unsigned int offset;\n  unsigned int rows;\n  unsigned int x;\n  unsigned int y;\n  unsigned int xc;\n  unsigned int yc;\n  unsigned int yc2;\n  unsigned int cs_y;\n  unsigned new_foreground;\n  unsigned new_background;\n  u8 cfwidth;\n  u8 cfheight;\n  u8 cfheight2;\n  u8 font_col;\n  u8 font_row;\n  u8 font_row2;\n  u8 split_textrow;\n  u8 split_fontrows;\n  bool forceUpdate = 0;\n  bool split_screen;\n  unsigned char cell[64];\n  unsigned long text_palette[16];\n\n  if (charmap_updated) {\n    BX_INFO((\"charmap update. Font Height is %d\", font_height));\n    for (unsigned c = 0; c < 256; c++) {\n      if (char_changed[c]) {\n        XFreePixmap(bx_x_display, vgafont[c]);\n\n        bool gfxchar = tm_info.line_graphics && ((c & 0xE0) == 0xC0);\n        j = 0;\n        memset(cell, 0, sizeof(cell));\n        for (i = 0; i < font_height * 2; i += 2) {\n          cell[i] |= ((vga_charmap[(c << 5) + j] & 0x01) << 7);\n          cell[i] |= ((vga_charmap[(c << 5) + j] & 0x02) << 5);\n          cell[i] |= ((vga_charmap[(c << 5) + j] & 0x04) << 3);\n          cell[i] |= ((vga_charmap[(c << 5) + j] & 0x08) << 1);\n          cell[i] |= ((vga_charmap[(c << 5) + j] & 0x10) >> 1);\n          cell[i] |= ((vga_charmap[(c << 5) + j] & 0x20) >> 3);\n          cell[i] |= ((vga_charmap[(c << 5) + j] & 0x40) >> 5);\n          cell[i] |= ((vga_charmap[(c << 5) + j] & 0x80) >> 7);\n          if (gfxchar) {\n            cell[i + 1] = (vga_charmap[(c << 5) + j] & 0x01);\n          }\n\n          j++;\n        }\n\n        vgafont[c] = XCreateBitmapFromData(bx_x_display, win,\n                                           (const char *)cell, 9, font_height);\n        if (vgafont[c] == None)\n          BX_PANIC((\"Can't create vga font [%d]\", c));\n        char_changed[c] = 0;\n      }\n    }\n\n    forceUpdate = 1;\n    charmap_updated = 0;\n  }\n\n  for (i = 0; i < 16; i++) {\n    text_palette[i] = col_vals[theVGA->get_actl_palette_idx(i)];\n  }\n\n  if ((tm_info.h_panning != h_panning) || (tm_info.v_panning != v_panning)) {\n    forceUpdate = 1;\n    h_panning = tm_info.h_panning;\n    v_panning = tm_info.v_panning;\n  }\n\n  if (tm_info.line_compare != line_compare) {\n    forceUpdate = 1;\n    line_compare = tm_info.line_compare;\n  }\n\n  // first invalidate character at previous and new cursor location\n  if ((prev_cursor_y < text_rows) && (prev_cursor_x < text_cols)) {\n    curs = prev_cursor_y * tm_info.line_offset + prev_cursor_x * 2;\n    old_text[curs] = ~new_text[curs];\n  }\n\n  if ((tm_info.cs_start <= tm_info.cs_end) &&\n      (tm_info.cs_start < font_height) && (cursor_y < text_rows) &&\n      (cursor_x < text_cols)) {\n    curs = cursor_y * tm_info.line_offset + cursor_x * 2;\n    old_text[curs] = ~new_text[curs];\n  } else {\n    curs = 0xffff;\n  }\n\n  rows = text_rows;\n  if (v_panning)\n    rows++;\n  y = 0;\n  cs_y = 0;\n  text_base = new_text - tm_info.start_address;\n  split_textrow = (line_compare + v_panning) / font_height;\n  split_fontrows = ((line_compare + v_panning) % font_height) + 1;\n  split_screen = 0;\n  do {\n    hchars = text_cols;\n    if (h_panning)\n      hchars++;\n    if (split_screen) {\n      yc = line_compare + cs_y * font_height + 1;\n      font_row = 0;\n      if (rows == 1) {\n        cfheight = (dimension_y - line_compare - 1) % font_height;\n        if (cfheight == 0)\n          cfheight = font_height;\n      } else {\n        cfheight = font_height;\n      }\n    } else if (v_panning) {\n      if (y == 0) {\n        yc = 0;\n        font_row = v_panning;\n        cfheight = font_height - v_panning;\n      } else {\n        yc = y * font_height - v_panning;\n        font_row = 0;\n        if (rows == 1) {\n          cfheight = v_panning;\n        } else {\n          cfheight = font_height;\n        }\n      }\n    } else {\n      yc = y * font_height;\n      font_row = 0;\n      cfheight = font_height;\n    }\n\n    if (!split_screen && (y == split_textrow)) {\n      if (split_fontrows < cfheight)\n        cfheight = split_fontrows;\n    }\n\n    new_line = new_text;\n    old_line = old_text;\n    x = 0;\n    offset = cs_y * tm_info.line_offset;\n    do {\n      if (h_panning) {\n        if (hchars > text_cols) {\n          xc = 0;\n          font_col = h_panning;\n          cfwidth = font_width - h_panning;\n        } else {\n          xc = x * font_width - h_panning;\n          font_col = 0;\n          if (hchars == 1) {\n            cfwidth = h_panning;\n          } else {\n            cfwidth = font_width;\n          }\n        }\n      } else {\n        xc = x * font_width;\n        font_col = 0;\n        cfwidth = font_width;\n      }\n\n      if (forceUpdate || (old_text[0] != new_text[0]) ||\n          (old_text[1] != new_text[1])) {\n        cChar = new_text[0];\n        new_foreground = new_text[1] & 0x0f;\n        new_background = (new_text[1] & 0xf0) >> 4;\n\n        XSetForeground(bx_x_display, gc, text_palette[new_foreground]);\n        XSetBackground(bx_x_display, gc, text_palette[new_background]);\n\n        XCopyPlane(bx_x_display, vgafont[cChar], win, gc, font_col, font_row,\n                   cfwidth, cfheight, xc, yc, 1);\n        if (offset == curs) {\n          XSetForeground(bx_x_display, gc, text_palette[new_background]);\n          XSetBackground(bx_x_display, gc, text_palette[new_foreground]);\n          if (font_row == 0) {\n            yc2 = yc + tm_info.cs_start;\n            font_row2 = tm_info.cs_start;\n            cfheight2 = tm_info.cs_end - tm_info.cs_start + 1;\n            if ((yc2 + cfheight2) > (dimension_y)) {\n              cfheight2 = dimension_y - yc2;\n            }\n          } else {\n            if (v_panning > tm_info.cs_start) {\n              yc2 = yc;\n              font_row2 = font_row;\n              cfheight2 = tm_info.cs_end - v_panning + 1;\n            } else {\n              yc2 = yc + tm_info.cs_start - v_panning;\n              font_row2 = tm_info.cs_start;\n              cfheight2 = tm_info.cs_end - tm_info.cs_start + 1;\n            }\n          }\n\n          if (yc2 < (dimension_y)) {\n            XCopyPlane(bx_x_display, vgafont[cChar], win, gc, font_col,\n                       font_row2, cfwidth, cfheight2, xc, yc2, 1);\n          }\n        }\n      }\n\n      x++;\n      new_text += 2;\n      old_text += 2;\n      offset += 2;\n    } while (--hchars);\n    if (!split_screen && (y == split_textrow)) {\n      new_text = text_base;\n      forceUpdate = 1;\n      cs_y = 0;\n      if (tm_info.split_hpanning)\n        h_panning = 0;\n      rows = ((dimension_y - line_compare + font_height - 2) / font_height) + 1;\n      split_screen = 1;\n    } else {\n      y++;\n      cs_y++;\n      new_text = new_line + tm_info.line_offset;\n      old_text = old_line + tm_info.line_offset;\n    }\n  } while (--rows);\n\n  h_panning = tm_info.h_panning;\n  prev_cursor_x = cursor_x;\n  prev_cursor_y = cursor_y;\n\n  XFlush(bx_x_display);\n}\n\nvoid bx_x11_gui_c::graphics_tile_update(u8 *tile, unsigned x0, unsigned y0) {\n  unsigned x;\n\n  unsigned y;\n\n  unsigned y_size;\n  unsigned color;\n  unsigned offset;\n  u8 b0;\n  u8 b1;\n  u8 b2;\n  u8 b3;\n\n  if ((y0 + y_tilesize) > dimension_y) {\n    y_size = dimension_y - y0;\n  } else {\n    y_size = y_tilesize;\n  }\n\n  switch (vga_bpp) {\n  case 8: // 8 bits per pixel\n    for (y = 0; y < y_size; y++) {\n      for (x = 0; x < x_tilesize; x++) {\n        color = col_vals[tile[y * x_tilesize + x]];\n        switch (imBPP) {\n        case 8: // 8 bits per pixel\n          ximage->data[imWide * y + x] = color;\n          break;\n\n        case 16: // 16 bits per pixel\n          offset = imWide * y + 2 * x;\n          b0 = color >> 0;\n          b1 = color >> 8;\n          if (ximage->byte_order == LSBFirst) {\n            ximage->data[offset + 0] = b0;\n            ximage->data[offset + 1] = b1;\n          } else { // MSBFirst\n            ximage->data[offset + 0] = b1;\n            ximage->data[offset + 1] = b0;\n          }\n          break;\n\n        case 24: // 24 bits per pixel\n          offset = imWide * y + 3 * x;\n          b0 = color >> 0;\n          b1 = color >> 8;\n          b2 = color >> 16;\n          if (ximage->byte_order == LSBFirst) {\n            ximage->data[offset + 0] = b0;\n            ximage->data[offset + 1] = b1;\n            ximage->data[offset + 2] = b2;\n          } else { // MSBFirst\n            ximage->data[offset + 0] = b2;\n            ximage->data[offset + 1] = b1;\n            ximage->data[offset + 2] = b0;\n          }\n          break;\n\n        case 32: // 32 bits per pixel\n          offset = imWide * y + 4 * x;\n          b0 = color >> 0;\n          b1 = color >> 8;\n          b2 = color >> 16;\n          b3 = color >> 24;\n          if (ximage->byte_order == LSBFirst) {\n            ximage->data[offset + 0] = b0;\n            ximage->data[offset + 1] = b1;\n            ximage->data[offset + 2] = b2;\n            ximage->data[offset + 3] = b3;\n          } else { // MSBFirst\n            ximage->data[offset + 0] = b3;\n            ximage->data[offset + 1] = b2;\n            ximage->data[offset + 2] = b1;\n            ximage->data[offset + 3] = b0;\n          }\n          break;\n\n        default:\n          BX_PANIC((\"X_graphics_tile_update: bits_per_pixel %u not implemented\",\n                    (unsigned)imBPP));\n          return;\n        }\n      }\n    }\n    break;\n\n  default:\n    BX_PANIC((\n        \"X_graphics_tile_update: bits_per_pixel %u handled by new graphics API\",\n        (unsigned)vga_bpp));\n    return;\n  }\n\n  XPutImage(bx_x_display, win, gc, ximage, 0, 0, x0, y0, x_tilesize, y_size);\n}\n\nbx_svga_tileinfo_t *bx_x11_gui_c::graphics_tile_info(bx_svga_tileinfo_t *info) {\n  if (!info) {\n    info = (bx_svga_tileinfo_t *)malloc(sizeof(bx_svga_tileinfo_t));\n    if (!info) {\n      return NULL;\n    }\n  }\n\n  info->bpp = ximage->bits_per_pixel;\n  info->pitch = ximage->bytes_per_line;\n  info->red_shift = 0;\n  info->green_shift = 0;\n  info->blue_shift = 0;\n  info->red_mask = ximage->red_mask;\n  info->green_mask = ximage->green_mask;\n  info->blue_mask = ximage->blue_mask;\n\n  int i;\n\n  int rf;\n\n  int gf;\n\n  int bf;\n  unsigned long red;\n  unsigned long green;\n  unsigned long blue;\n\n  i = rf = gf = bf = 0;\n  red = ximage->red_mask;\n  green = ximage->green_mask;\n  blue = ximage->blue_mask;\n\n  while (red || rf || green || gf || blue || bf) {\n    if (rf) {\n      if (!(red & 1)) {\n        info->red_shift = i;\n        rf = 0;\n      }\n    } else {\n      if (red & 1) {\n        rf = 1;\n      }\n    }\n\n    if (gf) {\n      if (!(green & 1)) {\n        info->green_shift = i;\n        gf = 0;\n      }\n    } else {\n      if (green & 1) {\n        gf = 1;\n      }\n    }\n\n    if (bf) {\n      if (!(blue & 1)) {\n        info->blue_shift = i;\n        bf = 0;\n      }\n    } else {\n      if (blue & 1) {\n        bf = 1;\n      }\n    }\n\n    i++;\n    red >>= 1;\n    green >>= 1;\n    blue >>= 1;\n  }\n\n  info->is_indexed = (default_visual->c_class != TrueColor) &&\n                     (default_visual->c_class != DirectColor);\n  info->is_little_endian = (ximage->byte_order == LSBFirst);\n\n  return info;\n}\n\nu8 *bx_x11_gui_c::graphics_tile_get(unsigned x0, unsigned y0, unsigned *w,\n                                    unsigned *h) {\n  if (x0 + x_tilesize > dimension_x) {\n    *w = dimension_x - x0;\n  } else {\n    *w = x_tilesize;\n  }\n\n  if (y0 + y_tilesize > dimension_y) {\n    *h = dimension_y - y0;\n  } else {\n    *h = y_tilesize;\n  }\n\n  return (u8 *)ximage->data + ximage->xoffset * ximage->bits_per_pixel / 8;\n}\n\nvoid bx_x11_gui_c::graphics_tile_update_in_place(unsigned x0, unsigned y0,\n                                                 unsigned w, unsigned h) {\n  XPutImage(bx_x_display, win, gc, ximage, 0, 0, x0, y0, w, h);\n}\n\nbool bx_x11_gui_c::palette_change(unsigned index, unsigned red, unsigned green,\n                                  unsigned blue) {\n\n  // returns: 0=no screen update needed (color map change has direct effect)\n  //          1=screen updated needed (redraw using current colormap)\n  XColor color;\n\n  color.flags = DoRed | DoGreen | DoBlue;\n  color.red = red << 8;\n  color.green = green << 8;\n  color.blue = blue << 8;\n\n  if (x_private_colormap) {\n\n    // if (SIM->get_param_bool(BXPN_PRIVATE_COLORMAP)->get()) {\n    color.pixel = index;\n    XStoreColor(bx_x_display, default_cmap, &color);\n    return (0); // no screen update needed\n  } else {\n    XAllocColor(bx_x_display, DefaultColormap(bx_x_display, bx_x_screen_num),\n                &color);\n    col_vals[index] = color.pixel;\n    return (1); // screen update needed\n  }\n}\n\nvoid bx_x11_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight,\n                                    unsigned fwidth, unsigned bpp) {\n  if ((bpp == 8) || (bpp == 15) || (bpp == 16) || (bpp == 24) || (bpp == 32)) {\n    vga_bpp = bpp;\n  } else {\n    BX_PANIC((\"%d bpp graphics mode not supported\", bpp));\n  }\n\n  if (fheight > 0) {\n    font_height = fheight;\n    font_width = fwidth;\n    text_cols = x / font_width;\n    text_rows = y / font_height;\n  }\n\n  if ((x != dimension_x) || (y != dimension_y)) {\n    XSizeHints hints;\n    long supplied_return;\n\n    if (XGetWMNormalHints(bx_x_display, win, &hints, &supplied_return) &&\n        supplied_return & PMaxSize) {\n      hints.max_width = hints.min_width = x;\n      hints.max_height = hints.min_height = y;\n      XSetWMNormalHints(bx_x_display, win, &hints);\n    }\n\n    XResizeWindow(bx_x_display, win, x, y);\n    dimension_x = x;\n    dimension_y = y;\n  }\n}\n\nvoid bx_x11_gui_c::exit(void) {\n  if (!x_init_done)\n    return;\n\n  // Delete the font bitmaps\n  for (int i = 0; i < 256; i++) {\n\n    // if (vgafont[i] != NULL)\n    XFreePixmap(bx_x_display, vgafont[i]);\n  }\n\n  if (bx_x_display)\n    XCloseDisplay(bx_x_display);\n  BX_INFO((\"Exit.\"));\n}\n\nstatic void warp_cursor(int dx, int dy) {\n  if (warp_dx || warp_dy || dx || dy) {\n    warp_dx = dx;\n    warp_dy = dy;\n    XWarpPointer(bx_x_display, None, None, 0, 0, 0, 0, dx, dy);\n  }\n}\n\nstatic void disable_cursor() {\n  static Cursor cursor;\n  static unsigned cursor_created = 0;\n\n  static int shape_width = 16;\n  static int shape_height = 16;\n  static int mask_width = 16;\n  static int mask_height = 16;\n\n  static u32 shape_bits[(16 * 16) / 32] = {\n      0x00000000, 0x00000000, 0x00000000, 0x00000000,\n      0x00000000, 0x00000000, 0x00000000, 0x00000000,\n  };\n  static u32 mask_bits[(16 * 16) / 32] = {\n      0x00000000, 0x00000000, 0x00000000, 0x00000000,\n      0x00000000, 0x00000000, 0x00000000, 0x00000000,\n  };\n\n  if (!cursor_created) {\n    Pixmap shape;\n\n    Pixmap mask;\n    XColor white;\n    XColor black;\n    shape = XCreatePixmapFromBitmapData(\n        bx_x_display, RootWindow(bx_x_display, bx_x_screen_num),\n        (char *)shape_bits, shape_width, shape_height, 1, 0, 1);\n    mask = XCreatePixmapFromBitmapData(\n        bx_x_display, RootWindow(bx_x_display, bx_x_screen_num),\n        (char *)mask_bits, mask_width, mask_height, 1, 0, 1);\n    XParseColor(bx_x_display, default_cmap, \"black\", &black);\n    XParseColor(bx_x_display, default_cmap, \"white\", &white);\n    cursor =\n        XCreatePixmapCursor(bx_x_display, shape, mask, &white, &black, 1, 1);\n    cursor_created = 1;\n  }\n\n  XDefineCursor(bx_x_display, win, cursor);\n}\n\nstatic void enable_cursor() { XUndefineCursor(bx_x_display, win); }\n\n/* convertStringToXKeysym is a keymap callback\n * used when reading the keymap file.\n * It converts a Symblic String to a GUI Constant\n *\n * It returns a u32 constant or BX_KEYMAP_UNKNOWN if it fails\n */\nstatic u32 convertStringToXKeysym(const char *string) {\n  if (strncmp(\"XK_\", string, 3) != 0)\n    return BX_KEYMAP_UNKNOWN;\n\n  KeySym keysym = XStringToKeysym(string + 3);\n\n  // failure, return unknown\n  if (keysym == NoSymbol)\n    return BX_KEYMAP_UNKNOWN;\n\n  return ((u32)keysym);\n}\n\nvoid bx_x11_gui_c::get_capabilities(u16 *xres, u16 *yres, u16 *bpp) {\n  *xres = 1024;\n  *yres = 768;\n  *bpp = 32;\n}\n#endif /* if BX_WITH_X11 */\n"
  },
  {
    "path": "src/gui/keymap.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n *  This file is based upon Bochs.\n *\n *  Copyright (C) 2002  MandrakeSoft S.A.\n *\n *    MandrakeSoft S.A.\n *    43, rue d'Aboukir\n *    75002 Paris - France\n *    http://www.linux-mandrake.com/\n *    http://www.mandrakesoft.com/\n *\n *  This library is free software; you can redistribute it and/or\n *  modify it under the terms of the GNU Lesser General Public\n *  License as published by the Free Software Foundation; either\n *  version 2 of the License, or (at your option) any later version.\n *\n *  This library is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n *  Lesser General Public License for more details.\n *\n *  You should have received a copy of the GNU Lesser General Public\n *  License along with this library; if not, write to the Free Software\n *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA\n */\n\n#include \"keymap.hpp\"\n#include \"../StdAfx.hpp\"\n#include \"../System.hpp\"\n#include \"gui.hpp\"\n\nconst char *bx_key_symbol[BX_KEY_NBKEYS] = {\n    \"BX_KEY_CTRL_L\",\n    \"BX_KEY_SHIFT_L\",\n    \"BX_KEY_F1\",\n    \"BX_KEY_F2\",\n    \"BX_KEY_F3\",\n    \"BX_KEY_F4\",\n    \"BX_KEY_F5\",\n    \"BX_KEY_F6\",\n    \"BX_KEY_F7\",\n    \"BX_KEY_F8\",\n    \"BX_KEY_F9\",\n    \"BX_KEY_F10\",\n    \"BX_KEY_F11\",\n    \"BX_KEY_F12\",\n    \"BX_KEY_CTRL_R\",\n    \"BX_KEY_SHIFT_R\",\n    \"BX_KEY_CAPS_LOCK\",\n    \"BX_KEY_NUM_LOCK\",\n    \"BX_KEY_ALT_L\",\n    \"BX_KEY_ALT_R\",\n    \"BX_KEY_A\",\n    \"BX_KEY_B\",\n    \"BX_KEY_C\",\n    \"BX_KEY_D\",\n    \"BX_KEY_E\",\n    \"BX_KEY_F\",\n    \"BX_KEY_G\",\n    \"BX_KEY_H\",\n    \"BX_KEY_I\",\n    \"BX_KEY_J\",\n    \"BX_KEY_K\",\n    \"BX_KEY_L\",\n    \"BX_KEY_M\",\n    \"BX_KEY_N\",\n    \"BX_KEY_O\",\n    \"BX_KEY_P\",\n    \"BX_KEY_Q\",\n    \"BX_KEY_R\",\n    \"BX_KEY_S\",\n    \"BX_KEY_T\",\n    \"BX_KEY_U\",\n    \"BX_KEY_V\",\n    \"BX_KEY_W\",\n    \"BX_KEY_X\",\n    \"BX_KEY_Y\",\n    \"BX_KEY_Z\",\n    \"BX_KEY_0\",\n    \"BX_KEY_1\",\n    \"BX_KEY_2\",\n    \"BX_KEY_3\",\n    \"BX_KEY_4\",\n    \"BX_KEY_5\",\n    \"BX_KEY_6\",\n    \"BX_KEY_7\",\n    \"BX_KEY_8\",\n    \"BX_KEY_9\",\n    \"BX_KEY_ESC\",\n    \"BX_KEY_SPACE\",\n    \"BX_KEY_SINGLE_QUOTE\",\n    \"BX_KEY_COMMA\",\n    \"BX_KEY_PERIOD\",\n    \"BX_KEY_SLASH\",\n    \"BX_KEY_SEMICOLON\",\n    \"BX_KEY_EQUALS\",\n    \"BX_KEY_LEFT_BRACKET\",\n    \"BX_KEY_BACKSLASH\",\n    \"BX_KEY_RIGHT_BRACKET\",\n    \"BX_KEY_MINUS\",\n    \"BX_KEY_GRAVE\",\n    \"BX_KEY_BACKSPACE\",\n    \"BX_KEY_ENTER\",\n    \"BX_KEY_TAB\",\n    \"BX_KEY_LEFT_BACKSLASH\",\n    \"BX_KEY_PRINT\",\n    \"BX_KEY_SCRL_LOCK\",\n    \"BX_KEY_PAUSE\",\n    \"BX_KEY_INSERT\",\n    \"BX_KEY_DELETE\",\n    \"BX_KEY_HOME\",\n    \"BX_KEY_END\",\n    \"BX_KEY_PAGE_UP\",\n    \"BX_KEY_PAGE_DOWN\",\n    \"BX_KEY_KP_ADD\",\n    \"BX_KEY_KP_SUBTRACT\",\n    \"BX_KEY_KP_END\",\n    \"BX_KEY_KP_DOWN\",\n    \"BX_KEY_KP_PAGE_DOWN\",\n    \"BX_KEY_KP_LEFT\",\n    \"BX_KEY_KP_RIGHT\",\n    \"BX_KEY_KP_HOME\",\n    \"BX_KEY_KP_UP\",\n    \"BX_KEY_KP_PAGE_UP\",\n    \"BX_KEY_KP_INSERT\",\n    \"BX_KEY_KP_DELETE\",\n    \"BX_KEY_KP_5\",\n    \"BX_KEY_UP\",\n    \"BX_KEY_DOWN\",\n    \"BX_KEY_LEFT\",\n    \"BX_KEY_RIGHT\",\n    \"BX_KEY_KP_ENTER\",\n    \"BX_KEY_KP_MULTIPLY\",\n    \"BX_KEY_KP_DIVIDE\",\n    \"BX_KEY_WIN_L\",\n    \"BX_KEY_WIN_R\",\n    \"BX_KEY_MENU\",\n    \"BX_KEY_ALT_SYSREQ\",\n    \"BX_KEY_CTRL_BREAK\",\n    \"BX_KEY_INT_BACK\",\n    \"BX_KEY_INT_FORWARD\",\n    \"BX_KEY_INT_STOP\",\n    \"BX_KEY_INT_MAIL\",\n    \"BX_KEY_INT_SEARCH\",\n    \"BX_KEY_INT_FAV\",\n    \"BX_KEY_INT_HOME\",\n    \"BX_KEY_POWER_MYCOMP\",\n    \"BX_KEY_POWER_CALC\",\n    \"BX_KEY_POWER_SLEEP\",\n    \"BX_KEY_POWER_POWER\",\n    \"BX_KEY_POWER_WAKE\",\n};\n\nbx_keymap_c *bx_keymap;\n\nbx_keymap_c::bx_keymap_c(CConfigurator *cfg) {\n  keymapCount = 0;\n  keymapTable = (BXKeyEntry *)NULL;\n  myCfg = cfg;\n}\n\nbx_keymap_c::~bx_keymap_c(void) {\n  if (keymapTable != NULL) {\n    free(keymapTable);\n    keymapTable = (BXKeyEntry *)NULL;\n  }\n\n  keymapCount = 0;\n}\n\n/**\n * Loads the configuration specified keymap file if keymapping is enabled\n * using convertStringToSymbol to convert strings to client constants\n **/\nvoid bx_keymap_c::loadKeymap(u32 stringToSymbol(const char *)) {\n  if (myCfg->get_bool_value(\"keyboard.use_mapping\", false))\n    loadKeymap(stringToSymbol,\n               myCfg->get_text_value(\"keyboard.map\", \"keys.map\"));\n}\n\n/**\n * Returns true if the keymap contains any valid key entries.\n **/\nbool bx_keymap_c::isKeymapLoaded() { return (keymapCount > 0); }\n\n///////////////////\n// I'll add these to the keymap object in a minute.\nstatic unsigned char *lineptr = NULL;\nstatic int lineCount;\n\nstatic void init_parse() { lineCount = 0; }\n\nstatic void init_parse_line(char *line_to_parse) {\n\n  // chop off newline\n  lineptr = (unsigned char *)line_to_parse;\n\n  char *nl;\n  if ((nl = strchr(line_to_parse, '\\n')) != NULL) {\n    *nl = 0;\n  }\n}\n\nstatic s32 get_next_word(char *output) {\n  char *copyp = output;\n\n  // find first nonspace\n  while (*lineptr && isspace(*lineptr))\n    lineptr++;\n  if (!*lineptr)\n    return -1; // nothing but spaces until end of line\n  if (*lineptr == '#')\n    return -1; // nothing but a comment\n\n  // copy nonspaces into the output\n  while (*lineptr && !isspace(*lineptr))\n    *copyp++ = *lineptr++;\n  *copyp = 0; // null terminate the copy\n\n  // there must be at least one nonspace, since that's why we stopped the\n  // first loop!\n  //  BX_ASSERT (copyp != output);\n  return 0;\n}\n\nstatic s32 get_next_keymap_line(FILE *fp, char *bxsym, char *modsym, s32 *ascii,\n                                char *hostsym) {\n  char line[256];\n  char buf[256];\n  line[0] = 0;\n  while (1) {\n    lineCount++;\n    if (!fgets(line, sizeof(line) - 1, fp))\n      return -1; // EOF\n    init_parse_line(line);\n    if (get_next_word(bxsym) >= 0) {\n      modsym[0] = 0;\n\n      char *p;\n      if ((p = strchr(bxsym, '+')) != NULL) {\n        *p = 0;            // truncate bxsym.\n        p++;               // move one char beyond the +\n        strcpy(modsym, p); // copy the rest to modsym\n      }\n\n      if (get_next_word(buf) < 0) {\n        BX_PANIC((\"keymap line %d: expected 3 columns\", lineCount));\n        return -1;\n      }\n\n      if (buf[0] == '\\'' && buf[2] == '\\'' && buf[3] == 0) {\n        *ascii = (u8)buf[1];\n      } else if (!strcmp(buf, \"space\")) {\n        *ascii = ' ';\n      } else if (!strcmp(buf, \"return\")) {\n        *ascii = '\\n';\n      } else if (!strcmp(buf, \"tab\")) {\n        *ascii = '\\t';\n      } else if (!strcmp(buf, \"backslash\")) {\n        *ascii = '\\\\';\n      } else if (!strcmp(buf, \"apostrophe\")) {\n        *ascii = '\\'';\n      } else if (!strcmp(buf, \"none\")) {\n        *ascii = -1;\n      } else {\n        BX_PANIC((\"keymap line %d: ascii equivalent is \\\"%s\\\" but it must be \"\n                  \"char constant like 'x', or one of space,tab,return,none\",\n                  lineCount, buf));\n      }\n\n      if (get_next_word(hostsym) < 0) {\n        BX_PANIC((\"keymap line %d: expected 3 columns\", lineCount));\n        return -1;\n      }\n\n      return 0;\n    }\n\n    // no words on this line, keep reading.\n  }\n}\n\n/**\n * Loads the specified keymap file using convertStringToSymbol to convert\n *strings to client constants.\n **/\nvoid bx_keymap_c::loadKeymap(u32 stringToSymbol(const char *),\n                             const char *filename) {\n  FILE *keymapFile;\n  char baseSym[256];\n  char modSym[256];\n  char hostSym[256];\n  s32 ascii = 0;\n  u32 baseKey;\n  u32 modKey;\n  u32 hostKey;\n\n  if ((keymapFile = fopen(filename, \"r\")) == NULL) {\n    BX_PANIC((\"Can not open keymap file '%s'.\", filename));\n    return;\n  }\n\n  BX_INFO((\"Loading keymap from '%s'\", filename));\n  init_parse();\n\n  // Read keymap file one line at a time\n  while (1) {\n    if (get_next_keymap_line(keymapFile, baseSym, modSym, &ascii, hostSym) <\n        0) {\n      break;\n    }\n\n    // convert X_KEY_* symbols to values\n    baseKey = convertStringToBXKey(baseSym);\n    modKey = convertStringToBXKey(modSym);\n    hostKey = 0;\n    if (stringToSymbol != NULL)\n      hostKey = stringToSymbol(hostSym);\n\n    BX_DEBUG((\"baseKey='%s' (%d), modSym='%s' (%d), ascii=%d, guisym='%s' (%d)\",\n              baseSym, baseKey, modSym, modKey, ascii, hostSym, hostKey));\n\n    // Check if data is valid\n    if (baseKey == BX_KEYMAP_UNKNOWN) {\n      BX_PANIC((\"line %d: unknown BX_KEY constant '%s'\", lineCount, baseSym));\n      continue;\n    }\n\n    if (hostKey == BX_KEYMAP_UNKNOWN) {\n      BX_PANIC((\"line %d: unknown host key name '%s' (wrong keymap ?)\",\n                lineCount, hostSym));\n      continue;\n    }\n\n    CHECK_REALLOCATION(\n        keymapTable,\n        realloc(keymapTable, (keymapCount + 1) * sizeof(BXKeyEntry)),\n        BXKeyEntry);\n\n    if (keymapTable == NULL)\n      BX_PANIC((\"Can not allocate memory for keymap table.\"));\n\n    keymapTable[keymapCount].baseKey = baseKey;\n    keymapTable[keymapCount].modKey = modKey;\n    keymapTable[keymapCount].ascii = ascii;\n    keymapTable[keymapCount].hostKey = hostKey;\n\n    keymapCount++;\n  }\n\n  BX_INFO((\"Loaded %d symbols\", keymapCount));\n\n  fclose(keymapFile);\n}\n\n/**\n * Convert a null-terminate string to a BX_KEY code.\n **/\nu32 bx_keymap_c::convertStringToBXKey(const char *string) {\n\n  // We look through the bx_key_symbol table to find the searched string\n  for (u16 i = 0; i < BX_KEY_NBKEYS; i++) {\n    if (strcmp(string, bx_key_symbol[i]) == 0) {\n      return i;\n    }\n  }\n\n  // Key is not known\n  return BX_KEYMAP_UNKNOWN;\n}\n\n/**\n * Finds an entry whose hostKey value matches the target value, and\n * returns a pointer to the corresponging BXKeyEntry structure.\n **/\nBXKeyEntry *bx_keymap_c::findHostKey(u32 key) {\n\n  // We look through the keymap table to find the searched key\n  for (u16 i = 0; i < keymapCount; i++) {\n    if (keymapTable[i].hostKey == key) {\n      BX_DEBUG((\"key 0x%02x matches hostKey for entry #%d\", key, i));\n      return &keymapTable[i];\n    }\n  }\n\n  BX_DEBUG((\"key %02x matches no entries\", key));\n\n  // Return default\n  return NULL;\n}\n\n/**\n * Finds an entry whose ASCII character matches the target value, and\n * returns a pointer to the corresponging BXKeyEntry structure.\n **/\nBXKeyEntry *bx_keymap_c::findAsciiChar(u8 ch) {\n  BX_DEBUG((\"findAsciiChar (0x%02x)\", ch));\n\n  // We look through the keymap table to find the searched key\n  for (u16 i = 0; i < keymapCount; i++) {\n    if (keymapTable[i].ascii == ch) {\n      BX_DEBUG((\"key %02x matches ascii for entry #%d\", ch, i));\n      return &keymapTable[i];\n    }\n  }\n\n  BX_DEBUG((\"key 0x%02x matches no entries\", ch));\n\n  // Return default\n  return NULL;\n}\n\nconst char *bx_keymap_c::getBXKeyName(u32 key) {\n  return bx_key_symbol[key & 0x7fffffff];\n}\n"
  },
  {
    "path": "src/gui/keymap.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n *  This file is based upon Bochs.\n *\n *  Copyright (C) 2002  MandrakeSoft S.A.\n *\n *    MandrakeSoft S.A.\n *    43, rue d'Aboukir\n *    75002 Paris - France\n *    http://www.linux-mandrake.com/\n *    http://www.mandrakesoft.com/\n *\n *  This library is free software; you can redistribute it and/or\n *  modify it under the terms of the GNU Lesser General Public\n *  License as published by the Free Software Foundation; either\n *  version 2 of the License, or (at your option) any later version.\n *\n *  This library is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n *  Lesser General Public License for more details.\n *\n *  You should have received a copy of the GNU Lesser General Public\n *  License along with this library; if not, write to the Free Software\n *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA\n */\n\n#include \"../Configurator.hpp\"\n\n// In case of unknown symbol\n#define BX_KEYMAP_UNKNOWN 0xFFFFFFFF\n\n/// Structure of an element of the keymap table\ntypedef struct {\n  u32 baseKey; // base key\n  u32 modKey;  // modifier key that must be held down\n  s32 ascii;   // ascii equivalent, if any\n  u32 hostKey; // value that the host's OS or library recognizes\n} BXKeyEntry;\n\n/**\n * \\brief Keymap, used to map host keys to scancodes.\n **/\nclass bx_keymap_c {\npublic:\n  bx_keymap_c(CConfigurator *cfg);\n  ~bx_keymap_c(void);\n\n  void loadKeymap(u32 stringToSymbol(const char *));\n  void loadKeymap(u32 stringToSymbol(const char *), const char *filename);\n  bool isKeymapLoaded();\n\n  BXKeyEntry *findHostKey(u32 hostkeynum);\n  BXKeyEntry *findAsciiChar(u8 ascii);\n  const char *getBXKeyName(u32 key);\n\nprivate:\n  u32 convertStringToBXKey(const char *);\n  CConfigurator *myCfg;\n\n  BXKeyEntry *keymapTable;\n  u16 keymapCount;\n};\n\nextern bx_keymap_c *bx_keymap;\n"
  },
  {
    "path": "src/gui/plugin.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n *  Copyright (C) 2002  MandrakeSoft S.A.\n *\n *    MandrakeSoft S.A.\n *    43, rue d'Aboukir\n *    75002 Paris - France\n *    http://www.linux-mandrake.com/\n *    http://www.mandrakesoft.com/\n *\n *  This library is free software; you can redistribute it and/or\n *  modify it under the terms of the GNU Lesser General Public\n *  License as published by the Free Software Foundation; either\n *  version 2 of the License, or (at your option) any later version.\n *\n *  This library is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n *  Lesser General Public License for more details.\n *\n *  You should have received a copy of the GNU Lesser General Public\n *  License along with this library; if not, write to the Free Software\n *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA\n */\n\n/////////////////////////////////////////////////////////////////////////\n//\n// This file provides macros and types needed for plugins.  It is based on\n// the plugin.h file from plex86, but with significant changes to make\n// it work in Bochs.\n// Plex86 is Copyright (C) 1999-2000  The plex86 developers team\n//\n/////////////////////////////////////////////////////////////////////////\n#ifndef __PLUGIN_H\n#define __PLUGIN_H\n\n#define PLUG_load_plugin(cfg, name)                                            \\\n  { lib##name##_LTX_plugin_init(cfg); }\n#define PLUG_unload_plugin(name)                                               \\\n  { lib##name##_LTX_plugin_fini(); }\n\n#define DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(mod)                               \\\n  int lib##mod##_LTX_plugin_init(CConfigurator *cfg);                          \\\n  void lib##mod##_LTX_plugin_fini(void);\n\n#if defined(HAVE_SDL)\nDECLARE_PLUGIN_INIT_FINI_FOR_MODULE(sdl)\n#endif\n#if defined(_WIN32)\nDECLARE_PLUGIN_INIT_FINI_FOR_MODULE(win32)\n#endif\n#if defined(HAVE_X11)\nDECLARE_PLUGIN_INIT_FINI_FOR_MODULE(x11)\n#endif\n#endif /* __PLUGIN_H */\n"
  },
  {
    "path": "src/gui/scancodes.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n *  This file is based upon Bochs.\n *\n *  Copyright (C) 2002  MandrakeSoft S.A.\n *\n *    MandrakeSoft S.A.\n *    43, rue d'Aboukir\n *    75002 Paris - France\n *    http://www.linux-mandrake.com/\n *    http://www.mandrakesoft.com/\n *\n *  This library is free software; you can redistribute it and/or\n *  modify it under the terms of the GNU Lesser General Public\n *  License as published by the Free Software Foundation; either\n *  version 2 of the License, or (at your option) any later version.\n *\n *  This library is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n *  Lesser General Public License for more details.\n *\n *  You should have received a copy of the GNU Lesser General Public\n *  License along with this library; if not, write to the Free Software\n *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA\n */\n\n#include \"../StdAfx.hpp\"\n\n//#include \"bochs.h\"\n#include \"scancodes.hpp\"\n\nunsigned char translation8042[256] = {\n    0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58, 0x64, 0x44, 0x42, 0x40,\n    0x3e, 0x0f, 0x29, 0x59, 0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a,\n    0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b, 0x67, 0x2e, 0x2d, 0x20,\n    0x12, 0x05, 0x04, 0x5c, 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d,\n    0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e, 0x6a, 0x72, 0x32, 0x24,\n    0x16, 0x08, 0x09, 0x5f, 0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60,\n    0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61, 0x6d, 0x73, 0x28, 0x74,\n    0x1a, 0x0d, 0x62, 0x6e, 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76,\n    0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b, 0x7c, 0x4f, 0x7d, 0x4b,\n    0x47, 0x7e, 0x7f, 0x6f, 0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45,\n    0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54, 0x80, 0x81, 0x82, 0x41,\n    0x54, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,\n    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,\n    0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,\n    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,\n    0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,\n    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb,\n    0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,\n    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,\n    0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,\n    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,\n    0xfc, 0xfd, 0xfe, 0xff};\n\n// Definition of scancodes make and break,\n// for each set (mf1/xt , mf2/at , mf3/ps2)\n// The table must be in BX_KEY order\n//\nscancode scancodes[BX_KEY_NBKEYS][3] = {\n    {\n        // BX_KEY_CTRL_L ( ibm 58)\n        {\"\\x1D\", \"\\x9D\"},\n        {\"\\x14\", \"\\xF0\\x14\"},\n        {\"\\x11\", \"\\xF0\\x11\"},\n    },\n\n    {\n        // BX_KEY_SHIFT_L ( ibm 44)\n        {\"\\x2A\", \"\\xAA\"},\n        {\"\\x12\", \"\\xF0\\x12\"},\n        {\"\\x12\", \"\\xF0\\x12\"},\n    },\n\n    {\n        // BX_KEY_F1 ( ibm 112 )\n        {\"\\x3B\", \"\\xBB\"},\n        {\"\\x05\", \"\\xF0\\x05\"},\n        {\"\\x07\", \"\\xF0\\x07\"},\n    },\n\n    {\n        // BX_KEY_F2 ( ibm 113 )\n        {\"\\x3C\", \"\\xBC\"},\n        {\"\\x06\", \"\\xF0\\x06\"},\n        {\"\\x0F\", \"\\xF0\\x0F\"},\n    },\n\n    {\n        // BX_KEY_F3 ( ibm 114 )\n        {\"\\x3D\", \"\\xBD\"},\n        {\"\\x04\", \"\\xF0\\x04\"},\n        {\"\\x17\", \"\\xF0\\x17\"},\n    },\n\n    {\n        // BX_KEY_F4 ( ibm 115 )\n        {\"\\x3E\", \"\\xBE\"},\n        {\"\\x0C\", \"\\xF0\\x0C\"},\n        {\"\\x1F\", \"\\xF0\\x1F\"},\n    },\n\n    {\n        // BX_KEY_F5 ( ibm 116 )\n        {\"\\x3F\", \"\\xBF\"},\n        {\"\\x03\", \"\\xF0\\x03\"},\n        {\"\\x27\", \"\\xF0\\x27\"},\n    },\n\n    {\n        // BX_KEY_F6 ( ibm 117 )\n        {\"\\x40\", \"\\xC0\"},\n        {\"\\x0B\", \"\\xF0\\x0B\"},\n        {\"\\x2F\", \"\\xF0\\x2F\"},\n    },\n\n    {\n        // BX_KEY_F7 ( ibm 118 )\n        {\"\\x41\", \"\\xC1\"},\n        {\"\\x83\", \"\\xF0\\x83\"},\n        {\"\\x37\", \"\\xF0\\x37\"},\n    },\n\n    {\n        // BX_KEY_F8 ( ibm 119 )\n        {\"\\x42\", \"\\xC2\"},\n        {\"\\x0A\", \"\\xF0\\x0A\"},\n        {\"\\x3F\", \"\\xF0\\x3F\"},\n    },\n\n    {\n        // BX_KEY_F9 ( ibm 120 )\n        {\"\\x43\", \"\\xC3\"},\n        {\"\\x01\", \"\\xF0\\x01\"},\n        {\"\\x47\", \"\\xF0\\x47\"},\n    },\n\n    {\n        // BX_KEY_F10 ( ibm 121 )\n        {\"\\x44\", \"\\xC4\"},\n        {\"\\x09\", \"\\xF0\\x09\"},\n        {\"\\x4F\", \"\\xF0\\x4F\"},\n    },\n\n    {\n        // BX_KEY_F11 ( ibm 122 )\n        {\"\\x57\", \"\\xD7\"},\n        {\"\\x78\", \"\\xF0\\x78\"},\n        {\"\\x56\", \"\\xF0\\x56\"},\n    },\n\n    {\n        // BX_KEY_F12 ( ibm 123 )\n        {\"\\x58\", \"\\xD8\"},\n        {\"\\x07\", \"\\xF0\\x07\"},\n        {\"\\x5E\", \"\\xF0\\x5E\"},\n    },\n\n    {\n        // BX_KEY_CTRL_R ( ibm 64 )\n        {\"\\xE0\\x1D\", \"\\xE0\\x9D\"},\n        {\"\\xE0\\x14\", \"\\xE0\\xF0\\x14\"},\n        {\"\\x58\", \"\\xF0x58\"},\n    },\n\n    {\n        // BX_KEY_SHIFT_R ( ibm 57 )\n        {\"\\x36\", \"\\xB6\"},\n        {\"\\x59\", \"\\xF0\\x59\"},\n        {\"\\x59\", \"\\xF0\\x59\"},\n    },\n\n    {\n        // BX_KEY_CAPS_LOCK ( ibm 30 )\n        {\"\\x3A\", \"\\xBA\"},\n        {\"\\x58\", \"\\xF0\\x58\"},\n        {\"\\x14\", \"\\xF0\\x14\"},\n    },\n\n    {\n        // BX_KEY_NUM_LOCK ( ibm 90 )\n        {\"\\x45\", \"\\xC5\"},\n        {\"\\x77\", \"\\xF0\\x77\"},\n        {\"\\x76\", \"\\xF0\\x76\"},\n    },\n\n    {\n        // BX_KEY_ALT_L ( ibm 60 )\n        {\"\\x38\", \"\\xB8\"},\n        {\"\\x11\", \"\\xF0\\x11\"},\n        {\"\\x19\", \"\\xF0\\x19\"},\n    },\n\n    {\n        // BX_KEY_ALT_R ( ibm 62 )\n        {\"\\xE0\\x38\", \"\\xE0\\xB8\"},\n        {\"\\xE0\\x11\", \"\\xE0\\xF0\\x11\"},\n        {\"\\x39\", \"\\xF0\\x39\"},\n    },\n\n    {\n        // BX_KEY_A ( ibm 31 )\n        {\"\\x1E\", \"\\x9E\"},\n        {\"\\x1C\", \"\\xF0\\x1C\"},\n        {\"\\x1C\", \"\\xF0\\x1C\"},\n    },\n\n    {\n        // BX_KEY_B ( ibm 50 )\n        {\"\\x30\", \"\\xB0\"},\n        {\"\\x32\", \"\\xF0\\x32\"},\n        {\"\\x32\", \"\\xF0\\x32\"},\n    },\n\n    {\n        // BX_KEY_C ( ibm 48 )\n        {\"\\x2E\", \"\\xAE\"},\n        {\"\\x21\", \"\\xF0\\x21\"},\n        {\"\\x21\", \"\\xF0\\x21\"},\n    },\n\n    {\n        // BX_KEY_D ( ibm 33 )\n        {\"\\x20\", \"\\xA0\"},\n        {\"\\x23\", \"\\xF0\\x23\"},\n        {\"\\x23\", \"\\xF0\\x23\"},\n    },\n\n    {\n        // BX_KEY_E ( ibm 19 )\n        {\"\\x12\", \"\\x92\"},\n        {\"\\x24\", \"\\xF0\\x24\"},\n        {\"\\x24\", \"\\xF0\\x24\"},\n    },\n\n    {\n        // BX_KEY_F ( ibm 34 )\n        {\"\\x21\", \"\\xA1\"},\n        {\"\\x2B\", \"\\xF0\\x2B\"},\n        {\"\\x2B\", \"\\xF0\\x2B\"},\n    },\n\n    {\n        // BX_KEY_G ( ibm 35 )\n        {\"\\x22\", \"\\xA2\"},\n        {\"\\x34\", \"\\xF0\\x34\"},\n        {\"\\x34\", \"\\xF0\\x34\"},\n    },\n\n    {\n        // BX_KEY_H ( ibm 36 )\n        {\"\\x23\", \"\\xA3\"},\n        {\"\\x33\", \"\\xF0\\x33\"},\n        {\"\\x33\", \"\\xF0\\x33\"},\n    },\n\n    {\n        // BX_KEY_I ( ibm 24 )\n        {\"\\x17\", \"\\x97\"},\n        {\"\\x43\", \"\\xF0\\x43\"},\n        {\"\\x43\", \"\\xF0\\x43\"},\n    },\n\n    {\n        // BX_KEY_J ( ibm 37 )\n        {\"\\x24\", \"\\xA4\"},\n        {\"\\x3B\", \"\\xF0\\x3B\"},\n        {\"\\x3B\", \"\\xF0\\x3B\"},\n    },\n\n    {\n        // BX_KEY_K ( ibm 38 )\n        {\"\\x25\", \"\\xA5\"},\n        {\"\\x42\", \"\\xF0\\x42\"},\n        {\"\\x42\", \"\\xF0\\x42\"},\n    },\n\n    {\n        // BX_KEY_L ( ibm 39 )\n        {\"\\x26\", \"\\xA6\"},\n        {\"\\x4B\", \"\\xF0\\x4B\"},\n        {\"\\x4B\", \"\\xF0\\x4B\"},\n    },\n\n    {\n        // BX_KEY_M ( ibm 52 )\n        {\"\\x32\", \"\\xB2\"},\n        {\"\\x3A\", \"\\xF0\\x3A\"},\n        {\"\\x3A\", \"\\xF0\\x3A\"},\n    },\n\n    {\n        // BX_KEY_N ( ibm 51 )\n        {\"\\x31\", \"\\xB1\"},\n        {\"\\x31\", \"\\xF0\\x31\"},\n        {\"\\x31\", \"\\xF0\\x31\"},\n    },\n\n    {\n        // BX_KEY_O ( ibm 25 )\n        {\"\\x18\", \"\\x98\"},\n        {\"\\x44\", \"\\xF0\\x44\"},\n        {\"\\x44\", \"\\xF0\\x44\"},\n    },\n\n    {\n        // BX_KEY_P ( ibm 26 )\n        {\"\\x19\", \"\\x99\"},\n        {\"\\x4D\", \"\\xF0\\x4D\"},\n        {\"\\x4D\", \"\\xF0\\x4D\"},\n    },\n\n    {\n        // BX_KEY_Q ( ibm 17 )\n        {\"\\x10\", \"\\x90\"},\n        {\"\\x15\", \"\\xF0\\x15\"},\n        {\"\\x15\", \"\\xF0\\x15\"},\n    },\n\n    {\n        // BX_KEY_R ( ibm 20 )\n        {\"\\x13\", \"\\x93\"},\n        {\"\\x2D\", \"\\xF0\\x2D\"},\n        {\"\\x2D\", \"\\xF0\\x2D\"},\n    },\n\n    {\n        // BX_KEY_S ( ibm 32 )\n        {\"\\x1F\", \"\\x9F\"},\n        {\"\\x1B\", \"\\xF0\\x1B\"},\n        {\"\\x1B\", \"\\xF0\\x1B\"},\n    },\n\n    {\n        // BX_KEY_T ( ibm 21 )\n        {\"\\x14\", \"\\x94\"},\n        {\"\\x2C\", \"\\xF0\\x2C\"},\n        {\"\\x2C\", \"\\xF0\\x2C\"},\n    },\n\n    {\n        // BX_KEY_U ( ibm 23 )\n        {\"\\x16\", \"\\x96\"},\n        {\"\\x3C\", \"\\xF0\\x3C\"},\n        {\"\\x3C\", \"\\xF0\\x3C\"},\n    },\n\n    {\n        // BX_KEY_V ( ibm 49 )\n        {\"\\x2F\", \"\\xAF\"},\n        {\"\\x2A\", \"\\xF0\\x2A\"},\n        {\"\\x2A\", \"\\xF0\\x2A\"},\n    },\n\n    {\n        // BX_KEY_W ( ibm 18 )\n        {\"\\x11\", \"\\x91\"},\n        {\"\\x1D\", \"\\xF0\\x1D\"},\n        {\"\\x1D\", \"\\xF0\\x1D\"},\n    },\n\n    {\n        // BX_KEY_X ( ibm 47 )\n        {\"\\x2D\", \"\\xAD\"},\n        {\"\\x22\", \"\\xF0\\x22\"},\n        {\"\\x22\", \"\\xF0\\x22\"},\n    },\n\n    {\n        // BX_KEY_Y ( ibm 22 )\n        {\"\\x15\", \"\\x95\"},\n        {\"\\x35\", \"\\xF0\\x35\"},\n        {\"\\x35\", \"\\xF0\\x35\"},\n    },\n\n    {\n        // BX_KEY_Z ( ibm 46 )\n        {\"\\x2C\", \"\\xAC\"},\n        {\"\\x1A\", \"\\xF0\\x1A\"},\n        {\"\\x1A\", \"\\xF0\\x1A\"},\n    },\n\n    {\n        // BX_KEY_0 ( ibm 11 )\n        {\"\\x0B\", \"\\x8B\"},\n        {\"\\x45\", \"\\xF0\\x45\"},\n        {\"\\x45\", \"\\xF0\\x45\"},\n    },\n\n    {\n        // BX_KEY_1 ( ibm 2 )\n        {\"\\x02\", \"\\x82\"},\n        {\"\\x16\", \"\\xF0\\x16\"},\n        {\"\\x16\", \"\\xF0\\x16\"},\n    },\n\n    {\n        // BX_KEY_2 ( ibm 3 )\n        {\"\\x03\", \"\\x83\"},\n        {\"\\x1E\", \"\\xF0\\x1E\"},\n        {\"\\x1E\", \"\\xF0\\x1E\"},\n    },\n\n    {\n        // BX_KEY_3 ( ibm 4 )\n        {\"\\x04\", \"\\x84\"},\n        {\"\\x26\", \"\\xF0\\x26\"},\n        {\"\\x26\", \"\\xF0\\x26\"},\n    },\n\n    {\n        // BX_KEY_4 ( ibm 5 )\n        {\"\\x05\", \"\\x85\"},\n        {\"\\x25\", \"\\xF0\\x25\"},\n        {\"\\x25\", \"\\xF0\\x25\"},\n    },\n\n    {\n        // BX_KEY_5 ( ibm 6 )\n        {\"\\x06\", \"\\x86\"},\n        {\"\\x2E\", \"\\xF0\\x2E\"},\n        {\"\\x2E\", \"\\xF0\\x2E\"},\n    },\n\n    {\n        // BX_KEY_6 ( ibm 7 )\n        {\"\\x07\", \"\\x87\"},\n        {\"\\x36\", \"\\xF0\\x36\"},\n        {\"\\x36\", \"\\xF0\\x36\"},\n    },\n\n    {\n        // BX_KEY_7 ( ibm 8 )\n        {\"\\x08\", \"\\x88\"},\n        {\"\\x3D\", \"\\xF0\\x3D\"},\n        {\"\\x3D\", \"\\xF0\\x3D\"},\n    },\n\n    {\n        // BX_KEY_8 ( ibm 9 )\n        {\"\\x09\", \"\\x89\"},\n        {\"\\x3E\", \"\\xF0\\x3E\"},\n        {\"\\x3E\", \"\\xF0\\x3E\"},\n    },\n\n    {\n        // BX_KEY_9 ( ibm 10 )\n        {\"\\x0A\", \"\\x8A\"},\n        {\"\\x46\", \"\\xF0\\x46\"},\n        {\"\\x46\", \"\\xF0\\x46\"},\n    },\n\n    {\n        // BX_KEY_ESC ( ibm 110 )\n        {\"\\x01\", \"\\x81\"},\n        {\"\\x76\", \"\\xF0\\x76\"},\n        {\"\\x08\", \"\\xF0\\x08\"},\n    },\n\n    {\n        // BX_KEY_SPACE ( ibm 61 )\n        {\"\\x39\", \"\\xB9\"},\n        {\"\\x29\", \"\\xF0\\x29\"},\n        {\"\\x29\", \"\\xF0\\x29\"},\n    },\n\n    {\n        // BX_KEY_SINGLE_QUOTE ( ibm 41 )\n        {\"\\x28\", \"\\xA8\"},\n        {\"\\x52\", \"\\xF0\\x52\"},\n        {\"\\x52\", \"\\xF0\\x52\"},\n    },\n\n    {\n        // BX_KEY_COMMA ( ibm 53 )\n        {\"\\x33\", \"\\xB3\"},\n        {\"\\x41\", \"\\xF0\\x41\"},\n        {\"\\x41\", \"\\xF0\\x41\"},\n    },\n\n    {\n        // BX_KEY_PERIOD ( ibm 54 )\n        {\"\\x34\", \"\\xB4\"},\n        {\"\\x49\", \"\\xF0\\x49\"},\n        {\"\\x49\", \"\\xF0\\x49\"},\n    },\n\n    {\n        // BX_KEY_SLASH ( ibm 55 )\n        {\"\\x35\", \"\\xB5\"},\n        {\"\\x4A\", \"\\xF0\\x4A\"},\n        {\"\\x4A\", \"\\xF0\\x4A\"},\n    },\n\n    {\n        // BX_KEY_SEMICOLON ( ibm 40 )\n        {\"\\x27\", \"\\xA7\"},\n        {\"\\x4C\", \"\\xF0\\x4C\"},\n        {\"\\x4C\", \"\\xF0\\x4C\"},\n    },\n\n    {\n        // BX_KEY_EQUALS ( ibm 13 )\n        {\"\\x0D\", \"\\x8D\"},\n        {\"\\x55\", \"\\xF0\\x55\"},\n        {\"\\x55\", \"\\xF0\\x55\"},\n    },\n\n    {\n        // BX_KEY_LEFT_BRACKET ( ibm 27 )\n        {\"\\x1A\", \"\\x9A\"},\n        {\"\\x54\", \"\\xF0\\x54\"},\n        {\"\\x54\", \"\\xF0\\x54\"},\n    },\n\n    {\n        // BX_KEY_BACKSLASH ( ibm 42, 29)\n        {\"\\x2B\", \"\\xAB\"},\n        {\"\\x5D\", \"\\xF0\\x5D\"},\n        {\"\\x53\", \"\\xF0\\x53\"},\n    },\n\n    {\n        // BX_KEY_RIGHT_BRACKET ( ibm 28 )\n        {\"\\x1B\", \"\\x9B\"},\n        {\"\\x5B\", \"\\xF0\\x5B\"},\n        {\"\\x5B\", \"\\xF0\\x5B\"},\n    },\n\n    {\n        // BX_KEY_MINUS ( ibm 12 )\n        {\"\\x0C\", \"\\x8C\"},\n        {\"\\x4E\", \"\\xF0\\x4E\"},\n        {\"\\x4E\", \"\\xF0\\x4E\"},\n    },\n\n    {\n        // BX_KEY_GRAVE ( ibm 1 )\n        {\"\\x29\", \"\\xA9\"},\n        {\"\\x0E\", \"\\xF0\\x0E\"},\n        {\"\\x0E\", \"\\xF0\\x0E\"},\n    },\n\n    {\n        // BX_KEY_BACKSPACE ( ibm 15 )\n        {\"\\x0E\", \"\\x8E\"},\n        {\"\\x66\", \"\\xF0\\x66\"},\n        {\"\\x66\", \"\\xF0\\x66\"},\n    },\n\n    {\n        // BX_KEY_ENTER ( ibm 43 )\n        {\"\\x1C\", \"\\x9C\"},\n        {\"\\x5A\", \"\\xF0\\x5A\"},\n        {\"\\x5A\", \"\\xF0\\x5A\"},\n    },\n\n    {\n        // BX_KEY_TAB ( ibm 16 )\n        {\"\\x0F\", \"\\x8F\"},\n        {\"\\x0D\", \"\\xF0\\x0D\"},\n        {\"\\x0D\", \"\\xF0\\x0D\"},\n    },\n\n    {\n        // BX_KEY_LEFT_BACKSLASH ( ibm 45 )\n        {\"\\x56\", \"\\xD6\"},\n        {\"\\x61\", \"\\xF0\\x61\"},\n        {\"\\x13\", \"\\xF0\\x13\"},\n    },\n\n    {\n        // BX_KEY_PRINT ( ibm 124 )\n        {\"\\xE0\\x2A\\xE0\\x37\", \"\\xE0\\xB7\\xE0\\xAA\"},\n        {\"\\xE0\\x12\\xE0\\x7C\", \"\\xE0\\xF0\\x7C\\xE0\\xF0\\x12\"},\n        {\"\\x57\", \"\\xF0\\x57\"},\n    },\n\n    {\n        // BX_KEY_SCRL_LOCK ( ibm 125 )\n        {\"\\x46\", \"\\xC6\"},\n        {\"\\x7E\", \"\\xF0\\x7E\"},\n        {\"\\x5F\", \"\\xF0\\x5F\"},\n    },\n\n    {\n        // BX_KEY_PAUSE ( ibm 126 )\n        {\"\\xE1\\x1D\\x45\\xE1\\x9D\\xC5\", \"\"},\n        {\"\\xE1\\x14\\x77\\xE1\\xF0\\x14\\xF0\\x77\", \"\"},\n        {\"\\x62\", \"\\xF0\\x62\"},\n    },\n\n    {\n        // BX_KEY_INSERT ( ibm 75 )\n        {\"\\xE0\\x52\", \"\\xE0\\xD2\"},\n        {\"\\xE0\\x70\", \"\\xE0\\xF0\\x70\"},\n        {\"\\x67\", \"\\xF0\\x67\"},\n    },\n\n    {\n        // BX_KEY_DELETE ( ibm 76 )\n        {\"\\xE0\\x53\", \"\\xE0\\xD3\"},\n        {\"\\xE0\\x71\", \"\\xE0\\xF0\\x71\"},\n        {\"\\x64\", \"\\xF0\\x64\"},\n    },\n\n    {\n        // BX_KEY_HOME ( ibm 80 )\n        {\"\\xE0\\x47\", \"\\xE0\\xC7\"},\n        {\"\\xE0\\x6C\", \"\\xE0\\xF0\\x6C\"},\n        {\"\\x6E\", \"\\xF0\\x6E\"},\n    },\n\n    {\n        // BX_KEY_END ( ibm 81 )\n        {\"\\xE0\\x4F\", \"\\xE0\\xCF\"},\n        {\"\\xE0\\x69\", \"\\xE0\\xF0\\x69\"},\n        {\"\\x65\", \"\\xF0\\x65\"},\n    },\n\n    {\n        // BX_KEY_PAGE_UP ( ibm 85 )\n        {\"\\xE0\\x49\", \"\\xE0\\xC9\"},\n        {\"\\xE0\\x7D\", \"\\xE0\\xF0\\x7D\"},\n        {\"\\x6F\", \"\\xF0\\x6F\"},\n    },\n\n    {\n        // BX_KEY_PAGE_DOWN ( ibm 86 )\n        {\"\\xE0\\x51\", \"\\xE0\\xD1\"},\n        {\"\\xE0\\x7A\", \"\\xE0\\xF0\\x7A\"},\n        {\"\\x6D\", \"\\xF0\\x6D\"},\n    },\n\n    {\n        // BX_KEY_KP_ADD ( ibm 106 )\n        {\"\\x4E\", \"\\xCE\"},\n        {\"\\x79\", \"\\xF0\\x79\"},\n        {\"\\x7C\", \"\\xF0\\x7C\"},\n    },\n\n    {\n        // BX_KEY_KP_SUBTRACT ( ibm 105 )\n        {\"\\x4A\", \"\\xCA\"},\n        {\"\\x7B\", \"\\xF0\\x7B\"},\n        {\"\\x84\", \"\\xF0\\x84\"},\n    },\n\n    {\n        // BX_KEY_KP_END ( ibm 93 )\n        {\"\\x4F\", \"\\xCF\"},\n        {\"\\x69\", \"\\xF0\\x69\"},\n        {\"\\x69\", \"\\xF0\\x69\"},\n    },\n\n    {\n        // BX_KEY_KP_DOWN ( ibm 98 )\n        {\"\\x50\", \"\\xD0\"},\n        {\"\\x72\", \"\\xF0\\x72\"},\n        {\"\\x72\", \"\\xF0\\x72\"},\n    },\n\n    {\n        // BX_KEY_KP_PAGE_DOWN ( ibm 103 )\n        {\"\\x51\", \"\\xD1\"},\n        {\"\\x7A\", \"\\xF0\\x7A\"},\n        {\"\\x7A\", \"\\xF0\\x7A\"},\n    },\n\n    {\n        // BX_KEY_KP_LEFT ( ibm 92 )\n        {\"\\x4B\", \"\\xCB\"},\n        {\"\\x6B\", \"\\xF0\\x6B\"},\n        {\"\\x6B\", \"\\xF0\\x6B\"},\n    },\n\n    {\n        // BX_KEY_KP_RIGHT ( ibm 102 )\n        {\"\\x4D\", \"\\xCD\"},\n        {\"\\x74\", \"\\xF0\\x74\"},\n        {\"\\x74\", \"\\xF0\\x74\"},\n    },\n\n    {\n        // BX_KEY_KP_HOME ( ibm 91 )\n        {\"\\x47\", \"\\xC7\"},\n        {\"\\x6C\", \"\\xF0\\x6C\"},\n        {\"\\x6C\", \"\\xF0\\x6C\"},\n    },\n\n    {\n        // BX_KEY_KP_UP ( ibm 96 )\n        {\"\\x48\", \"\\xC8\"},\n        {\"\\x75\", \"\\xF0\\x75\"},\n        {\"\\x75\", \"\\xF0\\x75\"},\n    },\n\n    {\n        // BX_KEY_KP_PAGE_UP ( ibm 101 )\n        {\"\\x49\", \"\\xC9\"},\n        {\"\\x7D\", \"\\xF0\\x7D\"},\n        {\"\\x7D\", \"\\xF0\\x7D\"},\n    },\n\n    {\n        // BX_KEY_KP_INSERT ( ibm 99 )\n        {\"\\x52\", \"\\xD2\"},\n        {\"\\x70\", \"\\xF0\\x70\"},\n        {\"\\x70\", \"\\xF0\\x70\"},\n    },\n\n    {\n        // BX_KEY_KP_DELETE ( ibm 104 )\n        {\"\\x53\", \"\\xD3\"},\n        {\"\\x71\", \"\\xF0\\x71\"},\n        {\"\\x71\", \"\\xF0\\x71\"},\n    },\n\n    {\n        // BX_KEY_KP_5 ( ibm 97 )\n        {\"\\x4C\", \"\\xCC\"},\n        {\"\\x73\", \"\\xF0\\x73\"},\n        {\"\\x73\", \"\\xF0\\x73\"},\n    },\n\n    {\n        // BX_KEY_UP ( ibm 83 )\n        {\"\\xE0\\x48\", \"\\xE0\\xC8\"},\n        {\"\\xE0\\x75\", \"\\xE0\\xF0\\x75\"},\n        {\"\\x63\", \"\\xF0\\x63\"},\n    },\n\n    {\n        // BX_KEY_DOWN ( ibm 84 )\n        {\"\\xE0\\x50\", \"\\xE0\\xD0\"},\n        {\"\\xE0\\x72\", \"\\xE0\\xF0\\x72\"},\n        {\"\\x60\", \"\\xF0\\x60\"},\n    },\n\n    {\n        // BX_KEY_LEFT ( ibm 79 )\n        {\"\\xE0\\x4B\", \"\\xE0\\xCB\"},\n        {\"\\xE0\\x6B\", \"\\xE0\\xF0\\x6B\"},\n        {\"\\x61\", \"\\xF0\\x61\"},\n    },\n\n    {\n        // BX_KEY_RIGHT ( ibm 89 )\n        {\"\\xE0\\x4D\", \"\\xE0\\xCD\"},\n        {\"\\xE0\\x74\", \"\\xE0\\xF0\\x74\"},\n        {\"\\x6A\", \"\\xF0\\x6A\"},\n    },\n\n    {\n        // BX_KEY_KP_ENTER ( ibm 108 )\n        {\"\\xE0\\x1C\", \"\\xE0\\x9C\"},\n        {\"\\xE0\\x5A\", \"\\xE0\\xF0\\x5A\"},\n        {\"\\x79\", \"\\xF0\\x79\"},\n    },\n\n    {\n        // BX_KEY_KP_MULTIPLY ( ibm 100 )\n        {\"\\x37\", \"\\xB7\"},\n        {\"\\x7C\", \"\\xF0\\x7C\"},\n        {\"\\x7E\", \"\\xF0\\x7E\"},\n    },\n\n    {\n        // BX_KEY_KP_DIVIDE ( ibm 95 )\n        {\"\\xE0\\x35\", \"\\xE0\\xB5\"},\n        {\"\\xE0\\x4A\", \"\\xE0\\xF0\\x4A\"},\n        {\"\\x77\", \"\\xF0\\x77\"},\n    },\n\n    {\n        // BX_KEY_WIN_L\n        {\"\\xE0\\x5B\", \"\\xE0\\xDB\"},\n        {\"\\xE0\\x1F\", \"\\xE0\\xF0\\x1F\"},\n        {\"\\x8B\", \"\\xF0\\x8B\"},\n    },\n\n    {\n        // BX_KEY_WIN_R\n        {\"\\xE0\\x5C\", \"\\xE0\\xDC\"},\n        {\"\\xE0\\x27\", \"\\xE0\\xF0\\x27\"},\n        {\"\\x8C\", \"\\xF0\\x8C\"},\n    },\n\n    {\n        // BX_KEY_MENU\n        {\"\\xE0\\x5D\", \"\\xE0\\xDD\"},\n        {\"\\xE0\\x2F\", \"\\xE0\\xF0\\x2F\"},\n        {\"\\x8D\", \"\\xF0\\x8D\"},\n    },\n\n    {\n        // BX_KEY_ALT_SYSREQ\n        {\"\\x54\", \"\\xD4\"},\n        {\"\\x84\", \"\\xF0\\x84\"},\n        {\"\\x57\", \"\\xF0\\x57\"},\n    },\n\n    {\n        // BX_KEY_CTRL_BREAK\n        {\"\\xE0\\x46\", \"\\xE0\\xC6\"},\n        {\"\\xE0\\x7E\", \"\\xE0\\xF0\\x7E\"},\n        {\"\\x62\", \"\\xF0\\x62\"},\n    },\n\n    {\n        // BX_KEY_INT_BACK\n        {\"\\xE0\\x6A\", \"\\xE0\\xEA\"},\n        {\"\\xE0\\x38\", \"\\xE0\\xF0\\x38\"},\n        {\"\\x38\", \"\\xF0\\x38\"},\n    },\n\n    {\n        // BX_KEY_INT_FORWARD\n        {\"\\xE0\\x69\", \"\\xE0\\xE9\"},\n        {\"\\xE0\\x30\", \"\\xE0\\xF0\\x30\"},\n        {\"\\x30\", \"\\xF0\\x30\"},\n    },\n\n    {\n        // BX_KEY_INT_STOP\n        {\"\\xE0\\x68\", \"\\xE0\\xE8\"},\n        {\"\\xE0\\x28\", \"\\xE0\\xF0\\x28\"},\n        {\"\\x28\", \"\\xF0\\x28\"},\n    },\n\n    {\n        // BX_KEY_INT_MAIL\n        {\"\\xE0\\x6C\", \"\\xE0\\xEC\"},\n        {\"\\xE0\\x48\", \"\\xE0\\xF0\\x48\"},\n        {\"\\x48\", \"\\xF0\\x48\"},\n    },\n\n    {\n        // BX_KEY_INT_SEARCH\n        {\"\\xE0\\x65\", \"\\xE0\\xE5\"},\n        {\"\\xE0\\x10\", \"\\xE0\\xF0\\x10\"},\n        {\"\\x10\", \"\\xF0\\x10\"},\n    },\n\n    {\n        // BX_KEY_INT_FAV\n        {\"\\xE0\\x66\", \"\\xE0\\xE6\"},\n        {\"\\xE0\\x18\", \"\\xE0\\xF0\\x18\"},\n        {\"\\x18\", \"\\xF0\\x18\"},\n    },\n\n    {\n        // BX_KEY_INT_HOME\n        {\"\\xE0\\x32\", \"\\xE0\\xB2\"},\n        {\"\\xE0\\x3A\", \"\\xE0\\xF0\\x3A\"},\n        {\"\\x97\", \"\\xF0\\x97\"},\n    },\n\n    {\n        // BX_KEY_POWER_MYCOMP\n        {\"\\xE0\\x6B\", \"\\xE0\\xEB\"},\n        {\"\\xE0\\x40\", \"\\xE0\\xF0\\x40\"},\n        {\"\\x40\", \"\\xF0\\x40\"},\n    },\n\n    {\n        // BX_KEY_POWER_CALC\n        {\"\\xE0\\x21\", \"\\xE0\\xA1\"},\n        {\"\\xE0\\x2B\", \"\\xE0\\xF0\\x2B\"},\n        {\"\\x99\", \"\\xF0\\x99\"},\n    },\n\n    {\n        // BX_KEY_POWER_SLEEP\n        {\"\\xE0\\x5F\", \"\\xE0\\xDF\"},\n        {\"\\xE0\\x3F\", \"\\xE0\\xF0\\x3F\"},\n        {\"\\x7F\", \"\\xF0\\x7F\"},\n    },\n\n    {\n        // BX_KEY_POWER_POWER\n        {\"\\xE0\\x5E\", \"\\xE0\\xDE\"},\n        {\"\\xE0\\x37\", \"\\xE0\\xF0\\x37\"},\n        {\"\", \"\"},\n    },\n\n    {\n        // BX_KEY_POWER_WAKE\n        {\"\\xE0\\x63\", \"\\xE0\\xE3\"},\n        {\"\\xE0\\x5E\", \"\\xE0\\xF0\\x5E\"},\n        {\"\", \"\"},\n    },\n\n};\n"
  },
  {
    "path": "src/gui/scancodes.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n *  This file is based upon Bochs.\n *\n *  Copyright (C) 2002  MandrakeSoft S.A.\n *\n *    MandrakeSoft S.A.\n *    43, rue d'Aboukir\n *    75002 Paris - France\n *    http://www.linux-mandrake.com/\n *    http://www.mandrakesoft.com/\n *\n *  This library is free software; you can redistribute it and/or\n *  modify it under the terms of the GNU Lesser General Public\n *  License as published by the Free Software Foundation; either\n *  version 2 of the License, or (at your option) any later version.\n *\n *  This library is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n *  Lesser General Public License for more details.\n *\n *  You should have received a copy of the GNU Lesser General Public\n *  License along with this library; if not, write to the Free Software\n *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA\n */\n\n#include \"gui.hpp\"\n#ifndef BX_SCANCODES_H\n#define BX_SCANCODES_H\n\n// Translation table of the 8042\nextern unsigned char translation8042[256];\n\ntypedef struct {\n  const char *make;\n  const char *brek;\n} scancode;\n\n// Scancodes table\nextern scancode scancodes[BX_KEY_NBKEYS][3];\n#endif\n"
  },
  {
    "path": "src/gui/sdl.cpp",
    "content": "/* ES40 emulator.\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n *\n * WWW    : http://es40.org\n * E-mail : camiel@camicom.com\n *\n *  This file is based upon Bochs.\n *\n *  Copyright (C) 2002  MandrakeSoft S.A.\n *\n *    MandrakeSoft S.A.\n *    43, rue d'Aboukir\n *    75002 Paris - France\n *    http://www.linux-mandrake.com/\n *    http://www.mandrakesoft.com/\n *\n *  This library is free software; you can redistribute it and/or\n *  modify it under the terms of the GNU Lesser General Public\n *  License as published by the Free Software Foundation; either\n *  version 2 of the License, or (at your option) any later version.\n *\n *  This library is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n *  Lesser General Public License for more details.\n *\n *  You should have received a copy of the GNU Lesser General Public\n *  License along with this library; if not, write to the Free Software\n *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA\n */\n\n#include \"../StdAfx.hpp\"\n\n#if defined(HAVE_SDL)\n#include \"../System.hpp\"\n#include \"../VGA.hpp\"\n#include \"gui.hpp\"\n#include \"keymap.hpp\"\n\n#include \"../Configurator.hpp\"\n#include \"../Keyboard.hpp\"\n\n#define _MULTI_THREAD\n\n// Define BX_PLUGGABLE in files that can be compiled into plugins.  For\n// platforms that require a special tag on exported symbols, BX_PLUGGABLE\n// is used to know when we are exporting symbols and when we are importing.\n#define BX_PLUGGABLE\n\n#include <SDL/SDL.h>\n#include <SDL/SDL_endian.h>\n#include <SDL/SDL_thread.h>\n#include <stdlib.h>\n\n#include \"sdl_fonts.hpp\"\n\n/**\n * \\brief GUI implementation using SDL.\n **/\nclass bx_sdl_gui_c : public bx_gui_c {\npublic:\n  bx_sdl_gui_c(CConfigurator *cfg);\n  virtual void specific_init(unsigned x_tilesize, unsigned y_tilesize);\n  virtual void text_update(u8 *old_text, u8 *new_text, unsigned long cursor_x,\n                           unsigned long cursor_y, bx_vga_tminfo_t tm_info,\n                           unsigned rows);\n  virtual void graphics_tile_update(u8 *snapshot, unsigned x, unsigned y);\n  virtual void handle_events(void);\n  virtual void flush(void);\n  virtual void clear_screen(void);\n  virtual bool palette_change(unsigned index, unsigned red, unsigned green,\n                              unsigned blue);\n  virtual void dimension_update(unsigned x, unsigned y, unsigned fheight = 0,\n                                unsigned fwidth = 0, unsigned bpp = 8);\n  virtual void mouse_enabled_changed_specific(bool val);\n  virtual void exit(void);\n  virtual bx_svga_tileinfo_t *graphics_tile_info(bx_svga_tileinfo_t *info);\n  virtual u8 *graphics_tile_get(unsigned x, unsigned y, unsigned *w,\n                                unsigned *h);\n  virtual void graphics_tile_update_in_place(unsigned x, unsigned y, unsigned w,\n                                             unsigned h);\n\nprivate:\n  CConfigurator *myCfg;\n};\n\n// declare one instance of the gui object and call macro to insert the\n// plugin code\nstatic bx_sdl_gui_c *theGui = NULL;\nIMPLEMENT_GUI_PLUGIN_CODE(sdl)\nstatic unsigned prev_cursor_x = 0;\nstatic unsigned prev_cursor_y = 0;\nstatic u32 convertStringToSDLKey(const char *string);\n\nSDL_Thread *sdl_thread;\nSDL_Surface *sdl_screen;\nSDL_Event sdl_event;\nint sdl_grab;\nunsigned res_x, res_y;\nunsigned half_res_x, half_res_y;\nstatic unsigned int text_cols = 80, text_rows = 25;\nu8 h_panning = 0, v_panning = 0;\nu16 line_compare = 1023;\nint fontwidth = 8, fontheight = 16;\nstatic unsigned vga_bpp = 8;\nunsigned tilewidth, tileheight;\nu32 palette[256];\nu8 old_mousebuttons = 0, new_mousebuttons = 0;\nint old_mousex = 0, new_mousex = 0;\nint old_mousey = 0, new_mousey = 0;\nbool just_warped = false;\n\nbx_sdl_gui_c::bx_sdl_gui_c(CConfigurator *cfg) {\n  myCfg = cfg;\n  bx_keymap = new bx_keymap_c(cfg);\n}\n\n#ifdef __MORPHOS__\nvoid bx_sdl_morphos_exit(void) {\n  SDL_Quit();\n  if (PowerSDLBase)\n    CloseLibrary(PowerSDLBase);\n}\n#endif\nvoid bx_sdl_gui_c::specific_init(unsigned x_tilesize, unsigned y_tilesize) {\n  int i;\n\n  int j;\n  u32 flags;\n\n  tilewidth = x_tilesize;\n  tileheight = y_tilesize;\n\n  for (i = 0; i < 256; i++)\n    for (j = 0; j < 16; j++)\n      vga_charmap[i * 32 + j] = sdl_font8x16[i][j];\n\n#ifdef __MORPHOS__\n  if (!(PowerSDLBase = OpenLibrary(\"powersdl.library\", 0))) {\n    BX_PANIC((\"Unable to open SDL libraries\"));\n    return;\n  }\n#endif\n  flags = SDL_INIT_VIDEO;\n  if (SDL_Init(flags) < 0) {\n    FAILURE(SDL, \"Unable to initialize SDL libraries\");\n  }\n\n#ifdef __MORPHOS__\n  atexit(bx_sdl_morphos_exit);\n#else\n  atexit(SDL_Quit);\n#endif\n  sdl_screen = NULL;\n\n  //  sdl_fullscreen_toggle = 0;\n  dimension_update(640, 480);\n\n  SDL_EnableKeyRepeat(250, 50);\n  SDL_WarpMouse(half_res_x, half_res_y);\n\n  // load keymap for sdl\n  if (myCfg->get_bool_value(\"keyboard.use_mapping\", false)) {\n    bx_keymap->loadKeymap(convertStringToSDLKey);\n  }\n\n  new_gfx_api = 1;\n}\n\nvoid bx_sdl_gui_c::text_update(u8 *old_text, u8 *new_text,\n                               unsigned long cursor_x, unsigned long cursor_y,\n                               bx_vga_tminfo_t tm_info, unsigned nrows) {\n  u8 *pfont_row;\n\n  u8 *old_line;\n\n  u8 *new_line;\n\n  u8 *text_base;\n  unsigned int cs_y;\n  unsigned int i;\n  unsigned int x;\n  unsigned int y;\n  unsigned int curs;\n  unsigned int hchars;\n  unsigned int offset;\n  u8 fontline;\n  u8 fontpixels;\n  u8 fontrows;\n  int rows;\n  u32 fgcolor;\n  u32 bgcolor;\n  u32 *buf;\n  u32 *buf_row;\n  u32 *buf_char;\n  u32 disp;\n  u16 font_row;\n  u16 mask;\n  u8 cfstart;\n  u8 cfwidth;\n  u8 cfheight;\n  u8 split_fontrows;\n  u8 split_textrow;\n  bool cursor_visible;\n  bool gfxcharw9;\n  bool invert;\n  bool forceUpdate;\n  bool split_screen;\n  u32 text_palette[16];\n\n  //  UNUSED(nrows);\n  forceUpdate = 0;\n  if (charmap_updated) {\n    forceUpdate = 1;\n    charmap_updated = 0;\n  }\n\n  for (i = 0; i < 16; i++) {\n    text_palette[i] = palette[theVGA->get_actl_palette_idx(i)];\n  }\n\n  if ((tm_info.h_panning != h_panning) || (tm_info.v_panning != v_panning)) {\n    forceUpdate = 1;\n    h_panning = tm_info.h_panning;\n    v_panning = tm_info.v_panning;\n  }\n\n  if (tm_info.line_compare != line_compare) {\n    forceUpdate = 1;\n    line_compare = tm_info.line_compare;\n  }\n\n  disp = sdl_screen->pitch / 4;\n  buf_row = (u32 *)sdl_screen->pixels;\n\n  // first invalidate character at previous and new cursor location\n  if ((prev_cursor_y < text_rows) && (prev_cursor_x < text_cols)) {\n    curs = prev_cursor_y * tm_info.line_offset + prev_cursor_x * 2;\n    old_text[curs] = ~new_text[curs];\n  }\n\n  cursor_visible =\n      ((tm_info.cs_start <= tm_info.cs_end) && (tm_info.cs_start < fontheight));\n  if ((cursor_visible) && (cursor_y < text_rows) && (cursor_x < text_cols)) {\n    curs = cursor_y * tm_info.line_offset + cursor_x * 2;\n    old_text[curs] = ~new_text[curs];\n  } else {\n    curs = 0xffff;\n  }\n\n  rows = text_rows;\n  if (v_panning)\n    rows++;\n  y = 0;\n  cs_y = 0;\n  text_base = new_text - tm_info.start_address;\n  split_textrow = (line_compare + v_panning) / fontheight;\n  split_fontrows = ((line_compare + v_panning) % fontheight) + 1;\n  split_screen = 0;\n\n  do {\n    buf = buf_row;\n    hchars = text_cols;\n    if (h_panning)\n      hchars++;\n    cfheight = fontheight;\n    cfstart = 0;\n    if (split_screen) {\n      if (rows == 1) {\n        cfheight = (res_y - line_compare - 1) % fontheight;\n        if (cfheight == 0)\n          cfheight = fontheight;\n      }\n    } else if (v_panning) {\n      if (y == 0) {\n        cfheight -= v_panning;\n        cfstart = v_panning;\n      } else if (rows == 1) {\n        cfheight = v_panning;\n      }\n    }\n\n    if (!split_screen && (y == split_textrow)) {\n      if ((split_fontrows - cfstart) < cfheight) {\n        cfheight = split_fontrows - cfstart;\n      }\n    }\n\n    new_line = new_text;\n    old_line = old_text;\n    x = 0;\n    offset = cs_y * tm_info.line_offset;\n    do {\n      cfwidth = fontwidth;\n      if (h_panning) {\n        if (hchars > text_cols) {\n          cfwidth -= h_panning;\n        } else if (hchars == 1) {\n          cfwidth = h_panning;\n        }\n      }\n\n      // check if char needs to be updated\n      if (forceUpdate || (old_text[0] != new_text[0]) ||\n          (old_text[1] != new_text[1])) {\n\n        // Get Foreground/Background pixel colors\n        fgcolor = text_palette[new_text[1] & 0x0F];\n        bgcolor = text_palette[(new_text[1] >> 4) & 0x0F];\n        invert = ((offset == curs) && (cursor_visible));\n        gfxcharw9 = ((tm_info.line_graphics) && ((new_text[0] & 0xE0) == 0xC0));\n\n        // Display this one char\n        fontrows = cfheight;\n        fontline = cfstart;\n        if (y > 0) {\n          pfont_row = (u8 *)&vga_charmap[(new_text[0] << 5)];\n        } else {\n          pfont_row = (u8 *)&vga_charmap[(new_text[0] << 5) + cfstart];\n        }\n\n        buf_char = buf;\n        do {\n          font_row = *pfont_row++;\n          if (gfxcharw9) {\n            font_row = (font_row << 1) | (font_row & 0x01);\n          } else {\n            font_row <<= 1;\n          }\n\n          if (hchars > text_cols) {\n            font_row <<= h_panning;\n          }\n\n          fontpixels = cfwidth;\n          if ((invert) && (fontline >= tm_info.cs_start) &&\n              (fontline <= tm_info.cs_end))\n            mask = 0x100;\n          else\n            mask = 0x00;\n          do {\n            if ((font_row & 0x100) == mask)\n              *buf = bgcolor;\n            else\n              *buf = fgcolor;\n            buf++;\n            font_row <<= 1;\n          } while (--fontpixels);\n          buf -= cfwidth;\n          buf += disp;\n          fontline++;\n        } while (--fontrows);\n\n        // restore output buffer ptr to start of this char\n        buf = buf_char;\n      }\n\n      // move to next char location on screen\n      buf += cfwidth;\n\n      // select next char in old/new text\n      new_text += 2;\n      old_text += 2;\n      offset += 2;\n      x++;\n\n      // process one entire horizontal row\n    } while (--hchars);\n\n    // go to next character row location\n    buf_row += disp * cfheight;\n    if (!split_screen && (y == split_textrow)) {\n      new_text = text_base;\n      forceUpdate = 1;\n      cs_y = 0;\n      if (tm_info.split_hpanning)\n        h_panning = 0;\n      rows = ((res_y - line_compare + fontheight - 2) / fontheight) + 1;\n      split_screen = 1;\n    } else {\n      new_text = new_line + tm_info.line_offset;\n      old_text = old_line + tm_info.line_offset;\n      cs_y++;\n      y++;\n    }\n  } while (--rows);\n  h_panning = tm_info.h_panning;\n  prev_cursor_x = cursor_x;\n  prev_cursor_y = cursor_y;\n}\n\nvoid bx_sdl_gui_c::graphics_tile_update(u8 *snapshot, unsigned x, unsigned y) {\n  u32 *buf;\n\n  u32 disp;\n  u32 *buf_row;\n  int i;\n  int j;\n\n  disp = sdl_screen->pitch / 4;\n  buf = (u32 *)sdl_screen->pixels + /*(headerbar_height+y)*disp +*/ x;\n\n  i = tileheight;\n  if (i + y > res_y)\n    i = res_y - y;\n\n  // FIXME\n  if (i <= 0)\n    return;\n\n  switch (vga_bpp) {\n  case 8: /* 8 bpp */\n    do {\n      buf_row = buf;\n      j = tilewidth;\n      do {\n        *buf++ = palette[*snapshot++];\n      } while (--j);\n      buf = buf_row + disp;\n    } while (--i);\n    break;\n\n  default:\n    BX_PANIC((\"%u bpp modes handled by new graphics API\", vga_bpp));\n    return;\n  }\n}\n\nbx_svga_tileinfo_t *bx_sdl_gui_c::graphics_tile_info(bx_svga_tileinfo_t *info) {\n  if (!info) {\n    info = (bx_svga_tileinfo_t *)malloc(sizeof(bx_svga_tileinfo_t));\n    if (!info) {\n      return NULL;\n    }\n  }\n\n  info->bpp = sdl_screen->format->BitsPerPixel;\n  info->pitch = sdl_screen->pitch;\n  info->red_shift = sdl_screen->format->Rshift + 8 - sdl_screen->format->Rloss;\n  info->green_shift =\n      sdl_screen->format->Gshift + 8 - sdl_screen->format->Gloss;\n  info->blue_shift = sdl_screen->format->Bshift + 8 - sdl_screen->format->Bloss;\n  info->red_mask = sdl_screen->format->Rmask;\n  info->green_mask = sdl_screen->format->Gmask;\n  info->blue_mask = sdl_screen->format->Bmask;\n  info->is_indexed = (sdl_screen->format->palette != NULL);\n\n#ifdef BX_LITTLE_ENDIAN\n  info->is_little_endian = 1;\n#else\n  info->is_little_endian = 0;\n#endif\n  return info;\n}\n\nu8 *bx_sdl_gui_c::graphics_tile_get(unsigned x0, unsigned y0, unsigned *w,\n                                    unsigned *h) {\n  if (x0 + tilewidth > res_x)\n    *w = res_x - x0;\n  else\n    *w = tilewidth;\n\n  if (y0 + tileheight > res_y)\n    *h = res_y - y0;\n  else\n    *h = tileheight;\n\n  return (u8 *)sdl_screen->pixels + sdl_screen->pitch * y0 +\n         sdl_screen->format->BytesPerPixel * x0;\n}\n\nvoid bx_sdl_gui_c::graphics_tile_update_in_place(unsigned x0, unsigned y0,\n                                                 unsigned w, unsigned h) {}\nstatic u32 sdl_sym_to_bx_key(SDLKey sym) {\n  switch (sym) {\n\n  //  case SDLK_UNKNOWN:              return BX_KEY_UNKNOWN;\n  //  case SDLK_FIRST:                return BX_KEY_FIRST;\n  case SDLK_BACKSPACE:\n    return BX_KEY_BACKSPACE;\n\n  case SDLK_TAB:\n    return BX_KEY_TAB;\n\n  //  case SDLK_CLEAR:                return BX_KEY_CLEAR;\n  case SDLK_RETURN:\n    return BX_KEY_ENTER;\n\n  case SDLK_PAUSE:\n    return BX_KEY_PAUSE;\n\n  case SDLK_ESCAPE:\n    return BX_KEY_ESC;\n\n  case SDLK_SPACE:\n    return BX_KEY_SPACE;\n\n  //  case SDLK_EXCLAIM:              return BX_KEY_EXCLAIM;\n  //  case SDLK_QUOTEDBL:             return BX_KEY_QUOTEDBL;\n  //  case SDLK_HASH:                 return BX_KEY_HASH;\n  //  case SDLK_DOLLAR:               return BX_KEY_DOLLAR;\n  //  case SDLK_AMPERSAND:            return BX_KEY_AMPERSAND;\n  case SDLK_QUOTE:\n    return BX_KEY_SINGLE_QUOTE;\n\n  //  case SDLK_LEFTPAREN:            return BX_KEY_LEFTPAREN;\n  //  case SDLK_RIGHTPAREN:           return BX_KEY_RIGHTPAREN;\n  //  case SDLK_ASTERISK:             return BX_KEY_ASTERISK;\n  //  case SDLK_PLUS:                 return BX_KEY_PLUS;\n  case SDLK_COMMA:\n    return BX_KEY_COMMA;\n\n  case SDLK_MINUS:\n    return BX_KEY_MINUS;\n\n  case SDLK_PERIOD:\n    return BX_KEY_PERIOD;\n\n  case SDLK_SLASH:\n    return BX_KEY_SLASH;\n\n  case SDLK_0:\n    return BX_KEY_0;\n\n  case SDLK_1:\n    return BX_KEY_1;\n\n  case SDLK_2:\n    return BX_KEY_2;\n\n  case SDLK_3:\n    return BX_KEY_3;\n\n  case SDLK_4:\n    return BX_KEY_4;\n\n  case SDLK_5:\n    return BX_KEY_5;\n\n  case SDLK_6:\n    return BX_KEY_6;\n\n  case SDLK_7:\n    return BX_KEY_7;\n\n  case SDLK_8:\n    return BX_KEY_8;\n\n  case SDLK_9:\n    return BX_KEY_9;\n\n  //  case SDLK_COLON:                return BX_KEY_COLON;\n  case SDLK_SEMICOLON:\n    return BX_KEY_SEMICOLON;\n\n  //  case SDLK_LESS:                 return BX_KEY_LESS;\n  case SDLK_EQUALS:\n    return BX_KEY_EQUALS;\n\n  //  case SDLK_GREATER:              return BX_KEY_GREATER;\n  //  case SDLK_QUESTION:             return BX_KEY_QUESTION;\n  //  case SDLK_AT:                   return BX_KEY_AT;\n\n  /*\n Skip uppercase letters\n*/\n  case SDLK_LEFTBRACKET:\n    return BX_KEY_LEFT_BRACKET;\n\n  case SDLK_BACKSLASH:\n    return BX_KEY_BACKSLASH;\n\n  case SDLK_RIGHTBRACKET:\n    return BX_KEY_RIGHT_BRACKET;\n\n  //  case SDLK_CARET:                return BX_KEY_CARET;\n  //  case SDLK_UNDERSCORE:           return BX_KEY_UNDERSCORE;\n  case SDLK_BACKQUOTE:\n    return BX_KEY_GRAVE;\n\n  case SDLK_a:\n    return BX_KEY_A;\n\n  case SDLK_b:\n    return BX_KEY_B;\n\n  case SDLK_c:\n    return BX_KEY_C;\n\n  case SDLK_d:\n    return BX_KEY_D;\n\n  case SDLK_e:\n    return BX_KEY_E;\n\n  case SDLK_f:\n    return BX_KEY_F;\n\n  case SDLK_g:\n    return BX_KEY_G;\n\n  case SDLK_h:\n    return BX_KEY_H;\n\n  case SDLK_i:\n    return BX_KEY_I;\n\n  case SDLK_j:\n    return BX_KEY_J;\n\n  case SDLK_k:\n    return BX_KEY_K;\n\n  case SDLK_l:\n    return BX_KEY_L;\n\n  case SDLK_m:\n    return BX_KEY_M;\n\n  case SDLK_n:\n    return BX_KEY_N;\n\n  case SDLK_o:\n    return BX_KEY_O;\n\n  case SDLK_p:\n    return BX_KEY_P;\n\n  case SDLK_q:\n    return BX_KEY_Q;\n\n  case SDLK_r:\n    return BX_KEY_R;\n\n  case SDLK_s:\n    return BX_KEY_S;\n\n  case SDLK_t:\n    return BX_KEY_T;\n\n  case SDLK_u:\n    return BX_KEY_U;\n\n  case SDLK_v:\n    return BX_KEY_V;\n\n  case SDLK_w:\n    return BX_KEY_W;\n\n  case SDLK_x:\n    return BX_KEY_X;\n\n  case SDLK_y:\n    return BX_KEY_Y;\n\n  case SDLK_z:\n    return BX_KEY_Z;\n\n  case SDLK_DELETE:\n    return BX_KEY_DELETE;\n\n  /* End of ASCII mapped keysyms */\n\n  /* Numeric keypad */\n  case SDLK_KP0:\n    return BX_KEY_KP_INSERT;\n\n  case SDLK_KP1:\n    return BX_KEY_KP_END;\n\n  case SDLK_KP2:\n    return BX_KEY_KP_DOWN;\n\n  case SDLK_KP3:\n    return BX_KEY_KP_PAGE_DOWN;\n\n  case SDLK_KP4:\n    return BX_KEY_KP_LEFT;\n\n  case SDLK_KP5:\n    return BX_KEY_KP_5;\n\n  case SDLK_KP6:\n    return BX_KEY_KP_RIGHT;\n\n  case SDLK_KP7:\n    return BX_KEY_KP_HOME;\n\n  case SDLK_KP8:\n    return BX_KEY_KP_UP;\n\n  case SDLK_KP9:\n    return BX_KEY_KP_PAGE_UP;\n\n  case SDLK_KP_PERIOD:\n    return BX_KEY_KP_DELETE;\n\n  case SDLK_KP_DIVIDE:\n    return BX_KEY_KP_DIVIDE;\n\n  case SDLK_KP_MULTIPLY:\n    return BX_KEY_KP_MULTIPLY;\n\n  case SDLK_KP_MINUS:\n    return BX_KEY_KP_SUBTRACT;\n\n  case SDLK_KP_PLUS:\n    return BX_KEY_KP_ADD;\n\n  case SDLK_KP_ENTER:\n    return BX_KEY_KP_ENTER;\n\n  //  case SDLK_KP_EQUALS:            return BX_KEY_KP_EQUALS;\n\n  /* Arrows + Home/End pad */\n  case SDLK_UP:\n    return BX_KEY_UP;\n\n  case SDLK_DOWN:\n    return BX_KEY_DOWN;\n\n  case SDLK_RIGHT:\n    return BX_KEY_RIGHT;\n\n  case SDLK_LEFT:\n    return BX_KEY_LEFT;\n\n  case SDLK_INSERT:\n    return BX_KEY_INSERT;\n\n  case SDLK_HOME:\n    return BX_KEY_HOME;\n\n  case SDLK_END:\n    return BX_KEY_END;\n\n  case SDLK_PAGEUP:\n    return BX_KEY_PAGE_UP;\n\n  case SDLK_PAGEDOWN:\n    return BX_KEY_PAGE_DOWN;\n\n  /* Function keys */\n  case SDLK_F1:\n    return BX_KEY_F1;\n\n  case SDLK_F2:\n    return BX_KEY_F2;\n\n  case SDLK_F3:\n    return BX_KEY_F3;\n\n  case SDLK_F4:\n    return BX_KEY_F4;\n\n  case SDLK_F5:\n    return BX_KEY_F5;\n\n  case SDLK_F6:\n    return BX_KEY_F6;\n\n  case SDLK_F7:\n    return BX_KEY_F7;\n\n  case SDLK_F8:\n    return BX_KEY_F8;\n\n  case SDLK_F9:\n    return BX_KEY_F9;\n\n  case SDLK_F10:\n    return BX_KEY_F10;\n\n  case SDLK_F11:\n    return BX_KEY_F11;\n\n  case SDLK_F12:\n    return BX_KEY_F12;\n\n  //  case SDLK_F13:                  return BX_KEY_F13;\n  //  case SDLK_F14:                  return BX_KEY_F14;\n  //  case SDLK_F15:                  return BX_KEY_F15;\n\n  /* Key state modifier keys */\n  case SDLK_NUMLOCK:\n    return BX_KEY_NUM_LOCK;\n\n  case SDLK_CAPSLOCK:\n    return BX_KEY_CAPS_LOCK;\n\n  case SDLK_SCROLLOCK:\n    return BX_KEY_SCRL_LOCK;\n\n  case SDLK_RSHIFT:\n    return BX_KEY_SHIFT_R;\n\n  case SDLK_LSHIFT:\n    return BX_KEY_SHIFT_L;\n\n  case SDLK_RCTRL:\n    return BX_KEY_CTRL_R;\n\n  case SDLK_LCTRL:\n    return BX_KEY_CTRL_L;\n\n  case SDLK_RALT:\n    return BX_KEY_ALT_R;\n\n  case SDLK_LALT:\n    return BX_KEY_ALT_L;\n\n  case SDLK_RMETA:\n    return BX_KEY_ALT_R;\n\n  case SDLK_LMETA:\n    return BX_KEY_WIN_L;\n\n  case SDLK_LSUPER:\n    return BX_KEY_WIN_L;\n\n  case SDLK_RSUPER:\n    return BX_KEY_WIN_R;\n\n  //  case SDLK_MODE:                 return BX_KEY_MODE;\n  //  case SDLK_COMPOSE:              return BX_KEY_COMPOSE;\n\n  /* Miscellaneous function keys */\n  case SDLK_PRINT:\n    return BX_KEY_PRINT;\n\n  case SDLK_BREAK:\n    return BX_KEY_PAUSE;\n\n  case SDLK_MENU:\n    return BX_KEY_MENU;\n#if 0\n\n  case SDLK_HELP:\n    return BX_KEY_HELP;\n\n  case SDLK_SYSREQ:\n    return BX_KEY_SYSREQ;\n\n  case SDLK_POWER:\n    return BX_KEY_POWER;\n\n  case SDLK_EURO:\n    return BX_KEY_EURO;\n\n  case SDLK_UNDO:\n    return BX_KEY_UNDO;\n#endif\n\n  default:\n    BX_ERROR((\"sdl keysym %d not mapped\", (int)sym));\n    return BX_KEY_UNHANDLED;\n  }\n}\n\nvoid bx_sdl_gui_c::handle_events(void) {\n  u32 key_event;\n\n  //  u8 mouse_state;\n  int wheel_status;\n\n  while (SDL_PollEvent(&sdl_event)) {\n    wheel_status = 0;\n    switch (sdl_event.type) {\n    case SDL_VIDEOEXPOSE:\n      SDL_UpdateRect(sdl_screen, 0, 0, res_x, res_y);\n      break;\n\n    case SDL_MOUSEMOTION:\n\n    //\t//fprintf (stderr, \"mouse event to (%d,%d), relative (%d,%d)\\n\",\n    //(int)(sdl_event.motion.x), (int)(sdl_event.motion.y),\n    //(int)sdl_event.motion.xrel, (int)sdl_event.motion.yrel); \tif (!sdl_grab) {\n    //\t  //fprintf (stderr, \"ignore mouse event because sdl_grab is off\\n\");\n    //\t  break;\n    //\t}\n    //\tif (just_warped\n    //\t    && sdl_event.motion.x == half_res_x\n    //\t    && sdl_event.motion.y == half_res_y) {\n    //\t  // This event was generated as a side effect of the WarpMouse,\n    //\t  // and it must be ignored.\n    //\t  //fprintf (stderr, \"ignore mouse event because it is a side effect of\n    //SDL_WarpMouse\\n\"); \t  just_warped = false; \t  break;\n    //\t}\n    //\t//fprintf (stderr, \"processing relative mouse event\\n\");\n    //        new_mousebuttons = ((sdl_event.motion.state &\n    //        0x01)|((sdl_event.motion.state>>1)&0x02)\n    //                            |((sdl_event.motion.state<<1)&0x04));\n    //        DEV_mouse_motion_ext(\n    //            sdl_event.motion.xrel,\n    //            -sdl_event.motion.yrel,\n    //            wheel_status,\n    //            new_mousebuttons);\n    //\told_mousebuttons = new_mousebuttons;\n    //\told_mousex = (int)(sdl_event.motion.x);\n    //\told_mousey = (int)(sdl_event.motion.y);\n    //\t//fprintf (stderr, \"warping mouse to center\\n\");\n    //\tSDL_WarpMouse(half_res_x, half_res_y);\n    //\tjust_warped = 1;\n    //\tbreak;\n    //\n    case SDL_MOUSEBUTTONDOWN:\n\n    //        if( (sdl_event.button.button == SDL_BUTTON_MIDDLE)\n    //            && ((SDL_GetModState() & KMOD_CTRL) > 0)\n    //            && (sdl_fullscreen_toggle == 0) )\n    //\t{\n    //\t  if( sdl_grab == 0 )\n    //\t  {\n    //\t    SDL_ShowCursor(0);\n    //\t    SDL_WM_GrabInput(SDL_GRAB_ON);\n    //\t  }\n    //\t  else\n    //\t  {\n    //\t    SDL_ShowCursor(1);\n    //\t    SDL_WM_GrabInput(SDL_GRAB_OFF);\n    //\t  }\n    //\t  sdl_grab = ~sdl_grab;\n    //\t  toggle_mouse_enable();\n    //\t  break;\n    //\t}\n    //#ifdef SDL_BUTTON_WHEELUP\n    //        // get the wheel status\n    //        if (sdl_event.button.button == SDL_BUTTON_WHEELUP) {\n    //          wheel_status = 1;\n    //        }\n    //        if (sdl_event.button.button == SDL_BUTTON_WHEELDOWN) {\n    //          wheel_status = -1;\n    //        }\n    //#endif\n    case SDL_MOUSEBUTTONUP:\n\n      //\t// figure out mouse state\n      //\tnew_mousex = (int)(sdl_event.button.x);\n      //\tnew_mousey = (int)(sdl_event.button.y);\n      //\t// SDL_GetMouseState() returns the state of all buttons\n      //\tmouse_state = SDL_GetMouseState(NULL, NULL);\n      //\tnew_mousebuttons =\n      //\t  (mouse_state & 0x01)    |\n      //\t  ((mouse_state>>1)&0x02) |\n      //\t  ((mouse_state<<1)&0x04) ;\n      //\t// filter out middle button if not fullscreen\n      //\tif( sdl_fullscreen_toggle == 0 )\n      //\t  new_mousebuttons &= 0x07;\n      //        // send motion information\n      //        DEV_mouse_motion_ext(\n      //            new_mousex - old_mousex,\n      //            -(new_mousey - old_mousey),\n      //            wheel_status,\n      //            new_mousebuttons);\n      //\t// mark current state to diff with next packet\n      //\told_mousebuttons = new_mousebuttons;\n      //\told_mousex = new_mousex;\n      //\told_mousey = new_mousey;\n      break;\n\n    //\n    case SDL_KEYDOWN:\n\n      // convert sym->bochs code\n      if (sdl_event.key.keysym.sym > SDLK_LAST)\n        break;\n      if (!myCfg->get_bool_value(\"keyboard.use_mapping\", false))\n\n      //    if (!SIM->get_param_bool(BXPN_KBD_USEMAPPING)->get())\n      {\n        key_event = sdl_sym_to_bx_key(sdl_event.key.keysym.sym);\n#if defined(DEBUG_KBD)\n        BX_DEBUG((\"keypress scancode=%d, sym=%d, bx_key = %d\",\n                  sdl_event.key.keysym.scancode, sdl_event.key.keysym.sym,\n                  key_event));\n#endif\n      } else {\n\n        /* use mapping */\n        BXKeyEntry *entry = bx_keymap->findHostKey(sdl_event.key.keysym.sym);\n        if (!entry) {\n          BX_ERROR((\"host key %d (0x%x) not mapped!\",\n                    (unsigned)sdl_event.key.keysym.sym,\n                    (unsigned)sdl_event.key.keysym.sym));\n          break;\n        }\n\n        key_event = entry->baseKey;\n      }\n\n      if (key_event == BX_KEY_UNHANDLED)\n        break;\n      theKeyboard->gen_scancode(key_event);\n      if ((key_event == BX_KEY_NUM_LOCK) || (key_event == BX_KEY_CAPS_LOCK)) {\n        theKeyboard->gen_scancode(key_event | BX_KEY_RELEASED);\n      }\n      break;\n\n    case SDL_KEYUP:\n\n      // filter out release of Windows/Fullscreen toggle and unsupported keys\n      if ((sdl_event.key.keysym.sym != SDLK_SCROLLOCK) &&\n          (sdl_event.key.keysym.sym < SDLK_LAST)) {\n\n        // convert sym->bochs code\n        if (!myCfg->get_bool_value(\"keyboard.use_mapping\", false)) {\n\n          // if (!SIM->get_param_bool(BXPN_KBD_USEMAPPING)->get()) {\n          key_event = sdl_sym_to_bx_key(sdl_event.key.keysym.sym);\n        } else {\n\n          /* use mapping */\n          BXKeyEntry *entry = bx_keymap->findHostKey(sdl_event.key.keysym.sym);\n          if (!entry) {\n            BX_ERROR((\"host key %d (0x%x) not mapped!\",\n                      (unsigned)sdl_event.key.keysym.sym,\n                      (unsigned)sdl_event.key.keysym.sym));\n            break;\n          }\n\n          key_event = entry->baseKey;\n        }\n\n        if (key_event == BX_KEY_UNHANDLED)\n          break;\n        if ((key_event == BX_KEY_NUM_LOCK) || (key_event == BX_KEY_CAPS_LOCK)) {\n          theKeyboard->gen_scancode(key_event);\n        }\n\n        theKeyboard->gen_scancode(key_event | BX_KEY_RELEASED);\n      }\n      break;\n\n    case SDL_QUIT:\n      FAILURE(Graceful, \"User requested shutdown\");\n    }\n  }\n}\n\n/**\n * Flush any changes to sdl_screen to the actual window.\n **/\nvoid bx_sdl_gui_c::flush(void) {\n  SDL_UpdateRect(sdl_screen, 0, 0, res_x, res_y);\n}\n\n/**\n * Clear sdl_screen display, and flush it.\n **/\nvoid bx_sdl_gui_c::clear_screen(void) {\n  int i = res_y;\n\n  int j;\n  u32 color;\n  u32 *buf;\n  u32 *buf_row;\n  u32 disp;\n\n  if (!sdl_screen)\n    return;\n\n  color = SDL_MapRGB(sdl_screen->format, 0, 0, 0);\n  disp = sdl_screen->pitch / 4;\n  buf = (u32 *)sdl_screen->pixels;\n\n  do {\n    buf_row = buf;\n    j = res_x;\n    while (j--)\n      *buf++ = color;\n    buf = buf_row + disp;\n  } while (--i);\n\n  flush();\n}\n\n/**\n * Set palette-entry index to the desired value.\n *\n * The palette is used in text-mode and in 8bpp VGA mode.\n **/\nbool bx_sdl_gui_c::palette_change(unsigned index, unsigned red, unsigned green,\n                                  unsigned blue) {\n  unsigned char palred = red & 0xFF;\n  unsigned char palgreen = green & 0xFF;\n  unsigned char palblue = blue & 0xFF;\n\n  if (index > 255)\n    return 0;\n\n  palette[index] = SDL_MapRGB(sdl_screen->format, palred, palgreen, palblue);\n\n  return 1;\n}\n\nvoid bx_sdl_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight,\n                                    unsigned fwidth, unsigned bpp) {\n  if ((bpp == 8) || (bpp == 15) || (bpp == 16) || (bpp == 24) || (bpp == 32)) {\n    vga_bpp = bpp;\n  } else {\n    FAILURE_1(SDL, \"%d bpp graphics mode not supported.\", bpp);\n  }\n\n  if (fheight > 0) {\n    fontheight = fheight;\n    fontwidth = fwidth;\n    text_cols = x / fontwidth;\n    text_rows = y / fontheight;\n  }\n\n  if ((x == res_x) && (y == res_y))\n    return;\n\n  if (sdl_screen) {\n    SDL_FreeSurface(sdl_screen);\n    sdl_screen = NULL;\n  }\n\n  sdl_screen = SDL_SetVideoMode(x, y /*+headerbar_height+statusbar_height*/, 32,\n                                SDL_SWSURFACE);\n  if (!sdl_screen) {\n    FAILURE_3(SDL, \"Unable to set requested videomode: %ix%i: %s   \\n\", x, y,\n              SDL_GetError());\n  }\n\n  res_x = x;\n  res_y = y;\n  half_res_x = x / 2;\n  half_res_y = y / 2;\n}\n\nvoid bx_sdl_gui_c::mouse_enabled_changed_specific(bool val) {\n  if (val == 1) {\n    SDL_ShowCursor(0);\n    SDL_WM_GrabInput(SDL_GRAB_ON);\n  } else {\n    SDL_ShowCursor(1);\n    SDL_WM_GrabInput(SDL_GRAB_OFF);\n  }\n\n  sdl_grab = val;\n}\n\nvoid bx_sdl_gui_c::exit(void) {\n  if (sdl_screen)\n    SDL_FreeSurface(sdl_screen);\n}\n\n/// key mapping for SDL\ntypedef struct {\n  const char *name;\n  u32 value;\n} keyTableEntry;\n\n#define DEF_SDL_KEY(key) {#key, key},\n\nkeyTableEntry keytable[] = {\n// this include provides all the entries.\n#include \"sdlkeys.hpp\"\n    // one final entry to mark the end\n    {NULL, 0}};\n\n// function to convert key names into SDLKey values.\n// This first try will be horribly inefficient, but it only has\n// to be done while loading a keymap.  Once the simulation starts,\n\n// this function won't be called.\nstatic u32 convertStringToSDLKey(const char *string) {\n  keyTableEntry *ptr;\n  for (ptr = &keytable[0]; ptr->name != NULL; ptr++) {\n#if defined(DEBUG_SDL_KEY)\n    printf(\"SDL: comparing string '%s' to SDL key '%s'   \\n\", string,\n           ptr->name);\n#endif\n    if (!strcmp(string, ptr->name))\n      return ptr->value;\n  }\n\n  return BX_KEYMAP_UNKNOWN;\n}\n#endif // defined(HAVE_SDL)\n"
  },
  {
    "path": "src/gui/sdl_fonts.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n *  This file is based upon Bochs.\n *\n *  Copyright (C) 2002  MandrakeSoft S.A.\n *\n *    MandrakeSoft S.A.\n *    43, rue d'Aboukir\n *    75002 Paris - France\n *    http://www.linux-mandrake.com/\n *    http://www.mandrakesoft.com/\n *\n *  This library is free software; you can redistribute it and/or\n *  modify it under the terms of the GNU Lesser General Public\n *  License as published by the Free Software Foundation; either\n *  version 2 of the License, or (at your option) any later version.\n *\n *  This library is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n *  Lesser General Public License for more details.\n *\n *  You should have received a copy of the GNU Lesser General Public\n *  License along with this library; if not, write to the Free Software\n *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA\n */\n\n#ifndef BX_SDL_H\n#define BX_SDL_H\n\nunsigned char sdl_font8x16[256][16] = {\n    {0, 0, 0, 0, 0, 0, 0, 0, // 0\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 0, 126, 129, 165, 129, 129, 189, // 1\n     153, 129, 129, 126, 0, 0, 0, 0},\n    {0, 0, 126, 255, 219, 255, 255, 195, // 2\n     231, 255, 255, 126, 0, 0, 0, 0},\n    {0, 0, 0, 0, 108, 254, 254, 254, // 3\n     254, 124, 56, 16, 0, 0, 0, 0},\n    {0, 0, 0, 0, 16, 56, 124, 254, // 4\n     124, 56, 16, 0, 0, 0, 0, 0},\n    {0, 0, 0, 24, 60, 60, 231, 231, // 5\n     231, 24, 24, 60, 0, 0, 0, 0},\n    {0, 0, 0, 24, 60, 126, 255, 255, // 6\n     126, 24, 24, 60, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 0, 24, 60, // 7\n     60, 24, 0, 0, 0, 0, 0, 0},\n    {255, 255, 255, 255, 255, 255, 231, 195, // 8\n     195, 231, 255, 255, 255, 255, 255, 255},\n    {0, 0, 0, 0, 0, 60, 102, 66, // 9\n     66, 102, 60, 0, 0, 0, 0, 0},\n    {255, 255, 255, 255, 255, 195, 153, 189, // 10\n     189, 153, 195, 255, 255, 255, 255, 255},\n    {0, 0, 30, 14, 26, 50, 120, 204, // 11\n     204, 204, 204, 120, 0, 0, 0, 0},\n    {0, 0, 60, 102, 102, 102, 102, 60, // 12\n     24, 126, 24, 24, 0, 0, 0, 0},\n    {0, 0, 63, 51, 63, 48, 48, 48, // 13\n     48, 112, 240, 224, 0, 0, 0, 0},\n    {0, 0, 127, 99, 127, 99, 99, 99, // 14\n     99, 103, 231, 230, 192, 0, 0, 0},\n    {0, 0, 0, 24, 24, 219, 60, 231, // 15\n     60, 219, 24, 24, 0, 0, 0, 0},\n    {0, 128, 192, 224, 240, 248, 254, 248, // 16\n     240, 224, 192, 128, 0, 0, 0, 0},\n    {0, 2, 6, 14, 30, 62, 254, 62, // 17\n     30, 14, 6, 2, 0, 0, 0, 0},\n    {0, 0, 24, 60, 126, 24, 24, 24, // 18\n     126, 60, 24, 0, 0, 0, 0, 0},\n    {0, 0, 102, 102, 102, 102, 102, 102, // 19\n     102, 0, 102, 102, 0, 0, 0, 0},\n    {0, 0, 127, 219, 219, 219, 123, 27, // 20\n     27, 27, 27, 27, 0, 0, 0, 0},\n    {0, 124, 198, 96, 56, 108, 198, 198, // 21\n     108, 56, 12, 198, 124, 0, 0, 0},\n    {0, 0, 0, 0, 0, 0, 0, 0, // 22\n     254, 254, 254, 254, 0, 0, 0, 0},\n    {0, 0, 24, 60, 126, 24, 24, 24, // 23\n     126, 60, 24, 126, 0, 0, 0, 0},\n    {0, 0, 24, 60, 126, 24, 24, 24, // 24\n     24, 24, 24, 24, 0, 0, 0, 0},\n    {0, 0, 24, 24, 24, 24, 24, 24, // 25\n     24, 126, 60, 24, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 24, 12, 254, // 26\n     12, 24, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 48, 96, 254, // 27\n     96, 48, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 0, 192, 192, // 28\n     192, 254, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 40, 108, 254, // 29\n     108, 40, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 16, 56, 56, 124, // 30\n     124, 254, 254, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 254, 254, 124, 124, // 31\n     56, 56, 16, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 0, 0, 0, // 32\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 0, 24, 60, 60, 60, 24, 24, // 33\n     24, 0, 24, 24, 0, 0, 0, 0},\n    {0, 102, 102, 102, 36, 0, 0, 0, // 34\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 108, 108, 254, 108, 108, // 35\n     108, 254, 108, 108, 0, 0, 0, 0},\n    {24, 24, 124, 198, 194, 192, 124, 6, // 36\n     6, 134, 198, 124, 24, 24, 0, 0},\n    {0, 0, 0, 0, 194, 198, 12, 24, // 37\n     48, 96, 198, 134, 0, 0, 0, 0},\n    {0, 0, 56, 108, 108, 56, 118, 220, // 38\n     204, 204, 204, 118, 0, 0, 0, 0},\n    {0, 48, 48, 48, 96, 0, 0, 0, // 39\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 0, 12, 24, 48, 48, 48, 48, // 40\n     48, 48, 24, 12, 0, 0, 0, 0},\n    {0, 0, 48, 24, 12, 12, 12, 12, // 41\n     12, 12, 24, 48, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 102, 60, 255, // 42\n     60, 102, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 24, 24, 126, // 43\n     24, 24, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 0, 0, 0, // 44\n     0, 24, 24, 24, 48, 0, 0, 0},\n    {0, 0, 0, 0, 0, 0, 0, 254, // 45\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 0, 0, 0, // 46\n     0, 0, 24, 24, 0, 0, 0, 0},\n    {0, 0, 0, 0, 2, 6, 12, 24, // 47\n     48, 96, 192, 128, 0, 0, 0, 0},\n    {0, 0, 56, 108, 198, 198, 214, 214, // 48\n     198, 198, 108, 56, 0, 0, 0, 0},\n    {0, 0, 24, 56, 120, 24, 24, 24, // 49\n     24, 24, 24, 126, 0, 0, 0, 0},\n    {0, 0, 124, 198, 6, 12, 24, 48, // 50\n     96, 192, 198, 254, 0, 0, 0, 0},\n    {0, 0, 124, 198, 6, 6, 60, 6, // 51\n     6, 6, 198, 124, 0, 0, 0, 0},\n    {0, 0, 12, 28, 60, 108, 204, 254, // 52\n     12, 12, 12, 30, 0, 0, 0, 0},\n    {0, 0, 254, 192, 192, 192, 252, 6, // 53\n     6, 6, 198, 124, 0, 0, 0, 0},\n    {0, 0, 56, 96, 192, 192, 252, 198, // 54\n     198, 198, 198, 124, 0, 0, 0, 0},\n    {0, 0, 254, 198, 6, 6, 12, 24, // 55\n     48, 48, 48, 48, 0, 0, 0, 0},\n    {0, 0, 124, 198, 198, 198, 124, 198, // 56\n     198, 198, 198, 124, 0, 0, 0, 0},\n    {0, 0, 124, 198, 198, 198, 126, 6, // 57\n     6, 6, 12, 120, 0, 0, 0, 0},\n    {0, 0, 0, 0, 24, 24, 0, 0, // 58\n     0, 24, 24, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 24, 24, 0, 0, // 59\n     0, 24, 24, 48, 0, 0, 0, 0},\n    {0, 0, 0, 6, 12, 24, 48, 96, // 60\n     48, 24, 12, 6, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 126, 0, 0, // 61\n     126, 0, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 96, 48, 24, 12, 6, // 62\n     12, 24, 48, 96, 0, 0, 0, 0},\n    {0, 0, 124, 198, 198, 12, 24, 24, // 63\n     24, 0, 24, 24, 0, 0, 0, 0},\n    {0, 0, 0, 124, 198, 198, 222, 222, // 64\n     222, 220, 192, 124, 0, 0, 0, 0},\n    {0, 0, 16, 56, 108, 198, 198, 254, // 65\n     198, 198, 198, 198, 0, 0, 0, 0},\n    {0, 0, 252, 102, 102, 102, 124, 102, // 66\n     102, 102, 102, 252, 0, 0, 0, 0},\n    {0, 0, 60, 102, 194, 192, 192, 192, // 67\n     192, 194, 102, 60, 0, 0, 0, 0},\n    {0, 0, 248, 108, 102, 102, 102, 102, // 68\n     102, 102, 108, 248, 0, 0, 0, 0},\n    {0, 0, 254, 102, 98, 104, 120, 104, // 69\n     96, 98, 102, 254, 0, 0, 0, 0},\n    {0, 0, 254, 102, 98, 104, 120, 104, // 70\n     96, 96, 96, 240, 0, 0, 0, 0},\n    {0, 0, 60, 102, 194, 192, 192, 222, // 71\n     198, 198, 102, 58, 0, 0, 0, 0},\n    {0, 0, 198, 198, 198, 198, 254, 198, // 72\n     198, 198, 198, 198, 0, 0, 0, 0},\n    {0, 0, 60, 24, 24, 24, 24, 24, // 73\n     24, 24, 24, 60, 0, 0, 0, 0},\n    {0, 0, 30, 12, 12, 12, 12, 12, // 74\n     204, 204, 204, 120, 0, 0, 0, 0},\n    {0, 0, 230, 102, 102, 108, 120, 120, // 75\n     108, 102, 102, 230, 0, 0, 0, 0},\n    {0, 0, 240, 96, 96, 96, 96, 96, // 76\n     96, 98, 102, 254, 0, 0, 0, 0},\n    {0, 0, 198, 238, 254, 254, 214, 198, // 77\n     198, 198, 198, 198, 0, 0, 0, 0},\n    {0, 0, 198, 230, 246, 254, 222, 206, // 78\n     198, 198, 198, 198, 0, 0, 0, 0},\n    {0, 0, 124, 198, 198, 198, 198, 198, // 79\n     198, 198, 198, 124, 0, 0, 0, 0},\n    {0, 0, 252, 102, 102, 102, 124, 96, // 80\n     96, 96, 96, 240, 0, 0, 0, 0},\n    {0, 0, 124, 198, 198, 198, 198, 198, // 81\n     198, 214, 222, 124, 12, 14, 0, 0},\n    {0, 0, 252, 102, 102, 102, 124, 108, // 82\n     102, 102, 102, 230, 0, 0, 0, 0},\n    {0, 0, 124, 198, 198, 96, 56, 12, // 83\n     6, 198, 198, 124, 0, 0, 0, 0},\n    {0, 0, 126, 126, 90, 24, 24, 24, // 84\n     24, 24, 24, 60, 0, 0, 0, 0},\n    {0, 0, 198, 198, 198, 198, 198, 198, // 85\n     198, 198, 198, 124, 0, 0, 0, 0},\n    {0, 0, 198, 198, 198, 198, 198, 198, // 86\n     198, 108, 56, 16, 0, 0, 0, 0},\n    {0, 0, 198, 198, 198, 198, 214, 214, // 87\n     214, 254, 238, 108, 0, 0, 0, 0},\n    {0, 0, 198, 198, 108, 124, 56, 56, // 88\n     124, 108, 198, 198, 0, 0, 0, 0},\n    {0, 0, 102, 102, 102, 102, 60, 24, // 89\n     24, 24, 24, 60, 0, 0, 0, 0},\n    {0, 0, 254, 198, 134, 12, 24, 48, // 90\n     96, 194, 198, 254, 0, 0, 0, 0},\n    {0, 0, 60, 48, 48, 48, 48, 48, // 91\n     48, 48, 48, 60, 0, 0, 0, 0},\n    {0, 0, 0, 128, 192, 224, 112, 56, // 92\n     28, 14, 6, 2, 0, 0, 0, 0},\n    {0, 0, 60, 12, 12, 12, 12, 12, // 93\n     12, 12, 12, 60, 0, 0, 0, 0},\n    {16, 56, 108, 198, 0, 0, 0, 0, // 94\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 0, 0, 0, // 95\n     0, 0, 0, 0, 0, 255, 0, 0},\n    {0, 48, 24, 12, 0, 0, 0, 0, // 96\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 120, 12, 124, // 97\n     204, 204, 204, 118, 0, 0, 0, 0},\n    {0, 0, 224, 96, 96, 120, 108, 102, // 98\n     102, 102, 102, 124, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 124, 198, 192, // 99\n     192, 192, 198, 124, 0, 0, 0, 0},\n    {0, 0, 28, 12, 12, 60, 108, 204, // 100\n     204, 204, 204, 118, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 124, 198, 254, // 101\n     192, 192, 198, 124, 0, 0, 0, 0},\n    {0, 0, 28, 54, 50, 48, 120, 48, // 102\n     48, 48, 48, 120, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 118, 204, 204, // 103\n     204, 204, 204, 124, 12, 204, 120, 0},\n    {0, 0, 224, 96, 96, 108, 118, 102, // 104\n     102, 102, 102, 230, 0, 0, 0, 0},\n    {0, 0, 24, 24, 0, 56, 24, 24, // 105\n     24, 24, 24, 60, 0, 0, 0, 0},\n    {0, 0, 6, 6, 0, 14, 6, 6, // 106\n     6, 6, 6, 6, 102, 102, 60, 0},\n    {0, 0, 224, 96, 96, 102, 108, 120, // 107\n     120, 108, 102, 230, 0, 0, 0, 0},\n    {0, 0, 56, 24, 24, 24, 24, 24, // 108\n     24, 24, 24, 60, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 236, 254, 214, // 109\n     214, 214, 214, 198, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 220, 102, 102, // 110\n     102, 102, 102, 102, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 124, 198, 198, // 111\n     198, 198, 198, 124, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 220, 102, 102, // 112\n     102, 102, 102, 124, 96, 96, 240, 0},\n    {0, 0, 0, 0, 0, 118, 204, 204, // 113\n     204, 204, 204, 124, 12, 12, 30, 0},\n    {0, 0, 0, 0, 0, 220, 118, 102, // 114\n     96, 96, 96, 240, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 124, 198, 96, // 115\n     56, 12, 198, 124, 0, 0, 0, 0},\n    {0, 0, 16, 48, 48, 252, 48, 48, // 116\n     48, 48, 54, 28, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 204, 204, 204, // 117\n     204, 204, 204, 118, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 198, 198, 198, // 118\n     198, 198, 108, 56, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 198, 198, 214, // 119\n     214, 214, 254, 108, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 198, 108, 56, // 120\n     56, 56, 108, 198, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 198, 198, 198, // 121\n     198, 198, 198, 126, 6, 12, 248, 0},\n    {0, 0, 0, 0, 0, 254, 204, 24, // 122\n     48, 96, 198, 254, 0, 0, 0, 0},\n    {0, 0, 14, 24, 24, 24, 112, 24, // 123\n     24, 24, 24, 14, 0, 0, 0, 0},\n    {0, 0, 24, 24, 24, 24, 24, 24, // 124\n     24, 24, 24, 24, 0, 0, 0, 0},\n    {0, 0, 112, 24, 24, 24, 14, 24, // 125\n     24, 24, 24, 112, 0, 0, 0, 0},\n    {0, 118, 220, 0, 0, 0, 0, 0, // 126\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 16, 56, 108, 198, // 127\n     198, 198, 254, 0, 0, 0, 0, 0},\n    {0, 0, 60, 102, 194, 192, 192, 192, // 128\n     192, 194, 102, 60, 24, 112, 0, 0},\n    {0, 0, 204, 0, 0, 204, 204, 204, // 129\n     204, 204, 204, 118, 0, 0, 0, 0},\n    {0, 12, 24, 48, 0, 124, 198, 254, // 130\n     192, 192, 198, 124, 0, 0, 0, 0},\n    {0, 16, 56, 108, 0, 120, 12, 124, // 131\n     204, 204, 204, 118, 0, 0, 0, 0},\n    {0, 0, 204, 0, 0, 120, 12, 124, // 132\n     204, 204, 204, 118, 0, 0, 0, 0},\n    {0, 96, 48, 24, 0, 120, 12, 124, // 133\n     204, 204, 204, 118, 0, 0, 0, 0},\n    {0, 56, 108, 56, 0, 120, 12, 124, // 134\n     204, 204, 204, 118, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 124, 198, 192, // 135\n     192, 192, 198, 124, 24, 112, 0, 0},\n    {0, 16, 56, 108, 0, 124, 198, 254, // 136\n     192, 192, 198, 124, 0, 0, 0, 0},\n    {0, 0, 198, 0, 0, 124, 198, 254, // 137\n     192, 192, 198, 124, 0, 0, 0, 0},\n    {0, 96, 48, 24, 0, 124, 198, 254, // 138\n     192, 192, 198, 124, 0, 0, 0, 0},\n    {0, 0, 102, 0, 0, 56, 24, 24, // 139\n     24, 24, 24, 60, 0, 0, 0, 0},\n    {0, 24, 60, 102, 0, 56, 24, 24, // 140\n     24, 24, 24, 60, 0, 0, 0, 0},\n    {0, 96, 48, 24, 0, 56, 24, 24, // 141\n     24, 24, 24, 60, 0, 0, 0, 0},\n    {0, 198, 0, 16, 56, 108, 198, 198, // 142\n     254, 198, 198, 198, 0, 0, 0, 0},\n    {56, 108, 56, 16, 56, 108, 198, 198, // 143\n     254, 198, 198, 198, 0, 0, 0, 0},\n    {12, 24, 0, 254, 102, 98, 104, 120, // 144\n     104, 98, 102, 254, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 236, 54, 54, // 145\n     126, 216, 216, 110, 0, 0, 0, 0},\n    {0, 0, 62, 108, 204, 204, 254, 204, // 146\n     204, 204, 204, 206, 0, 0, 0, 0},\n    {0, 16, 56, 108, 0, 124, 198, 198, // 147\n     198, 198, 198, 124, 0, 0, 0, 0},\n    {0, 0, 198, 0, 0, 124, 198, 198, // 148\n     198, 198, 198, 124, 0, 0, 0, 0},\n    {0, 96, 48, 24, 0, 124, 198, 198, // 149\n     198, 198, 198, 124, 0, 0, 0, 0},\n    {0, 48, 120, 204, 0, 204, 204, 204, // 150\n     204, 204, 204, 118, 0, 0, 0, 0},\n    {0, 96, 48, 24, 0, 204, 204, 204, // 151\n     204, 204, 204, 118, 0, 0, 0, 0},\n    {0, 0, 198, 0, 0, 198, 198, 198, // 152\n     198, 198, 198, 126, 6, 12, 120, 0},\n    {0, 198, 0, 124, 198, 198, 198, 198, // 153\n     198, 198, 198, 124, 0, 0, 0, 0},\n    {0, 198, 0, 198, 198, 198, 198, 198, // 154\n     198, 198, 198, 124, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 124, 206, 222, // 155\n     246, 230, 198, 124, 0, 0, 0, 0},\n    {0, 56, 108, 100, 96, 240, 96, 96, // 156\n     96, 96, 230, 252, 0, 0, 0, 0},\n    {0, 4, 124, 206, 206, 214, 214, 214, // 157\n     214, 230, 230, 124, 64, 0, 0, 0},\n    {0, 0, 0, 0, 0, 198, 108, 56, // 158\n     56, 108, 198, 0, 0, 0, 0, 0},\n    {0, 14, 27, 24, 24, 24, 126, 24, // 159\n     24, 24, 216, 112, 0, 0, 0, 0},\n    {0, 24, 48, 96, 0, 120, 12, 124, // 160\n     204, 204, 204, 118, 0, 0, 0, 0},\n    {0, 12, 24, 48, 0, 56, 24, 24, // 161\n     24, 24, 24, 60, 0, 0, 0, 0},\n    {0, 24, 48, 96, 0, 124, 198, 198, // 162\n     198, 198, 198, 124, 0, 0, 0, 0},\n    {0, 24, 48, 96, 0, 204, 204, 204, // 163\n     204, 204, 204, 118, 0, 0, 0, 0},\n    {0, 0, 118, 220, 0, 220, 102, 102, // 164\n     102, 102, 102, 102, 0, 0, 0, 0},\n    {118, 220, 0, 198, 230, 246, 254, 222, // 165\n     206, 198, 198, 198, 0, 0, 0, 0},\n    {0, 0, 60, 108, 108, 62, 0, 126, // 166\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 0, 56, 108, 108, 56, 0, 124, // 167\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 0, 48, 48, 0, 48, 48, 96, // 168\n     192, 198, 198, 124, 0, 0, 0, 0},\n    {0, 0, 124, 130, 178, 170, 178, 170, // 169\n     170, 130, 124, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 0, 254, 6, // 170\n     6, 6, 6, 0, 0, 0, 0, 0},\n    {0, 96, 224, 98, 102, 108, 24, 48, // 171\n     96, 220, 134, 12, 24, 62, 0, 0},\n    {0, 96, 224, 98, 102, 108, 24, 48, // 172\n     102, 206, 154, 63, 6, 6, 0, 0},\n    {0, 0, 24, 24, 0, 24, 24, 24, // 173\n     60, 60, 60, 24, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 54, 108, 216, // 174\n     108, 54, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 216, 108, 54, // 175\n     108, 216, 0, 0, 0, 0, 0, 0},\n    {17, 68, 17, 68, 17, 68, 17, 68, // 176\n     17, 68, 17, 68, 17, 68, 17, 68},\n    {85, 170, 85, 170, 85, 170, 85, 170, // 177\n     85, 170, 85, 170, 85, 170, 85, 170},\n    {221, 119, 221, 119, 221, 119, 221, 119, // 178\n     221, 119, 221, 119, 221, 119, 221, 119},\n    {24, 24, 24, 24, 24, 24, 24, 24, // 179\n     24, 24, 24, 24, 24, 24, 24, 24},\n    {24, 24, 24, 24, 24, 24, 24, 248, // 180\n     24, 24, 24, 24, 24, 24, 24, 24},\n    {96, 192, 16, 56, 108, 198, 198, 254, // 181\n     198, 198, 198, 198, 0, 0, 0, 0},\n    {124, 198, 16, 56, 108, 198, 198, 254, // 182\n     198, 198, 198, 198, 0, 0, 0, 0},\n    {12, 6, 16, 56, 108, 198, 198, 254, // 183\n     198, 198, 198, 198, 0, 0, 0, 0},\n    {0, 0, 124, 130, 154, 162, 162, 162, // 184\n     154, 130, 124, 0, 0, 0, 0, 0},\n    {54, 54, 54, 54, 54, 246, 6, 246, // 185\n     54, 54, 54, 54, 54, 54, 54, 54},\n    {54, 54, 54, 54, 54, 54, 54, 54, // 186\n     54, 54, 54, 54, 54, 54, 54, 54},\n    {0, 0, 0, 0, 0, 254, 6, 246, // 187\n     54, 54, 54, 54, 54, 54, 54, 54},\n    {54, 54, 54, 54, 54, 246, 6, 254, // 188\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 0, 24, 24, 124, 198, 192, 192, // 189\n     198, 124, 24, 24, 0, 0, 0, 0},\n    {0, 0, 0, 102, 102, 60, 24, 126, // 190\n     24, 126, 24, 24, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 0, 0, 248, // 191\n     24, 24, 24, 24, 24, 24, 24, 24},\n    {24, 24, 24, 24, 24, 24, 24, 31, // 192\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {24, 24, 24, 24, 24, 24, 24, 255, // 193\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 0, 0, 255, // 194\n     24, 24, 24, 24, 24, 24, 24, 24},\n    {24, 24, 24, 24, 24, 24, 24, 31, // 195\n     24, 24, 24, 24, 24, 24, 24, 24},\n    {0, 0, 0, 0, 0, 0, 0, 255, // 196\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {24, 24, 24, 24, 24, 24, 24, 255, // 197\n     24, 24, 24, 24, 24, 24, 24, 24},\n    {0, 0, 118, 220, 0, 120, 12, 124, // 198\n     204, 204, 204, 118, 0, 0, 0, 0},\n    {118, 220, 0, 56, 108, 198, 198, 254, // 199\n     198, 198, 198, 198, 0, 0, 0, 0},\n    {54, 54, 54, 54, 54, 55, 48, 63, // 200\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 63, 48, 55, // 201\n     54, 54, 54, 54, 54, 54, 54, 54},\n    {54, 54, 54, 54, 54, 247, 0, 255, // 202\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 255, 0, 247, // 203\n     54, 54, 54, 54, 54, 54, 54, 54},\n    {54, 54, 54, 54, 54, 55, 48, 55, // 204\n     54, 54, 54, 54, 54, 54, 54, 54},\n    {0, 0, 0, 0, 0, 255, 0, 255, // 205\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {54, 54, 54, 54, 54, 247, 0, 247, // 206\n     54, 54, 54, 54, 54, 54, 54, 54},\n    {0, 0, 0, 0, 198, 124, 198, 198, // 207\n     198, 198, 124, 198, 0, 0, 0, 0},\n    {0, 0, 52, 24, 44, 6, 62, 102, // 208\n     102, 102, 102, 60, 0, 0, 0, 0},\n    {0, 0, 248, 108, 102, 102, 246, 102, // 209\n     102, 102, 108, 248, 0, 0, 0, 0},\n    {56, 108, 0, 254, 102, 98, 104, 120, // 210\n     104, 98, 102, 254, 0, 0, 0, 0},\n    {0, 198, 0, 254, 102, 98, 104, 120, // 211\n     104, 98, 102, 254, 0, 0, 0, 0},\n    {48, 24, 0, 254, 102, 98, 104, 120, // 212\n     104, 98, 102, 254, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 56, 24, 24, // 213\n     24, 24, 24, 60, 0, 0, 0, 0},\n    {12, 24, 0, 60, 24, 24, 24, 24, // 214\n     24, 24, 24, 60, 0, 0, 0, 0},\n    {60, 102, 0, 60, 24, 24, 24, 24, // 215\n     24, 24, 24, 60, 0, 0, 0, 0},\n    {0, 102, 0, 60, 24, 24, 24, 24, // 216\n     24, 24, 24, 60, 0, 0, 0, 0},\n    {24, 24, 24, 24, 24, 24, 24, 248, // 217\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 0, 0, 31, // 218\n     24, 24, 24, 24, 24, 24, 24, 24},\n    {255, 255, 255, 255, 255, 255, 255, 255, // 219\n     255, 255, 255, 255, 255, 255, 255, 255},\n    {0, 0, 0, 0, 0, 0, 0, 255, // 220\n     255, 255, 255, 255, 255, 255, 255, 255},\n    {0, 24, 24, 24, 24, 24, 0, 0, // 221\n     24, 24, 24, 24, 24, 0, 0, 0},\n    {48, 24, 0, 60, 24, 24, 24, 24, // 222\n     24, 24, 24, 60, 0, 0, 0, 0},\n    {255, 255, 255, 255, 255, 255, 255, 0, // 223\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {24, 48, 0, 124, 198, 198, 198, 198, // 224\n     198, 198, 198, 124, 0, 0, 0, 0},\n    {0, 0, 120, 204, 204, 204, 216, 204, // 225\n     198, 198, 198, 204, 0, 0, 0, 0},\n    {56, 108, 0, 124, 198, 198, 198, 198, // 226\n     198, 198, 198, 124, 0, 0, 0, 0},\n    {48, 24, 0, 124, 198, 198, 198, 198, // 227\n     198, 198, 198, 124, 0, 0, 0, 0},\n    {0, 0, 118, 220, 0, 124, 198, 198, // 228\n     198, 198, 198, 124, 0, 0, 0, 0},\n    {118, 220, 0, 124, 198, 198, 198, 198, // 229\n     198, 198, 198, 124, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 102, 102, 102, // 230\n     102, 102, 102, 124, 96, 96, 192, 0},\n    {0, 0, 224, 96, 96, 124, 102, 102, // 231\n     102, 102, 102, 124, 96, 96, 240, 0},\n    {0, 0, 240, 96, 124, 102, 102, 102, // 232\n     102, 124, 96, 240, 0, 0, 0, 0},\n    {24, 48, 0, 198, 198, 198, 198, 198, // 233\n     198, 198, 198, 124, 0, 0, 0, 0},\n    {56, 108, 0, 198, 198, 198, 198, 198, // 234\n     198, 198, 198, 124, 0, 0, 0, 0},\n    {48, 24, 0, 198, 198, 198, 198, 198, // 235\n     198, 198, 198, 124, 0, 0, 0, 0},\n    {0, 12, 24, 48, 0, 198, 198, 198, // 236\n     198, 198, 198, 126, 6, 12, 248, 0},\n    {12, 24, 0, 102, 102, 102, 102, 60, // 237\n     24, 24, 24, 60, 0, 0, 0, 0},\n    {0, 255, 0, 0, 0, 0, 0, 0, // 238\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 12, 24, 48, 0, 0, 0, 0, // 239\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 0, 0, 254, // 240\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 24, 24, 126, 24, // 241\n     24, 0, 0, 126, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 0, 0, 0, // 242\n     0, 0, 0, 0, 255, 0, 255, 0},\n    {0, 224, 48, 98, 54, 236, 24, 48, // 243\n     102, 206, 154, 63, 6, 6, 0, 0},\n    {0, 0, 127, 219, 219, 219, 123, 27, // 244\n     27, 27, 27, 27, 0, 0, 0, 0},\n    {0, 124, 198, 96, 56, 108, 198, 198, // 245\n     108, 56, 12, 198, 124, 0, 0, 0},\n    {0, 0, 0, 0, 0, 24, 0, 126, // 246\n     0, 24, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 0, 0, 0, // 247\n     0, 0, 0, 24, 12, 120, 0, 0},\n    {0, 56, 108, 108, 56, 0, 0, 0, // 248\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 198, 0, 0, 0, 0, 0, 0, // 249\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 0, 0, 24, // 250\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 24, 56, 24, 24, 24, 60, 0, // 251\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 124, 6, 60, 6, 6, 124, 0, // 252\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 60, 102, 12, 24, 50, 126, 0, // 253\n     0, 0, 0, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 126, 126, 126, 126, // 254\n     126, 126, 126, 0, 0, 0, 0, 0},\n    {0, 0, 0, 0, 0, 0, 0, 0, // 255\n     0, 0, 0, 0, 0, 0, 0, 0}};\n\nunsigned char sdl_font8x8[256][8] = {\n    {0, 0, 0, 0, 0, 0, 0, 0},                 // 0\n    {126, 129, 165, 129, 189, 153, 129, 126}, // 1\n    {126, 255, 219, 255, 195, 231, 255, 126}, // 2\n    {108, 254, 254, 254, 124, 56, 16, 0},     // 3\n    {16, 56, 124, 254, 124, 56, 16, 0},       // 4\n    {56, 124, 56, 254, 254, 214, 16, 56},     // 5\n    {16, 56, 124, 254, 254, 124, 16, 56},     // 6\n    {0, 0, 24, 60, 60, 24, 0, 0},             // 7\n    {255, 255, 231, 195, 195, 231, 255, 255}, // 8\n    {0, 60, 102, 66, 66, 102, 60, 0},         // 9\n    {255, 195, 153, 189, 189, 153, 195, 255}, // 10\n    {15, 7, 15, 125, 204, 204, 204, 120},     // 11\n    {60, 102, 102, 102, 60, 24, 126, 24},     // 12\n    {63, 51, 63, 48, 48, 112, 240, 224},      // 13\n    {127, 99, 127, 99, 99, 103, 230, 192},    // 14\n    {24, 219, 60, 231, 231, 60, 219, 24},     // 15\n    {128, 224, 248, 254, 248, 224, 128, 0},   // 16\n    {2, 14, 62, 254, 62, 14, 2, 0},           // 17\n    {24, 60, 126, 24, 24, 126, 60, 24},       // 18\n    {102, 102, 102, 102, 102, 0, 102, 0},     // 19\n    {127, 219, 219, 123, 27, 27, 27, 0},      // 20\n    {62, 97, 60, 102, 102, 60, 134, 124},     // 21\n    {0, 0, 0, 0, 126, 126, 126, 0},           // 22\n    {24, 60, 126, 24, 126, 60, 24, 255},      // 23\n    {24, 60, 126, 24, 24, 24, 24, 0},         // 24\n    {24, 24, 24, 24, 126, 60, 24, 0},         // 25\n    {0, 24, 12, 254, 12, 24, 0, 0},           // 26\n    {0, 48, 96, 254, 96, 48, 0, 0},           // 27\n    {0, 0, 192, 192, 192, 254, 0, 0},         // 28\n    {0, 36, 102, 255, 102, 36, 0, 0},         // 29\n    {0, 24, 60, 126, 255, 255, 0, 0},         // 30\n    {0, 255, 255, 126, 60, 24, 0, 0},         // 31\n    {0, 0, 0, 0, 0, 0, 0, 0},                 // 32\n    {24, 60, 60, 24, 24, 0, 24, 0},           // 33\n    {102, 102, 36, 0, 0, 0, 0, 0},            // 34\n    {108, 108, 254, 108, 254, 108, 108, 0},   // 35\n    {24, 62, 96, 60, 6, 124, 24, 0},          // 36\n    {0, 198, 204, 24, 48, 102, 198, 0},       // 37\n    {56, 108, 56, 118, 220, 204, 118, 0},     // 38\n    {24, 24, 48, 0, 0, 0, 0, 0},              // 39\n    {12, 24, 48, 48, 48, 24, 12, 0},          // 40\n    {48, 24, 12, 12, 12, 24, 48, 0},          // 41\n    {0, 102, 60, 231, 60, 102, 0, 0},         // 42\n    {0, 24, 24, 126, 24, 24, 0, 0},           // 43\n    {0, 0, 0, 0, 0, 24, 24, 48},              // 44\n    {0, 0, 0, 126, 0, 0, 0, 0},               // 45\n    {0, 0, 0, 0, 0, 24, 24, 0},               // 46\n    {6, 12, 24, 48, 96, 192, 128, 0},         // 47\n    {124, 198, 206, 222, 246, 230, 124, 0},   // 48\n    {24, 56, 24, 24, 24, 24, 126, 0},         // 49\n    {124, 198, 6, 28, 48, 102, 254, 0},       // 50\n    {124, 198, 6, 60, 6, 198, 124, 0},        // 51\n    {28, 60, 108, 204, 254, 12, 30, 0},       // 52\n    {254, 192, 192, 252, 6, 198, 124, 0},     // 53\n    {56, 96, 192, 252, 198, 198, 124, 0},     // 54\n    {254, 198, 12, 24, 48, 48, 48, 0},        // 55\n    {124, 198, 198, 124, 198, 198, 124, 0},   // 56\n    {124, 198, 198, 126, 6, 12, 120, 0},      // 57\n    {0, 24, 24, 0, 0, 24, 24, 0},             // 58\n    {0, 24, 24, 0, 0, 24, 24, 48},            // 59\n    {6, 12, 24, 48, 24, 12, 6, 0},            // 60\n    {0, 0, 126, 0, 0, 126, 0, 0},             // 61\n    {96, 48, 24, 12, 24, 48, 96, 0},          // 62\n    {124, 198, 12, 24, 24, 0, 24, 0},         // 63\n    {124, 198, 222, 222, 222, 192, 120, 0},   // 64\n    {56, 108, 198, 254, 198, 198, 198, 0},    // 65\n    {252, 102, 102, 124, 102, 102, 252, 0},   // 66\n    {60, 102, 192, 192, 192, 102, 60, 0},     // 67\n    {248, 108, 102, 102, 102, 108, 248, 0},   // 68\n    {254, 98, 104, 120, 104, 98, 254, 0},     // 69\n    {254, 98, 104, 120, 104, 96, 240, 0},     // 70\n    {60, 102, 192, 192, 206, 102, 58, 0},     // 71\n    {198, 198, 198, 254, 198, 198, 198, 0},   // 72\n    {60, 24, 24, 24, 24, 24, 60, 0},          // 73\n    {30, 12, 12, 12, 204, 204, 120, 0},       // 74\n    {230, 102, 108, 120, 108, 102, 230, 0},   // 75\n    {240, 96, 96, 96, 98, 102, 254, 0},       // 76\n    {198, 238, 254, 254, 214, 198, 198, 0},   // 77\n    {198, 230, 246, 222, 206, 198, 198, 0},   // 78\n    {124, 198, 198, 198, 198, 198, 124, 0},   // 79\n    {252, 102, 102, 124, 96, 96, 240, 0},     // 80\n    {124, 198, 198, 198, 198, 206, 124, 14},  // 81\n    {252, 102, 102, 124, 108, 102, 230, 0},   // 82\n    {60, 102, 48, 24, 12, 102, 60, 0},        // 83\n    {126, 126, 90, 24, 24, 24, 60, 0},        // 84\n    {198, 198, 198, 198, 198, 198, 124, 0},   // 85\n    {198, 198, 198, 198, 198, 108, 56, 0},    // 86\n    {198, 198, 198, 214, 214, 254, 108, 0},   // 87\n    {198, 198, 108, 56, 108, 198, 198, 0},    // 88\n    {102, 102, 102, 60, 24, 24, 60, 0},       // 89\n    {254, 198, 140, 24, 50, 102, 254, 0},     // 90\n    {60, 48, 48, 48, 48, 48, 60, 0},          // 91\n    {192, 96, 48, 24, 12, 6, 2, 0},           // 92\n    {60, 12, 12, 12, 12, 12, 60, 0},          // 93\n    {16, 56, 108, 198, 0, 0, 0, 0},           // 94\n    {0, 0, 0, 0, 0, 0, 0, 255},               // 95\n    {48, 24, 12, 0, 0, 0, 0, 0},              // 96\n    {0, 0, 120, 12, 124, 204, 118, 0},        // 97\n    {224, 96, 124, 102, 102, 102, 220, 0},    // 98\n    {0, 0, 124, 198, 192, 198, 124, 0},       // 99\n    {28, 12, 124, 204, 204, 204, 118, 0},     // 100\n    {0, 0, 124, 198, 254, 192, 124, 0},       // 101\n    {60, 102, 96, 248, 96, 96, 240, 0},       // 102\n    {0, 0, 118, 204, 204, 124, 12, 248},      // 103\n    {224, 96, 108, 118, 102, 102, 230, 0},    // 104\n    {24, 0, 56, 24, 24, 24, 60, 0},           // 105\n    {6, 0, 6, 6, 6, 102, 102, 60},            // 106\n    {224, 96, 102, 108, 120, 108, 230, 0},    // 107\n    {56, 24, 24, 24, 24, 24, 60, 0},          // 108\n    {0, 0, 236, 254, 214, 214, 214, 0},       // 109\n    {0, 0, 220, 102, 102, 102, 102, 0},       // 110\n    {0, 0, 124, 198, 198, 198, 124, 0},       // 111\n    {0, 0, 220, 102, 102, 124, 96, 240},      // 112\n    {0, 0, 118, 204, 204, 124, 12, 30},       // 113\n    {0, 0, 220, 118, 96, 96, 240, 0},         // 114\n    {0, 0, 126, 192, 124, 6, 252, 0},         // 115\n    {48, 48, 252, 48, 48, 54, 28, 0},         // 116\n    {0, 0, 204, 204, 204, 204, 118, 0},       // 117\n    {0, 0, 198, 198, 198, 108, 56, 0},        // 118\n    {0, 0, 198, 214, 214, 254, 108, 0},       // 119\n    {0, 0, 198, 108, 56, 108, 198, 0},        // 120\n    {0, 0, 198, 198, 198, 126, 6, 252},       // 121\n    {0, 0, 126, 76, 24, 50, 126, 0},          // 122\n    {14, 24, 24, 112, 24, 24, 14, 0},         // 123\n    {24, 24, 24, 24, 24, 24, 24, 0},          // 124\n    {112, 24, 24, 14, 24, 24, 112, 0},        // 125\n    {118, 220, 0, 0, 0, 0, 0, 0},             // 126\n    {0, 16, 56, 108, 198, 198, 254, 0},       // 127\n    {124, 198, 192, 192, 198, 124, 12, 120},  // 128\n    {204, 0, 204, 204, 204, 204, 118, 0},     // 129\n    {12, 24, 124, 198, 254, 192, 124, 0},     // 130\n    {124, 130, 120, 12, 124, 204, 118, 0},    // 131\n    {198, 0, 120, 12, 124, 204, 118, 0},      // 132\n    {48, 24, 120, 12, 124, 204, 118, 0},      // 133\n    {48, 48, 120, 12, 124, 204, 118, 0},      // 134\n    {0, 0, 126, 192, 192, 126, 12, 56},       // 135\n    {124, 130, 124, 198, 254, 192, 124, 0},   // 136\n    {198, 0, 124, 198, 254, 192, 124, 0},     // 137\n    {48, 24, 124, 198, 254, 192, 124, 0},     // 138\n    {102, 0, 56, 24, 24, 24, 60, 0},          // 139\n    {124, 130, 56, 24, 24, 24, 60, 0},        // 140\n    {48, 24, 0, 56, 24, 24, 60, 0},           // 141\n    {198, 56, 108, 198, 254, 198, 198, 0},    // 142\n    {56, 108, 124, 198, 254, 198, 198, 0},    // 143\n    {24, 48, 254, 192, 248, 192, 254, 0},     // 144\n    {0, 0, 126, 18, 254, 144, 254, 0},        // 145\n    {62, 108, 204, 254, 204, 204, 206, 0},    // 146\n    {124, 130, 124, 198, 198, 198, 124, 0},   // 147\n    {198, 0, 124, 198, 198, 198, 124, 0},     // 148\n    {48, 24, 124, 198, 198, 198, 124, 0},     // 149\n    {120, 132, 0, 204, 204, 204, 118, 0},     // 150\n    {96, 48, 204, 204, 204, 204, 118, 0},     // 151\n    {198, 0, 198, 198, 198, 126, 6, 252},     // 152\n    {198, 56, 108, 198, 198, 108, 56, 0},     // 153\n    {198, 0, 198, 198, 198, 198, 124, 0},     // 154\n    {0, 2, 124, 206, 214, 230, 124, 128},     // 155\n    {56, 108, 100, 240, 96, 102, 252, 0},     // 156\n    {58, 108, 206, 214, 230, 108, 184, 0},    // 157\n    {0, 198, 108, 56, 108, 198, 0, 0},        // 158\n    {14, 27, 24, 60, 24, 216, 112, 0},        // 159\n    {24, 48, 120, 12, 124, 204, 118, 0},      // 160\n    {12, 24, 0, 56, 24, 24, 60, 0},           // 161\n    {12, 24, 124, 198, 198, 198, 124, 0},     // 162\n    {24, 48, 204, 204, 204, 204, 118, 0},     // 163\n    {118, 220, 0, 220, 102, 102, 102, 0},     // 164\n    {118, 220, 0, 230, 246, 222, 206, 0},     // 165\n    {60, 108, 108, 62, 0, 126, 0, 0},         // 166\n    {56, 108, 108, 56, 0, 124, 0, 0},         // 167\n    {24, 0, 24, 24, 48, 99, 62, 0},           // 168\n    {126, 129, 185, 165, 185, 165, 129, 126}, // 169\n    {0, 0, 0, 254, 6, 6, 0, 0},               // 170\n    {99, 230, 108, 126, 51, 102, 204, 15},    // 171\n    {99, 230, 108, 122, 54, 106, 223, 6},     // 172\n    {24, 0, 24, 24, 60, 60, 24, 0},           // 173\n    {0, 51, 102, 204, 102, 51, 0, 0},         // 174\n    {0, 204, 102, 51, 102, 204, 0, 0},        // 175\n    {34, 136, 34, 136, 34, 136, 34, 136},     // 176\n    {85, 170, 85, 170, 85, 170, 85, 170},     // 177\n    {119, 221, 119, 221, 119, 221, 119, 221}, // 178\n    {24, 24, 24, 24, 24, 24, 24, 24},         // 179\n    {24, 24, 56, 248, 56, 24, 24, 24},        // 180\n    {48, 96, 56, 108, 198, 254, 198, 0},      // 181\n    {124, 130, 56, 108, 198, 254, 198, 0},    // 182\n    {24, 12, 56, 108, 198, 254, 198, 0},      // 183\n    {126, 129, 157, 161, 161, 157, 129, 126}, // 184\n    {54, 54, 246, 6, 246, 54, 54, 54},        // 185\n    {54, 54, 54, 54, 54, 54, 54, 54},         // 186\n    {0, 0, 254, 6, 246, 54, 54, 54},          // 187\n    {54, 54, 246, 6, 254, 0, 0, 0},           // 188\n    {24, 24, 126, 192, 192, 126, 24, 24},     // 189\n    {102, 102, 60, 126, 24, 126, 24, 24},     // 190\n    {0, 0, 0, 240, 56, 24, 24, 24},           // 191\n    {24, 24, 28, 15, 0, 0, 0, 0},             // 192\n    {24, 24, 60, 255, 0, 0, 0, 0},            // 193\n    {0, 0, 0, 255, 60, 24, 24, 24},           // 194\n    {48, 48, 56, 63, 56, 48, 48, 48},         // 195\n    {0, 0, 0, 255, 0, 0, 0, 0},               // 196\n    {24, 24, 24, 60, 231, 60, 24, 24},        // 197\n    {240, 120, 120, 120, 60, 60, 60, 28},     // 198\n    {30, 60, 60, 60, 120, 120, 120, 112},     // 199\n    {15, 63, 63, 120, 120, 0, 1, 3},          // 200\n    {192, 224, 240, 240, 240, 240, 240, 224}, // 201\n    {0, 0, 0, 0, 0, 0, 0, 0},                 // 202\n    {0, 0, 0, 0, 0, 0, 0, 0},                 // 203\n    {30, 30, 14, 15, 15, 7, 7, 0},            // 204\n    {240, 240, 224, 224, 192, 192, 192, 0},   // 205\n    {6, 13, 27, 55, 47, 127, 126, 30},        // 206\n    {0, 252, 255, 255, 143, 119, 243, 3},     // 207\n    {0, 1, 7, 143, 143, 207, 207, 199},       // 208\n    {0, 248, 254, 254, 31, 15, 192, 248},     // 209\n    {0, 0, 0, 0, 0, 0, 0, 0},                 // 210\n    {0, 0, 0, 0, 0, 0, 0, 0},                 // 211\n    {30, 30, 30, 31, 15, 7, 7, 1},            // 212\n    {3, 3, 3, 7, 143, 255, 254, 252},         // 213\n    {195, 192, 192, 207, 143, 7, 7, 1},       // 214\n    {254, 255, 31, 15, 143, 254, 254, 248},   // 215\n    {102, 0, 60, 24, 24, 24, 60, 0},          // 216\n    {24, 24, 56, 240, 0, 0, 0, 0},            // 217\n    {0, 0, 0, 15, 28, 24, 24, 24},            // 218\n    {255, 255, 255, 255, 255, 255, 255, 255}, // 219\n    {0, 0, 0, 0, 255, 255, 255, 255},         // 220\n    {24, 24, 24, 0, 0, 24, 24, 24},           // 221\n    {48, 24, 60, 24, 24, 24, 60, 0},          // 222\n    {255, 255, 255, 255, 0, 0, 0, 0},         // 223\n    {0, 0, 0, 0, 0, 0, 0, 255},               // 224\n    {0, 0, 0, 0, 0, 255, 0, 255},             // 225\n    {0, 0, 0, 255, 0, 255, 0, 255},           // 226\n    {0, 255, 0, 255, 0, 255, 0, 255},         // 227\n    {0, 255, 0, 255, 0, 255, 0, 0},           // 228\n    {0, 255, 0, 255, 0, 0, 0, 0},             // 229\n    {0, 255, 0, 0, 0, 0, 0, 0},               // 230\n    {224, 128, 0, 0, 0, 0, 128, 224},         // 231\n    {248, 254, 255, 255, 255, 255, 254, 248}, // 232\n    {24, 48, 198, 198, 198, 198, 124, 0},     // 233\n    {124, 130, 0, 198, 198, 198, 124, 0},     // 234\n    {96, 48, 198, 198, 198, 198, 124, 0},     // 235\n    {24, 48, 198, 198, 198, 126, 6, 252},     // 236\n    {12, 24, 102, 102, 60, 24, 60, 0},        // 237\n    {255, 0, 0, 0, 0, 0, 0, 0},               // 238\n    {12, 24, 48, 0, 0, 0, 0, 0},              // 239\n    {0, 0, 0, 126, 0, 0, 0, 0},               // 240\n    {24, 24, 126, 24, 24, 0, 126, 0},         // 241\n    {0, 0, 0, 0, 0, 255, 0, 255},             // 242\n    {225, 50, 228, 58, 246, 42, 95, 134},     // 243\n    {127, 219, 219, 123, 27, 27, 27, 0},      // 244\n    {62, 97, 60, 102, 102, 60, 134, 124},     // 245\n    {0, 24, 0, 126, 0, 24, 0, 0},             // 246\n    {0, 0, 0, 0, 0, 24, 12, 56},              // 247\n    {56, 108, 108, 56, 0, 0, 0, 0},           // 248\n    {0, 198, 0, 0, 0, 0, 0, 0},               // 249\n    {0, 0, 0, 24, 0, 0, 0, 0},                // 250\n    {24, 56, 24, 24, 60, 0, 0, 0},            // 251\n    {120, 12, 56, 12, 120, 0, 0, 0},          // 252\n    {120, 12, 24, 48, 124, 0, 0, 0},          // 253\n    {0, 0, 60, 60, 60, 60, 0, 0},             // 254\n    {0, 0, 0, 0, 0, 0, 0, 0}};                // 255\n#endif\n"
  },
  {
    "path": "src/gui/sdlkeys.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n *  This file is based upon Bochs.\n *\n *  Copyright (C) 2002  MandrakeSoft S.A.\n *\n *    MandrakeSoft S.A.\n *    43, rue d'Aboukir\n *    75002 Paris - France\n *    http://www.linux-mandrake.com/\n *    http://www.mandrakesoft.com/\n *\n *  This library is free software; you can redistribute it and/or\n *  modify it under the terms of the GNU Lesser General Public\n *  License as published by the Free Software Foundation; either\n *  version 2 of the License, or (at your option) any later version.\n *\n *  This library is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n *  Lesser General Public License for more details.\n *\n *  You should have received a copy of the GNU Lesser General Public\n *  License along with this library; if not, write to the Free Software\n *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA\n */\n\nDEF_SDL_KEY(SDLK_UNKNOWN)\nDEF_SDL_KEY(SDLK_FIRST)\nDEF_SDL_KEY(SDLK_BACKSPACE)\nDEF_SDL_KEY(SDLK_TAB)\nDEF_SDL_KEY(SDLK_CLEAR)\nDEF_SDL_KEY(SDLK_RETURN)\nDEF_SDL_KEY(SDLK_PAUSE)\nDEF_SDL_KEY(SDLK_ESCAPE)\nDEF_SDL_KEY(SDLK_SPACE)\nDEF_SDL_KEY(SDLK_EXCLAIM)\nDEF_SDL_KEY(SDLK_QUOTEDBL)\nDEF_SDL_KEY(SDLK_HASH)\nDEF_SDL_KEY(SDLK_DOLLAR)\nDEF_SDL_KEY(SDLK_AMPERSAND)\nDEF_SDL_KEY(SDLK_QUOTE)\nDEF_SDL_KEY(SDLK_LEFTPAREN)\nDEF_SDL_KEY(SDLK_RIGHTPAREN)\nDEF_SDL_KEY(SDLK_ASTERISK)\nDEF_SDL_KEY(SDLK_PLUS)\nDEF_SDL_KEY(SDLK_COMMA)\nDEF_SDL_KEY(SDLK_MINUS)\nDEF_SDL_KEY(SDLK_PERIOD)\nDEF_SDL_KEY(SDLK_SLASH)\nDEF_SDL_KEY(SDLK_0)\nDEF_SDL_KEY(SDLK_1)\nDEF_SDL_KEY(SDLK_2)\nDEF_SDL_KEY(SDLK_3)\nDEF_SDL_KEY(SDLK_4)\nDEF_SDL_KEY(SDLK_5)\nDEF_SDL_KEY(SDLK_6)\nDEF_SDL_KEY(SDLK_7)\nDEF_SDL_KEY(SDLK_8)\nDEF_SDL_KEY(SDLK_9)\nDEF_SDL_KEY(SDLK_COLON)\nDEF_SDL_KEY(SDLK_SEMICOLON)\nDEF_SDL_KEY(SDLK_LESS)\nDEF_SDL_KEY(SDLK_EQUALS)\nDEF_SDL_KEY(SDLK_GREATER)\nDEF_SDL_KEY(SDLK_QUESTION)\nDEF_SDL_KEY(SDLK_AT)\n\n// DEF_SDL_KEY( /*  )\n// DEF_SDL_KEY( Skip uppercase letters )\n// DEF_SDL_KEY( */ )\nDEF_SDL_KEY(SDLK_LEFTBRACKET)\nDEF_SDL_KEY(SDLK_BACKSLASH)\nDEF_SDL_KEY(SDLK_RIGHTBRACKET)\nDEF_SDL_KEY(SDLK_CARET)\nDEF_SDL_KEY(SDLK_UNDERSCORE)\nDEF_SDL_KEY(SDLK_BACKQUOTE)\nDEF_SDL_KEY(SDLK_a)\nDEF_SDL_KEY(SDLK_b)\nDEF_SDL_KEY(SDLK_c)\nDEF_SDL_KEY(SDLK_d)\nDEF_SDL_KEY(SDLK_e)\nDEF_SDL_KEY(SDLK_f)\nDEF_SDL_KEY(SDLK_g)\nDEF_SDL_KEY(SDLK_h)\nDEF_SDL_KEY(SDLK_i)\nDEF_SDL_KEY(SDLK_j)\nDEF_SDL_KEY(SDLK_k)\nDEF_SDL_KEY(SDLK_l)\nDEF_SDL_KEY(SDLK_m)\nDEF_SDL_KEY(SDLK_n)\nDEF_SDL_KEY(SDLK_o)\nDEF_SDL_KEY(SDLK_p)\nDEF_SDL_KEY(SDLK_q)\nDEF_SDL_KEY(SDLK_r)\nDEF_SDL_KEY(SDLK_s)\nDEF_SDL_KEY(SDLK_t)\nDEF_SDL_KEY(SDLK_u)\nDEF_SDL_KEY(SDLK_v)\nDEF_SDL_KEY(SDLK_w)\nDEF_SDL_KEY(SDLK_x)\nDEF_SDL_KEY(SDLK_y)\nDEF_SDL_KEY(SDLK_z)\nDEF_SDL_KEY(SDLK_DELETE)\nDEF_SDL_KEY(SDLK_WORLD_0)\nDEF_SDL_KEY(SDLK_WORLD_1)\nDEF_SDL_KEY(SDLK_WORLD_2)\nDEF_SDL_KEY(SDLK_WORLD_3)\nDEF_SDL_KEY(SDLK_WORLD_4)\nDEF_SDL_KEY(SDLK_WORLD_5)\nDEF_SDL_KEY(SDLK_WORLD_6)\nDEF_SDL_KEY(SDLK_WORLD_7)\nDEF_SDL_KEY(SDLK_WORLD_8)\nDEF_SDL_KEY(SDLK_WORLD_9)\nDEF_SDL_KEY(SDLK_WORLD_10)\nDEF_SDL_KEY(SDLK_WORLD_11)\nDEF_SDL_KEY(SDLK_WORLD_12)\nDEF_SDL_KEY(SDLK_WORLD_13)\nDEF_SDL_KEY(SDLK_WORLD_14)\nDEF_SDL_KEY(SDLK_WORLD_15)\nDEF_SDL_KEY(SDLK_WORLD_16)\nDEF_SDL_KEY(SDLK_WORLD_17)\nDEF_SDL_KEY(SDLK_WORLD_18)\nDEF_SDL_KEY(SDLK_WORLD_19)\nDEF_SDL_KEY(SDLK_WORLD_20)\nDEF_SDL_KEY(SDLK_WORLD_21)\nDEF_SDL_KEY(SDLK_WORLD_22)\nDEF_SDL_KEY(SDLK_WORLD_23)\nDEF_SDL_KEY(SDLK_WORLD_24)\nDEF_SDL_KEY(SDLK_WORLD_25)\nDEF_SDL_KEY(SDLK_WORLD_26)\nDEF_SDL_KEY(SDLK_WORLD_27)\nDEF_SDL_KEY(SDLK_WORLD_28)\nDEF_SDL_KEY(SDLK_WORLD_29)\nDEF_SDL_KEY(SDLK_WORLD_30)\nDEF_SDL_KEY(SDLK_WORLD_31)\nDEF_SDL_KEY(SDLK_WORLD_32)\nDEF_SDL_KEY(SDLK_WORLD_33)\nDEF_SDL_KEY(SDLK_WORLD_34)\nDEF_SDL_KEY(SDLK_WORLD_35)\nDEF_SDL_KEY(SDLK_WORLD_36)\nDEF_SDL_KEY(SDLK_WORLD_37)\nDEF_SDL_KEY(SDLK_WORLD_38)\nDEF_SDL_KEY(SDLK_WORLD_39)\nDEF_SDL_KEY(SDLK_WORLD_40)\nDEF_SDL_KEY(SDLK_WORLD_41)\nDEF_SDL_KEY(SDLK_WORLD_42)\nDEF_SDL_KEY(SDLK_WORLD_43)\nDEF_SDL_KEY(SDLK_WORLD_44)\nDEF_SDL_KEY(SDLK_WORLD_45)\nDEF_SDL_KEY(SDLK_WORLD_46)\nDEF_SDL_KEY(SDLK_WORLD_47)\nDEF_SDL_KEY(SDLK_WORLD_48)\nDEF_SDL_KEY(SDLK_WORLD_49)\nDEF_SDL_KEY(SDLK_WORLD_50)\nDEF_SDL_KEY(SDLK_WORLD_51)\nDEF_SDL_KEY(SDLK_WORLD_52)\nDEF_SDL_KEY(SDLK_WORLD_53)\nDEF_SDL_KEY(SDLK_WORLD_54)\nDEF_SDL_KEY(SDLK_WORLD_55)\nDEF_SDL_KEY(SDLK_WORLD_56)\nDEF_SDL_KEY(SDLK_WORLD_57)\nDEF_SDL_KEY(SDLK_WORLD_58)\nDEF_SDL_KEY(SDLK_WORLD_59)\nDEF_SDL_KEY(SDLK_WORLD_60)\nDEF_SDL_KEY(SDLK_WORLD_61)\nDEF_SDL_KEY(SDLK_WORLD_62)\nDEF_SDL_KEY(SDLK_WORLD_63)\nDEF_SDL_KEY(SDLK_WORLD_64)\nDEF_SDL_KEY(SDLK_WORLD_65)\nDEF_SDL_KEY(SDLK_WORLD_66)\nDEF_SDL_KEY(SDLK_WORLD_67)\nDEF_SDL_KEY(SDLK_WORLD_68)\nDEF_SDL_KEY(SDLK_WORLD_69)\nDEF_SDL_KEY(SDLK_WORLD_70)\nDEF_SDL_KEY(SDLK_WORLD_71)\nDEF_SDL_KEY(SDLK_WORLD_72)\nDEF_SDL_KEY(SDLK_WORLD_73)\nDEF_SDL_KEY(SDLK_WORLD_74)\nDEF_SDL_KEY(SDLK_WORLD_75)\nDEF_SDL_KEY(SDLK_WORLD_76)\nDEF_SDL_KEY(SDLK_WORLD_77)\nDEF_SDL_KEY(SDLK_WORLD_78)\nDEF_SDL_KEY(SDLK_WORLD_79)\nDEF_SDL_KEY(SDLK_WORLD_80)\nDEF_SDL_KEY(SDLK_WORLD_81)\nDEF_SDL_KEY(SDLK_WORLD_82)\nDEF_SDL_KEY(SDLK_WORLD_83)\nDEF_SDL_KEY(SDLK_WORLD_84)\nDEF_SDL_KEY(SDLK_WORLD_85)\nDEF_SDL_KEY(SDLK_WORLD_86)\nDEF_SDL_KEY(SDLK_WORLD_87)\nDEF_SDL_KEY(SDLK_WORLD_88)\nDEF_SDL_KEY(SDLK_WORLD_89)\nDEF_SDL_KEY(SDLK_WORLD_90)\nDEF_SDL_KEY(SDLK_WORLD_91)\nDEF_SDL_KEY(SDLK_WORLD_92)\nDEF_SDL_KEY(SDLK_WORLD_93)\nDEF_SDL_KEY(SDLK_WORLD_94)\nDEF_SDL_KEY(SDLK_WORLD_95)\nDEF_SDL_KEY(SDLK_KP0)\nDEF_SDL_KEY(SDLK_KP1)\nDEF_SDL_KEY(SDLK_KP2)\nDEF_SDL_KEY(SDLK_KP3)\nDEF_SDL_KEY(SDLK_KP4)\nDEF_SDL_KEY(SDLK_KP5)\nDEF_SDL_KEY(SDLK_KP6)\nDEF_SDL_KEY(SDLK_KP7)\nDEF_SDL_KEY(SDLK_KP8)\nDEF_SDL_KEY(SDLK_KP9)\nDEF_SDL_KEY(SDLK_KP_PERIOD)\nDEF_SDL_KEY(SDLK_KP_DIVIDE)\nDEF_SDL_KEY(SDLK_KP_MULTIPLY)\nDEF_SDL_KEY(SDLK_KP_MINUS)\nDEF_SDL_KEY(SDLK_KP_PLUS)\nDEF_SDL_KEY(SDLK_KP_ENTER)\nDEF_SDL_KEY(SDLK_KP_EQUALS)\nDEF_SDL_KEY(SDLK_UP)\nDEF_SDL_KEY(SDLK_DOWN)\nDEF_SDL_KEY(SDLK_RIGHT)\nDEF_SDL_KEY(SDLK_LEFT)\nDEF_SDL_KEY(SDLK_INSERT)\nDEF_SDL_KEY(SDLK_HOME)\nDEF_SDL_KEY(SDLK_END)\nDEF_SDL_KEY(SDLK_PAGEUP)\nDEF_SDL_KEY(SDLK_PAGEDOWN)\nDEF_SDL_KEY(SDLK_F1)\nDEF_SDL_KEY(SDLK_F2)\nDEF_SDL_KEY(SDLK_F3)\nDEF_SDL_KEY(SDLK_F4)\nDEF_SDL_KEY(SDLK_F5)\nDEF_SDL_KEY(SDLK_F6)\nDEF_SDL_KEY(SDLK_F7)\nDEF_SDL_KEY(SDLK_F8)\nDEF_SDL_KEY(SDLK_F9)\nDEF_SDL_KEY(SDLK_F10)\nDEF_SDL_KEY(SDLK_F11)\nDEF_SDL_KEY(SDLK_F12)\nDEF_SDL_KEY(SDLK_F13)\nDEF_SDL_KEY(SDLK_F14)\nDEF_SDL_KEY(SDLK_F15)\nDEF_SDL_KEY(SDLK_NUMLOCK)\nDEF_SDL_KEY(SDLK_CAPSLOCK)\nDEF_SDL_KEY(SDLK_SCROLLOCK)\nDEF_SDL_KEY(SDLK_RSHIFT)\nDEF_SDL_KEY(SDLK_LSHIFT)\nDEF_SDL_KEY(SDLK_RCTRL)\nDEF_SDL_KEY(SDLK_LCTRL)\nDEF_SDL_KEY(SDLK_RALT)\nDEF_SDL_KEY(SDLK_LALT)\nDEF_SDL_KEY(SDLK_RMETA)\nDEF_SDL_KEY(SDLK_LMETA)\nDEF_SDL_KEY(SDLK_LSUPER)\nDEF_SDL_KEY(SDLK_RSUPER)\nDEF_SDL_KEY(SDLK_MODE)\nDEF_SDL_KEY(SDLK_COMPOSE)\nDEF_SDL_KEY(SDLK_HELP)\nDEF_SDL_KEY(SDLK_PRINT)\nDEF_SDL_KEY(SDLK_SYSREQ)\nDEF_SDL_KEY(SDLK_BREAK)\nDEF_SDL_KEY(SDLK_MENU)\nDEF_SDL_KEY(SDLK_POWER)\nDEF_SDL_KEY(SDLK_EURO)\nDEF_SDL_KEY(SDLK_UNDO)\n"
  },
  {
    "path": "src/gui/vga.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n *  This file is based upon Bochs.\n *\n *  Copyright (C) 2002  MandrakeSoft S.A.\n *\n *    MandrakeSoft S.A.\n *    43, rue d'Aboukir\n *    75002 Paris - France\n *    http://www.linux-mandrake.com/\n *    http://www.mandrakesoft.com/\n *\n *  This library is free software; you can redistribute it and/or\n *  modify it under the terms of the GNU Lesser General Public\n *  License as published by the Free Software Foundation; either\n *  version 2 of the License, or (at your option) any later version.\n *\n *  This library is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n *  Lesser General Public License for more details.\n *\n *  You should have received a copy of the GNU Lesser General Public\n *  License along with this library; if not, write to the Free Software\n *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA\n */\n\n#ifndef BX_IODEV_VGA_H\n#define BX_IODEV_VGA_H\n\n// Make colour\n#define MAKE_COLOUR                                                            \\\n  (red, red_shiftfrom, red_shiftto, red_mask, green, green_shiftfrom,          \\\n   green_shiftto, green_mask, blue, blue_shiftfrom, blue_shiftto,              \\\n   blue_mask)(((((red_shiftto) > (red_shiftfrom))                              \\\n                    ? (red) << ((red_shiftto) - (red_shiftfrom))               \\\n                    : (red) >> ((red_shiftfrom) - (red_shiftto))) &            \\\n               (red_mask)) |                                                   \\\n              ((((green_shiftto) > (green_shiftfrom))                          \\\n                    ? (green) << ((green_shiftto) - (green_shiftfrom))         \\\n                    : (green) >> ((green_shiftfrom) - (green_shiftto))) &      \\\n               (green_mask)) |                                                 \\\n              ((((blue_shiftto) > (blue_shiftfrom))                            \\\n                    ? (blue) << ((blue_shiftto) - (blue_shiftfrom))            \\\n                    : (blue) >> ((blue_shiftfrom) - (blue_shiftto))) &         \\\n               (blue_mask)))\n#if BX_SUPPORT_VBE\n#define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB 8\n#define VBE_DISPI_4BPP_PLANE_SHIFT 21\n\n#define VBE_DISPI_BANK_ADDRESS 0xA0000\n#define VBE_DISPI_BANK_SIZE_KB 64\n\n#define VBE_DISPI_MAX_XRES 1600\n#define VBE_DISPI_MAX_YRES 1200\n#define VBE_DISPI_MAX_BPP 32\n\n#define VBE_DISPI_IOPORT_INDEX 0x01CE\n#define VBE_DISPI_IOPORT_DATA 0x01CF\n\n#define VBE_DISPI_IOPORT_INDEX_OLD 0xFF80\n#define VBE_DISPI_IOPORT_DATA_OLD 0xFF81\n\n#define VBE_DISPI_INDEX_ID 0x0\n#define VBE_DISPI_INDEX_XRES 0x1\n#define VBE_DISPI_INDEX_YRES 0x2\n#define VBE_DISPI_INDEX_BPP 0x3\n#define VBE_DISPI_INDEX_ENABLE 0x4\n#define VBE_DISPI_INDEX_BANK 0x5\n#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6\n#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7\n#define VBE_DISPI_INDEX_X_OFFSET 0x8\n#define VBE_DISPI_INDEX_Y_OFFSET 0x9\n\n#define VBE_DISPI_ID0 0xB0C0\n#define VBE_DISPI_ID1 0xB0C1\n#define VBE_DISPI_ID2 0xB0C2\n#define VBE_DISPI_ID3 0xB0C3\n#define VBE_DISPI_ID4 0xB0C4\n\n#define VBE_DISPI_BPP_4 0x04\n#define VBE_DISPI_BPP_8 0x08\n#define VBE_DISPI_BPP_15 0x0F\n#define VBE_DISPI_BPP_16 0x10\n#define VBE_DISPI_BPP_24 0x18\n#define VBE_DISPI_BPP_32 0x20\n\n#define VBE_DISPI_DISABLED 0x00\n#define VBE_DISPI_ENABLED 0x01\n#define VBE_DISPI_GETCAPS 0x02\n#define VBE_DISPI_8BIT_DAC 0x20\n#define VBE_DISPI_LFB_ENABLED 0x40\n#define VBE_DISPI_NOCLEARMEM 0x80\n\n#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000\n\n#define VBE_DISPI_TOTAL_VIDEO_MEMORY_KB (VBE_DISPI_TOTAL_VIDEO_MEMORY_MB * 1024)\n#define VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES                                     \\\n  (VBE_DISPI_TOTAL_VIDEO_MEMORY_KB * 1024)\n#define BX_MAX_XRES VBE_DISPI_MAX_XRES\n#define BX_MAX_YRES VBE_DISPI_MAX_YRES\n\n#elif BX_SUPPORT_CLGD54XX\n#define BX_MAX_XRES 1280\n#define BX_MAX_YRES 1024\n\n#else\n#define BX_MAX_XRES 800\n#define BX_MAX_YRES 600\n#endif // BX_SUPPORT_VBE\n#define X_TILESIZE 16\n#define Y_TILESIZE 24\n#define BX_NUM_X_TILES (BX_MAX_XRES / X_TILESIZE)\n#define BX_NUM_Y_TILES (BX_MAX_YRES / Y_TILESIZE)\n\n// Support varying number of rows of text.  This used to\n// be limited to only 25 lines.\n#define BX_MAX_TEXT_LINES 100\n\n//  struct {\n//    u16  vbe_cur_dispi;\n//    u16  vbe_xres;\n//    u16  vbe_yres;\n//    u16  vbe_bpp;\n//    u16  vbe_max_xres;\n//    u16  vbe_max_yres;\n//    u16  vbe_max_bpp;\n//    u16  vbe_bank;\n//    bool vbe_enabled;\n//    u16  vbe_curindex;\n//    u32  vbe_visible_screen_size; /**< in bytes */\n//    u16  vbe_offset_x;\t\t /**< Virtual screen x start (in pixels)\n//    */ u16  vbe_offset_y;\t\t /**< Virtual screen y start (in pixels)\n//    */ u16  vbe_virtual_xres; u16  vbe_virtual_yres; u32  vbe_virtual_start;\n//    /**< For dealing with bpp>8, this is where the virtual screen starts. */\n//    u8   vbe_bpp_multiplier;  /**< We have to save this b/c sometimes we need\n//    to recalculate stuff with it. */ bool vbe_lfb_enabled; bool\n//    vbe_get_capabilities; bool vbe_8bit_dac;\n//  } s;  // state information\n#endif\n"
  },
  {
    "path": "src/lockstep.cpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#include \"StdAfx.hpp\"\n\n#include \"lockstep.hpp\"\n\n#if defined(IDB) && (defined(LS_MASTER) || defined(LS_SLAVE))\nint ls_Socket;\n\n#if defined(LS_MASTER)\nchar ls_IP[30];\n#else\nint ls_listenSocket;\n#endif\nvoid lockstep_init() {\n  struct sockaddr_in Address;\n\n#if defined(_WIN32)\n\n  // Windows Sockets only work after calling WSAStartup.\n  WSADATA wsa;\n  WSAStartup(0x0101, &wsa);\n#endif // defined (_WIN32)\n#if defined(LS_MASTER)\n  int result = -1;\n  printf(\"Please enter the IP address of the lockstep slave to connect to: \");\n  scanf(\"%s\", ls_IP);\n\n  ls_Socket = socket(AF_INET, SOCK_STREAM, 0);\n\n  Address.sin_family = AF_INET;\n  Address.sin_port = htons(21260);\n  Address.sin_addr.s_addr = inet_addr(ls_IP);\n\n  printf(\"%%LST-I-WAIT: Waiting to initiate lockstep connection to %s.\\n\",\n         ls_IP);\n\n  while (result == -1)\n    result = connect(ls_Socket, (struct sockaddr *)&Address,\n                     sizeof(struct sockaddr));\n\n#else // defined(LS_MASTER)\n  socklen_t nAddressSize = sizeof(struct sockaddr_in);\n\n  ls_listenSocket = socket(AF_INET, SOCK_STREAM, 0);\n  if (ls_listenSocket == INVALID_SOCKET)\n    printf(\"%%LST-F-NOSOCK Could not open lockstep socket to listen on!\\n\");\n\n  Address.sin_addr.s_addr = INADDR_ANY;\n  Address.sin_port = htons(21260);\n  Address.sin_family = AF_INET;\n\n  int optval = 1;\n  setsockopt(ls_listenSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&optval,\n             sizeof(optval));\n  bind(ls_listenSocket, (struct sockaddr *)&Address, sizeof(Address));\n  listen(ls_listenSocket, 1);\n\n  printf(\"%%LST-I-WAIT: Waiting for lockstep connection on port %d.\\n\", 21260);\n\n  //  Wait until we have a connection\n  ls_Socket = INVALID_SOCKET;\n  while (ls_Socket == INVALID_SOCKET)\n    ls_Socket =\n        accept(ls_listenSocket, (struct sockaddr *)&Address, &nAddressSize);\n#endif\n  printf(\"%%LST-I-INIT: Lock-step connection initialized.\\n\");\n}\n\nvoid lockstep_sync_m2s(char *s) {\n#if defined(LS_MASTER)\n  send(ls_Socket, s, strlen(s) + 1, 0);\n\n#else\n  fd_set readset;\n  unsigned char buffer[1000];\n  ssize_t size;\n  struct timeval tv;\n\n  buffer[0] = 0;\n\n  while (strcmp((char *)buffer, s)) {\n    FD_ZERO(&readset);\n    FD_SET(ls_Socket, &readset);\n    tv.tv_sec = 30;\n    tv.tv_usec = 0;\n    while (select(ls_Socket + 1, &readset, NULL, NULL, &tv) <= 0)\n      ;\n    size = recv(ls_Socket, (char *)buffer, 999, 0);\n    buffer[size + 1] = 0; // force null termination.\n  }\n#endif\n}\n\nvoid lockstep_sync_s2m(char *s) {\n#if defined(LS_SLAVE)\n  send(ls_Socket, s, strlen(s) + 1, 0);\n\n#else\n  fd_set readset;\n  unsigned char buffer[1000];\n  ssize_t size;\n  struct timeval tv;\n\n  buffer[0] = 0;\n\n  while (strcmp((char *)buffer, s)) {\n    FD_ZERO(&readset);\n    FD_SET(ls_Socket, &readset);\n    tv.tv_sec = 30;\n    tv.tv_usec = 0;\n    while (select(ls_Socket + 1, &readset, NULL, NULL, &tv) <= 0)\n      ;\n    size = recv(ls_Socket, (char *)buffer, 999, 0);\n    buffer[size + 1] = 0; // force null termination.\n  }\n#endif\n}\n\nchar cmpbuffer[10000];\n\nvoid lockstep_compare(char *s) {\n#if defined(LS_SLAVE)\n  send(ls_Socket, s, strlen(s) + 1, 0);\n\n#else\n  fd_set readset;\n  ssize_t size;\n  struct timeval tv;\n  char *b1;\n  char *b2;\n  char *n1;\n  char *n2;\n\n  FD_ZERO(&readset);\n  FD_SET(ls_Socket, &readset);\n  tv.tv_sec = 30;\n  tv.tv_usec = 0;\n  while (select(ls_Socket + 1, &readset, NULL, NULL, &tv) <= 0)\n    ;\n  size = recv(ls_Socket, cmpbuffer, 99999, 0);\n  cmpbuffer[size + 1] = 0; // force null termination.\n\n  //  printf(\"Comparing <%s> AND <%s>\\n\",s,buffer);\n  b1 = s;\n  b2 = cmpbuffer;\n\n  while (b1 && b2) {\n    n1 = strchr(b1, '\\n');\n    n2 = strchr(b2, '\\n');\n    if (n1)\n      *n1++ = '\\0';\n    if (n2)\n      *n2++ = '\\0';\n    if (strcmp(b1, b2)) {\n      printf(\n          \"*************** LOCKSTEP: DIFFERENCE ENCOUNTERED ***************\\n\");\n      printf(\" local system: %s\\n\", b1);\n      printf(\"remote system: %s\\n\", b2);\n      printf(\n          \"***************     PRESS ENTER TO CONTINUE      ***************\\n\");\n      getc(stdin);\n    }\n\n    b1 = n1;\n    b2 = n2;\n  }\n#endif\n}\n\nvoid lockstep_send(char *s) {\n\n  //  printf(\"<send %s>\",s);\n  fd_set readset;\n  ssize_t size;\n  struct timeval tv;\n\n  char sConf[100] = \"\";\n  while (strcmp(sConf, \"ACK\")) {\n    send(ls_Socket, s, strlen(s) + 1, 0);\n    FD_ZERO(&readset);\n    FD_SET(ls_Socket, &readset);\n    tv.tv_sec = 5;\n    tv.tv_usec = 0;\n    if (select(ls_Socket + 1, &readset, NULL, NULL, &tv) > 0) {\n      size = recv(ls_Socket, sConf, 99, 0);\n      sConf[size + 1] = 0; // force null termination.\n    }\n  }\n}\n\nvoid lockstep_receive(char *s, int sz) {\n  fd_set readset;\n  ssize_t size = 0;\n  struct timeval tv;\n  s[0] = 'R';\n\n  while (!size) {\n    FD_ZERO(&readset);\n    FD_SET(ls_Socket, &readset);\n    tv.tv_sec = 30;\n    tv.tv_usec = 0;\n    if (select(ls_Socket + 1, &readset, NULL, NULL, &tv) > 0) {\n      size = recv(ls_Socket, s, sz - 1, 0);\n      s[size + 1] = 0; // force null termination.\n    }\n  }\n\n  send(ls_Socket, \"ACK\", 4, 0);\n}\n#endif // defined(IDB) && (defined(LS_MASTER) || defined(LS_SLAVE))\n"
  },
  {
    "path": "src/lockstep.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_LOCKSTEP_H)\n#define INCLUDED_LOCKSTEP_H\n\n#include \"telnet.hpp\"\n\n#if defined(IDB) && (defined(LS_MASTER) || defined(LS_SLAVE))\nextern int ls_Socket;\n\n#if defined(LS_MASTER)\nextern char ls_IP[30];\n#else\nextern int ls_listenSocket;\n#endif\nvoid lockstep_init();\nvoid lockstep_sync_m2s(char *s);\nvoid lockstep_sync_s2m(char *s);\nvoid lockstep_compare(char *s);\nvoid lockstep_send(char *s);\nvoid lockstep_receive(char *s, int sz);\n#endif // defined(IDB) && (defined(LS_MASTER) || defined(LS_SLAVE))\n#endif // !defined(INCLUDED_LOCKSTEP_H)\n"
  },
  {
    "path": "src/make_unique.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Copyright (C) 2020  Remy van Elst\n * Website: https://github.com/lenticularis39/axpbox\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#ifndef AXPBOX_MAKE_UNIQUE_H\n#define AXPBOX_MAKE_UNIQUE_H\n#include <memory>\n/* Allow C++11 code to use std::make_unique\n * example ifdef:  #if __cplusplus < 201402L\n */\nnamespace std\n{\ntemplate<typename T, typename ...Args>\nstd::unique_ptr<T> make_unique( Args&& ...args )\n{\n  return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) );\n}\n}\n#endif // AXPBOX_MAKE_UNIQUE_H\n"
  },
  {
    "path": "src/telnet.hpp",
    "content": "/* AXPbox Alpha Emulator\n * Copyright (C) 2020 Tomáš Glozar\n * Website: https://github.com/lenticularis39/axpbox\n *\n * Forked from: ES40 emulator\n * Copyright (C) 2007-2008 by the ES40 Emulator Project\n * Copyright (C) 2007 by Camiel Vanderhoeven\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,\n * USA.\n *\n * Although this is not required, the author would appreciate being notified of,\n * and receiving any modifications you may make to the source code that might\n * serve the general public.\n */\n\n#if !defined(INCLUDED_TELNET_H)\n#define INCLUDED_TELNET_H\n\n#if defined(HAVE_WINSOCK2_H)\n#include <winsock2.h>\n#endif\n\n#if defined(HAVE_WS2TCPIP_H)\n#include <ws2tcpip.h>\n#endif\n\n#if defined(HAVE_SYS_SOCKET_H)\n#include <sys/socket.h>\n#endif\n\n#if defined(HAVE_SOCKET_H)\n#include <socket.h>\n#endif\n\n#if defined(HAVE_IN_H)\n#include <in.h>\n#endif\n\n#if defined(HAVE_INET_H)\n#include <inet.h>\n#endif\n\n#if defined(HAVE_ARPA_INET_H)\n#include <arpa/inet.h>\n#endif\n\n#if defined(HAVE_ARPA_TELNET_H)\n#include <arpa/telnet.h>\n#endif\n\n#if defined(HAVE_NETINET_IN_H)\n#include <netinet/in.h>\n#endif\n\n#if defined(HAVE_SYS_SELECT_H)\n#include <sys/select.h>\n#endif\n\n#if defined(HAVE_ERRNO_H)\n#include <errno.h>\n#endif\n\n#if defined(HAVE_FCNTL_H)\n#include <fcntl.h>\n#endif\n\n#if defined(HAVE_SIGNAL_H)\n#include <signal.h>\n#endif\n\n#if defined(_WIN32) && !defined(__GNUWIN32__)\ntypedef size_t ssize_t;\ntypedef int socklen_t;\n#endif // _WIN32\n\n#if defined(__VMS)\n#define INVALID_SOCKET -1\ntypedef unsigned int socklen_t;\n#endif // __VMS\n\n#if defined(_WIN32) || defined(__VMS)\n#define IAC 255   /* interpret as command: */\n#define DONT 254  /* you are not to use option */\n#define DO 253    /* please, you use option */\n#define WONT 252  /* I won't use option */\n#define WILL 251  /* I will use option */\n#define SB 250    /* interpret as subnegotiation */\n#define GA 249    /* you may reverse the line */\n#define EL 248    /* erase the current line */\n#define EC 247    /* erase the current character */\n#define AYT 246   /* are you there */\n#define AO 245    /* abort output--but let prog finish */\n#define IP 244    /* interrupt process--permanently */\n#define BREAK 243 /* break */\n#define DM 242    /* data mark--for connect. cleaning */\n#define NOP 241   /* nop */\n#define SE 240    /* end sub negotiation */\n#define EOR 239   /* end of record (transparent mode) */\n#define ABORT 238 /* Abort process */\n#define SUSP 237  /* Suspend process */\n#define xEOF 236  /* End of file: EOF is already used... */\n\n#define SYNCH 242       /* for telfunc calls */\n#define TELOPT_ECHO 1   /* echo */\n#define TELOPT_SGA 3    /* suppress go ahead */\n#define TELOPT_NAWS 31  /* window size */\n#define TELOPT_LFLOW 33 /* remote flow control */\n\n#else // defined(_WIN32) || defined(__VMS)\n#define INVALID_SOCKET 1\n#endif // defined (_WIN32) || defined(__VMS)\n\n/* inet_aton -- Emulate BSD inet_aton via inet_addr.\n *\n * Useful on systems that don't have inet_aton, such as Solaris,\n * to let your code use the better inet_aton interface and use autoconf\n * and AC_REPLACE_FUNCS([inet_aton]).\n *\n * Copyright (C) 2003 Matthias Andree <matthias.andree@gmx.de>\n */\n#if !defined(HAVE_INET_ATON)\ninline int inet_aton(const char *name, struct in_addr *addr) {\n  unsigned long a = inet_addr(name);\n  addr->s_addr = a;\n  return a != (unsigned int)-1;\n}\n#endif\n#endif // !defined(INCLUDED_TELNET_H)\n"
  },
  {
    "path": "test/disk/unwritable/axp_correct.log",
    "content": "%FLS-F-NOREST: Flash could not be restored from flash.rom\nEmulator Failure: Runtime exception: pci0.15(ali_ide).disk0.0(file): file disk-unwritable.img is not writable: DiskFile.cpp, line L\nStop threads:\nFreeing memory in use by system...\n"
  },
  {
    "path": "test/disk/unwritable/es40.cfg",
    "content": "sys0 = tsunami\n{\n  memory.bits = 26;\n  rom.srm = \"cl67srmrom.exe\";\n  rom.decompressed = \"decompressed.rom\";\n  rom.flash = \"flash.rom\";\n  rom.dpr = \"dpr.rom\";\n\n  cpu0 = ev68cb\n  {\n    speed = 800M;\n    icache = false;\n  }\n\n  serial0 = serial\n  {\n    address = \"127.0.0.1\";\n    port = 21000;\n  }\n\n\n  pci0.15 = ali_ide\n  {\n    disk0.0 = file\n    {\n      file = \"disk-unwritable.img\";\n      read_only = false;\n      cdrom = false;\n      autocreate_size = 100M;\n    }\n  }\n\n  pci0.7 = ali\n  {\n  }\n\n  pci0.19 = ali_usb\n  {\n  }\n}\n"
  },
  {
    "path": "test/disk/unwritable/test.sh",
    "content": "#!/bin/bash\n\ntouch disk-unwritable.img\nchmod 400 disk-unwritable.img\n\n# Download the firmware\nif [[ ! -f \"cl67srmrom.exe\" ]]; then\n  wget 'http://raymii.org/s/inc/downloads/es40-srmon/cl67srmrom.exe'\nfi\n\n# Start AXPbox\nif [[ -f ../../../build/axpbox ]]; then\n  ../../../build/axpbox run | tee axp.log\nelif [[ -f ../../../../build/axpbox ]]; then\n  ../../../../build/axpbox run | tee axp.log;\nelse\n   ../../build/axpbox run | tee axp.log\nfi\n\nchmod 700 disk-unwritable.img\nrm disk-unwritable.img\n\n# OS X github runner has weiro sed version, use gnu one there.\nSED=/usr/bin/sed\nif [[ -f \"/usr/local/opt/gnu-sed/libexec/gnubin/sed\" ]]; then\n  SED=/usr/local/opt/gnu-sed/libexec/gnubin/sed\nfi\n\n${SED} -i -e 's$/[^ ]*/DiskFile.cpp$DiskFile.cpp$g' -e 's/line [0-9]*/line L/g' -e '/$Id/d' axp.log\n\necho -n -e '\\033[1;31m'\ndiff -c axp_correct.log axp.log && echo -e '\\033[1;32mdiff clean\\033[0m'\nresult=$?\necho -n -e '\\033[0m'\n\nrm -f axp.log cl67* *.rom\nexit $result\n"
  },
  {
    "path": "test/rom/es40.cfg",
    "content": "sys0 = tsunami\n{\n  memory.bits = 26;\n  rom.srm = \"cl67srmrom.exe\";\n  rom.decompressed = \"decompressed.rom\";\n  rom.flash = \"flash.rom\";\n  rom.dpr = \"dpr.rom\";\n\n  cpu0 = ev68cb\n  {\n    speed = 800M;\n    icache = false;\n  }\n\n  serial0 = serial\n  {\n    address = \"127.0.0.1\";\n    port = 21000;\n  }\n\n\n  pci0.15 = ali_ide\n  {\n  }\n\n  pci0.7 = ali\n  {\n  }\n\n  pci0.19 = ali_usb\n  {\n  }\n}\n"
  },
  {
    "path": "test/rom/test.ps1",
    "content": "# Download the firmware\nInvoke-WebRequest -Uri 'http://raymii.org/s/inc/downloads/es40-srmon/cl67srmrom.exe' -OutFile 'cl67srmrom.exe'\n\n# Start AXPbox\nStart-Process '..\\..\\..\\build\\Release\\axpbox' -ArgumentList 'run' -NoNewWindow  -RedirectStandardOutput stdout.txt -RedirectStandardError stderr.txt\n\n# Wait for AXPbox to start\nStart-Sleep -Seconds 5\n\n# Connect to terminal\nStart-Process -FilePath 'nc' -ArgumentList '-t', '127.0.0.1', '21000' -NoNewWindow -RedirectStandardOutput 'axp.log'\n\n# Wait for the last line of log to become P00>>>\n$timeout = 300\nwhile ($true) {\n    if ($timeout -eq 0) {\n        Write-Host \"waiting for SRM prompt timed out\" -ForegroundColor Red\n        exit 1\n    }\n\n#    echo \"=== start axp.log ===\"\n#    Get-Content -Path 'axp.log' -Raw\n#    echo \"=== end axp.log ===\"\n\n    $content = Get-Content -Path 'axp.log' -Raw\n    $contentWithoutNullBytes = $content -replace '\\0', ''\n\n    if ($contentWithoutNullBytes -match \"P00>>>\") {\n        exit 0\n    }\n\n    Start-Sleep -Seconds 1\n    $timeout--\n}\n\nStop-Process -Name 'nc'\n"
  },
  {
    "path": "test/rom/test.sh",
    "content": "#!/bin/bash\nexport LC_CTYPE=C\nexport LANG=C\nexport LC_ALL=C\n\n# Download the firmware\nwget 'http://raymii.org/s/inc/downloads/es40-srmon/cl67srmrom.exe'\n\n# Start AXPbox\nif [[ -f ../../../build/axpbox ]]; then\n  ../../../build/axpbox run &\n  AXPBOX_PID=$!\nelse # Travis\n  ../../build/axpbox run &\n  AXPBOX_PID=$!\nfi\n\n# Wait for AXPbox to start\nsleep 5\n\n# Connect to terminal\nnc -t 127.0.0.1 21000 | tee axp.log &\nNETCAT_PID=$!\n\n# Wait for the last line of log to become P00>>>\ntimeout=600\nwhile true\ndo\n  if [ $timeout -eq 0 ]\n  then\n    echo \"waiting for SRM prompt timed out\" >&2\n    exit 1\n  fi\n\n  # print last line and remove null byte from it\n  if [ \"$(LC_ALL=C sed -n '$p' axp.log | LC_ALL=C sed 's/\\x00//g')\" == \"P00>>>\"  ]\n  then\n    echo\n    break\n  fi\n\n  sleep 1\n  timeout=$(($timeout - 1))\ndone\n\nkill $NETCAT_PID\nkill $AXPBOX_PID\n\necho -n -e '\\033[1;31m'\ndiff -c axp_correct.log axp.log && echo -e '\\033[1;32mdiff clean\\033[0m'\nresult=$?\necho -n -e '\\033[0m'\n\nrm -f axp.log cl67* *.rom\nexit $result\n"
  },
  {
    "path": "test/run",
    "content": "#!/bin/bash\nsuccess=0\n\nfunction message() {\n  echo -n -e '\\033[1;36m' >&2\n  echo $1 >&2\n  echo -n -e '\\033[0m' >&2\n}\n\nfunction run_test() {\n  local old_pwd=$(pwd)\n\n  message \"[test] Started test $1 at $(date)\"\n\n  cd \"test/$1\"\n  ./test.sh\n  local result=$?\n  cd \"$old_pwd\"\n\n  if [ \"$result\" -eq \"0\" ]\n  then\n    message \"[test] Test $1 finished at $(date)\" >&2\n  else\n    success=1\n    message \"[test] Test $1 failed at $(date)\" >&2\n  fi\n}\n\nmessage \"[test] This is the AXPbox test script\"\n\nrun_test rom\nrun_test disk/unwritable\n\nif [ \"$success\" -ne \"0\" ]\nthen\n  message \"[test] Some tests failed, please check the log\"\nelse\n  message \"[test] All tests passed\"\nfi\n\nexit \"$success\"\n"
  }
]