diff --git a/.github/workflows/cmake_linux.yml b/.github/workflows/cmake_linux.yml index c62c1087d..a7206dec6 100644 --- a/.github/workflows/cmake_linux.yml +++ b/.github/workflows/cmake_linux.yml @@ -11,6 +11,7 @@ on: - cmake/** - "**/CMakeLists.txt" - "CMakePresets.json" + - "!.github/workflows/**" - .github/workflows/cmake_linux.yml - vcpkg.json - "!**/Makefile*" @@ -21,7 +22,7 @@ on: - cmake/** - "**/CMakeLists.txt" - "CMakePresets.json" - - .github/workflows/** + - "!.github/workflows/**" - .github/workflows/cmake_linux.yml - vcpkg.json - "!**/Makefile*" @@ -29,12 +30,10 @@ on: jobs: linux: - name: "${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, x86_64" - runs-on: ubuntu-22.04 + name: "${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, ${{ matrix.environment.arch }}" - env: - BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed + runs-on: ${{ matrix.environment.runner }} strategy: fail-fast: true @@ -69,6 +68,20 @@ jobs: qttranslations5-l10n libevdev-dev libxkbcommon-x11-dev + environment: + - arch: x86_64 + toolchain: ./cmake/flags-gcc-x86_64.cmake + slug: "-x86_64" + runner: ubuntu-22.04 + - arch: arm64 + toolchain: ./cmake/flags-gcc-aarch64.cmake + slug: -arm64 + runner: ubuntu-22.04-arm + exclude: + - dynarec: + new: off + environment: + arch: arm64 steps: - name: Install dependencies @@ -93,28 +106,17 @@ jobs: with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - - name: Install sonar-scanner and build-wrapper - uses: SonarSource/sonarcloud-github-c-cpp@v3 - - name: Configure CMake run: >- cmake -G Ninja -S . -B build --preset ${{ matrix.build.preset }} - --toolchain ./cmake/flags-gcc-x86_64.cmake + --toolchain ${{ matrix.environment.toolchain }} -D NEW_DYNAREC=${{ matrix.dynarec.new }} -D CMAKE_INSTALL_PREFIX=./build/artifacts -D QT=${{ matrix.ui.qt }} - name: Build run: | - build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build - - - name: Run sonar-scanner - if: 0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: | - sonar-scanner --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" + cmake --build build - name: Generate package run: | @@ -123,5 +125,5 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v4 with: - name: '86Box${{ matrix.ui.slug }}${{ matrix.dynarec.slug }}${{ matrix.build.slug }}-UbuntuJammy-x86_64-gha${{ github.run_number }}' + name: '86Box${{ matrix.ui.slug }}${{ matrix.dynarec.slug }}${{ matrix.build.slug }}-UbuntuJammy${{ matrix.environment.slug }}-gha${{ github.run_number }}' path: build/artifacts/** diff --git a/.github/workflows/cmake_macos.yml b/.github/workflows/cmake_macos.yml index 647b1181c..8235b7df4 100644 --- a/.github/workflows/cmake_macos.yml +++ b/.github/workflows/cmake_macos.yml @@ -11,6 +11,7 @@ on: - cmake/** - "**/CMakeLists.txt" - "CMakePresets.json" + - "!.github/workflows/**" - .github/workflows/cmake_macos.yml - vcpkg.json - "!**/Makefile*" @@ -21,7 +22,7 @@ on: - cmake/** - "**/CMakeLists.txt" - "CMakePresets.json" - - .github/workflows/** + - "!.github/workflows/**" - .github/workflows/cmake_macos.yml - vcpkg.json - "!**/Makefile*" @@ -29,13 +30,11 @@ on: jobs: macos13-x86_64: + name: "${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, x86_64" runs-on: macos-13 - env: - BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed - strategy: fail-fast: true matrix: @@ -83,9 +82,6 @@ jobs: with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - - name: Install sonar-scanner and build-wrapper - uses: SonarSource/sonarcloud-github-c-cpp@v3 - - name: Configure CMake run: >- cmake -G Ninja -S . -B build --preset ${{ matrix.build.preset }} @@ -99,20 +95,10 @@ jobs: -D LIBSERIALPORT_ROOT=$(brew --prefix libserialport) - name: Build - run: | - build-wrapper-macosx-x86 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build - - - name: Run sonar-scanner - if: 0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: | - sonar-scanner --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" + run: cmake --build build - name: Generate package - run: | - cmake --install build + run: cmake --install build - name: Upload artifact uses: actions/upload-artifact@v4 @@ -121,13 +107,11 @@ jobs: path: build/artifacts/** macos14-arm64: + name: "${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, arm64" runs-on: macos-14 -# env: -# BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed - strategy: fail-fast: true matrix: @@ -175,9 +159,6 @@ jobs: with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis -# - name: Install sonar-scanner and build-wrapper -# uses: SonarSource/sonarcloud-github-c-cpp@v3 - - name: Configure CMake run: >- cmake -G Ninja -S . -B build --preset ${{ matrix.build.preset }} @@ -191,20 +172,10 @@ jobs: -D LIBSERIALPORT_ROOT=$(brew --prefix libserialport) - name: Build - run: | - cmake --build build - -# - name: Run sonar-scanner -# if: 0 -# env: -# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -# SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} -# run: | -# sonar-scanner --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" + run: cmake --build build - name: Generate package - run: | - cmake --install build + run: cmake --install build - name: Upload artifact uses: actions/upload-artifact@v4 diff --git a/.github/workflows/cmake_windows_msys2.yml b/.github/workflows/cmake_windows_msys2.yml index 5157cec51..9a7a9fb81 100644 --- a/.github/workflows/cmake_windows_msys2.yml +++ b/.github/workflows/cmake_windows_msys2.yml @@ -11,6 +11,7 @@ on: - cmake/** - "**/CMakeLists.txt" - "CMakePresets.json" + - "!.github/workflows/**" - .github/workflows/cmake_windows_msys2.yml - vcpkg.json - "!**/Makefile*" @@ -21,6 +22,7 @@ on: - cmake/** - "**/CMakeLists.txt" - "CMakePresets.json" + - "!.github/workflows/**" - .github/workflows/cmake_windows_msys2.yml - vcpkg.json - "!**/Makefile*" @@ -28,13 +30,11 @@ on: jobs: msys2: + name: "${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, ${{ matrix.environment.msystem }}" runs-on: ${{ matrix.environment.runner }} - env: - BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed - defaults: run: shell: msys2 {0} @@ -43,23 +43,47 @@ jobs: fail-fast: true matrix: build: - - name: Dev Debug +# - name: Regular +# preset: regular + - name: Debug preset: dev_debug - slug: -Dev-Debug + slug: -Debug - name: Dev preset: development slug: -Dev dynarec: - name: ODR new: off + slug: -ODR - name: NDR new: on slug: -NDR + ui: + - name: Qt GUI + qt: on + static: on + slug: -Qt + packages: >- + qt5-base:p + qt5-tools:p + vulkan-headers:p environment: +# - msystem: MSYS +# toolchain: ./cmake/flags-gcc-x86_64.cmake +# slug: "-MSYS64" - msystem: MINGW64 + prefix: mingw-w64-x86_64 toolchain: ./cmake/flags-gcc-x86_64.cmake slug: "-64" runner: windows-2022 +# - msystem: CLANG64 +# prefix: mingw-w64-clang-x86_64 +# toolchain: ./cmake/llvm-win32-x86_64.cmake +# slug: "CLANG64" +# - msystem: UCRT64 +# prefix: mingw-w64-ucrt-x86_64 +# toolchain: ./cmake/flags-gcc-x86_64.cmake +# slug: "UCRT64" - msystem: CLANGARM64 toolchain: ./cmake/flags-gcc-aarch64.cmake slug: -arm64 @@ -100,9 +124,6 @@ jobs: with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - # - name: Install sonar-scanner and build-wrapper - # uses: SonarSource/sonarcloud-github-c-cpp@v3 - - name: Configure CMake run: >- cmake -G Ninja -S . -B build --preset ${{ matrix.build.preset }} @@ -110,20 +131,9 @@ jobs: -D NEW_DYNAREC=${{ matrix.dynarec.new }} -D CMAKE_INSTALL_PREFIX=./build/artifacts - # - name: Build - # run: | - # .sonar/build-wrapper-win-x86/build-wrapper-win-x86-64.exe --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build - - name: Build run: cmake --build build - # - name: Run sonar-scanner - # env: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - # run: | - # .sonar/sonar-scanner-5.0.1.3006-windows/bin/sonar-scanner.bat --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" - - name: Generate package run: cmake --install build diff --git a/.github/workflows/codeql_linux.yml b/.github/workflows/codeql_linux.yml index 2b542b186..b8fb93ef6 100644 --- a/.github/workflows/codeql_linux.yml +++ b/.github/workflows/codeql_linux.yml @@ -9,6 +9,7 @@ on: - cmake/** - "**/CMakeLists.txt" - "CMakePresets.json" + - "!.github/workflows/**" - .github/workflows/codeql_linux.yml - vcpkg.json - "!**/Makefile*" @@ -20,7 +21,7 @@ on: - cmake/** - "**/CMakeLists.txt" - "CMakePresets.json" - - .github/workflows/** + - "!.github/workflows/**" - .github/workflows/codeql_linux.yml - vcpkg.json - "!**/Makefile*" @@ -32,10 +33,13 @@ jobs: analyze-linux: - name: "Analyze Linux GCC 11 (${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, x86_64)" + name: "Analyze (${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, x86_64)" runs-on: ubuntu-22.04 + env: + BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed + permissions: actions: read contents: read @@ -48,12 +52,12 @@ jobs: build: # - name: Regular # preset: regular -# - name: Debug -# preset: debug -# slug: -Debug - - name: Dev + - name: Debug preset: dev_debug - slug: -Dev + slug: -Debug +# - name: Dev +# preset: development +# slug: -Dev dynarec: - name: ODR new: off @@ -64,6 +68,7 @@ jobs: ui: - name: SDL GUI qt: off + static: on - name: Qt GUI qt: on slug: -Qt @@ -95,6 +100,11 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + + - name: Install Build Wrapper + uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v5 - name: Initialize CodeQL uses: github/codeql-action/init@v3 @@ -111,9 +121,23 @@ jobs: -D QT=${{ matrix.ui.qt }} - name: Build - run: cmake --build build + run: | + build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 with: category: "/language:${{matrix.language}}" + + - name: SonarQube Scan + if: matrix.build.preset == 'dev_debug' && matrix.dynarec.new == 'on' && matrix.ui.qt == 'on' && env.SONAR_TOKEN != '' +# if: 0 + uses: SonarSource/sonarqube-scan-action@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} +# SONAR_ROOT_CERT: ${{ secrets.SONAR_ROOT_CERT }} + with: + # Consult https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/scanners/sonarscanner/ for more information and options + args: > + --define sonar.cfamily.compile-commands="${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" diff --git a/.github/workflows/codeql_macos.yml b/.github/workflows/codeql_macos.yml index eeab0ecc8..203f385ff 100644 --- a/.github/workflows/codeql_macos.yml +++ b/.github/workflows/codeql_macos.yml @@ -9,6 +9,7 @@ on: - cmake/** - "**/CMakeLists.txt" - "CMakePresets.json" + - "!.github/workflows/**" - .github/workflows/codeql_macos.yml - vcpkg.json - "!**/Makefile*" @@ -20,7 +21,7 @@ on: - cmake/** - "**/CMakeLists.txt" - "CMakePresets.json" - - .github/workflows/** + - "!.github/workflows/**" - .github/workflows/codeql_macos.yml - vcpkg.json - "!**/Makefile*" @@ -32,10 +33,13 @@ jobs: analyze-macos13-x86_64: - name: "${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, x86_64" + name: "Analyze (${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, x86_64)" runs-on: macos-13 + env: + BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed + permissions: actions: read contents: read @@ -48,12 +52,12 @@ jobs: build: # - name: Regular # preset: regular -# - name: Debug -# preset: debug -# slug: -Debug - - name: Dev + - name: Debug preset: dev_debug - slug: -Dev + slug: -Debug +# - name: Dev +# preset: development +# slug: -Dev dynarec: - name: ODR new: off @@ -74,7 +78,6 @@ jobs: - name: Install dependencies run: >- brew install - ninja sdl2 rtmidi openal-soft @@ -86,6 +89,11 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + + - name: Install Build Wrapper + uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v5 - name: Initialize CodeQL uses: github/codeql-action/init@v3 @@ -106,9 +114,23 @@ jobs: -D LIBSERIALPORT_ROOT=$(brew --prefix libserialport) - name: Build - run: cmake --build build + run: | + build-wrapper-macosx-x86 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 with: category: "/language:${{matrix.language}}" + + - name: SonarQube Scan +# if: matrix.build.preset == 'dev_debug' && matrix.dynarec.new == 'on' && matrix.ui.qt == 'on' && env.SONAR_TOKEN != '' + if: 0 + uses: SonarSource/sonarqube-scan-action@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} +# SONAR_ROOT_CERT: ${{ secrets.SONAR_ROOT_CERT }} + with: + # Consult https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/scanners/sonarscanner/ for more information and options + args: > + --define sonar.cfamily.compile-commands="${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" diff --git a/.github/workflows/codeql_windows_msys2.yml b/.github/workflows/codeql_windows_msys2.yml index f513831e8..c7edae77f 100644 --- a/.github/workflows/codeql_windows_msys2.yml +++ b/.github/workflows/codeql_windows_msys2.yml @@ -9,6 +9,7 @@ on: - cmake/** - "**/CMakeLists.txt" - "CMakePresets.json" + - "!.github/workflows/**" - .github/workflows/codeql_windows_msys2.yml - vcpkg.json - "!**/Makefile*" @@ -20,7 +21,7 @@ on: - cmake/** - "**/CMakeLists.txt" - "CMakePresets.json" - - .github/workflows/** + - "!.github/workflows/**" - .github/workflows/codeql_windows_msys2.yml - vcpkg.json - "!**/Makefile*" @@ -32,9 +33,12 @@ jobs: analyze-msys2: - name: "${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, ${{ matrix.environment.msystem }}" + name: "Analyze (${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, ${{ matrix.environment.msystem }})" - runs-on: windows-2022 + runs-on: ${{ matrix.environment.runner }} + + env: + BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed permissions: actions: read @@ -52,12 +56,12 @@ jobs: build: # - name: Regular # preset: regular -# - name: Debug -# preset: debug -# slug: -Debug - - name: Dev + - name: Debug preset: dev_debug - slug: -Dev + slug: -Debug +# - name: Dev +# preset: development +# slug: -Dev dynarec: - name: ODR new: off @@ -77,21 +81,37 @@ jobs: environment: # - msystem: MSYS # toolchain: ./cmake/flags-gcc-x86_64.cmake +# slug: "-MSYS64" - msystem: MINGW64 prefix: mingw-w64-x86_64 toolchain: ./cmake/flags-gcc-x86_64.cmake + slug: "-64" + runner: windows-2022 # - msystem: CLANG64 # prefix: mingw-w64-clang-x86_64 # toolchain: ./cmake/llvm-win32-x86_64.cmake - - msystem: UCRT64 - prefix: mingw-w64-ucrt-x86_64 - toolchain: ./cmake/flags-gcc-x86_64.cmake +# slug: "CLANG64" +# runner: windows-2022 +# - msystem: UCRT64 +# prefix: mingw-w64-ucrt-x86_64 +# toolchain: ./cmake/flags-gcc-x86_64.cmake +# slug: "UCRT64" +# runner: windows-2022 +# - msystem: CLANGARM64 +# toolchain: ./cmake/flags-gcc-aarch64.cmake +# slug: -arm64 +# runner: windows-11-arm + exclude: + - dynarec: + new: off + environment: + msystem: CLANGARM64 steps: - name: Prepare MSYS2 environment uses: msys2/setup-msys2@v2 with: - release: false + release: true update: true msystem: ${{ matrix.environment.msystem }} pacboy: >- @@ -109,9 +129,15 @@ jobs: fluidsynth:p libserialport:p ${{ matrix.ui.packages }} + openmp:p - name: Checkout repository uses: actions/checkout@v4 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + +# - name: Install Build Wrapper +# uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v5 - name: Initialize CodeQL uses: github/codeql-action/init@v3 @@ -128,11 +154,27 @@ jobs: -D QT=${{ matrix.ui.qt }} -D STATIC_BUILD=${{ matrix.ui.static }} + # - name: Build + # run: | + # .sonar/build-wrapper-win-x86/build-wrapper-win-x86-64.exe --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build + - name: Build run: cmake --build build - - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 with: category: "/language:${{matrix.language}}" + + - name: SonarQube Scan +# if: matrix.build.preset == 'dev_debug' && matrix.dynarec.new == 'on' && matrix.ui.qt == 'on' && env.SONAR_TOKEN != '' + if: 0 + uses: SonarSource/sonarqube-scan-action@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} +# SONAR_ROOT_CERT: ${{ secrets.SONAR_ROOT_CERT }} + with: + # Consult https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/scanners/sonarscanner/ for more information and options + args: > + --define sonar.cfamily.compile-commands="${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" diff --git a/src/cpu/808x.c b/src/cpu/808x.c index dda688ee1..2e24d3c49 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -90,44 +90,44 @@ static bool cpu_md_write_disable = 1; #define fetch_ea_32(val) #define PREFETCH_RUN(a, b, c, d, e, f, g, h) -#define CYCLES(val) \ - { \ - wait(val, 0); \ +#define CYCLES(val) \ + { \ + wait_cycs(val, 0); \ } #define CLOCK_CYCLES_ALWAYS(val) \ { \ - wait(val, 0); \ + wait_cycs(val, 0); \ } #if 0 # define CLOCK_CYCLES_FPU(val) \ { \ - wait(val, 0); \ + wait_cycs(val, 0); \ } -# define CLOCK_CYCLES(val) \ - { \ - if (fpu_cycles > 0) { \ - fpu_cycles -= (val); \ - if (fpu_cycles < 0) { \ - wait(val, 0); \ - } \ - } else { \ - wait(val, 0); \ - } \ +# define CLOCK_CYCLES(val) \ + { \ + if (fpu_cycles > 0) { \ + fpu_cycles -= (val); \ + if (fpu_cycles < 0) { \ + wait_cycs(val, 0); \ + } \ + } else { \ + wait_cycs(val, 0); \ + } \ } # define CONCURRENCY_CYCLES(c) fpu_cycles = (c) #else -# define CLOCK_CYCLES(val) \ - { \ - wait(val, 0); \ +# define CLOCK_CYCLES(val) \ + { \ + wait_cycs(val, 0); \ } # define CLOCK_CYCLES_FPU(val) \ { \ - wait(val, 0); \ + wait_cycs(val, 0); \ } # define CONCURRENCY_CYCLES(c) @@ -298,7 +298,7 @@ fetch_and_bus(int c, int bus) } static void -wait(int c, int bus) +wait_cycs(int c, int bus) { cycles -= c; fetch_and_bus(c, bus); @@ -340,13 +340,13 @@ cpu_io(int bits, int out, uint16_t port) int old_cycles = cycles; if (out) { - wait(is_mazovia ? 5 : 4, 1); + wait_cycs(is_mazovia ? 5 : 4, 1); if (bits == 16) { if (is8086 && !(port & 1)) { old_cycles = cycles; outw(port, AX); } else { - wait(is_mazovia ? 5 : 4, 1); + wait_cycs(is_mazovia ? 5 : 4, 1); old_cycles = cycles; outb(port++, AL); outb(port, AH); @@ -356,13 +356,13 @@ cpu_io(int bits, int out, uint16_t port) outb(port, AL); } } else { - wait(is_mazovia ? 5 : 4, 1); + wait_cycs(is_mazovia ? 5 : 4, 1); if (bits == 16) { if (is8086 && !(port & 1)) { old_cycles = cycles; AX = inw(port); } else { - wait(is_mazovia ? 5 : 4, 1); + wait_cycs(is_mazovia ? 5 : 4, 1); old_cycles = cycles; AL = inb(port++); AH = inb(port); @@ -382,7 +382,7 @@ readmemb(uint32_t a) { uint8_t ret; - wait(4, 1); + wait_cycs(4, 1); ret = read_mem_b(a); return ret; @@ -406,11 +406,11 @@ readmemw(uint32_t s, uint16_t a) { uint16_t ret; - wait(4, 1); + wait_cycs(4, 1); if (is8086 && !(a & 1)) ret = read_mem_w(s + a); else { - wait(4, 1); + wait_cycs(4, 1); ret = read_mem_b(s + a); ret |= read_mem_b(s + ((is186 && !is_nec) ? (a + 1) : (a + 1) & 0xffff)) << 8; } @@ -465,7 +465,7 @@ writememb(uint32_t s, uint32_t a, uint8_t v) { uint32_t addr = s + a; - wait(4, 1); + wait_cycs(4, 1); write_mem_b(addr, v); if ((addr >= 0xf0000) && (addr <= 0xfffff)) @@ -478,12 +478,12 @@ writememw(uint32_t s, uint32_t a, uint16_t v) { uint32_t addr = s + a; - wait(4, 1); + wait_cycs(4, 1); if (is8086 && !(a & 1)) write_mem_w(addr, v); else { write_mem_b(addr, v & 0xff); - wait(4, 1); + wait_cycs(4, 1); addr = s + ((is186 && !is_nec) ? (a + 1) : ((a + 1) & 0xffff)); write_mem_b(addr, v >> 8); } @@ -560,7 +560,7 @@ pfq_fetchb_common(void) /* Reset prefetch queue internal position. */ pfq_ip = cpu_state.pc; /* Fill the queue. */ - wait(4 - (biu_cycles & 3), 0); + wait_cycs(4 - (biu_cycles & 3), 0); } /* Fetch. */ @@ -574,7 +574,7 @@ pfq_fetchb(void) uint8_t ret; ret = pfq_fetchb_common(); - wait(1, 0); + wait_cycs(1, 0); return ret; } @@ -586,7 +586,7 @@ pfq_fetchw(void) uint16_t temp; temp = pfq_fetchb_common(); - wait(1, 0); + wait_cycs(1, 0); temp |= (pfq_fetchb_common() << 8); return temp; @@ -760,38 +760,38 @@ do_mod_rm(void) if (cpu_mod == 3) return; - wait(1, 0); + wait_cycs(1, 0); if ((rmdat & 0xc7) == 0x06) { - wait(1, 0); + wait_cycs(1, 0); cpu_state.eaaddr = pfq_fetchw(); easeg = ovr_seg ? *ovr_seg : ds; - wait(1, 0); + wait_cycs(1, 0); return; } else switch (cpu_rm) { case 0: case 3: - wait(2, 0); + wait_cycs(2, 0); break; case 1: case 2: - wait(3, 0); + wait_cycs(3, 0); break; } cpu_state.eaaddr = (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]); easeg = ovr_seg ? *ovr_seg : *mod1seg[cpu_rm]; switch (rmdat & 0xc0) { case 0x40: - wait(3, 0); + wait_cycs(3, 0); cpu_state.eaaddr += sign_extend(pfq_fetchb()); break; case 0x80: - wait(3, 0); + wait_cycs(3, 0); cpu_state.eaaddr += pfq_fetchw(); break; } cpu_state.eaaddr &= 0xffff; - wait(2, 0); + wait_cycs(2, 0); } #undef getr8 @@ -983,7 +983,7 @@ access(int num, UNUSED(int bits)) case 62: case 66: case 68: - wait(1, 0); + wait_cycs(1, 0); break; case 3: case 11: @@ -999,7 +999,7 @@ access(int num, UNUSED(int bits)) case 52: case 53: case 54: - wait(2, 0); + wait_cycs(2, 0); break; case 16: case 18: @@ -1008,7 +1008,7 @@ access(int num, UNUSED(int bits)) case 32: case 37: case 42: - wait(3, 0); + wait_cycs(3, 0); break; case 10: case 12: @@ -1021,59 +1021,59 @@ access(int num, UNUSED(int bits)) case 39: case 41: case 60: - wait(4, 0); + wait_cycs(4, 0); break; case 4: case 70: - wait(5, 0); + wait_cycs(5, 0); break; case 31: case 38: case 40: - wait(6, 0); + wait_cycs(6, 0); break; case 5: if (opcode == 0xcc) - wait(7, 0); + wait_cycs(7, 0); else - wait(4, 0); + wait_cycs(4, 0); break; case 36: - wait(1, 0); + wait_cycs(1, 0); pfq_clear(); - wait(1, 0); + wait_cycs(1, 0); if (cpu_mod != 3) - wait(1, 0); - wait(3, 0); + wait_cycs(1, 0); + wait_cycs(3, 0); break; case 43: - wait(2, 0); + wait_cycs(2, 0); pfq_clear(); - wait(1, 0); + wait_cycs(1, 0); break; case 57: if (cpu_mod != 3) - wait(2, 0); - wait(4, 0); + wait_cycs(2, 0); + wait_cycs(4, 0); break; case 58: if (cpu_mod != 3) - wait(1, 0); - wait(4, 0); + wait_cycs(1, 0); + wait_cycs(4, 0); break; case 59: - wait(2, 0); + wait_cycs(2, 0); pfq_clear(); if (cpu_mod != 3) - wait(1, 0); - wait(3, 0); + wait_cycs(1, 0); + wait_cycs(3, 0); break; case 65: - wait(1, 0); + wait_cycs(1, 0); pfq_clear(); - wait(2, 0); + wait_cycs(2, 0); if (cpu_mod != 3) - wait(1, 0); + wait_cycs(1, 0); break; } } @@ -1096,7 +1096,7 @@ interrupt(uint16_t addr) old_cs = CS; access(5, 16); new_ip = readmemw(0, cpu_state.eaaddr); - wait(1, 0); + wait_cycs(1, 0); cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; access(6, 16); new_cs = readmemw(0, cpu_state.eaaddr); @@ -1132,7 +1132,7 @@ interrupt_brkem(uint16_t addr) old_cs = CS; access(5, 16); new_ip = readmemw(0, cpu_state.eaaddr); - wait(1, 0); + wait_cycs(1, 0); cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; access(6, 16); new_cs = readmemw(0, cpu_state.eaaddr); @@ -1201,7 +1201,7 @@ custom_nmi(void) access(5, 16); (void) readmemw(0, cpu_state.eaaddr); new_ip = custom_nmi_vector & 0xffff; - wait(1, 0); + wait_cycs(1, 0); cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; access(6, 16); (void) readmemw(0, cpu_state.eaaddr); @@ -1260,20 +1260,20 @@ check_interrupts(void) repeating = 0; completed = 1; ovr_seg = NULL; - wait(3, 0); + wait_cycs(3, 0); /* ACK to PIC */ temp = pic_irq_ack(); - wait(4, 1); - wait(1, 0); + wait_cycs(4, 1); + wait_cycs(1, 0); /* ACK to PIC */ temp = pic_irq_ack(); - wait(4, 1); - wait(1, 0); + wait_cycs(4, 1); + wait_cycs(1, 0); in_lock = 0; clear_lock = 0; - wait(1, 0); + wait_cycs(1, 0); /* Here is where temp should be filled, but we cheat. */ - wait(3, 0); + wait_cycs(3, 0); opcode = 0x00; interrupt(temp); } @@ -1287,7 +1287,7 @@ rep_action(int bits) if (in_rep == 0) return 0; - wait(2, 0); + wait_cycs(2, 0); t = CX; if (irq_pending() && (repeating != 0)) { access(71, bits); @@ -1299,16 +1299,16 @@ rep_action(int bits) t = 0; } if (t == 0) { - wait(1, 0); + wait_cycs(1, 0); completed = 1; repeating = 0; return 1; } --CX; completed = 0; - wait(2, 0); + wait_cycs(2, 0); if (!repeating) - wait(2, 0); + wait_cycs(2, 0); return 0; } @@ -1318,7 +1318,7 @@ jump(uint16_t delta) uint16_t old_ip; access(67, 8); pfq_clear(); - wait(5, 0); + wait_cycs(5, 0); old_ip = cpu_state.pc; set_ip((cpu_state.pc + delta) & 0xffff); return old_ip; @@ -1342,9 +1342,9 @@ jcc(uint8_t opcode, int cond) { /* int8_t offset; */ - wait(1, 0); + wait_cycs(1, 0); cpu_data = pfq_fetchb(); - wait(1, 0); + wait_cycs(1, 0); if ((!cond) == !!(opcode & 0x01)) jump_short(); } @@ -1534,32 +1534,32 @@ mul(uint16_t a, uint16_t b) bit_count = 16; high_bit = 0x8000; } else - wait(8, 0); + wait_cycs(8, 0); size_mask = (1 << bit_count) - 1; if ((rmdat & 0x38) == 0x28) { if (!top_bit(a, bit_count)) { if (top_bit(b, bit_count)) { - wait(1, 0); + wait_cycs(1, 0); if ((b & size_mask) != ((opcode & 1) ? 0x8000 : 0x80)) - wait(1, 0); + wait_cycs(1, 0); b = ~b + 1; negate = 1; } } else { - wait(1, 0); + wait_cycs(1, 0); a = ~a + 1; negate = 1; if (top_bit(b, bit_count)) { b = ~b + 1; negate = 0; } else - wait(4, 0); + wait_cycs(4, 0); } - wait(10, 0); + wait_cycs(10, 0); } - wait(3, 0); + wait_cycs(3, 0); } c = 0; @@ -1567,13 +1567,13 @@ mul(uint16_t a, uint16_t b) carry = (a & 1) != 0; a >>= 1; for (i = 0; i < bit_count; ++i) { - wait(7, 0); + wait_cycs(7, 0); if (carry) { cpu_src = c; cpu_dest = b; add(bit_count); c = cpu_data & size_mask; - wait(1, 0); + wait_cycs(1, 0); carry = !!(cpu_state.flags & C_FLAG); } r = (c >> 1) + (carry ? high_bit : 0); @@ -1588,7 +1588,7 @@ mul(uint16_t a, uint16_t b) a = (~a + 1) & size_mask; if (a == 0) ++c; - wait(9, 0); + wait_cycs(9, 0); } cpu_data = a; cpu_dest = c; @@ -1633,7 +1633,7 @@ set_co_mul(UNUSED(int bits), int carry) set_of(carry); set_zf_ex(!carry); if (!carry) - wait(1, 0); + wait_cycs(1, 0); } /* Was div(), renamed to avoid conflicts with stdlib div(). */ @@ -1664,28 +1664,28 @@ x86_div(uint16_t l, uint16_t h) h &= size_mask; negative = 1; dividend_negative = 1; - wait(4, 0); + wait_cycs(4, 0); } if (top_bit(cpu_src, bit_count)) { cpu_src = ~cpu_src + 1; negative = !negative; } else - wait(1, 0); - wait(9, 0); + wait_cycs(1, 0); + wait_cycs(9, 0); } - wait(3, 0); + wait_cycs(3, 0); } - wait(8, 0); + wait_cycs(8, 0); cpu_src &= size_mask; if (h >= cpu_src) { if (opcode != 0xd4) - wait(1, 0); + wait_cycs(1, 0); interrupt(0); return 0; } if (opcode != 0xd4) - wait(1, 0); - wait(2, 0); + wait_cycs(1, 0); + wait_cycs(2, 0); carry = 1; for (b = 0; b < bit_count; ++b) { r = (l << 1) + (carry ? 1 : 0); @@ -1694,32 +1694,32 @@ x86_div(uint16_t l, uint16_t h) r = (h << 1) + (carry ? 1 : 0); carry = top_bit(h, bit_count); h = r; - wait(8, 0); + wait_cycs(8, 0); if (carry) { carry = 0; h -= cpu_src; if (b == bit_count - 1) - wait(2, 0); + wait_cycs(2, 0); } else { carry = cpu_src > h; if (!carry) { h -= cpu_src; - wait(1, 0); + wait_cycs(1, 0); if (b == bit_count - 1) - wait(2, 0); + wait_cycs(2, 0); } } } l = ~((l << 1) + (carry ? 1 : 0)); if (opcode != 0xd4 && (rmdat & 0x38) == 0x38) { - wait(4, 0); + wait_cycs(4, 0); if (top_bit(l, bit_count)) { if (cpu_mod == 3) - wait(1, 0); + wait_cycs(1, 0); interrupt(0); return 0; } - wait(7, 0); + wait_cycs(7, 0); if (negative) l = ~l + 1; if (dividend_negative) @@ -1778,7 +1778,7 @@ aa(void) { set_pzs(8); AL = cpu_data & 0x0f; - wait(6, 0); + wait_cycs(6, 0); } static void @@ -1848,7 +1848,7 @@ cpu_inb(uint16_t port) int old_cycles = cycles; uint8_t ret; - wait(is_mazovia ? 5 : 4, 1); + wait_cycs(is_mazovia ? 5 : 4, 1); old_cycles = cycles; ret = inb(port); @@ -1864,12 +1864,12 @@ cpu_inw(uint16_t port) int old_cycles = cycles; uint16_t ret; - wait(is_mazovia ? 5 : 4, 1); + wait_cycs(is_mazovia ? 5 : 4, 1); if (is8086 && !(port & 1)) { old_cycles = cycles; ret = inw(port); } else { - wait(is_mazovia ? 5 : 4, 1); + wait_cycs(is_mazovia ? 5 : 4, 1); old_cycles = cycles; ret = inb(port++); ret |= (inb(port) << 8); @@ -1885,7 +1885,7 @@ cpu_outb(uint16_t port, uint16_t val) { int old_cycles = cycles; - wait(is_mazovia ? 5 : 4, 1); + wait_cycs(is_mazovia ? 5 : 4, 1); old_cycles = cycles; outb(port, val); @@ -1898,13 +1898,13 @@ cpu_outw(uint16_t port, uint16_t val) { int old_cycles = cycles; - wait(is_mazovia ? 5 : 4, 1); + wait_cycs(is_mazovia ? 5 : 4, 1); if (is8086 && !(port & 1)) { old_cycles = cycles; outw(port, val); } else { - wait(is_mazovia ? 5 : 4, 1); + wait_cycs(is_mazovia ? 5 : 4, 1); old_cycles = cycles; outb(port++, val); outb(port, val >> 8); @@ -1954,7 +1954,7 @@ execx86(int cycs) in_lock = 0; clear_lock = 0; } - wait(1, 0); + wait_cycs(1, 0); } completed = 1; @@ -1963,7 +1963,7 @@ execx86(int cycs) switch (opcode) { case 0x60: /*PUSHA/PUSH R*/ orig_sp = SP; - wait(1, 0); + wait_cycs(1, 0); push(&AX); push(&CX); push(&DX); @@ -1975,7 +1975,7 @@ execx86(int cycs) handled = 1; break; case 0x61: /*POPA/POP R*/ - wait(9, 0); + wait_cycs(9, 0); DI = pop(); SI = pop(); BP = pop(); @@ -2007,7 +2007,7 @@ execx86(int cycs) case 0x65: if (is_nec) { /* REPC/REPNC */ - wait(1, 0); + wait_cycs(1, 0); in_rep = (opcode == 0x64 ? 1 : 2); rep_c_flag = 1; completed = 0; @@ -2017,7 +2017,7 @@ execx86(int cycs) case 0x68: wordtopush = pfq_fetchw(); - wait(1, 0); + wait_cycs(1, 0); push(&wordtopush); handled = 1; break; @@ -2057,12 +2057,12 @@ execx86(int cycs) bits = 8 << (opcode & 1); handled = 1; if (!repeating) - wait(2, 0); + wait_cycs(2, 0); if (rep_action(bits)) break; else if (!repeating) - wait(7, 0); + wait_cycs(7, 0); if (bits == 16) { writememw(es, DI, cpu_inw(DX)); @@ -2085,12 +2085,12 @@ execx86(int cycs) bits = 8 << (opcode & 1); handled = 1; if (!repeating) - wait(2, 0); + wait_cycs(2, 0); if (rep_action(bits)) break; else if (!repeating) - wait(7, 0); + wait_cycs(7, 0); if (bits == 16) { cpu_outw(DX, readmemw(dest_seg, SI)); @@ -2133,12 +2133,12 @@ execx86(int cycs) bits = 8 << (opcode & 1); do_mod_rm(); if (cpu_mod == 3) - wait(1, 0); + wait_cycs(1, 0); access(53, bits); cpu_data = get_ea(); cpu_src = pfq_fetchb(); - wait((cpu_mod != 3) ? 9 : 6, 0); + wait_cycs((cpu_mod != 3) ? 9 : 6, 0); if (!is_nec) cpu_src &= 0x1F; @@ -2210,7 +2210,7 @@ execx86(int cycs) break; } if ((opcode & 2) != 0) - wait(4, 0); + wait_cycs(4, 0); --cpu_src; } access(17, bits); @@ -2244,7 +2244,7 @@ execx86(int cycs) switch (opcode) { case 0x28: /* ROL4 r/m */ do_mod_rm(); - wait(21, 0); + wait_cycs(21, 0); temp_val = geteab(); temp_al = AL; @@ -2262,7 +2262,7 @@ execx86(int cycs) case 0x2a: /* ROR4 r/m */ do_mod_rm(); - wait(21, 0); + wait_cycs(21, 0); temp_val = geteab(); temp_al = AL; @@ -2281,7 +2281,7 @@ execx86(int cycs) case 0x19: /* TEST1 r16/m16, imm4 */ bits = 8 << (opcode & 0x1); do_mod_rm(); - wait(3, 0); + wait_cycs(3, 0); bit = (opcode & 0x8) ? (pfq_fetchb()) : (CL); bit &= ((1 << (3 + (opcode & 0x1))) - 1); @@ -2299,7 +2299,7 @@ execx86(int cycs) case 0x1f: /* NOT1 r16/m16, imm4 */ bits = 8 << (opcode & 0x1); do_mod_rm(); - wait(3, 0); + wait_cycs(3, 0); bit = (opcode & 0x8) ? (pfq_fetchb()) : (CL); bit &= ((1 << (3 + (opcode & 0x1))) - 1); @@ -2319,7 +2319,7 @@ execx86(int cycs) case 0x1d: /* SET1 r16/m16, imm4 */ bits = 8 << (opcode & 0x1); do_mod_rm(); - wait(3, 0); + wait_cycs(3, 0); bit = (opcode & 0x8) ? (pfq_fetchb()) : (CL); bit &= ((1 << (3 + (opcode & 0x1))) - 1); @@ -2339,7 +2339,7 @@ execx86(int cycs) case 0x1b: /* CLR1 r16/m16, imm4 */ bits = 8 << (opcode & 0x1); do_mod_rm(); - wait(3, 0); + wait_cycs(3, 0); bit = (opcode & 0x8) ? (pfq_fetchb()) : (CL); bit &= ((1 << (3 + (opcode & 0x1))) - 1); @@ -2362,9 +2362,9 @@ execx86(int cycs) nibble = 0; srcseg = ovr_seg ? *ovr_seg : ds; - wait(5, 0); + wait_cycs(5, 0); for (i = 0; i < ((nibbles_count / 2) + odd); i++) { - wait(19, 0); + wait_cycs(19, 0); destcmp = read_mem_b((es) + DI + i); for (nibble = 0; nibble < 2; nibble++) { destbyte = destcmp >> (nibble ? 4 : 0); @@ -2397,9 +2397,9 @@ execx86(int cycs) nibble = 0; srcseg = ovr_seg ? *ovr_seg : ds; - wait(5, 0); + wait_cycs(5, 0); for (i = 0; i < ((nibbles_count / 2) + odd); i++) { - wait(19, 0); + wait_cycs(19, 0); destcmp = read_mem_b((es) + DI + i); for (nibble = 0; nibble < 2; nibble++) { destbyte = destcmp >> (nibble ? 4 : 0); @@ -2432,9 +2432,9 @@ execx86(int cycs) nibble = 0; srcseg = ovr_seg ? *ovr_seg : ds; - wait(5, 0); + wait_cycs(5, 0); for (i = 0; i < ((nibbles_count / 2) + odd); i++) { - wait(19, 0); + wait_cycs(19, 0); destcmp = read_mem_b((es) + DI + i); for (nibble = 0; nibble < 2; nibble++) { destbyte = destcmp >> (nibble ? 4 : 0); @@ -2460,7 +2460,7 @@ execx86(int cycs) case 0x31: /* INS reg1, reg2 */ case 0x39: /* INS reg8, imm4 */ do_mod_rm(); - wait(1, 0); + wait_cycs(1, 0); bit_length = ((opcode & 0x8) ? (pfq_fetchb() & 0xF) : (getr8(cpu_reg) & 0xF)) + 1; bit_offset = getr8(cpu_rm) & 0xF; @@ -2489,7 +2489,7 @@ execx86(int cycs) case 0x33: /* EXT reg1, reg2 */ case 0x3b: /* EXT reg8, imm4 */ do_mod_rm(); - wait(1, 0); + wait_cycs(1, 0); bit_length = ((opcode & 0x8) ? (pfq_fetchb() & 0xF) : (getr8(cpu_reg) & 0xF)) + 1; bit_offset = getr8(cpu_rm) & 0xF; @@ -2537,7 +2537,7 @@ execx86(int cycs) pfq_pos = 0; } else load_seg(pop(), _opseg[(opcode >> 3) & 0x03]); - wait(1, 0); + wait_cycs(1, 0); /* All POP segment instructions suppress interrupts for one instruction. */ noint = 1; break; @@ -2546,7 +2546,7 @@ execx86(int cycs) case 0x2E: /*CS:*/ case 0x36: /*SS:*/ case 0x3E: /*DS:*/ - wait(1, 0); + wait_cycs(1, 0); ovr_seg = opseg[(opcode >> 3) & 0x03]; completed = 0; break; @@ -2597,21 +2597,21 @@ execx86(int cycs) cpu_src = tempw; } if (cpu_mod != 3) - wait(2, 0); - wait(1, 0); + wait_cycs(2, 0); + wait_cycs(1, 0); alu_op(bits); if (cpu_alu_op != 7) { if ((opcode & 2) == 0) { access(10, bits); set_ea(cpu_data); if (cpu_mod == 3) - wait(1, 0); + wait_cycs(1, 0); } else { set_reg(cpu_reg, cpu_data); - wait(1, 0); + wait_cycs(1, 0); } } else - wait(1, 0); + wait_cycs(1, 0); break; case 0x04: @@ -2632,7 +2632,7 @@ execx86(int cycs) case 0x3d: /* alu A, imm */ bits = 8 << (opcode & 1); - wait(1, 0); + wait_cycs(1, 0); cpu_data = pfq_fetch(); cpu_dest = get_accum(bits); /* AX/AL */ cpu_src = cpu_data; @@ -2640,7 +2640,7 @@ execx86(int cycs) alu_op(bits); if (cpu_alu_op != 7) set_accum(bits, cpu_data); - wait(1, 0); + wait_cycs(1, 0); break; case 0x27: /*DAA*/ @@ -2663,7 +2663,7 @@ execx86(int cycs) } AL = cpu_dest; set_pzs(8); - wait(3, 0); + wait_cycs(3, 0); break; case 0x2F: /*DAS*/ cpu_dest = AL; @@ -2685,10 +2685,10 @@ execx86(int cycs) } AL = cpu_dest; set_pzs(8); - wait(3, 0); + wait_cycs(3, 0); break; case 0x37: /*AAA*/ - wait(1, 0); + wait_cycs(1, 0); if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { cpu_src = 6; ++AH; @@ -2696,7 +2696,7 @@ execx86(int cycs) } else { cpu_src = 0; clear_ca(); - wait(1, 0); + wait_cycs(1, 0); } cpu_dest = AL; cpu_data = cpu_dest + cpu_src; @@ -2704,7 +2704,7 @@ execx86(int cycs) aa(); break; case 0x3F: /*AAS*/ - wait(1, 0); + wait_cycs(1, 0); if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { cpu_src = 6; --AH; @@ -2712,7 +2712,7 @@ execx86(int cycs) } else { cpu_src = 0; clear_ca(); - wait(1, 0); + wait_cycs(1, 0); } cpu_dest = AL; cpu_data = cpu_dest - cpu_src; @@ -2737,7 +2737,7 @@ execx86(int cycs) case 0x4E: case 0x4F: /* INCDEC rw */ - wait(1, 0); + wait_cycs(1, 0); cpu_dest = cpu_state.regs[opcode & 7].w; cpu_src = 1; bits = 16; @@ -2774,7 +2774,7 @@ execx86(int cycs) case 0x5F: access(23, 16); cpu_state.regs[opcode & 0x07].w = pop(); - wait(1, 0); + wait_cycs(1, 0); break; case 0x60: /*JO alias*/ @@ -2841,20 +2841,20 @@ execx86(int cycs) cpu_data = get_ea(); cpu_dest = cpu_data; if (cpu_mod != 3) - wait(3, 0); + wait_cycs(3, 0); if (opcode == 0x81) { if (cpu_mod == 3) - wait(1, 0); + wait_cycs(1, 0); cpu_src = pfq_fetchw(); } else { if (cpu_mod == 3) - wait(1, 0); + wait_cycs(1, 0); if (opcode == 0x83) cpu_src = sign_extend(pfq_fetchb()); else cpu_src = pfq_fetchb() | 0xff00; } - wait(1, 0); + wait_cycs(1, 0); cpu_alu_op = (rmdat & 0x38) >> 3; alu_op(bits); if (cpu_alu_op != 7) { @@ -2862,7 +2862,7 @@ execx86(int cycs) set_ea(cpu_data); } else { if (cpu_mod != 3) - wait(1, 0); + wait_cycs(1, 0); } break; @@ -2875,8 +2875,8 @@ execx86(int cycs) cpu_data = get_ea(); test(bits, cpu_data, get_reg(cpu_reg)); if (cpu_mod == 3) - wait(2, 0); - wait(2, 0); + wait_cycs(2, 0); + wait_cycs(2, 0); break; case 0x86: case 0x87: @@ -2887,7 +2887,7 @@ execx86(int cycs) cpu_data = get_ea(); cpu_src = get_reg(cpu_reg); set_reg(cpu_reg, cpu_data); - wait(3, 0); + wait_cycs(3, 0); access(12, bits); set_ea(cpu_src); break; @@ -2897,7 +2897,7 @@ execx86(int cycs) /* MOV rm, reg */ bits = 8 << (opcode & 1); do_mod_rm(); - wait(1, 0); + wait_cycs(1, 0); access(13, bits); set_ea(get_reg(cpu_reg)); break; @@ -2908,15 +2908,15 @@ execx86(int cycs) do_mod_rm(); access(50, bits); set_reg(cpu_reg, get_ea()); - wait(1, 0); + wait_cycs(1, 0); if (cpu_mod != 3) - wait(2, 0); + wait_cycs(2, 0); break; case 0x8C: /*MOV w,sreg*/ do_mod_rm(); if (cpu_mod == 3) - wait(1, 0); + wait_cycs(1, 0); access(14, 16); seteaw(_opseg[(rmdat & 0x18) >> 3]->seg); break; @@ -2924,9 +2924,9 @@ execx86(int cycs) case 0x8D: /*LEA*/ do_mod_rm(); cpu_state.regs[cpu_reg].w = cpu_state.eaaddr; - wait(1, 0); + wait_cycs(1, 0); if (cpu_mod != 3) - wait(2, 0); + wait_cycs(2, 0); break; case 0x8E: /*MOV sreg,w*/ @@ -2938,23 +2938,23 @@ execx86(int cycs) pfq_pos = 0; } else load_seg(tempw, _opseg[(rmdat & 0x18) >> 3]); - wait(1, 0); + wait_cycs(1, 0); if (cpu_mod != 3) - wait(2, 0); + wait_cycs(2, 0); if (((rmdat & 0x18) >> 3) == 2) noint = 1; break; case 0x8F: /*POPW*/ do_mod_rm(); - wait(1, 0); + wait_cycs(1, 0); cpu_src = cpu_state.eaaddr; access(24, 16); if (cpu_mod != 3) - wait(2, 0); + wait_cycs(2, 0); cpu_data = pop(); cpu_state.eaaddr = cpu_src; - wait(2, 0); + wait_cycs(2, 0); access(15, 16); seteaw(cpu_data); break; @@ -2968,30 +2968,30 @@ execx86(int cycs) case 0x96: case 0x97: /* XCHG AX, rw */ - wait(1, 0); + wait_cycs(1, 0); cpu_data = cpu_state.regs[opcode & 7].w; cpu_state.regs[opcode & 7].w = AX; AX = cpu_data; - wait(1, 0); + wait_cycs(1, 0); break; case 0x98: /*CBW*/ - wait(1, 0); + wait_cycs(1, 0); AX = sign_extend(AL); break; case 0x99: /*CWD*/ - wait(4, 0); + wait_cycs(4, 0); if (!top_bit(AX, 16)) DX = 0; else { - wait(1, 0); + wait_cycs(1, 0); DX = 0xffff; } break; case 0x9A: /*CALL FAR*/ - wait(1, 0); + wait_cycs(1, 0); new_ip = pfq_fetchw(); - wait(1, 0); + wait_cycs(1, 0); new_cs = pfq_fetchw(); pfq_clear(); access(31, 16); @@ -3005,11 +3005,11 @@ execx86(int cycs) break; case 0x9B: /*WAIT*/ if (!repeating) - wait(2, 0); - wait(5, 0); + wait_cycs(2, 0); + wait_cycs(5, 0); #ifdef NO_HACK if (irq_pending()) { - wait(7, 0); + wait_cycs(7, 0); check_interrupts(); } else { repeating = 1; @@ -3017,7 +3017,7 @@ execx86(int cycs) clock_end(); } #else - wait(7, 0); + wait_cycs(7, 0); check_interrupts(); #endif break; @@ -3035,16 +3035,16 @@ execx86(int cycs) cpu_state.flags = pop() | 0x8002; else cpu_state.flags = pop() | 0x0002; - wait(1, 0); + wait_cycs(1, 0); sync_to_i8080(); break; case 0x9E: /*SAHF*/ - wait(1, 0); + wait_cycs(1, 0); cpu_state.flags = (cpu_state.flags & 0xff02) | AH; - wait(2, 0); + wait_cycs(2, 0); break; case 0x9F: /*LAHF*/ - wait(1, 0); + wait_cycs(1, 0); AH = cpu_state.flags & 0xd7; break; @@ -3052,17 +3052,17 @@ execx86(int cycs) case 0xA1: /* MOV A, [iw] */ bits = 8 << (opcode & 1); - wait(1, 0); + wait_cycs(1, 0); cpu_state.eaaddr = pfq_fetchw(); access(1, bits); set_accum(bits, readmem((ovr_seg ? *ovr_seg : ds))); - wait(1, 0); + wait_cycs(1, 0); break; case 0xA2: case 0xA3: /* MOV [iw], A */ bits = 8 << (opcode & 1); - wait(1, 0); + wait_cycs(1, 0); cpu_state.eaaddr = pfq_fetchw(); access(7, bits); writemem((ovr_seg ? *ovr_seg : ds), get_accum(bits)); @@ -3074,18 +3074,18 @@ execx86(int cycs) case 0xAD: /* LODS */ bits = 8 << (opcode & 1); if (!repeating) { - wait(1, 0); + wait_cycs(1, 0); if ((opcode & 8) == 0 && in_rep != 0) - wait(1, 0); + wait_cycs(1, 0); } if (rep_action(bits)) { - wait(1, 0); + wait_cycs(1, 0); if ((opcode & 8) != 0) - wait(1, 0); + wait_cycs(1, 0); break; } if (in_rep != 0 && (opcode & 8) != 0) - wait(1, 0); + wait_cycs(1, 0); access(20, bits); lods(bits); if ((opcode & 8) == 0) { @@ -3094,12 +3094,12 @@ execx86(int cycs) } else { set_accum(bits, cpu_data); if (in_rep != 0) - wait(2, 0); + wait_cycs(2, 0); } if (in_rep == 0) { - wait(3, 0); + wait_cycs(3, 0); if ((opcode & 8) != 0) - wait(1, 0); + wait_cycs(1, 0); break; } repeating = 1; @@ -3112,19 +3112,19 @@ execx86(int cycs) case 0xAF: /* SCAS */ bits = 8 << (opcode & 1); if (!repeating) - wait(1, 0); + wait_cycs(1, 0); if (rep_action(bits)) { - wait(2, 0); + wait_cycs(2, 0); break; } if (in_rep != 0) - wait(1, 0); - wait(1, 0); + wait_cycs(1, 0); + wait_cycs(1, 0); cpu_dest = get_accum(bits); if ((opcode & 8) == 0) { access(21, bits); lods(bits); - wait(1, 0); + wait_cycs(1, 0); cpu_dest = cpu_data; } access(2, bits); @@ -3133,14 +3133,14 @@ execx86(int cycs) DI = string_increment(bits); cpu_src = cpu_data; sub(bits); - wait(2, 0); + wait_cycs(2, 0); if (in_rep == 0) { - wait(3, 0); + wait_cycs(3, 0); break; } if ((!!(cpu_state.flags & (rep_c_flag ? C_FLAG : Z_FLAG))) == (in_rep == 1)) { completed = 1; - wait(4, 0); + wait_cycs(4, 0); break; } repeating = 1; @@ -3151,29 +3151,29 @@ execx86(int cycs) case 0xA9: /* TEST A, imm */ bits = 8 << (opcode & 1); - wait(1, 0); + wait_cycs(1, 0); cpu_data = pfq_fetch(); test(bits, get_accum(bits), cpu_data); - wait(1, 0); + wait_cycs(1, 0); break; case 0xAA: case 0xAB: /* STOS */ bits = 8 << (opcode & 1); if (!repeating) { - wait(1, 0); + wait_cycs(1, 0); if (in_rep != 0) - wait(1, 0); + wait_cycs(1, 0); } if (rep_action(bits)) { - wait(1, 0); + wait_cycs(1, 0); break; } cpu_data = AX; access(28, bits); stos(bits); if (in_rep == 0) { - wait(3, 0); + wait_cycs(3, 0); break; } repeating = 1; @@ -3188,12 +3188,12 @@ execx86(int cycs) case 0xB5: case 0xB6: case 0xB7: - wait(1, 0); + wait_cycs(1, 0); if (opcode & 0x04) cpu_state.regs[opcode & 0x03].b.h = pfq_fetchb(); else cpu_state.regs[opcode & 0x03].b.l = pfq_fetchb(); - wait(1, 0); + wait_cycs(1, 0); break; case 0xB8: @@ -3204,9 +3204,9 @@ execx86(int cycs) case 0xBD: case 0xBE: case 0xBF: - wait(1, 0); + wait_cycs(1, 0); cpu_state.regs[opcode & 0x07].w = pfq_fetchw(); - wait(1, 0); + wait_cycs(1, 0); break; case 0xC0: @@ -3220,28 +3220,28 @@ execx86(int cycs) /* RET */ bits = 8 + (opcode & 0x08); if ((opcode & 9) != 1) - wait(1, 0); + wait_cycs(1, 0); if (!(opcode & 1)) { cpu_src = pfq_fetchw(); - wait(1, 0); + wait_cycs(1, 0); } if ((opcode & 9) == 9) - wait(1, 0); + wait_cycs(1, 0); pfq_clear(); access(26, bits); new_ip = pop(); - wait(2, 0); + wait_cycs(2, 0); if ((opcode & 8) == 0) new_cs = CS; else { access(42, bits); new_cs = pop(); if (opcode & 1) - wait(1, 0); + wait_cycs(1, 0); } if (!(opcode & 1)) { SP += cpu_src; - wait(1, 0); + wait_cycs(1, 0); } load_cs(new_cs); access(72, bits); @@ -3259,7 +3259,7 @@ execx86(int cycs) access(57, bits); read_ea2(bits); load_seg(cpu_data, (opcode & 0x01) ? &cpu_state.seg_ds : &cpu_state.seg_es); - wait(1, 0); + wait_cycs(1, 0); break; case 0xC6: @@ -3267,12 +3267,12 @@ execx86(int cycs) /* MOV rm, imm */ bits = 8 << (opcode & 1); do_mod_rm(); - wait(1, 0); + wait_cycs(1, 0); if (cpu_mod != 3) - wait(2, 0); + wait_cycs(2, 0); cpu_data = pfq_fetch(); if (cpu_mod == 3) - wait(1, 0); + wait_cycs(1, 0); access(16, bits); set_ea(cpu_data); break; @@ -3281,13 +3281,13 @@ execx86(int cycs) interrupt(3); break; case 0xCD: /*INT*/ - wait(1, 0); + wait_cycs(1, 0); interrupt(pfq_fetchb()); break; case 0xCE: /*INTO*/ - wait(3, 0); + wait_cycs(3, 0); if (cpu_state.flags & V_FLAG) { - wait(2, 0); + wait_cycs(2, 0); interrupt(4); } break; @@ -3295,7 +3295,7 @@ execx86(int cycs) case 0xCF: /*IRET*/ access(43, 8); new_ip = pop(); - wait(3, 0); + wait_cycs(3, 0); access(44, 8); new_cs = pop(); load_cs(new_cs); @@ -3306,7 +3306,7 @@ execx86(int cycs) cpu_state.flags = pop() | 0x8002; else cpu_state.flags = pop() | 0x0002; - wait(5, 0); + wait_cycs(5, 0); noint = 1; nmi_enable = 1; if (is_nec && !(cpu_state.flags & MD_FLAG)) @@ -3321,15 +3321,15 @@ execx86(int cycs) bits = 8 << (opcode & 1); do_mod_rm(); if (cpu_mod == 3) - wait(1, 0); + wait_cycs(1, 0); access(53, bits); cpu_data = get_ea(); if ((opcode & 2) == 0) { cpu_src = 1; - wait((cpu_mod != 3) ? 4 : 0, 0); + wait_cycs((cpu_mod != 3) ? 4 : 0, 0); } else { cpu_src = CL; - wait((cpu_mod != 3) ? 9 : 6, 0); + wait_cycs((cpu_mod != 3) ? 9 : 6, 0); } if (is186 && !is_nec) cpu_src &= 0x1F; @@ -3401,7 +3401,7 @@ execx86(int cycs) break; } if ((opcode & 2) != 0) - wait(4, 0); + wait_cycs(4, 0); --cpu_src; } access(17, bits); @@ -3409,7 +3409,7 @@ execx86(int cycs) break; case 0xD4: /*AAM*/ - wait(1, 0); + wait_cycs(1, 0); #ifdef NO_VARIANT_ON_NEC if (is_nec) { (void) pfq_fetchb(); @@ -3425,7 +3425,7 @@ execx86(int cycs) } break; case 0xD5: /*AAD*/ - wait(1, 0); + wait_cycs(1, 0); if (is_nec) { (void) pfq_fetchb(); mul(10, AH); @@ -3440,9 +3440,9 @@ execx86(int cycs) break; case 0xD6: /*SALC*/ if (!is_nec) { - wait(1, 0); + wait_cycs(1, 0); AL = (cpu_state.flags & C_FLAG) ? 0xff : 0x00; - wait(1, 0); + wait_cycs(1, 0); break; } fallthrough; @@ -3450,7 +3450,7 @@ execx86(int cycs) cpu_state.eaaddr = (BX + AL) & 0xffff; access(4, 8); AL = readmemb((ovr_seg ? *ovr_seg : ds) + cpu_state.eaaddr); - wait(1, 0); + wait_cycs(1, 0); break; case 0xD8: @@ -3531,9 +3531,9 @@ execx86(int cycs) } cpu_state.pc = tempw; /* Do this as the x87 code advances it, which is needed on the 286+ core, but not here. */ - wait(1, 0); + wait_cycs(1, 0); if (cpu_mod != 3) - wait(2, 0); + wait_cycs(2, 0); break; case 0xE0: @@ -3541,10 +3541,10 @@ execx86(int cycs) case 0xE2: case 0xE3: /* LOOP */ - wait(3, 0); + wait_cycs(3, 0); cpu_data = pfq_fetchb(); if (opcode != 0xe2) - wait(1, 0); + wait_cycs(1, 0); if (opcode != 0xe3) { --CX; oldc = (CX != 0); @@ -3574,7 +3574,7 @@ execx86(int cycs) case 0xEF: bits = 8 << (opcode & 1); if ((opcode & 0x0e) != 0x0c) - wait(1, 0); + wait_cycs(1, 0); if ((opcode & 8) == 0) cpu_data = pfq_fetchb(); else @@ -3586,7 +3586,7 @@ execx86(int cycs) cpu_io(16, 0, cpu_data); else cpu_io(8, 0, cpu_data); - wait(1, 0); + wait_cycs(1, 0); } else { if ((opcode & 8) == 0) access(8, bits); @@ -3600,19 +3600,19 @@ execx86(int cycs) break; case 0xE8: /*CALL rel 16*/ - wait(1, 0); + wait_cycs(1, 0); cpu_state.oldpc = jump_near(); access(34, 8); push((uint16_t *) &(cpu_state.oldpc)); break; case 0xE9: /*JMP rel 16*/ - wait(1, 0); + wait_cycs(1, 0); jump_near(); break; case 0xEA: /*JMP far*/ - wait(1, 0); + wait_cycs(1, 0); addr = pfq_fetchw(); - wait(1, 0); + wait_cycs(1, 0); tempw = pfq_fetchw(); load_cs(tempw); access(70, 8); @@ -3620,22 +3620,22 @@ execx86(int cycs) set_ip(addr); break; case 0xEB: /*JMP rel*/ - wait(1, 0); + wait_cycs(1, 0); cpu_data = (int8_t) pfq_fetchb(); jump_short(); - wait(1, 0); + wait_cycs(1, 0); break; case 0xF0: case 0xF1: /*LOCK - F1 is alias*/ in_lock = 1; - wait(1, 0); + wait_cycs(1, 0); completed = 0; break; case 0xF2: /*REPNE*/ case 0xF3: /*REPE*/ - wait(1, 0); + wait_cycs(1, 0); in_rep = (opcode == 0xf2 ? 1 : 2); completed = 0; rep_c_flag = 0; @@ -3643,12 +3643,12 @@ execx86(int cycs) case 0xF4: /*HLT*/ if (!repeating) { - wait(1, 0); + wait_cycs(1, 0); pfq_clear(); } - wait(1, 0); + wait_cycs(1, 0); if (irq_pending()) { - wait(cycles & 1, 0); + wait_cycs(cycles & 1, 0); check_interrupts(); } else { repeating = 1; @@ -3657,7 +3657,7 @@ execx86(int cycs) } break; case 0xF5: /*CMC*/ - wait(1, 0); + wait_cycs(1, 0); cpu_state.flags ^= C_FLAG; break; @@ -3671,18 +3671,18 @@ execx86(int cycs) case 0x00: case 0x08: /* TEST */ - wait(2, 0); + wait_cycs(2, 0); if (cpu_mod != 3) - wait(1, 0); + wait_cycs(1, 0); cpu_src = pfq_fetch(); - wait(1, 0); + wait_cycs(1, 0); test(bits, cpu_data, cpu_src); if (cpu_mod != 3) - wait(1, 0); + wait_cycs(1, 0); break; case 0x10: /* NOT */ case 0x18: /* NEG */ - wait(2, 0); + wait_cycs(2, 0); if ((rmdat & 0x38) == 0x10) cpu_data = ~cpu_data; else { @@ -3696,7 +3696,7 @@ execx86(int cycs) case 0x20: /* MUL */ case 0x28: /* IMUL */ old_flags = cpu_state.flags; - wait(1, 0); + wait_cycs(1, 0); mul(get_accum(bits), cpu_data); if (opcode & 1) { AX = cpu_data; @@ -3713,7 +3713,7 @@ execx86(int cycs) set_sf(bits); set_pf(); if (cpu_mod != 3) - wait(1, 0); + wait_cycs(1, 0); /* NOTE: When implementing the V20, care should be taken to not change the zero flag. */ if (is_nec) @@ -3722,10 +3722,10 @@ execx86(int cycs) case 0x30: /* DIV */ case 0x38: /* IDIV */ if (cpu_mod != 3) - wait(1, 0); + wait_cycs(1, 0); cpu_src = cpu_data; if (x86_div(AL, AH)) - wait(1, 0); + wait_cycs(1, 0); break; } break; @@ -3733,19 +3733,19 @@ execx86(int cycs) case 0xF8: case 0xF9: /* CLCSTC */ - wait(1, 0); + wait_cycs(1, 0); set_cf(opcode & 1); break; case 0xFA: case 0xFB: /* CLISTI */ - wait(1, 0); + wait_cycs(1, 0); set_if(opcode & 1); break; case 0xFC: case 0xFD: /* CLDSTD */ - wait(1, 0); + wait_cycs(1, 0); set_df(opcode & 1); break; @@ -3770,22 +3770,22 @@ execx86(int cycs) } do_af(); set_pzs(bits); - wait(2, 0); + wait_cycs(2, 0); access(19, bits); set_ea(cpu_data); break; case 0x10: /* CALL rm */ cpu_data_opff_rm(); access(63, bits); - wait(1, 0); + wait_cycs(1, 0); pfq_clear(); - wait(4, 0); + wait_cycs(4, 0); if (cpu_mod != 3) - wait(1, 0); - wait(1, 0); /* Wait. */ + wait_cycs(1, 0); + wait_cycs(1, 0); /* Wait. */ cpu_state.oldpc = cpu_state.pc; set_ip(cpu_data); - wait(2, 0); + wait_cycs(2, 0); access(35, bits); push((uint16_t *) &(cpu_state.oldpc)); break; @@ -3799,7 +3799,7 @@ execx86(int cycs) access(36, bits); push(&(CS)); access(64, bits); - wait(4, 0); + wait_cycs(4, 0); cpu_state.oldpc = cpu_state.pc; load_cs(new_cs); set_ip(new_ip); @@ -3825,7 +3825,7 @@ execx86(int cycs) case 0x30: /* PUSH rm */ case 0x38: if (cpu_mod != 3) - wait(1, 0); + wait_cycs(1, 0); access(38, bits); push((uint16_t *) &(cpu_data)); break; @@ -3835,7 +3835,7 @@ execx86(int cycs) default: x808x_log("Illegal opcode: %02X\n", opcode); pfq_fetchb(); - wait(8, 0); + wait_cycs(8, 0); break; } } diff --git a/src/cpu/x87_ops.h b/src/cpu/x87_ops.h index 0bd8209e1..1e4504949 100644 --- a/src/cpu/x87_ops.h +++ b/src/cpu/x87_ops.h @@ -22,6 +22,20 @@ */ #include #include +#if defined(_MSC_VER) && !defined(__clang__) +# if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 +# define X87_INLINE_ASM +# endif +#else +# if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 || defined _M_X64 || defined __amd64__ +# define X87_INLINE_ASM +# endif +#endif + +#ifdef X87_INLINE_ASM +#include +#endif + #include "x87_timings.h" #ifdef _MSC_VER # include @@ -38,7 +52,9 @@ extern void fpu_log(const char *fmt, ...); extern double exp_pow_table[0x800]; +#ifndef X87_INLINE_ASM static int rounding_modes[4] = { FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZERO }; +#endif #define ST(x) cpu_state.ST[((cpu_state.TOP + (x)) & 7)] @@ -64,16 +80,6 @@ typedef union { }; } double_decompose_t; -#if defined(_MSC_VER) && !defined(__clang__) -# if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 -# define X87_INLINE_ASM -# endif -#else -# if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 || defined _M_X64 || defined __amd64__ -# define X87_INLINE_ASM -# endif -#endif - #ifdef FPU_8087 # define x87_div(dst, src1, src2) \ do { \ @@ -575,7 +581,7 @@ static int FPU_ILLEGAL_a16(UNUSED(uint32_t fetchdat)) { geteaw(); - wait(timing_rr, 0); + wait_cycs(timing_rr, 0); return 0; } #else diff --git a/src/cpu/x87_ops_arith.h b/src/cpu/x87_ops_arith.h index 8d0c02167..bf3fbf253 100644 --- a/src/cpu/x87_ops_arith.h +++ b/src/cpu/x87_ops_arith.h @@ -1,3 +1,46 @@ + +#ifdef X87_INLINE_ASM +static inline double float_add(double src, double val, int round) +{ + int rounding_mode_orig; + + __m128d xmm_src = _mm_load_sd(&src); + __m128d xmm_dst = _mm_load_sd(&val); + __m128d xmm_res; + + rounding_mode_orig = _MM_GET_ROUNDING_MODE(); + if (round == 0) _MM_SET_ROUNDING_MODE(_MM_ROUND_NEAREST); + if (round == 1) _MM_SET_ROUNDING_MODE(_MM_ROUND_DOWN); + if (round == 2) _MM_SET_ROUNDING_MODE(_MM_ROUND_UP); + if (round == 3) _MM_SET_ROUNDING_MODE(_MM_ROUND_TOWARD_ZERO); + + xmm_res = _mm_add_sd(xmm_src, xmm_dst); + + _MM_SET_ROUNDING_MODE(rounding_mode_orig); + + return _mm_cvtsd_f64(xmm_res); +} + +#define DO_FADD(use_var) \ + do \ + { \ + ST(0) = float_add(ST(0), use_var, (cpu_state.npxc >> 10) & 3); \ + } \ + while (0) + +#else +#define DO_FADD(use_var) \ + do \ + { \ + if ((cpu_state.npxc >> 10) & 3) \ + fesetround(rounding_modes[(cpu_state.npxc >> 10) & 3]); \ + ST(0) += use_var; \ + if ((cpu_state.npxc >> 10) & 3) \ + fesetround(FE_TONEAREST); \ + } \ + while (0) +#endif + #define opFPU(name, optype, a_size, load_var, get, use_var, cycle_postfix) \ static int opFADD##name##_a##a_size(UNUSED(uint32_t fetchdat)) \ { \ @@ -8,11 +51,7 @@ load_var = get(); \ if (cpu_state.abrt) \ return 1; \ - if ((cpu_state.npxc >> 10) & 3) \ - fesetround(rounding_modes[(cpu_state.npxc >> 10) & 3]); \ - ST(0) += use_var; \ - if ((cpu_state.npxc >> 10) & 3) \ - fesetround(FE_TONEAREST); \ + DO_FADD(use_var); \ FP_TAG_VALID; \ CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fadd##cycle_postfix) : ((x87_timings.fadd##cycle_postfix) * cpu_multi)); \ CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fadd##cycle_postfix) : ((x87_concurrency.fadd##cycle_postfix) * cpu_multi)); \ diff --git a/src/cpu/x87_ops_misc.h b/src/cpu/x87_ops_misc.h index 9a01f7496..417beea62 100644 --- a/src/cpu/x87_ops_misc.h +++ b/src/cpu/x87_ops_misc.h @@ -7,7 +7,7 @@ opFI(uint32_t fetchdat) cpu_state.npxc &= ~0x80; if (rmdat == 0xe1) cpu_state.npxc |= 0x80; - wait(3, 0); + wait_cycs(3, 0); return 0; } #else diff --git a/src/cpu/x87_ops_sf.h b/src/cpu/x87_ops_sf.h index 0d4fee81a..adbaa2003 100644 --- a/src/cpu/x87_ops_sf.h +++ b/src/cpu/x87_ops_sf.h @@ -354,7 +354,7 @@ sf_FI(uint32_t fetchdat) fpu_state.cwd &= ~FPU_SW_Summary; if (rmdat == 0xe1) fpu_state.cwd |= FPU_SW_Summary; - wait(3, 0); + wait_cycs(3, 0); return 0; } #else diff --git a/src/include/86box/vid_cga.h b/src/include/86box/vid_cga.h index 04616431e..2198154ed 100644 --- a/src/include/86box/vid_cga.h +++ b/src/include/86box/vid_cga.h @@ -8,15 +8,13 @@ * * Emulation of the old and new IBM CGA graphics cards. * - * - * * Authors: Sarah Walker, - * Miran Grca, , + * Miran Grca, * Connor Hyde / starfrost, * * Copyright 2008-2018 Sarah Walker. * Copyright 2016-2018 Miran Grca. - * Copyright 2025 starfrost (refactoring) + * Copyright 2025 starfrost (refactoring). */ #ifndef VIDEO_CGA_H @@ -24,8 +22,7 @@ // Mode flags for the CGA. // Set by writing to 3D8 -typedef enum cga_mode_flags_e -{ +typedef enum cga_mode_flags_e { CGA_MODE_FLAG_HIGHRES = 1 << 0, // 80-column text mode CGA_MODE_FLAG_GRAPHICS = 1 << 1, // Graphics mode CGA_MODE_FLAG_BW = 1 << 2, // Black and white @@ -35,8 +32,7 @@ typedef enum cga_mode_flags_e } cga_mode_flags; // Motorola MC6845 CRTC registers -typedef enum cga_crtc_registers_e -{ +typedef enum cga_crtc_registers_e { CGA_CRTC_HTOTAL = 0x0, // Horizontal total (total number of characters incl. hsync) CGA_CRTC_HDISP = 0x1, // Horizontal display CGA_CRTC_HSYNC_POS = 0x2, // Horizontal position of horizontal ysnc @@ -58,8 +54,7 @@ typedef enum cga_crtc_registers_e } cga_crtc_registers; // Registers for the CGA -typedef enum cga_registers_e -{ +typedef enum cga_registers_e { CGA_REGISTER_CRTC_INDEX = 0x3D4, CGA_REGISTER_CRTC_DATA = 0x3D5, CGA_REGISTER_MODE_CONTROL = 0x3D8, @@ -129,11 +124,11 @@ uint8_t cga_read(uint32_t addr, void *priv); void cga_recalctimings(cga_t *cga); void cga_poll(void *priv); -#ifdef EMU_DEVICE_H -extern const device_config_t cga_config[]; - -extern const device_t cga_device; -extern const device_t cga_pravetz_device; -#endif - +//#ifdef EMU_DEVICE_H +//extern const device_config_t cga_config[]; +// +//extern const device_t cga_device; +//extern const device_t cga_pravetz_device; +//#endif +// #endif /*VIDEO_CGA_H*/ diff --git a/src/include/86box/vid_quadcolor.h b/src/include/86box/vid_quadcolor.h new file mode 100644 index 000000000..41b39dfb0 --- /dev/null +++ b/src/include/86box/vid_quadcolor.h @@ -0,0 +1,93 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Quadram Quadcolor I / I+II emulation + * + * Authors: Benedikt Freisen, + * Jasmine Iwanek, + * + * Copyright 2024 Benedikt Freisen. + Copyright 2025 Jasmine Iwanek. + */ + +#ifndef _VID_QUADCOLOR_H_ +#define _VID_QUADCOLOR_H_ + +typedef struct quadcolor_t { + mem_mapping_t mapping; + mem_mapping_t mapping_2; + + int crtcreg; +#if 0 + uint8_t crtc[CGA_NUM_CRTC_REGS]; +#else + uint8_t crtc[32]; +#endif + uint8_t cgastat; + + uint8_t cgamode; + uint8_t cgacol; + + uint8_t lp_strobe; + + uint8_t quadcolor_ctrl; + uint8_t quadcolor_2_oe; + uint16_t page_offset; + + int fontbase; + int linepos; + int displine; + int scanline; + int vc; + int cgadispon; + int cursorvisible; // Determines if the cursor is visible FOR THE CURRENT SCANLINE. + int cursoron; + int cgablink; + int vsynctime; + int vadj; + uint16_t memaddr; + uint16_t memaddr_backup; + int oddeven; + + int qc2idx; + uint8_t qc2mask; + + uint64_t dispontime; + uint64_t dispofftime; + pc_timer_t timer; + + int firstline; + int lastline; + + int drawcursor; + + int fullchange; + + uint8_t *vram; + uint8_t *vram_2; + + uint8_t charbuffer[256]; + + int revision; + int composite; + int rgb_type; + int double_type; + + int has_2nd_charset; + int has_quadcolor_2; +} quadcolor_t; + +void quadcolor_init(quadcolor_t *quadcolor); +void quadcolor_out(uint16_t addr, uint8_t val, void *priv); +uint8_t quadcolor_in(uint16_t addr, void *priv); +void quadcolor_write(uint32_t addr, uint8_t val, void *priv); +uint8_t quadcolor_read(uint32_t addr, void *priv); +void quadcolor_recalctimings(quadcolor_t *quadcolor); +void quadcolor_poll(void *priv); + +#endif /* _VID_QUADCOLOR_H_ */ diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index 8a18f0865..14f3c933a 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -30,6 +30,7 @@ # define FLAG_S3_911_16BIT 256 # define FLAG_512K_MASK 512 # define FLAG_NO_SHIFT3 1024 /* Needed for Bochs VBE. */ +# define FLAG_PRECISETIME 2048 /* Needed for Copper demo if on dynarec. */ struct monitor_t; typedef struct hwcursor_t { @@ -137,6 +138,9 @@ typedef struct svga_t { int ps_bit_bug; int ati_4color; int vblankend; + int panning_blank; + int render_line_offset; + int start_retrace_latch; /*The three variables below allow us to implement memory maps like that seen on a 1MB Trio64 : 0MB-1MB - VRAM diff --git a/src/include/86box/vid_svga_render.h b/src/include/86box/vid_svga_render.h index 226ab8a18..7ead95838 100644 --- a/src/include/86box/vid_svga_render.h +++ b/src/include/86box/vid_svga_render.h @@ -55,6 +55,7 @@ extern void svga_render_4bpp_lowres(svga_t *svga); extern void svga_render_4bpp_highres(svga_t *svga); extern void svga_render_8bpp_lowres(svga_t *svga); extern void svga_render_8bpp_highres(svga_t *svga); +extern void svga_render_4bpp_tseng_highres(svga_t *svga); extern void svga_render_8bpp_clone_highres(svga_t *svga); extern void svga_render_8bpp_tseng_lowres(svga_t *svga); extern void svga_render_8bpp_tseng_highres(svga_t *svga); diff --git a/src/include/86box/video.h b/src/include/86box/video.h index 986529d6f..62fea0b9a 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -399,6 +399,13 @@ extern const device_t gd5446_pci_device; extern const device_t gd5446_stb_pci_device; extern const device_t gd5480_pci_device; + +/* IBM CGA*/ +extern const device_t cga_device; + +/* pravetz CGA */ +extern const device_t cga_pravetz_device; + /* Compaq CGA */ extern const device_t compaq_cga_device; extern const device_t compaq_cga_2_device; @@ -491,6 +498,9 @@ extern const device_t paradise_wd90c11_megapc_device; extern const device_t paradise_wd90c11_device; extern const device_t paradise_wd90c30_device; +/* Quadram Quadcolor I / I + II */ +extern const device_t quadcolor_device; + /* Realtek (S)VGA */ extern const device_t realtek_rtg3105_device; extern const device_t realtek_rtg3106_device; diff --git a/src/machine/m_xt_zenith.c b/src/machine/m_xt_zenith.c index 62c6496d1..2159c18e5 100644 --- a/src/machine/m_xt_zenith.c +++ b/src/machine/m_xt_zenith.c @@ -45,7 +45,7 @@ #include <86box/serial.h> #include <86box/machine.h> #include <86box/io.h> -#include <86box/vid_cga.h> +#include <86box/video.h> #include <86box/plat_unused.h> typedef struct { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index d5e2af58b..87dd38786 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -14730,7 +14730,7 @@ const machine_t machines[] = { .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, .ram = { - .min = 1024, + .min = 8192, .max = 1572864, .step = 8192 }, @@ -14770,7 +14770,7 @@ const machine_t machines[] = { .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, .ram = { - .min = 1024, + .min = 8192, .max = 1572864, .step = 8192 }, diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index afb5fcc1d..eb7d6ac44 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -790,20 +790,6 @@ main(int argc, char *argv[]) main_window->installEventFilter(&manager_socket); } - /* Warn the user about unsupported configs */ - if (cpu_override) { - QMessageBox warningbox(QMessageBox::Icon::Warning, QObject::tr("You are loading an unsupported configuration"), - QObject::tr("CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid."), - QMessageBox::NoButton, main_window); - warningbox.addButton(QObject::tr("Continue"), QMessageBox::AcceptRole); - warningbox.addButton(QObject::tr("Exit"), QMessageBox::RejectRole); - warningbox.exec(); - if (warningbox.result() == QDialog::Accepted) { - confirm_exit_cmdl = 0; /* skip the confirmation prompt without touching the config */ - emit main_window->close(); - } - } - // pc_reset_hard_init(); QTimer onesec; diff --git a/src/qt/qt_updatedetails.cpp b/src/qt/qt_updatedetails.cpp index 1d6846dd6..dceeea47c 100644 --- a/src/qt/qt_updatedetails.cpp +++ b/src/qt/qt_updatedetails.cpp @@ -102,10 +102,10 @@ UpdateDetails::visitDownloadPage(const UpdateCheck::UpdateChannel &channel) { switch (channel) { case UpdateCheck::UpdateChannel::Stable: - QDesktopServices::openUrl(QUrl("https://ci.86box.net/job/86Box/lastSuccessfulBuild/artifact/")); - break; - case UpdateCheck::UpdateChannel::CI: QDesktopServices::openUrl(QUrl("https://github.com/86Box/86Box/releases/latest")); - break; + break; + case UpdateCheck::UpdateChannel::CI: + QDesktopServices::openUrl(QUrl("https://ci.86box.net/job/86Box/lastSuccessfulBuild/artifact/")); + break; } } diff --git a/src/qt/qt_vmmanager_addmachine.cpp b/src/qt/qt_vmmanager_addmachine.cpp index db40972a1..597c2ef11 100644 --- a/src/qt/qt_vmmanager_addmachine.cpp +++ b/src/qt/qt_vmmanager_addmachine.cpp @@ -210,7 +210,13 @@ NameAndLocationPage(QWidget *parent) { setTitle(tr("System name and location")); - dirValidate = QRegularExpression(R"(^[^\\/:*?"<>|\s]+$)"); +#if defined(_WIN32) + dirValidate = QRegularExpression(R"(^[^\\/:*?"<>|]+$)"); +#elif defined(__APPLE__) + dirValidate = QRegularExpression(R"(^[^/:]+$)"); +#else + dirValidate = QRegularExpression(R"(^[^/]+$)"); +#endif const auto topLabel = new QLabel(tr("Enter the name of the system and choose the location")); topLabel->setWordWrap(true); @@ -282,7 +288,7 @@ NameAndLocationPage::isComplete() const if (systemName->text().isEmpty()) { systemNameValidation->setText(tr("Please enter a system name")); } else if (!systemName->text().contains(dirValidate)) { - systemNameValidation->setText(tr("System name cannot contain a space or certain characters")); + systemNameValidation->setText(tr("System name cannot contain certain characters")); } else if (const QDir newDir = QDir::cleanPath(systemLocation->text() + "/" + systemName->text()); newDir.exists()) { systemNameValidation->setText(tr("System name already exists")); } else { diff --git a/src/qt/qt_vmmanager_main.cpp b/src/qt/qt_vmmanager_main.cpp index 88b9456cc..8d59b0996 100644 --- a/src/qt/qt_vmmanager_main.cpp +++ b/src/qt/qt_vmmanager_main.cpp @@ -72,10 +72,6 @@ VMManagerMain::VMManagerMain(QWidget *parent) : } }); - QAction convertToP3(tr("Convert system to PIII")); - contextMenu.addAction(&convertToP3); - convertToP3.setEnabled(false); - QAction setSystemIcon(tr("Set icon")); contextMenu.addAction(&setSystemIcon); connect(&setSystemIcon, &QAction::triggered, [this] { @@ -460,6 +456,7 @@ VMManagerMain::onPreferencesUpdated() void VMManagerMain::backgroundUpdateCheckStart() const { +#if EMU_BUILD_NUM != 0 auto updateChannel = UpdateCheck::UpdateChannel::CI; #ifdef RELEASE_BUILD updateChannel = UpdateCheck::UpdateChannel::Stable; @@ -468,6 +465,7 @@ VMManagerMain::backgroundUpdateCheckStart() const connect(updateCheck, &UpdateCheck::updateCheckComplete, this, &VMManagerMain::backgroundUpdateCheckComplete); connect(updateCheck, &UpdateCheck::updateCheckError, this, &VMManagerMain::backgroundUpdateCheckError); updateCheck->checkForUpdates(); +#endif } void diff --git a/src/qt/qt_vmmanager_mainwindow.cpp b/src/qt/qt_vmmanager_mainwindow.cpp index 767bbcef2..a6f598f58 100644 --- a/src/qt/qt_vmmanager_mainwindow.cpp +++ b/src/qt/qt_vmmanager_mainwindow.cpp @@ -48,8 +48,13 @@ VMManagerMainWindow(QWidget *parent) connect(ui->actionNew_Machine, &QAction::triggered, vmm, &VMManagerMain::newMachineWizard); // Set up menu actions - connect(ui->actionCheck_for_updates, &QAction::triggered, this, &VMManagerMainWindow::checkForUpdatesTriggered); - + // (Disable this if the EMU_BUILD_NUM == 0) + #if EMU_BUILD_NUM == 0 + ui->actionCheck_for_updates->setVisible(false); + #else + connect(ui->actionCheck_for_updates, &QAction::triggered, this, &VMManagerMainWindow::checkForUpdatesTriggered); + #endif + // TODO: Remove all of this (all the way to END REMOVE) once certain the search will no longer be in the toolbar. // BEGIN REMOVE // Everything is still setup here for it but it is all hidden. None of it will be diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt index 4cac8b76d..1159c93e2 100644 --- a/src/video/CMakeLists.txt +++ b/src/video/CMakeLists.txt @@ -55,8 +55,9 @@ add_library(vid OBJECT vid_cga_colorplus.c vid_cga_ncr.c vid_cga_olivetti.c - vid_cga_toshiba_t1000.c - vid_cga_toshiba_t3100e.c + vid_cga_quadcolor.c + vid_cga_toshiba_t1000.c + vid_cga_toshiba_t3100e.c # PCJr/Tandy vid_pcjr.c diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index b1e38fef7..c8191a876 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -3819,7 +3819,7 @@ ibm8514_recalctimings(svga_t *svga) } else { if (dev->on) { dev->hdisp = (dev->hdisped + 1) << 3; - dev->h_total = (dev->htotal + 1) << 3; + dev->h_total = dev->htotal + 1; if (dev->h_total == 1) /*Default to 1024x768 87hz 8514/A htotal timings if it goes to 0.*/ dev->h_total = 0x9e; @@ -3854,6 +3854,7 @@ ibm8514_recalctimings(svga_t *svga) dev->h_disp = dev->hdisp; dev->dispend = dev->vdisp; + dev->h_disp_time = dev->hdisp >> 3; if (dev->accel.advfunc_cntl & 0x04) svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / 44900000.0; diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index c5cb2ccca..df8965caf 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -2707,9 +2707,9 @@ mach_set_resolution(mach_t *mach, svga_t *svga) { ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - dev->h_total = (dev->htotal + 1) << 3; + dev->h_total = (dev->htotal + 1); if (dev->h_total == 8) /*Default to 1024x768 87hz 8514/A htotal timings if it goes to 0.*/ - dev->h_total = 0x9e << 3; + dev->h_total = 0x9e; dev->hdisp = (dev->hdisped + 1) << 3; @@ -2730,7 +2730,7 @@ mach_set_resolution(mach_t *mach, svga_t *svga) switch (mach->shadow_set & 0x03) { case 0x01: if (!(dev->accel.advfunc_cntl & 0x04)) { - dev->h_total = 0x64 << 3; + dev->h_total = 0x64; dev->hdisp = 640; dev->vdisp = 480; dev->v_total = 0x0419; @@ -2739,7 +2739,7 @@ mach_set_resolution(mach_t *mach, svga_t *svga) break; case 0x02: if (dev->accel.advfunc_cntl & 0x04) { - dev->h_total = 0x9e << 3; + dev->h_total = 0x9e; dev->hdisp = 1024; dev->vdisp = 768; dev->v_total = 0x0669; @@ -2754,7 +2754,7 @@ mach_set_resolution(mach_t *mach, svga_t *svga) } else if ((dev->disp_cntl >> 5) == 2) { /*Reset 8514/A to defaults if needed.*/ if (dev->accel.advfunc_cntl & 0x04) { if (dev->hdisp == 640) { - dev->h_total = 0x9e << 3; + dev->h_total = 0x9e; dev->hdisp = 1024; dev->vdisp = 768; dev->v_total = 0x0669; @@ -2763,7 +2763,7 @@ mach_set_resolution(mach_t *mach, svga_t *svga) } } else { if (dev->hdisp == 1024) { - dev->h_total = 0x64 << 3; + dev->h_total = 0x64; dev->hdisp = 640; dev->vdisp = 480; dev->v_total = 0x0419; @@ -2926,6 +2926,8 @@ mach_recalctimings(svga_t *svga) else if (dev->h_disp == 640) dev->dispend = 480; + dev->h_disp_time = dev->hdisp >> 3; + svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / svga->getclock((mach->accel.clock_sel >> 2) & 0x0f, svga->clock_gen); if (mach->accel.clock_sel & 0x40) svga->clock_8514 *= 2; diff --git a/src/video/vid_cga.c b/src/video/vid_cga.c index 2abfe6a5c..1ca742890 100644 --- a/src/video/vid_cga.c +++ b/src/video/vid_cga.c @@ -8,15 +8,13 @@ * * Emulation of the old and new IBM CGA graphics cards. * - * - * * Authors: Sarah Walker, * Miran Grca, * W. M. Martinez, * * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 Miran Grca. - * Copyright 2023 W. M. Martinez + * Copyright 2023 W. M. Martinez */ #include #include @@ -284,7 +282,7 @@ cga_render(cga_t *cga, int line) buffer32->line[line][column + (cga->crtc[CGA_CRTC_HDISP] << 4) + 8] = (cga->cgacol & 15) + 16; } } - if (cga->cgamode & CGA_MODE_FLAG_HIGHRES) { + if (cga->cgamode & CGA_MODE_FLAG_HIGHRES) { /* 80-column text */ for (x = 0; x < cga->crtc[CGA_CRTC_HDISP]; x++) { if (cga->cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) { chr = cga->charbuffer[x << 1]; @@ -342,7 +340,7 @@ cga_render(cga_t *cga, int line) } } } - } else if (!(cga->cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS)) { + } else if (!(cga->cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS)) { /* not hi-res (but graphics) => 4-color mode */ cols[0] = (cga->cgacol & 15) | 16; col = (cga->cgacol & 16) ? 24 : 16; if (cga->cgamode & CGA_MODE_FLAG_BW) { @@ -372,7 +370,7 @@ cga_render(cga_t *cga, int line) dat <<= 2; } } - } else { + } else { /* 2-color hi-res graphics mode */ cols[0] = 0; cols[1] = (cga->cgacol & 15) + 16; for (x = 0; x < cga->crtc[CGA_CRTC_HDISP]; x++) { @@ -500,7 +498,7 @@ cga_interpolate(cga_t *cga, int x, int y, int w, int h) interim_1 = cga_interpolate_lookup(cga, prev_color, black, quotient); interim_2 = cga_interpolate_lookup(cga, black, next_color, quotient); - final = cga_interpolate_lookup(cga, interim_1, interim_2, quotient); + final = cga_interpolate_lookup(cga, interim_1, interim_2, quotient); buffer32->line[i][j] = final.color; } @@ -746,9 +744,8 @@ void * cga_standalone_init(UNUSED(const device_t *info)) { int display_type; - cga_t *cga = malloc(sizeof(cga_t)); + cga_t *cga = calloc(1, sizeof(cga_t)); - memset(cga, 0, sizeof(cga_t)); video_inform(VIDEO_FLAG_TYPE_CGA, &timing_cga); display_type = device_get_config_int("display_type"); diff --git a/src/video/vid_cga_olivetti.c b/src/video/vid_cga_olivetti.c index 8be40ee2e..147529f6e 100644 --- a/src/video/vid_cga_olivetti.c +++ b/src/video/vid_cga_olivetti.c @@ -38,6 +38,7 @@ #include <86box/rom.h> #include <86box/device.h> #include <86box/vid_cga.h> +extern const device_config_t cga_config[]; /* defined in vid_cga.c */ #include <86box/vid_ogc.h> #include <86box/vid_cga_comp.h> #include <86box/plat_unused.h> diff --git a/src/video/vid_cga_quadcolor.c b/src/video/vid_cga_quadcolor.c new file mode 100644 index 000000000..5974682c8 --- /dev/null +++ b/src/video/vid_cga_quadcolor.c @@ -0,0 +1,981 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Quadram Quadcolor I / I+II emulation + * + * Authors: Sarah Walker, + * Miran Grca, + * W. M. Martinez, + * Benedikt Freisen, + * Jasmine Iwanek, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2023 W. M. Martinez + * Copyright 2024 Benedikt Freisen. + * Copyright 2025 Jasmine Iwanek. + */ + +/* This has been derived from CGA emulation */ +/* omissions: simulated snow (Quadcolor has dual-ported RAM), single and dual 8x16 font configuration */ +/* additions: ports 0x3dd and 0x3de, 2nd char set, 2nd VRAM bank, hi-res bg color, Quadcolor II memory and mode */ +/* assumptions: MA line 12 XORed with Bank Select, hi-res bg is also border color, QC2 mode has simple address counter */ + +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include "cpu.h" +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/pit.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/device.h> +#include <86box/video.h> +#include <86box/vid_cga.h> +#include <86box/vid_quadcolor.h> +#include <86box/vid_cga_comp.h> +#include <86box/plat_unused.h> + +#define CGA_RGB 0 +#define CGA_COMPOSITE 1 + +#define COMPOSITE_OLD 0 +#define COMPOSITE_NEW 1 + +#define DOUBLE_NONE 0 +#define DOUBLE_SIMPLE 1 +#define DOUBLE_INTERPOLATE_SRGB 2 +#define DOUBLE_INTERPOLATE_LINEAR 3 + +#define DEVICE_VRAM 0x8000 +#define DEVICE_VRAM_MASK 0x7fff + +typedef union { + uint32_t color; + struct { + uint8_t b; + uint8_t g; + uint8_t r; + uint8_t a; + }; +} color_t; + +static uint8_t crtcmask[32] = { + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static uint8_t interp_lut[2][256][256]; + +static video_timings_t timing_quadcolor = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 }; + +void quadcolor_recalctimings(quadcolor_t *quadcolor); + +static void +quadcolor_update_latch(quadcolor_t *quadcolor) +{ + uint32_t lp_latch = quadcolor->displine * quadcolor->crtc[CGA_CRTC_HDISP]; + + quadcolor->crtc[CGA_CRTC_LIGHT_PEN_ADDR_HIGH] = (lp_latch >> 8) & 0x3f; + quadcolor->crtc[CGA_CRTC_LIGHT_PEN_ADDR_LOW] = lp_latch & 0xff; +} + +void +quadcolor_out(uint16_t addr, uint8_t val, void *priv) +{ + quadcolor_t *quadcolor = (quadcolor_t *) priv; + uint8_t old; + + if ((addr >= 0x3d0) && (addr <= 0x3d7)) + addr = (addr & 0xff9) | 0x004; + + switch (addr) { + case CGA_REGISTER_CRTC_INDEX: + quadcolor->crtcreg = val & 31; + return; + case CGA_REGISTER_CRTC_DATA: + old = quadcolor->crtc[quadcolor->crtcreg]; + quadcolor->crtc[quadcolor->crtcreg] = val & crtcmask[quadcolor->crtcreg]; + if (old != val) { + // Recalc the timings if we are writing any invalid CRTC register or a valid CRTC register + // except the CURSOR and LIGHT PEN registers + if ((quadcolor->crtcreg < 0xe) || (quadcolor->crtcreg > 0x11)) { + quadcolor->fullchange = changeframecount; + quadcolor_recalctimings(quadcolor); + } + } + return; + case CGA_REGISTER_MODE_CONTROL: + old = quadcolor->cgamode; + quadcolor->cgamode = val; + + if (old ^ val) { + if ((old ^ val) & 0x07) + update_cga16_color(val); + + quadcolor_recalctimings(quadcolor); + } + return; + case CGA_REGISTER_COLOR_SELECT: + old = quadcolor->cgacol; + quadcolor->cgacol = val; + if (old ^ val) + quadcolor_recalctimings(quadcolor); + return; + + case CGA_REGISTER_CLEAR_LIGHT_PEN_LATCH: + if (quadcolor->lp_strobe == 1) + quadcolor->lp_strobe = 0; + return; + case CGA_REGISTER_SET_LIGHT_PEN_LATCH: + if (quadcolor->lp_strobe == 0) { + quadcolor->lp_strobe = 1; + quadcolor_update_latch(quadcolor); + } + return; + + case 0x3dd: + quadcolor->quadcolor_ctrl = val & 0x3f; + /* helper variable that can be XORed onto the VRAM address to select the page to display */ + quadcolor->page_offset = (val & 0x10) << 8; + /* in dual 8x8 font configuration, use fontbase 256 if "Character Set Select" bit is set */ + if (quadcolor->has_2nd_charset) + quadcolor->fontbase = (val & 0x20) << 3; + return; + case 0x3de: + /* NOTE: the polarity of this register is the opposite of what the manual says */ + if (quadcolor->has_quadcolor_2) + quadcolor->quadcolor_2_oe = !(val & 0x10); + return; + + default: + break; + } +} + +uint8_t +quadcolor_in(uint16_t addr, void *priv) +{ + quadcolor_t *quadcolor = (quadcolor_t *) priv; + uint8_t ret = 0xff; + + if ((addr >= 0x3d0) && (addr <= 0x3d7)) + addr = (addr & 0xff9) | 0x004; + + switch (addr) { + case CGA_REGISTER_CRTC_INDEX: + ret = quadcolor->crtcreg; + break; + case CGA_REGISTER_CRTC_DATA: + ret = quadcolor->crtc[quadcolor->crtcreg]; + break; + case CGA_REGISTER_STATUS: + ret = quadcolor->cgastat; + break; + case CGA_REGISTER_CLEAR_LIGHT_PEN_LATCH: + if (quadcolor->lp_strobe == 1) + quadcolor->lp_strobe = 0; + break; + case CGA_REGISTER_SET_LIGHT_PEN_LATCH: + if (quadcolor->lp_strobe == 0) { + quadcolor->lp_strobe = 1; + quadcolor_update_latch(quadcolor); + } + break; + + default: + break; + } + + return ret; +} + +void +quadcolor_waitstates(UNUSED(void *priv)) +{ + int ws_array[16] = { 3, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8 }; + int ws; + + ws = ws_array[cycles & 0xf]; + cycles -= ws; +} + +void +quadcolor_write(uint32_t addr, uint8_t val, void *priv) +{ + quadcolor_t *quadcolor = (quadcolor_t *) priv; + + quadcolor->vram[addr & DEVICE_VRAM_MASK] = val; + quadcolor_waitstates(quadcolor); +} + +uint8_t +quadcolor_read(uint32_t addr, void *priv) +{ + quadcolor_t *quadcolor = (quadcolor_t *) priv; + + quadcolor_waitstates(quadcolor); + return quadcolor->vram[addr & DEVICE_VRAM_MASK]; +} + +void +quadcolor_2_write(uint32_t addr, uint8_t val, void *priv) +{ + quadcolor_t *quadcolor = (quadcolor_t *) priv; + quadcolor->vram_2[addr & 0xffff] = val; +} + +uint8_t +quadcolor_2_read(uint32_t addr, void *priv) +{ + quadcolor_t *quadcolor = (quadcolor_t *) priv; + return quadcolor->vram_2[addr & 0xffff]; +} + +void +quadcolor_recalctimings(quadcolor_t *quadcolor) +{ + double disptime; + double _dispontime; + double _dispofftime; + + if (quadcolor->cgamode & CGA_MODE_FLAG_HIGHRES) { + disptime = (double) (quadcolor->crtc[CGA_CRTC_HTOTAL] + 1); + _dispontime = (double) quadcolor->crtc[CGA_CRTC_HDISP]; + } else { + disptime = (double) ((quadcolor->crtc[CGA_CRTC_HTOTAL] + 1) << 1); + _dispontime = (double) (quadcolor->crtc[CGA_CRTC_HDISP] << 1); + } + _dispofftime = disptime - _dispontime; + _dispontime = _dispontime * CGACONST; + _dispofftime = _dispofftime * CGACONST; + quadcolor->dispontime = (uint64_t) (_dispontime); + quadcolor->dispofftime = (uint64_t) (_dispofftime); +} + +static inline uint8_t +get_next_qc2_pixel(quadcolor_t *quadcolor) +{ + uint8_t mask = quadcolor->qc2mask; + quadcolor->qc2mask = ~quadcolor->qc2mask; + uint8_t pixel = (quadcolor->vram_2[quadcolor->qc2idx] & mask) >> (quadcolor->qc2mask & 4); + + quadcolor->qc2idx += quadcolor->qc2mask >> 7; + + return quadcolor->quadcolor_2_oe ? pixel : 0; +} + +static void +quadcolor_render(quadcolor_t *quadcolor, int line) +{ + uint16_t cursoraddr = (quadcolor->crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (quadcolor->crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & DEVICE_VRAM_MASK; + int drawcursor; + int x; + int column; + uint8_t chr; + uint8_t attr; + uint16_t dat; + int cols[4]; + int col; + + int32_t highres_graphics_flag = (CGA_MODE_FLAG_HIGHRES_GRAPHICS | CGA_MODE_FLAG_GRAPHICS); + + if (((quadcolor->cgamode & highres_graphics_flag) == highres_graphics_flag)) { + for (column = 0; column < 8; ++column) { + buffer32->line[line][column] = 0; + if (quadcolor->cgamode & CGA_MODE_FLAG_HIGHRES) + buffer32->line[line][column + (quadcolor->crtc[CGA_CRTC_HDISP] << 3) + 8] = (quadcolor->quadcolor_ctrl & 15); /* TODO: Is Quadcolor bg color actually relevant, here? */ + else + buffer32->line[line][column + (quadcolor->crtc[CGA_CRTC_HDISP] << 4) + 8] = (quadcolor->quadcolor_ctrl & 15); /* TODO: Is Quadcolor bg color actually relevant, here? */ + } + } else { + for (column = 0; column < 8; ++column) { + buffer32->line[line][column] = (quadcolor->cgacol & 15) + 16; + if (quadcolor->cgamode & CGA_MODE_FLAG_HIGHRES) + buffer32->line[line][column + (quadcolor->crtc[CGA_CRTC_HDISP] << 3) + 8] = (quadcolor->cgacol & 15) + 16; + else + buffer32->line[line][column + (quadcolor->crtc[CGA_CRTC_HDISP] << 4) + 8] = (quadcolor->cgacol & 15) + 16; + } + } + if (quadcolor->cgamode & CGA_MODE_FLAG_HIGHRES) { /* 80-column text */ + for (x = 0; x < quadcolor->crtc[CGA_CRTC_HDISP]; x++) { + if (quadcolor->cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) { + chr = quadcolor->charbuffer[x << 1]; + attr = quadcolor->charbuffer[(x << 1) + 1]; + } else + chr = attr = 0; + drawcursor = ((quadcolor->memaddr == cursoraddr) && quadcolor->cursorvisible && quadcolor->cursoron); + cols[1] = (attr & 15) + 16; + if (quadcolor->cgamode & CGA_MODE_FLAG_BLINK) { + cols[0] = ((attr >> 4) & 7) + 16; + if ((quadcolor->cgablink & 8) && (attr & 0x80) && !quadcolor->drawcursor) + cols[1] = cols[0]; + } else + cols[0] = (attr >> 4) + 16; + if (drawcursor) { + for (column = 0; column < 8; column++) { + buffer32->line[line][(x << 3) + column + 8] + = (cols[(fontdat[chr + quadcolor->fontbase][quadcolor->scanline & 7] & (1 << (column ^ 7))) ? 1 : 0] ^ 15) | get_next_qc2_pixel(quadcolor); + } + } else { + for (column = 0; column < 8; column++) { + buffer32->line[line][(x << 3) + column + 8] + = cols[(fontdat[chr + quadcolor->fontbase][quadcolor->scanline & 7] & (1 << (column ^ 7))) ? 1 : 0] | get_next_qc2_pixel(quadcolor); + } + } + quadcolor->memaddr++; + } + } else if (!(quadcolor->cgamode & CGA_MODE_FLAG_GRAPHICS)) { /* not graphics (nor 80-column text) => 40-column text */ + for (x = 0; x < quadcolor->crtc[CGA_CRTC_HDISP]; x++) { + if (quadcolor->cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) { + chr = quadcolor->vram[(quadcolor->page_offset ^ (quadcolor->memaddr << 1)) & DEVICE_VRAM_MASK]; + attr = quadcolor->vram[(quadcolor->page_offset ^ ((quadcolor->memaddr << 1) + 1)) & DEVICE_VRAM_MASK]; + } else + chr = attr = 0; + drawcursor = ((quadcolor->memaddr == cursoraddr) && quadcolor->cursorvisible && quadcolor->cursoron); + cols[1] = (attr & 15) + 16; + if (quadcolor->cgamode & CGA_MODE_FLAG_BLINK) { + cols[0] = ((attr >> 4) & 7) + 16; + if ((quadcolor->cgablink & 8) && (attr & 0x80)) + cols[1] = cols[0]; + } else + cols[0] = (attr >> 4) + 16; + quadcolor->memaddr++; + if (drawcursor) { + for (column = 0; column < 8; column++) { + dat = (cols[(fontdat[chr + quadcolor->fontbase][quadcolor->scanline & 7] & (1 << (column ^ 7))) ? 1 : 0] ^ 15); + buffer32->line[line][(x << 4) + (column << 1) + 8] = dat | get_next_qc2_pixel(quadcolor); + buffer32->line[line][(x << 4) + (column << 1) + 9] = dat | get_next_qc2_pixel(quadcolor); + + } + } else { + for (column = 0; column < 8; column++) { + dat = cols[(fontdat[chr + quadcolor->fontbase][quadcolor->scanline & 7] & (1 << (column ^ 7))) ? 1 : 0]; + buffer32->line[line][(x << 4) + (column << 1) + 8] = dat | get_next_qc2_pixel(quadcolor); + buffer32->line[line][(x << 4) + (column << 1) + 9] = dat | get_next_qc2_pixel(quadcolor); + + } + } + } + } else if (!(quadcolor->cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS)) { /* not hi-res (but graphics) => 4-color mode */ + cols[0] = (quadcolor->cgacol & 15) | 16; + col = (quadcolor->cgacol & 16) ? 24 : 16; + if (quadcolor->cgamode & CGA_MODE_FLAG_BW) { + cols[1] = col | 3; /* Cyan */ + cols[2] = col | 4; /* Red */ + cols[3] = col | 7; /* White */ + } else if (quadcolor->cgacol & 32) { + cols[1] = col | 3; /* Cyan */ + cols[2] = col | 5; /* Magenta */ + cols[3] = col | 7; /* White */ + } else { + cols[1] = col | 2; /* Green */ + cols[2] = col | 4; /* Red */ + cols[3] = col | 6; /* Yellow */ + } + for (x = 0; x < quadcolor->crtc[CGA_CRTC_HDISP]; x++) { + if (quadcolor->cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) + dat = (quadcolor->vram[quadcolor->page_offset ^ (((quadcolor->memaddr << 1) & 0x1fff) + ((quadcolor->scanline & 1) * 0x2000))] << 8) | + quadcolor->vram[quadcolor->page_offset ^ (((quadcolor->memaddr << 1) & 0x1fff) + ((quadcolor->scanline & 1) * 0x2000) + 1)]; + else + dat = 0; + quadcolor->memaddr++; + for (column = 0; column < 8; column++) { + buffer32->line[line][(x << 4) + (column << 1) + 8] = cols[dat >> 14] | get_next_qc2_pixel(quadcolor); + buffer32->line[line][(x << 4) + (column << 1) + 9] = cols[dat >> 14] | get_next_qc2_pixel(quadcolor); + dat <<= 2; + } + } + } else { /* 2-color hi-res graphics mode */ + cols[0] = quadcolor->quadcolor_ctrl & 15; /* background color (Quadcolor-specific) */; + cols[1] = (quadcolor->cgacol & 15) + 16; + for (x = 0; x < quadcolor->crtc[CGA_CRTC_HDISP]; x++) { + if (quadcolor->cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) /* video enabled */ + dat = (quadcolor->vram[quadcolor->page_offset ^ (((quadcolor->memaddr << 1) & 0x1fff) + ((quadcolor->scanline & 1) * 0x2000))] << 8) | + quadcolor->vram[quadcolor->page_offset ^ (((quadcolor->memaddr << 1) & 0x1fff) + ((quadcolor->scanline & 1) * 0x2000) + 1)]; + else + dat = quadcolor->quadcolor_ctrl & 15; /* TODO: Is Quadcolor bg color actually relevant, here? Probably. See QC2 manual p.46 1. */; + quadcolor->memaddr++; + for (column = 0; column < 16; column++) { + buffer32->line[line][(x << 4) + column + 8] = cols[dat >> 15] | get_next_qc2_pixel(quadcolor); + dat <<= 1; + } + } + } +} + +static void +quadcolor_render_blank(quadcolor_t *quadcolor, int line) +{ + int32_t highres_graphics_flag = (CGA_MODE_FLAG_HIGHRES_GRAPHICS | CGA_MODE_FLAG_GRAPHICS); + + /* `+ 16` isn't in PCem's version */ + int col = ((quadcolor->cgamode & highres_graphics_flag) == highres_graphics_flag) ? (quadcolor->quadcolor_ctrl & 15) + 16 : (quadcolor->cgacol & 15) + 16; /* TODO: Is Quadcolor bg color actually relevant, here? */ + + if (quadcolor->cgamode & CGA_MODE_FLAG_HIGHRES) + hline(buffer32, 0, line, (quadcolor->crtc[CGA_CRTC_HDISP] << 3) + 16, col); + else + hline(buffer32, 0, line, (quadcolor->crtc[CGA_CRTC_HDISP] << 4) + 16, col); +} + +static void +quadcolor_render_process(quadcolor_t *quadcolor, int line) +{ + int x; + uint8_t border; + int32_t highres_graphics_flag = (CGA_MODE_FLAG_HIGHRES_GRAPHICS | CGA_MODE_FLAG_GRAPHICS); + + if (quadcolor->cgamode & CGA_MODE_FLAG_HIGHRES) + x = (quadcolor->crtc[CGA_CRTC_HDISP] << 3) + 16; + else + x = (quadcolor->crtc[CGA_CRTC_HDISP] << 4) + 16; + + if (quadcolor->composite) { + border = ((quadcolor->cgamode & highres_graphics_flag) == highres_graphics_flag) ? 0 : (quadcolor->cgacol & 15); + + Composite_Process(quadcolor->cgamode, border, x >> 2, buffer32->line[line]); + } else + video_process_8(x, line); +} + +static uint8_t +quadcolor_interpolate_srgb(uint8_t co1, uint8_t co2, double fraction) +{ + uint8_t ret = ((co2 - co1) * fraction + co1); + + return ret; +} + +static uint8_t +quadcolor_interpolate_linear(uint8_t co1, uint8_t co2, double fraction) +{ + double c1, c2; + double r1, r2; + uint8_t ret; + + c1 = ((double) co1) / 255.0; + c1 = pow((co1 >= 0) ? c1 : -c1, 2.19921875); + if (co1 <= 0) + c1 = -c1; + c2 = ((double) co2) / 255.0; + c2 = pow((co2 >= 0) ? c2 : -c2, 2.19921875); + if (co2 <= 0) + c2 = -c2; + r1 = ((c2 - c1) * fraction + c1); + r2 = pow((r1 >= 0.0) ? r1 : -r1, 1.0 / 2.19921875); + if (r1 <= 0.0) + r2 = -r2; + ret = (uint8_t) round(r2 * 255.0); + + return ret; +} + +static color_t +quadcolor_interpolate_lookup(quadcolor_t *quadcolor, color_t color1, color_t color2, UNUSED(double fraction)) +{ + color_t ret; + uint8_t dt = quadcolor->double_type - DOUBLE_INTERPOLATE_SRGB; + + ret.a = 0x00; + ret.r = interp_lut[dt][color1.r][color2.r]; + ret.g = interp_lut[dt][color1.g][color2.g]; + ret.b = interp_lut[dt][color1.b][color2.b]; + + return ret; +} + +static void +quadcolor_interpolate(quadcolor_t *quadcolor, int x, int y, int w, int h) +{ + double quotient = 0.5; + + for (int i = y; i < (y + h); i++) { + if (i & 1) for (int j = x; j < (x + w); j++) { + int prev = i - 1; + int next = i + 1; + color_t prev_color, next_color; + color_t black; + color_t interim_1, interim_2; + color_t final; + + if (i < 0) + continue; + + black.color = 0x00000000; + + if ((prev >= 0) && (prev < (y + h))) + prev_color.color = buffer32->line[prev][j]; + else + prev_color.color = 0x00000000; + + if ((next >= 0) && (next < (y + h))) + next_color.color = buffer32->line[next][j]; + else + next_color.color = 0x00000000; + + interim_1 = quadcolor_interpolate_lookup(quadcolor, prev_color, black, quotient); + interim_2 = quadcolor_interpolate_lookup(quadcolor, black, next_color, quotient); + final = quadcolor_interpolate_lookup(quadcolor, interim_1, interim_2, quotient); + + buffer32->line[i][j] = final.color; + } + } +} + +static void +quadcolor_blit_memtoscreen(quadcolor_t *quadcolor, int x, int y, int w, int h) +{ + if (quadcolor->double_type > DOUBLE_SIMPLE) + quadcolor_interpolate(quadcolor, x, y, w, h); + + video_blit_memtoscreen(x, y, w, h); +} + +void +quadcolor_poll(void *priv) +{ + quadcolor_t *quadcolor = (quadcolor_t *) priv; + int x; + int scanline_old; + int oldvc; + int xs_temp; + int ys_temp; + int old_ma; + + if (!quadcolor->linepos) { + timer_advance_u64(&quadcolor->timer, quadcolor->dispofftime); + quadcolor->cgastat |= 1; + quadcolor->linepos = 1; + scanline_old = quadcolor->scanline; + if ((quadcolor->crtc[CGA_CRTC_INTERLACE] & 3) == 3) + quadcolor->scanline = ((quadcolor->scanline << 1) + quadcolor->oddeven) & 7; + if (quadcolor->cgadispon) { + if (quadcolor->displine < quadcolor->firstline) { + quadcolor->firstline = quadcolor->displine; + video_wait_for_buffer(); + } + quadcolor->lastline = quadcolor->displine; + switch (quadcolor->double_type) { + default: + quadcolor_render(quadcolor, quadcolor->displine << 1); + quadcolor_render_blank(quadcolor, (quadcolor->displine << 1) + 1); + break; + case DOUBLE_NONE: + quadcolor_render(quadcolor, quadcolor->displine); + break; + case DOUBLE_SIMPLE: + old_ma = quadcolor->memaddr; + quadcolor_render(quadcolor, quadcolor->displine << 1); + quadcolor->memaddr = old_ma; + quadcolor_render(quadcolor, (quadcolor->displine << 1) + 1); + break; + } + } else { + switch (quadcolor->double_type) { + default: + quadcolor_render_blank(quadcolor, quadcolor->displine << 1); + break; + case DOUBLE_NONE: + quadcolor_render_blank(quadcolor, quadcolor->displine); + break; + case DOUBLE_SIMPLE: + quadcolor_render_blank(quadcolor, quadcolor->displine << 1); + quadcolor_render_blank(quadcolor, (quadcolor->displine << 1) + 1); + break; + } + } + + switch (quadcolor->double_type) { + default: + quadcolor_render_process(quadcolor, quadcolor->displine << 1); + quadcolor_render_process(quadcolor, (quadcolor->displine << 1) + 1); + break; + case DOUBLE_NONE: + quadcolor_render_process(quadcolor, quadcolor->displine); + break; + } + + quadcolor->scanline = scanline_old; + if (quadcolor->vc == quadcolor->crtc[CGA_CRTC_VSYNC] && !quadcolor->scanline) + quadcolor->cgastat |= 8; + quadcolor->displine++; + if (quadcolor->displine >= 360) + quadcolor->displine = 0; + } else { + timer_advance_u64(&quadcolor->timer, quadcolor->dispontime); + quadcolor->linepos = 0; + if (quadcolor->vsynctime) { + quadcolor->vsynctime--; + if (!quadcolor->vsynctime) + quadcolor->cgastat &= ~8; + quadcolor->qc2idx = 0; + quadcolor->qc2mask = 0xf0; + } + if (quadcolor->scanline == (quadcolor->crtc[CGA_CRTC_CURSOR_END] & 31) || ((quadcolor->crtc[CGA_CRTC_INTERLACE] & 3) == 3 && + quadcolor->scanline == ((quadcolor->crtc[CGA_CRTC_CURSOR_END] & 31) >> 1))) { + quadcolor->cursorvisible = 0; + } + if ((quadcolor->crtc[CGA_CRTC_INTERLACE] & 3) == 3 && quadcolor->scanline == (quadcolor->crtc[CGA_CRTC_MAX_SCANLINE_ADDR] >> 1)) + quadcolor->memaddr_backup = quadcolor->memaddr; + if (quadcolor->vadj) { + quadcolor->scanline++; + quadcolor->scanline &= 31; + quadcolor->memaddr = quadcolor->memaddr_backup; + quadcolor->vadj--; + if (!quadcolor->vadj) { + quadcolor->cgadispon = 1; + quadcolor->memaddr = quadcolor->memaddr_backup = (quadcolor->crtc[CGA_CRTC_START_ADDR_LOW] | (quadcolor->crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & DEVICE_VRAM_MASK; + quadcolor->scanline = 0; + } + } else if (quadcolor->scanline == quadcolor->crtc[CGA_CRTC_MAX_SCANLINE_ADDR]) { + quadcolor->memaddr_backup = quadcolor->memaddr; + quadcolor->scanline = 0; + oldvc = quadcolor->vc; + quadcolor->vc++; + quadcolor->vc &= 127; + + if (quadcolor->vc == quadcolor->crtc[CGA_CRTC_VDISP]) + quadcolor->cgadispon = 0; + + if (oldvc == quadcolor->crtc[CGA_CRTC_VTOTAL]) { + quadcolor->vc = 0; + quadcolor->vadj = quadcolor->crtc[CGA_CRTC_VTOTAL_ADJUST]; + if (!quadcolor->vadj) { + quadcolor->cgadispon = 1; + quadcolor->memaddr = quadcolor->memaddr_backup = (quadcolor->crtc[CGA_CRTC_START_ADDR_LOW] | (quadcolor->crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & DEVICE_VRAM_MASK; + } + + switch (quadcolor->crtc[CGA_CRTC_CURSOR_START] & 0x60) { + case 0x20: + quadcolor->cursoron = 0; + break; + case 0x60: + quadcolor->cursoron = quadcolor->cgablink & 0x10; + break; + default: + quadcolor->cursoron = quadcolor->cgablink & 0x08; + break; + } + } + + if (quadcolor->vc == quadcolor->crtc[CGA_CRTC_VSYNC]) { + quadcolor->cgadispon = 0; + quadcolor->displine = 0; + quadcolor->vsynctime = 16; + if (quadcolor->crtc[CGA_CRTC_VSYNC]) { + if (quadcolor->cgamode & CGA_MODE_FLAG_HIGHRES) + x = (quadcolor->crtc[CGA_CRTC_HDISP] << 3) + 16; + else + x = (quadcolor->crtc[CGA_CRTC_HDISP] << 4) + 16; + quadcolor->lastline++; + + xs_temp = x; + ys_temp = quadcolor->lastline - quadcolor->firstline; + if (quadcolor->double_type > DOUBLE_NONE) + ys_temp <<= 1; + + if ((xs_temp > 0) && (ys_temp > 0)) { + if (xs_temp < 64) + xs_temp = 656; + if (ys_temp < 32) + ys_temp = 200; + if (!enable_overscan) + xs_temp -= 16; + + if ((quadcolor->cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) && ((xs_temp != xsize) || + (ys_temp != ysize) || video_force_resize_get())) { + xsize = xs_temp; + ysize = ys_temp; + if (quadcolor->double_type > DOUBLE_NONE) + set_screen_size(xsize, ysize + (enable_overscan ? 16 : 0)); + else + set_screen_size(xsize, ysize + (enable_overscan ? 8 : 0)); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + if (quadcolor->double_type > DOUBLE_NONE) { + if (enable_overscan) + quadcolor_blit_memtoscreen(quadcolor, 0, (quadcolor->firstline - 4) << 1, + xsize, ((quadcolor->lastline - quadcolor->firstline) << 1) + 16); + else + quadcolor_blit_memtoscreen(quadcolor, 8, quadcolor->firstline << 1, + xsize, (quadcolor->lastline - quadcolor->firstline) << 1); + } else { + if (enable_overscan) + video_blit_memtoscreen(0, quadcolor->firstline - 4, + xsize, (quadcolor->lastline - quadcolor->firstline) + 8); + else + video_blit_memtoscreen(8, quadcolor->firstline, + xsize, quadcolor->lastline - quadcolor->firstline); + } + } + + frames++; + + video_res_x = xsize; + video_res_y = ysize; + if (quadcolor->cgamode & CGA_MODE_FLAG_HIGHRES) { + video_res_x /= 8; + video_res_y /= quadcolor->crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1; + video_bpp = 0; + } else if (!(quadcolor->cgamode & CGA_MODE_FLAG_GRAPHICS)) { + video_res_x /= 16; + video_res_y /= quadcolor->crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1; + video_bpp = 0; + } else if (!(quadcolor->cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS)) { + video_res_x /= 2; + video_bpp = 2; + } else + video_bpp = 1; + } + quadcolor->firstline = 1000; + quadcolor->lastline = 0; + quadcolor->cgablink++; + quadcolor->oddeven ^= 1; + } + } else { + quadcolor->scanline++; + quadcolor->scanline &= 31; + quadcolor->memaddr = quadcolor->memaddr_backup; + } + if (quadcolor->cgadispon) + quadcolor->cgastat &= ~1; + if (quadcolor->scanline == (quadcolor->crtc[CGA_CRTC_CURSOR_START] & 31) || ((quadcolor->crtc[CGA_CRTC_INTERLACE] & 3) == 3 && + quadcolor->scanline == ((quadcolor->crtc[CGA_CRTC_CURSOR_START] & 31) >> 1))) + quadcolor->cursorvisible = 1; + if (quadcolor->cgadispon && (quadcolor->cgamode & CGA_MODE_FLAG_HIGHRES)) { + for (x = 0; x < (quadcolor->crtc[CGA_CRTC_HDISP] << 1); x++) + quadcolor->charbuffer[x] = quadcolor->vram[(quadcolor->page_offset ^ ((quadcolor->memaddr << 1) + x)) & DEVICE_VRAM_MASK]; + } + } +} + +void +quadcolor_init(quadcolor_t *quadcolor) +{ + timer_add(&quadcolor->timer, quadcolor_poll, quadcolor, 1); + quadcolor->composite = 0; +} + +void * +quadcolor_standalone_init(UNUSED(const device_t *info)) +{ + int display_type; + quadcolor_t *quadcolor = calloc(1, sizeof(quadcolor_t)); + + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_quadcolor); + + display_type = device_get_config_int("display_type"); + quadcolor->composite = (display_type != CGA_RGB); + quadcolor->revision = device_get_config_int("composite_type"); + quadcolor->has_2nd_charset = device_get_config_int("has_2nd_charset"); + quadcolor->has_quadcolor_2 = device_get_config_int("has_quadcolor_2"); + + quadcolor->vram = malloc(DEVICE_VRAM); + quadcolor->vram_2 = malloc(0x10000); + + cga_comp_init(quadcolor->revision); + timer_add(&quadcolor->timer, quadcolor_poll, quadcolor, 1); + mem_mapping_add(&quadcolor->mapping, 0xb8000, 0x08000, quadcolor_read, NULL, NULL, quadcolor_write, NULL, NULL, NULL /*quadcolor->vram*/, MEM_MAPPING_EXTERNAL, quadcolor); + /* add mapping for vram_2 at 0xd0000, mirrored at 0xe0000 */ + if (quadcolor->has_quadcolor_2) + mem_mapping_add(&quadcolor->mapping_2, 0xd0000, 0x20000, quadcolor_2_read, NULL, NULL, quadcolor_2_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, + quadcolor); + + io_sethandler(0x03d0, 0x0010, quadcolor_in, NULL, NULL, quadcolor_out, NULL, NULL, quadcolor); + + overscan_x = overscan_y = 16; + + quadcolor->rgb_type = device_get_config_int("rgb_type"); + cga_palette = (quadcolor->rgb_type << 1); + cgapal_rebuild(); + update_cga16_color(quadcolor->cgamode); + + quadcolor->double_type = device_get_config_int("double_type"); + + for (uint16_t i = 0; i < 256; i++) { + for (uint16_t j = 0; j < 256; j++) { + interp_lut[0][i][j] = quadcolor_interpolate_srgb(i, j, 0.5); + interp_lut[1][i][j] = quadcolor_interpolate_linear(i, j, 0.5); + } + } + + switch(device_get_config_int("font")) { + case 0: + loadfont(FONT_IBM_MDA_437_PATH, 0); + break; + case 1: + loadfont(FONT_IBM_MDA_437_NORDIC_PATH, 0); + break; + case 4: + loadfont(FONT_TULIP_DGA_PATH, 0); + break; + } + + return quadcolor; +} + +void +quadcolor_close(void *priv) +{ + quadcolor_t *quadcolor = (quadcolor_t *) priv; + + free(quadcolor->vram); + free(quadcolor->vram_2); + free(quadcolor); +} + +void +quadcolor_speed_changed(void *priv) +{ + quadcolor_t *quadcolor = (quadcolor_t *) priv; + + quadcolor_recalctimings(quadcolor); +} + +// clang-format off +const device_config_t quadcolor_config[] = { + { + .name = "display_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = CGA_RGB, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "RGB", .value = CGA_RGB }, + { .description = "Composite", .value = CGA_COMPOSITE }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { + .name = "composite_type", + .description = "Composite type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = COMPOSITE_OLD, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Old", .value = COMPOSITE_OLD }, + { .description = "New", .value = COMPOSITE_NEW }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { + .name = "rgb_type", + .description = "RGB type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 5, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Color (generic)", .value = 0 }, + { .description = "Green Monochrome", .value = 1 }, + { .description = "Amber Monochrome", .value = 2 }, + { .description = "Gray Monochrome", .value = 3 }, + { .description = "Color (no brown)", .value = 4 }, + { .description = "Color (IBM 5153)", .value = 5 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { + .name = "double_type", + .description = "Line doubling type", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = DOUBLE_NONE, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "None", .value = DOUBLE_NONE }, + { .description = "Simple doubling", .value = DOUBLE_SIMPLE }, + { .description = "sRGB interpolation", .value = DOUBLE_INTERPOLATE_SRGB }, + { .description = "Linear interpolation", .value = DOUBLE_INTERPOLATE_LINEAR }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { + .name = "font", + .description = "Font", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "US (CP 437)", .value = 0 }, + { .description = "IBM Nordic (CP 437-Nordic)", .value = 1 }, + { .description = "Tulip DGA", .value = 4 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { + .name = "has_2nd_charset", + .description = "Has secondary 8x8 character set", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "has_quadcolor_2", + .description = "Has Quadcolor II daughter board", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "contrast", + .description = "Alternate monochrome contrast", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +}; +// clang-format on + +const device_t quadcolor_device = { + .name = "Quadram Quadcolor I / I+II", + .internal_name = "quadcolor", + .flags = DEVICE_ISA, + .local = 0, + .init = quadcolor_standalone_init, + .close = quadcolor_close, + .reset = NULL, + .available = NULL, + .speed_changed = quadcolor_speed_changed, + .force_redraw = NULL, + .config = quadcolor_config +}; diff --git a/src/video/vid_et3000.c b/src/video/vid_et3000.c index a82f93385..a75a63829 100644 --- a/src/video/vid_et3000.c +++ b/src/video/vid_et3000.c @@ -476,6 +476,20 @@ et3000_recalctimings(svga_t *svga) svga->clock = (cpuclock * (double) (1ULL << 32)) / 36000000.0; break; } + + if (svga->render == svga_render_4bpp_highres) + svga->render = svga_render_4bpp_tseng_highres; +} + +static int +et3000_line_compare(svga_t* svga) +{ + if (svga->split > svga->vsyncstart) { + /* Don't do line compare if we're already in vertical retrace. */ + /* This makes picture bouncing effect work on Copper demo. */ + return 0; + } + return 1; } static void * @@ -511,6 +525,7 @@ et3000_init(const device_t *info) dev->svga.miscout = 1; dev->svga.packed_chain4 = 1; + dev->svga.line_compare = et3000_line_compare; return dev; } diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index a99cb8872..b19aad20a 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -723,6 +723,17 @@ et4000_recalctimings(svga_t *svga) svga->rowoffset <<= 1; svga->render = svga_render_8bpp_highres; } + + if (svga->render == svga_render_4bpp_highres) + svga->render = svga_render_4bpp_tseng_highres; + + if (dev->type == ET4000_TYPE_TC6058AF) { + if (svga->render == svga_render_8bpp_lowres) + svga->render = svga_render_8bpp_tseng_lowres; + + else if (svga->render == svga_render_8bpp_highres) + svga->render = svga_render_8bpp_tseng_highres; + } } static void @@ -773,6 +784,17 @@ et4000_mca_feedb(UNUSED(void *priv)) return et4000->pos_regs[2] & 1; } +static int +et4000_line_compare(svga_t* svga) +{ + if (svga->split > svga->vsyncstart) { + /* Don't do line compare if we're already in vertical retrace. */ + /* This makes picture bouncing effect work on Copper demo. */ + return 0; + } + return 1; +} + static void * et4000_init(const device_t *info) { @@ -881,8 +903,13 @@ et4000_init(const device_t *info) if (dev->type >= ET4000_TYPE_ISA) dev->svga.ramdac = device_add(&sc1502x_ramdac_device); + if (dev->type == ET4000_TYPE_TC6058AF) + dev->svga.adv_flags |= FLAG_PRECISETIME; + dev->vram_mask = dev->vram_size - 1; + dev->svga.line_compare = et4000_line_compare; + rom_init(&dev->bios_rom, fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index 533bd1f28..2e9a7796a 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -600,6 +600,9 @@ et4000w32p_recalctimings(svga_t *svga) } } } + + if (svga->render == svga_render_4bpp_highres) + svga->render = svga_render_4bpp_tseng_highres; } void diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 2073fb8c0..8ed71645e 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -703,6 +703,13 @@ svga_recalctimings(svga_t *svga) int old_monitor_overscan_x = svga->monitor->mon_overscan_x; int old_monitor_overscan_y = svga->monitor->mon_overscan_y; + if (svga->adv_flags & FLAG_PRECISETIME) { +#ifdef USE_DYNAREC + if (cpu_use_dynarec) + update_tsc(); +#endif + } + svga->vtotal = svga->crtc[6]; svga->dispend = svga->crtc[0x12]; svga->vsyncstart = svga->crtc[0x10]; @@ -1024,7 +1031,7 @@ svga_recalctimings(svga_t *svga) svga->y_add = svga->vtotal - svga->vblankend - 1; svga->monitor->mon_overscan_y = svga->y_add + abs(svga->vblankstart - svga->dispend); - if ((svga->dispend >= 2048) || (svga->y_add < 0)) { + if ((dev->dispend >= 2048) || (svga->y_add < 0)) { svga->y_add = 0; svga->monitor->mon_overscan_y = 0; } @@ -1087,7 +1094,7 @@ svga_recalctimings(svga_t *svga) if (ibm8514_active && (svga->dev8514 != NULL)) { if (dev->on) { disptime8514 = dev->h_total; - _dispontime8514 = dev->h_disp; + _dispontime8514 = dev->h_disp_time; svga_log("HTOTAL=%d, HDISP=%d.\n", dev->h_total, dev->h_disp); } } @@ -1253,6 +1260,7 @@ svga_do_render(svga_t *svga) } if (!svga->override) { + svga->render_line_offset = svga->start_retrace_latch - svga->crtc[0x4]; svga->render(svga); svga->x_add = svga->left_overscan; @@ -1435,10 +1443,8 @@ svga_poll(void *priv) svga->memaddr_backup = (svga->memaddr_backup << 2); svga->scanline = 0; - if (svga->attrregs[0x10] & 0x20) { - svga->scrollcache = 0; - svga->x_add = svga->left_overscan; - } + if (svga->attrregs[0x10] & 0x20) + svga->panning_blank = 1; } } if (svga->vc == svga->dispend) { @@ -1516,6 +1522,8 @@ svga_poll(void *priv) if (svga->vsync_callback) svga->vsync_callback(svga); + + svga->start_retrace_latch = svga->crtc[0x4]; } #if 0 if (svga->vc == lines_num) { @@ -1526,25 +1534,6 @@ svga_poll(void *priv) svga->dispon = 1; svga->displine = (svga->interlace && svga->oddeven) ? 1 : 0; - svga->scrollcache = (svga->attrregs[0x13] & 0x0f); - if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ - if (svga->seqregs[1] & 1) - svga->scrollcache &= 0x07; - else { - svga->scrollcache++; - if (svga->scrollcache > 8) - svga->scrollcache = 0; - } - } else if ((svga->render == svga_render_2bpp_lowres) || (svga->render == svga_render_2bpp_highres) || (svga->render == svga_render_4bpp_lowres) || (svga->render == svga_render_4bpp_highres)) - svga->scrollcache &= 0x07; - else - svga->scrollcache = (svga->scrollcache & 0x06) >> 1; - - if ((svga->seqregs[1] & 8) || (svga->render == svga_render_8bpp_lowres)) - svga->scrollcache <<= 1; - - svga->x_add = svga->left_overscan - svga->scrollcache; - svga->linecountff = 0; svga->hwcursor_on = 0; @@ -1555,9 +1544,37 @@ svga_poll(void *priv) svga->overlay_on = 0; svga->overlay_latch = svga->overlay; + + svga->panning_blank = 0; } + if (svga->scanline == (svga->crtc[10] & 31)) svga->cursorvisible = 1; + + if (svga->panning_blank) { + svga->scrollcache = 0; + svga->x_add = svga->left_overscan; + } else { + svga->scrollcache = (svga->attrregs[0x13] & 0x0f); + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ + if (svga->seqregs[1] & 1) + svga->scrollcache &= 0x07; + else { + svga->scrollcache++; + if (svga->scrollcache > 8) + svga->scrollcache = 0; + } + } else if ((svga->render == svga_render_2bpp_lowres) || (svga->render == svga_render_2bpp_highres) || + (svga->render == svga_render_4bpp_lowres) || (svga->render == svga_render_4bpp_highres)) + svga->scrollcache &= 0x07; + else + svga->scrollcache = (svga->scrollcache & 0x06) >> 1; + + if ((svga->seqregs[1] & 8) || (svga->render == svga_render_8bpp_lowres)) + svga->scrollcache <<= 1; + + svga->x_add = svga->left_overscan - svga->scrollcache; + } } } diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index 0f9a4a253..0c3252414 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -744,6 +744,13 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) return; p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; + if (svga->render_line_offset) { + if (svga->render_line_offset > 0) { + memset(p, svga->overscan_color, charwidth * svga->render_line_offset * sizeof(uint32_t)); + p += charwidth * svga->render_line_offset; + } + } + if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; @@ -900,6 +907,12 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) else p += charwidth; } + + if (svga->render_line_offset < 0) { + uint32_t *orig_line = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; + memmove(orig_line, orig_line + (charwidth * -svga->render_line_offset), (svga->hdisp) * 4); + memset((orig_line + svga->hdisp) - (charwidth * -svga->render_line_offset), svga->overscan_color, charwidth * -svga->render_line_offset * 4); + } } /* @@ -913,6 +926,126 @@ void svga_render_4bpp_highres(svga_t *svga) { svga_render_indexed_gfx(svga, true void svga_render_8bpp_lowres(svga_t *svga) { svga_render_indexed_gfx(svga, false, true); } void svga_render_8bpp_highres(svga_t *svga) { svga_render_indexed_gfx(svga, true, true); } +void +svga_render_4bpp_tseng_highres(svga_t *svga) +{ + int changed_offset; + int x; + int oddeven; + uint32_t addr; + uint32_t *p; + uint8_t edat[4]; + uint8_t dat; + uint32_t changed_addr; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->force_old_addr) { + changed_offset = (svga->memaddr + (svga->scanline & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; + + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) { + p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { + addr = svga->memaddr; + oddeven = 0; + + if (!(svga->crtc[0x17] & 0x40)) { + addr = (addr << 1) & svga->vram_mask; + + if (svga->seqregs[1] & 4) + oddeven = (addr & 4) ? 1 : 0; + + addr &= ~7; + + if ((svga->crtc[0x17] & 0x20) && (svga->memaddr & 0x20000)) + addr |= 4; + if (!(svga->crtc[0x17] & 0x20) && (svga->memaddr & 0x8000)) + addr |= 4; + } + + if (!(svga->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((svga->scanline & 1) ? 0x8000 : 0); + if (!(svga->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((svga->scanline & 2) ? 0x10000 : 0); + + if (svga->seqregs[1] & 4) { + edat[0] = svga->vram[addr | oddeven]; + edat[2] = svga->vram[addr | oddeven | 0x2]; + edat[1] = edat[3] = 0; + svga->memaddr += 2; + } else { + *(uint32_t *) (&edat[0]) = *(uint32_t *) (&svga->vram[addr]); + svga->memaddr += 4; + } + svga->memaddr &= svga->vram_mask; + + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + p[0] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[1] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[2] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[4] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[5] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[6] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + + p += 8; + } + } + } else { + changed_addr = svga->remap_func(svga, svga->memaddr); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { + p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { + addr = svga->remap_func(svga, svga->memaddr); + oddeven = 0; + + if (svga->seqregs[1] & 4) { + oddeven = (addr & 4) ? 1 : 0; + edat[0] = svga->vram[addr | oddeven]; + edat[2] = svga->vram[addr | oddeven | 0x2]; + edat[1] = edat[3] = 0; + svga->memaddr += 2; + } else { + *(uint32_t *) (&edat[0]) = *(uint32_t *) (&svga->vram[addr]); + svga->memaddr += 4; + } + svga->memaddr &= svga->vram_mask; + + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + p[0] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[1] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[2] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[4] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[5] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[6] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + + p += 8; + } + } + } +} + void svga_render_8bpp_clone_highres(svga_t *svga) { @@ -1163,13 +1296,20 @@ svga_render_8bpp_tseng_lowres(svga_t *svga) if ((svga->displine + svga->y_add) < 0) return; - if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->fullchange || svga->render_line_offset) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; + if (svga->render_line_offset) { + if (svga->render_line_offset > 0) { + memset(p, svga->overscan_color, 8 * svga->render_line_offset * sizeof(uint32_t)); + p += 8 * svga->render_line_offset; + } + } + for (int x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { dat = *(uint32_t *) (&svga->vram[svga->memaddr & svga->vram_display_mask]); if (svga->attrregs[0x10] & 0x80) @@ -1191,6 +1331,11 @@ svga_render_8bpp_tseng_lowres(svga_t *svga) svga->memaddr += 4; p += 8; } + if (svga->render_line_offset < 0) { + uint32_t *orig_line = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; + memmove(orig_line, orig_line + (8 * -svga->render_line_offset), (svga->hdisp) * 4); + memset((orig_line + svga->hdisp) - (8 * -svga->render_line_offset), svga->overscan_color, 8 * -svga->render_line_offset * 4); + } svga->memaddr &= svga->vram_display_mask; } } @@ -1204,13 +1349,20 @@ svga_render_8bpp_tseng_highres(svga_t *svga) if ((svga->displine + svga->y_add) < 0) return; - if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->fullchange || svga->render_line_offset) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; + if (svga->render_line_offset) { + if (svga->render_line_offset > 0) { + memset(p, svga->overscan_color, 8 * svga->render_line_offset * sizeof(uint32_t)); + p += 8 * svga->render_line_offset; + } + } + for (int x = 0; x <= (svga->hdisp /* + svga->scrollcache*/); x += 8) { dat = *(uint32_t *) (&svga->vram[svga->memaddr & svga->vram_display_mask]); if (svga->attrregs[0x10] & 0x80) @@ -1249,6 +1401,13 @@ svga_render_8bpp_tseng_highres(svga_t *svga) svga->memaddr += 8; p += 8; } + + if (svga->render_line_offset < 0) { + uint32_t *orig_line = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; + memmove(orig_line, orig_line + (8 * -svga->render_line_offset), (svga->hdisp) * 4); + memset((orig_line + svga->hdisp) - (8 * -svga->render_line_offset), svga->overscan_color, 8 * -svga->render_line_offset * 4); + } + svga->memaddr &= svga->vram_display_mask; } } diff --git a/src/video/vid_table.c b/src/video/vid_table.c index b97defe8c..2e42e5c2c 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -67,6 +67,7 @@ video_cards[] = { { .device = &ati18800_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &ati18800_wonder_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &cga_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &quadcolor_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &sega_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &jega_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &gd5401_isa_device, .flags = VIDEO_FLAG_TYPE_NONE },