Merge branch 'master'

This commit is contained in:
MaxwellS04
2025-07-04 10:23:17 +07:00
35 changed files with 1917 additions and 498 deletions

View File

@@ -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/**

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

File diff suppressed because it is too large Load Diff

View File

@@ -22,6 +22,20 @@
*/
#include <math.h>
#include <fenv.h>
#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 <immintrin.h>
#endif
#include "x87_timings.h"
#ifdef _MSC_VER
# include <intrin.h>
@@ -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

View File

@@ -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)); \

View File

@@ -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

View File

@@ -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

View File

@@ -8,15 +8,13 @@
*
* Emulation of the old and new IBM CGA graphics cards.
*
*
*
* Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>,
* Miran Grca, <mgrca8@gmail.com>
* Connor Hyde / starfrost, <mario64crashed@gmail.com>
*
* 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*/

View File

@@ -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, <https://pcem-emulator.co.uk/>
* Jasmine Iwanek, <jriwanek@gmail.com>
*
* 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_ */

View File

@@ -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

View File

@@ -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);

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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
},

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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 {

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -8,15 +8,13 @@
*
* Emulation of the old and new IBM CGA graphics cards.
*
*
*
* Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
* W. M. Martinez, <anikom15@outlook.com>
*
* Copyright 2008-2019 Sarah Walker.
* Copyright 2016-2019 Miran Grca.
* Copyright 2023 W. M. Martinez
* Copyright 2023 W. M. Martinez
*/
#include <stdio.h>
#include <stdint.h>
@@ -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");

View File

@@ -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>

View File

@@ -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, <https://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
* W. M. Martinez, <anikom15@outlook.com>
* Benedikt Freisen, <https://pcem-emulator.co.uk/>
* Jasmine Iwanek, <jriwanek@gmail.com>
*
* 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 <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <math.h>
#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
};

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -600,6 +600,9 @@ et4000w32p_recalctimings(svga_t *svga)
}
}
}
if (svga->render == svga_render_4bpp_highres)
svga->render = svga_render_4bpp_tseng_highres;
}
void

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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 },