Merge branch 'master' into feature/global-config

This commit is contained in:
David Hrdlička
2025-08-06 12:26:10 +02:00
committed by GitHub
715 changed files with 96594 additions and 40250 deletions

View File

@@ -96,3 +96,4 @@ AppDir:
AppImage:
arch: !ENV '${arch_appimage}'
file_name: !ENV '${appimage_path}'
comp: gzip

View File

@@ -603,7 +603,7 @@ else
grep -q " bullseye " /etc/apt/sources.list || echo [!] WARNING: System not running the expected Debian version
# Establish general dependencies.
pkgs="cmake ninja-build pkg-config git wget p7zip-full extra-cmake-modules wayland-protocols tar gzip file appstream qttranslations5-l10n"
pkgs="cmake ninja-build pkg-config git wget p7zip-full extra-cmake-modules wayland-protocols tar gzip file appstream qttranslations5-l10n python3-pip python3-venv squashfs-tools"
if [ "$(dpkg --print-architecture)" = "$arch_deb" ]
then
pkgs="$pkgs build-essential"
@@ -1141,55 +1141,32 @@ EOF
# Copy line.
echo "$line" >> AppImageBuilder-generated.yml
# Workaround for appimage-builder issues 272 and 283 (i686 and armhf are also missing)
if [ "$arch_appimage" != "x86_64" -a "$line" = " files:" ]
then
# Some mild arbitrary code execution with a dummy package...
[ ! -d /runtime ] && sudo apt-get -y -o 'DPkg::Post-Invoke::=mkdir -p /runtime; chmod 777 /runtime' install libsixel1 > /dev/null 2>&1
echo " include:" >> AppImageBuilder-generated.yml
for loader in "/lib/$libdir/ld-linux"*.so.*
do
for loader_copy in "$loader" "/lib/$(basename "$loader")"
do
if [ ! -e "/runtime/compat$loader_copy" ]
then
mkdir -p "/runtime/compat$(dirname "$loader_copy")"
ln -s "$loader" "/runtime/compat$loader_copy"
fi
echo " - /runtime/compat$loader_copy" >> AppImageBuilder-generated.yml
done
done
fi
done < .ci/AppImageBuilder.yml
# Download appimage-builder if necessary.
appimage_builder_url="https://github.com/AppImageCrafters/appimage-builder/releases/download/v1.1.0/appimage-builder-1.1.0-$(uname -m).AppImage"
appimage_builder_binary="$cache_dir/$(basename "$appimage_builder_url")"
if [ ! -e "$appimage_builder_binary" ]
appimage_builder_commit=22fefa298f9cee922a651a6f65a46fe0ccbfa34e # from issue 376
appimage_builder_dir="$cache_dir/appimage-builder-$appimage_builder_commit"
if [ ! -x "$appimage_builder_dir/bin/appimage-builder" ]
then
rm -rf "$cache_dir/"*".AppImage" # remove old versions
wget -qO "$appimage_builder_binary" "$appimage_builder_url"
rm -rf "$cache_dir/appimage-builder-"* # remove old versions
python3 -m venv "$appimage_builder_dir" # venv to solve some Debian setuptools headaches
"$appimage_builder_dir/bin/pip" install -U "git+https://github.com/AppImageCrafters/appimage-builder.git@$appimage_builder_commit"
fi
# Symlink appimage-builder binary and global cache directory.
# Symlink appimage-builder global cache directory.
rm -rf appimage-builder.AppImage appimage-builder-cache "$project-"*".AppImage" # also remove any dangling AppImages which may interfere with the renaming process
ln -s "$appimage_builder_binary" appimage-builder.AppImage
chmod u+x appimage-builder.AppImage
mkdir -p "$cache_dir/appimage-builder-cache"
ln -s "$cache_dir/appimage-builder-cache" appimage-builder-cache
# Run appimage-builder in extract-and-run mode for Docker compatibility.
# Run appimage-builder from the virtual environment created above.
# --appdir is a workaround for appimage-builder issue 270 reported by us.
for retry in 1 2 3 4 5
do
project="$project" project_id="$project_id" project_version="$project_version" project_icon="$project_icon" arch_deb="$arch_deb" \
arch_appimage="$arch_appimage" appimage_path="$cwd/$package_name.AppImage" APPIMAGE_EXTRACT_AND_RUN=1 ./appimage-builder.AppImage \
arch_appimage="$arch_appimage" appimage_path="$cwd/$package_name.AppImage" "$appimage_builder_dir/bin/appimage-builder" \
--recipe AppImageBuilder-generated.yml --appdir "$(grep -oP '^\s+path: \K(.+)' AppImageBuilder-generated.yml)"
status=$?
[ $status -eq 0 ] && break
[ $status -eq 127 ] && rm -rf /tmp/appimage_extracted_*
done
# Remove appimage-builder binary on failure, just in case it's corrupted.

View File

@@ -8,6 +8,7 @@ on:
- cmake/**
- "**/CMakeLists.txt"
- "CMakePresets.json"
- "!.github/workflows/**"
- .github/workflows/cmake_linux.yml
- vcpkg.json
- "!**/Makefile*"
@@ -18,7 +19,7 @@ on:
- cmake/**
- "**/CMakeLists.txt"
- "CMakePresets.json"
- .github/workflows/**
- "!.github/workflows/**"
- .github/workflows/cmake_linux.yml
- vcpkg.json
- "!**/Makefile*"
@@ -26,12 +27,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
@@ -66,6 +65,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
@@ -90,28 +103,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: |
@@ -120,5 +122,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

@@ -8,6 +8,7 @@ on:
- cmake/**
- "**/CMakeLists.txt"
- "CMakePresets.json"
- "!.github/workflows/**"
- .github/workflows/cmake_macos.yml
- vcpkg.json
- "!**/Makefile*"
@@ -18,7 +19,7 @@ on:
- cmake/**
- "**/CMakeLists.txt"
- "CMakePresets.json"
- .github/workflows/**
- "!.github/workflows/**"
- .github/workflows/cmake_macos.yml
- vcpkg.json
- "!**/Makefile*"
@@ -26,13 +27,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:
@@ -66,7 +65,6 @@ jobs:
- name: Install dependencies
run: >-
brew install
ninja
sdl2
rtmidi
openal-soft
@@ -81,9 +79,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 }}
@@ -97,20 +92,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
@@ -119,13 +104,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:
@@ -159,12 +142,12 @@ jobs:
- name: Install dependencies
run: >-
brew install
ninja
sdl2
rtmidi
openal-soft
fluidsynth
libslirp
vde
libserialport
${{ matrix.ui.packages }}
@@ -173,9 +156,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 }}
@@ -189,20 +169,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

@@ -8,6 +8,7 @@ on:
- cmake/**
- "**/CMakeLists.txt"
- "CMakePresets.json"
- "!.github/workflows/**"
- .github/workflows/cmake_windows_msys2.yml
- vcpkg.json
- "!**/Makefile*"
@@ -18,6 +19,7 @@ on:
- cmake/**
- "**/CMakeLists.txt"
- "CMakePresets.json"
- "!.github/workflows/**"
- .github/workflows/cmake_windows_msys2.yml
- vcpkg.json
- "!**/Makefile*"
@@ -25,13 +27,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}
@@ -40,23 +40,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
@@ -97,9 +121,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 }}
@@ -107,20 +128,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

@@ -3,34 +3,43 @@ name: CodeQL Analysis (Linux)
on:
push:
branches: [ "master" ]
paths:
- src/**
- cmake/**
- "**/CMakeLists.txt"
- "CMakePresets.json"
- "!.github/workflows/**"
- .github/workflows/codeql_linux.yml
- vcpkg.json
- "!**/Makefile*"
pull_request:
branches: [ "master" ]
paths:
- src/**
- cmake/**
- "**/CMakeLists.txt"
- "CMakePresets.json"
- .github/workflows/**
- "!.github/workflows/**"
- .github/workflows/codeql_linux.yml
- vcpkg.json
- "!**/Makefile*"
schedule:
- cron: '22 11 * * 0'
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
@@ -43,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
@@ -59,6 +68,7 @@ jobs:
ui:
- name: SDL GUI
qt: off
static: on
- name: Qt GUI
qt: on
slug: -Qt
@@ -90,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
@@ -106,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

@@ -3,34 +3,43 @@ name: CodeQL Analysis (macos)
on:
push:
branches: [ "master" ]
paths:
- src/**
- cmake/**
- "**/CMakeLists.txt"
- "CMakePresets.json"
- "!.github/workflows/**"
- .github/workflows/codeql_macos.yml
- vcpkg.json
- "!**/Makefile*"
pull_request:
branches: [ "master" ]
paths:
- src/**
- cmake/**
- "**/CMakeLists.txt"
- "CMakePresets.json"
- .github/workflows/**
- "!.github/workflows/**"
- .github/workflows/codeql_macos.yml
- vcpkg.json
- "!**/Makefile*"
schedule:
- cron: '22 11 * * 0'
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
@@ -43,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
@@ -69,7 +78,6 @@ jobs:
- name: Install dependencies
run: >-
brew install
ninja
sdl2
rtmidi
openal-soft
@@ -81,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
@@ -101,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

@@ -3,33 +3,42 @@ name: CodeQL Analysis (Windows, msys2)
on:
push:
branches: [ "master" ]
paths:
- src/**
- cmake/**
- "**/CMakeLists.txt"
- "CMakePresets.json"
- "!.github/workflows/**"
- .github/workflows/codeql_windows_msys2.yml
- vcpkg.json
- "!**/Makefile*"
pull_request:
branches: [ "master" ]
paths:
- src/**
- cmake/**
- "**/CMakeLists.txt"
- "CMakePresets.json"
- .github/workflows/**
- "!.github/workflows/**"
- .github/workflows/codeql_windows_msys2.yml
- vcpkg.json
- "!**/Makefile*"
schedule:
- cron: '22 11 * * 0'
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
@@ -47,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
@@ -72,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: >-
@@ -104,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
@@ -123,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"

View File

@@ -137,6 +137,7 @@ option(GDBSTUB "Enable GDB stub server for debugging"
option(DEV_BRANCH "Development branch" OFF)
option(DISCORD "Discord Rich Presence support" ON)
option(DEBUGREGS486 "Enable debug register opeartion on 486+ CPUs" OFF)
option(LIBASAN "Enable compilation with the addresss sanitizer" OFF)
if((ARCH STREQUAL "arm64") OR (ARCH STREQUAL "arm"))
set(NEW_DYNAREC ON)
@@ -173,21 +174,17 @@ endif()
# Option Description Def. Condition Otherwise
# ------ ----------- ---- ------------ ---------
cmake_dependent_option(AMD_K5 "AMD K5" ON "DEV_BRANCH" OFF)
cmake_dependent_option(AN430TX "Intel AN430TX" ON "DEV_BRANCH" OFF)
cmake_dependent_option(CDROM_MITSUMI "Mitsumi CDROM" ON "DEV_BRANCH" OFF)
cmake_dependent_option(G100 "Matrox Productiva G100" ON "DEV_BRANCH" OFF)
cmake_dependent_option(GUSMAX "Gravis UltraSound MAX" ON "DEV_BRANCH" OFF)
cmake_dependent_option(ISAMEM_RAMPAGE "AST Rampage" ON "DEV_BRANCH" OFF)
cmake_dependent_option(ISAMEM_IAB "Intel Above Board" ON "DEV_BRANCH" OFF)
cmake_dependent_option(ISAMEM_BRAT "BocaRAM/AT" ON "DEV_BRANCH" OFF)
cmake_dependent_option(LASERXT "VTech Laser XT" ON "DEV_BRANCH" OFF)
cmake_dependent_option(OLIVETTI "Olivetti M290" ON "DEV_BRANCH" OFF)
cmake_dependent_option(OPEN_AT "OpenAT" ON "DEV_BRANCH" OFF)
cmake_dependent_option(OPL4ML "OPL4-ML daughterboard" ON "DEV_BRANCH" OFF)
cmake_dependent_option(PCL "Generic PCL5e Printer" ON "DEV_BRANCH" OFF)
cmake_dependent_option(SIO_DETECT "Super I/O Detection Helper" ON "DEV_BRANCH" OFF)
cmake_dependent_option(WACOM "Wacom Input Devices" ON "DEV_BRANCH" OFF)
cmake_dependent_option(XL24 "ATI VGA Wonder XL24 (ATI-28800-6)" ON "DEV_BRANCH" OFF)
cmake_dependent_option(NETSWITCH "Network Switch Support" ON "DEV_BRANCH" OFF)
# Ditto but for Qt
if(QT)
@@ -225,7 +222,15 @@ if(NOT EMU_BUILD_NUM)
set(EMU_BUILD_NUM 0)
endif()
if(NOT EMU_COPYRIGHT_YEAR)
set(EMU_COPYRIGHT_YEAR 2024)
set(EMU_COPYRIGHT_YEAR 2025)
endif()
# Libasan
if(LIBASAN)
add_compile_options(-fsanitize=address)
add_link_options(-fsanitize=address)
endif()
set(CMAKE_TOP_LEVEL_PROCESSED TRUE)
add_subdirectory(src)

View File

@@ -26,9 +26,9 @@ Minimum system requirements and recommendations
* macOS version: macOS High Sierra 10.13 or newer
* 4 GB of RAM or higher
Performance may vary depending on both host and guest configuration. Most emulation logic is executed in a single thread; therefore, systems with better IPC (instructions per clock) generally should be able to emulate higher clock speeds.
Performance may vary depending on host and guest configuration. Most emulation logic is executed in a single thread. Therefore, systems with greater IPC (instructions per clock) capacity should be able to emulate higher clock speeds.
It is also recommended to use a manager application with 86Box for easier handling of multiple virtual machines.
For easier handling of multiple virtual machines, use a manager application:
* [Avalonia 86](https://github.com/notBald/Avalonia86) by [notBald](https://github.com/notBald) (Windows and Linux)
* [86Box Manager](https://github.com/86Box/86BoxManager) by [Overdoze](https://github.com/daviunic) (Windows only)
@@ -37,7 +37,7 @@ It is also recommended to use a manager application with 86Box for easier handli
* [Linbox-qt5](https://github.com/Dungeonseeker/linbox-qt5) by [Dungeonseeker](https://github.com/Dungeonseeker/) (Linux focused, should work on Windows though untested)
* [MacBox for 86Box](https://github.com/Moonif/MacBox) by [Moonif](https://github.com/Moonif) (MacOS only)
It is also possible to use 86Box on its own with the `--vmpath`/`-P` command line option.
To use 86Box on its own, use the `--vmpath`/`-P` command line option.
Getting started
---------------
@@ -47,7 +47,7 @@ See [our documentation](https://86box.readthedocs.io/en/latest/index.html) for a
Community
---------
We operate an IRC channel and a Discord server for discussing 86Box, its development and anything related to retro computing. We look forward to hearing from you!
We operate an IRC channel and a Discord server for discussing 86Box, its development, and anything related to retro computing. We look forward to hearing from you!
[![Visit our IRC channel](https://kiwiirc.com/buttons/irc.ringoflightning.net/86Box.png)](https://kiwiirc.com/client/irc.ringoflightning.net/?nick=86box|?#86Box)

View File

@@ -70,6 +70,7 @@
#include <86box/unittester.h>
#include <86box/novell_cardkey.h>
#include <86box/isamem.h>
#include <86box/isarom.h>
#include <86box/isartc.h>
#include <86box/lpt.h>
#include <86box/serial.h>
@@ -87,7 +88,7 @@
#include <86box/scsi_device.h>
#include <86box/cdrom.h>
#include <86box/cdrom_interface.h>
#include <86box/zip.h>
#include <86box/rdisk.h>
#include <86box/mo.h>
#include <86box/scsi_disk.h>
#include <86box/cdrom_image.h>
@@ -168,7 +169,6 @@ int vid_api = 0; /* (C) video r
int vid_cga_contrast = 0; /* (C) video */
int video_fullscreen = 0; /* (C) video */
int video_fullscreen_scale = 0; /* (C) video */
int video_fullscreen_first = 0; /* (G) video */
int enable_overscan = 0; /* (C) video */
int force_43 = 0; /* (C) video */
int video_filter_method = 1; /* (C) video */
@@ -182,12 +182,12 @@ int postcard_enabled = 0; /* (C) enable
int unittester_enabled = 0; /* (C) enable unit tester device */
int gameport_type[GAMEPORT_MAX] = { 0, 0 }; /* (C) enable gameports */
int isamem_type[ISAMEM_MAX] = { 0, 0, 0, 0 }; /* (C) enable ISA mem cards */
int isarom_type[ISAROM_MAX] = { 0, 0, 0, 0 }; /* (C) enable ISA ROM cards */
int isartc_type = 0; /* (C) enable ISA RTC card */
int gfxcard[GFXCARD_MAX] = { 0, 0 }; /* (C) graphics/video card */
int show_second_monitors = 1; /* (C) show non-primary monitors */
int sound_is_float = 1; /* (C) sound uses FP values */
int voodoo_enabled = 0; /* (C) video option */
int lba_enhancer_enabled = 0; /* (C) enable Vision Systems LBA Enhancer */
int ibm8514_standalone_enabled = 0; /* (C) video option */
int xga_standalone_enabled = 0; /* (C) video option */
int da2_standalone_enabled = 0; /* (C) video option */
@@ -216,12 +216,15 @@ int test_mode = 0; /* (C) Test mo
char uuid[MAX_UUID_LEN] = { '\0' }; /* (C) UUID or machine identifier */
int sound_muted = 0; /* (C) Is sound muted? */
int inhibit_multimedia_keys; /* (G) Inhibit multimedia keys on Windows. */
int force_10ms; /* (C) Force 10ms CPU frame intervals. */
int other_ide_present = 0; /* IDE controllers from non-IDE cards are
present */
int other_scsi_present = 0; /* SCSI controllers from non-SCSI cards are
present */
int is_pcjr = 0; /* The current machine is PCjr. */
// Accelerator key array
struct accelKey acc_keys[NUM_ACCELS];
@@ -252,6 +255,8 @@ struct accelKey def_acc_keys[NUM_ACCELS] = {
.seq="Ctrl+Alt+M" }
};
char vmm_path[1024] = { '\0'}; /* TEMPORARY - VM manager path to scan for VMs */
int vmm_enabled = 0;
/* Statistics. */
extern int mmuflush;
@@ -600,8 +605,8 @@ pc_show_usage(char *s)
#ifdef _WIN32
"-D or --debug\t\t\t- force debug output logging\n"
#endif
#if 0
"-E or --nographic\t\t- forces the old behavior\n"
#if 1
"-E or --vmmpath\t\t- vm manager path\n"
#endif
"-F or --fullscreen\t\t- start in fullscreen mode\n"
"-G or --lang langid\t\t- start with specified language\n"
@@ -638,7 +643,7 @@ pc_show_usage(char *s)
ui_msgbox(MBX_ANSI | ((s == NULL) ? MBX_INFO : MBX_WARNING), p);
#else
if (s == NULL)
pclog(p);
pclog("%s", p);
else
ui_msgbox(MBX_ANSI | MBX_WARNING, p);
#endif
@@ -736,13 +741,18 @@ usage:
} else if (!strcasecmp(argv[c], "--debug") || !strcasecmp(argv[c], "-D")) {
force_debug = 1;
#endif
#ifdef ENABLE_NG
} else if (!strcasecmp(argv[c], "--nographic") || !strcasecmp(argv[c], "-E")) {
/* Currently does nothing, but if/when we implement a built-in manager,
it's going to force the manager not to run, allowing the old usage
without parameter. */
ng = 1;
#endif
//#ifdef ENABLE_NG
} else if (!strcasecmp(argv[c], "--vmmpath") ||
!strcasecmp(argv[c], "-E")) {
/* Using this variable for vm manager path
Temporary solution!*/
if ((c+1) == argc) goto usage;
char *vp = argv[++c];
if ((strlen(vp) + 1) >= sizeof(vmm_path))
memcpy(vmm_path, vp, sizeof(vmm_path));
else
memcpy(vmm_path, vp, strlen(vp) + 1);
//#endif
} else if (!strcasecmp(argv[c], "--fullscreen") || !strcasecmp(argv[c], "-F")) {
start_in_fullscreen = 1;
} else if (!strcasecmp(argv[c], "--logfile") || !strcasecmp(argv[c], "-L")) {
@@ -782,7 +792,11 @@ usage:
goto usage;
temp2 = (char *) calloc(2048, 1);
sscanf(argv[++c], "%c:%s", &drive, temp2);
if (sscanf(argv[++c], "%c:%2047s", &drive, temp2) != 2) {
fprintf(stderr, "Invalid input format for --image option.\n");
free(temp2);
goto usage;
}
if (drive > 0x40)
drive = (drive & 0x1f) - 1;
else
@@ -1029,9 +1043,21 @@ usage:
* This is where we start outputting to the log file,
* if there is one. Create a little info header first.
*/
struct tm time_buf;
(void) time(&now);
info = localtime(&now);
strftime(temp, sizeof(temp), "%Y/%m/%d %H:%M:%S", info);
#ifdef _WIN32
if (localtime_s(&time_buf, &now) == 0)
info = &time_buf;
#else
info = localtime_r(&now, &time_buf);
#endif
if (info)
strftime(temp, sizeof(temp), "%Y/%m/%d %H:%M:%S", info);
else
strcpy(temp, "unknown");
pclog("#\n# %ls v%ls logfile, created %s\n#\n",
EMU_NAME_W, EMU_VERSION_FULL_W, temp);
pclog("# VM: %s\n#\n", vm_name);
@@ -1042,48 +1068,55 @@ usage:
}
pclog("# Global configuration file: %s\n", global_cfg_path);
pclog("# VM configuration file: %s\n#\n\n", cfg_path);
/*
* We are about to read the configuration file, which MAY
* put data into global variables (the hard- and floppy
* disks are an example) so we have to initialize those
* modules before we load the config..
*/
hdd_init();
network_init();
mouse_init();
cdrom_global_init();
zip_global_init();
mo_global_init();
/* Initialize the keyboard accelerator list with default values */
for (int x = 0; x < NUM_ACCELS; x++) {
strcpy(acc_keys[x].name, def_acc_keys[x].name);
strcpy(acc_keys[x].desc, def_acc_keys[x].desc);
strcpy(acc_keys[x].seq, def_acc_keys[x].seq);
pclog("# Configuration file: %s\n#\n\n", cfg_path);
if (strlen(vmm_path) != 0) {
vmm_enabled = 1;
pclog("# VM Manager enabled. Path: %s\n", vmm_path);
}
/* Load the configuration file. */
config_load();
if (!vmm_enabled) {
/*
* We are about to read the configuration file, which MAY
* put data into global variables (the hard- and floppy
* disks are an example) so we have to initialize those
* modules before we load the config..
*/
hdd_init();
network_init();
mouse_init();
cdrom_global_init();
rdisk_global_init();
mo_global_init();
/* Clear the CMOS and/or BIOS flash file, if we were started with
the relevant parameter(s). */
if (clear_cmos) {
delete_nvr_file(0);
clear_cmos = 0;
}
/* Initialize the keyboard accelerator list with default values */
for (int x = 0; x < NUM_ACCELS; x++) {
strcpy(acc_keys[x].name, def_acc_keys[x].name);
strcpy(acc_keys[x].desc, def_acc_keys[x].desc);
strcpy(acc_keys[x].seq, def_acc_keys[x].seq);
}
if (clear_flash) {
delete_nvr_file(1);
clear_flash = 0;
}
/* Load the configuration file. */
config_load();
for (uint8_t i = 0; i < FDD_NUM; i++) {
if (fn[i] != NULL) {
if (strlen(fn[i]) <= 511)
strncpy(floppyfns[i], fn[i], 511);
free(fn[i]);
fn[i] = NULL;
/* Clear the CMOS and/or BIOS flash file, if we were started with
the relevant parameter(s). */
if (clear_cmos) {
delete_nvr_file(0);
clear_cmos = 0;
}
if (clear_flash) {
delete_nvr_file(1);
clear_flash = 0;
}
for (uint8_t i = 0; i < FDD_NUM; i++) {
if (fn[i] != NULL) {
if (strlen(fn[i]) <= 511)
strncpy(floppyfns[i], fn[i], 511);
free(fn[i]);
fn[i] = NULL;
}
}
}
@@ -1249,6 +1282,11 @@ pc_init_modules(void)
machine_status_init();
serial_set_next_inst(0);
lpt_set_3bc_used(0);
lpt_set_next_inst(0);
for (c = 0; c <= 0x7ff; c++) {
int64_t exp = c - 1023; /* 1023 = BIAS64 */
exp_pow_table[c] = pow(2.0, (double) exp);
@@ -1268,20 +1306,48 @@ pc_send_ca(uint16_t sc)
if (keyboard_mode >= 0x81) {
/* Use R-Alt because PS/55 DOS and OS/2 assign L-Alt Kanji */
keyboard_input(1, 0x1D); /* Ctrl key pressed */
if (keyboard_get_in_reset())
return;
keyboard_input(1, 0x138); /* R-Alt key pressed */
if (keyboard_get_in_reset())
return;
keyboard_input(1, sc);
if (keyboard_get_in_reset())
return;
usleep(50000);
if (keyboard_get_in_reset())
return;
keyboard_input(0, sc);
if (keyboard_get_in_reset())
return;
keyboard_input(0, 0x138); /* R-Alt key released */
if (keyboard_get_in_reset())
return;
keyboard_input(0, 0x1D); /* Ctrl key released */
if (keyboard_get_in_reset())
return;
} else {
keyboard_input(1, 0x1D); /* Ctrl key pressed */
if (keyboard_get_in_reset())
return;
keyboard_input(1, 0x38); /* Alt key pressed */
if (keyboard_get_in_reset())
return;
keyboard_input(1, sc);
if (keyboard_get_in_reset())
return;
usleep(50000);
if (keyboard_get_in_reset())
return;
keyboard_input(0, sc);
if (keyboard_get_in_reset())
return;
keyboard_input(0, 0x38); /* Alt key released */
if (keyboard_get_in_reset())
return;
keyboard_input(0, 0x1D); /* Ctrl key released */
if (keyboard_get_in_reset())
return;
}
}
@@ -1335,10 +1401,6 @@ pc_reset_hard_close(void)
lpt_devices_close();
#ifdef UNCOMMENT_LATER
lpt_close();
#endif
nvr_save();
nvr_close();
@@ -1354,7 +1416,7 @@ pc_reset_hard_close(void)
cdrom_close();
zip_close();
rdisk_close();
mo_close();
@@ -1367,6 +1429,9 @@ pc_reset_hard_close(void)
cpu_close();
serial_set_next_inst(0);
lpt_set_3bc_used(0);
lpt_set_next_inst(0);
}
/*
@@ -1405,6 +1470,8 @@ pc_reset_hard_init(void)
scsi_reset();
scsi_device_init();
ide_hard_reset();
/* Initialize the actual machine and its basic modules. */
machine_init();
@@ -1426,6 +1493,7 @@ pc_reset_hard_init(void)
/* Initialize parallel devices. */
/* note: PLIP LPT side has to be initialized before the network side */
lpt_standalone_init();
lpt_devices_init();
/* Reset and reconfigure the serial ports. */
@@ -1448,9 +1516,6 @@ pc_reset_hard_init(void)
fdd_reset();
/* Reset the CD-ROM Controller module. */
cdrom_interface_reset();
/* Reset and reconfigure the SCSI layer. */
scsi_card_init();
@@ -1458,9 +1523,16 @@ pc_reset_hard_init(void)
cdrom_hard_reset();
/* Reset the CD-ROM Controller module. */
cdrom_interface_reset();
mo_hard_reset();
zip_hard_reset();
rdisk_hard_reset();
/* Reset any ISA ROM cards. */
isarom_reset();
/* Reset any ISA RTC cards. */
isartc_reset();
@@ -1489,9 +1561,6 @@ pc_reset_hard_init(void)
if (unittester_enabled)
device_add(&unittester_device);
if (lba_enhancer_enabled)
device_add(&lba_enhancer_device);
if (novell_keycard_enabled)
device_add(&novell_keycard_device);
@@ -1549,19 +1618,19 @@ update_mouse_msg(void)
*(wcp - 1) = L'\0';
mbstowcs(wcpu, cpu_s->name, strlen(cpu_s->name) + 1);
#ifdef _WIN32
swprintf(mouse_msg[0], sizeof_w(mouse_msg[0]), L"%%i%%%% - %ls",
swprintf(mouse_msg[0], sizeof_w(mouse_msg[0]), L"%%i.%%i%%%% - %ls",
plat_get_string(STRING_MOUSE_CAPTURE));
swprintf(mouse_msg[1], sizeof_w(mouse_msg[1]), L"%%i%%%% - %ls",
swprintf(mouse_msg[1], sizeof_w(mouse_msg[1]), L"%%i.%%i%%%% - %ls",
(mouse_get_buttons() > 2) ? plat_get_string(STRING_MOUSE_RELEASE) : plat_get_string(STRING_MOUSE_RELEASE_MMB));
wcsncpy(mouse_msg[2], L"%i%%", sizeof_w(mouse_msg[2]));
wcsncpy(mouse_msg[2], L"%i.%i%%", sizeof_w(mouse_msg[2]));
#else
swprintf(mouse_msg[0], sizeof_w(mouse_msg[0]), L"%ls v%ls - %%i%%%% - %ls - %ls/%ls - %ls",
swprintf(mouse_msg[0], sizeof_w(mouse_msg[0]), L"%ls v%ls - %%i.%%i%%%% - %ls - %ls/%ls - %ls",
EMU_NAME_W, EMU_VERSION_FULL_W, wmachine, wcpufamily, wcpu,
plat_get_string(STRING_MOUSE_CAPTURE));
swprintf(mouse_msg[1], sizeof_w(mouse_msg[1]), L"%ls v%ls - %%i%%%% - %ls - %ls/%ls - %ls",
swprintf(mouse_msg[1], sizeof_w(mouse_msg[1]), L"%ls v%ls - %%i.%%i%%%% - %ls - %ls/%ls - %ls",
EMU_NAME_W, EMU_VERSION_FULL_W, wmachine, wcpufamily, wcpu,
(mouse_get_buttons() > 2) ? plat_get_string(STRING_MOUSE_RELEASE) : plat_get_string(STRING_MOUSE_RELEASE_MMB));
swprintf(mouse_msg[2], sizeof_w(mouse_msg[2]), L"%ls v%ls - %%i%%%% - %ls - %ls/%ls",
swprintf(mouse_msg[2], sizeof_w(mouse_msg[2]), L"%ls v%ls - %%i.%%i%%%% - %ls - %ls/%ls",
EMU_NAME_W, EMU_VERSION_FULL_W, wmachine, wcpufamily, wcpu);
#endif
}
@@ -1622,13 +1691,17 @@ pc_close(UNUSED(thread_t *ptr))
cdrom_close();
zip_close();
rdisk_close();
mo_close();
scsi_disk_close();
gdbstub_close();
#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64))
mem_free();
#endif
}
#ifdef __APPLE__
@@ -1667,7 +1740,7 @@ pc_run(void)
/* Run a block of code. */
startblit();
cpu_exec((int32_t) cpu_s->rspeed / 100);
cpu_exec((int32_t) cpu_s->rspeed / (force_10ms ? 100 : 1000));
ack_pause();
#ifdef USE_GDBSTUB /* avoid a KBC FIFO overflow when CPU emulation is stalled */
if (gdbstub_step == GDBSTUB_EXEC) {
@@ -1682,14 +1755,14 @@ pc_run(void)
/* Done with this frame, update statistics. */
framecount++;
if (++framecountx >= 100) {
if (++framecountx >= (force_10ms ? 100 : 1000)) {
framecountx = 0;
frames = 0;
}
if (title_update) {
mouse_msg_idx = ((mouse_type == MOUSE_TYPE_NONE) || (mouse_input_mode >= 1)) ? 2 : !!mouse_capture;
swprintf(temp, sizeof_w(temp), mouse_msg[mouse_msg_idx], fps);
swprintf(temp, sizeof_w(temp), mouse_msg[mouse_msg_idx], fps / (force_10ms ? 1 : 10), force_10ms ? 0 : (fps % 10));
#ifdef __APPLE__
/* Needed due to modifying the UI on the non-main thread is a big no-no. */
dispatch_async_f(dispatch_get_main_queue(), wcsdup((const wchar_t *) temp), _ui_window_title);
@@ -1891,4 +1964,4 @@ int FindAccelerator(const char *name) {
}
// No key was found
return -1;
}
}

View File

@@ -16,6 +16,10 @@
# Copyright 2024 Jasmine Iwanek.
#
if(NOT CMAKE_TOP_LEVEL_PROCESSED)
message(FATAL_ERROR "Incorrect source directory specified. Delete your build directory and retry with the top-level directory instead")
endif()
if(APPLE)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
endif()
@@ -99,7 +103,7 @@ if(INSTRUMENT)
add_compile_definitions(USE_INSTRUMENT)
endif()
target_link_libraries(86Box cpu chipset mch dev mem fdd game cdrom zip mo hdd
target_link_libraries(86Box cpu chipset mch dev mem fdd game cdrom rdisk mo hdd
net print scsi sio snd utils vid voodoo plat ui)
if(HAIKU)
@@ -149,16 +153,6 @@ if(APPLE)
target_link_libraries(86Box Freetype::Freetype)
endif()
find_package(SDL2 REQUIRED)
include_directories(${SDL2_INCLUDE_DIRS})
if(STATIC_BUILD AND TARGET SDL2::SDL2-static)
target_link_libraries(86Box SDL2::SDL2-static)
elseif(TARGET SDL2::SDL2)
target_link_libraries(86Box SDL2::SDL2)
else()
target_link_libraries(86Box ${SDL2_LIBRARIES})
endif()
find_package(PNG REQUIRED)
include_directories(${PNG_INCLUDE_DIRS})
target_link_libraries(86Box PNG::PNG)

View File

@@ -36,6 +36,7 @@
#include <86box/pit.h>
#include <86box/apm.h>
#include <86box/acpi.h>
#include <86box/dma.h>
#include <86box/machine.h>
#include <86box/i2c.h>
#include <86box/video.h>
@@ -1025,8 +1026,13 @@ acpi_reg_write_common_regs(UNUSED(int size), uint16_t addr, uint8_t val, void *p
nvr_reg_write(0x000f, 0xff, dev->nvr);
}
if (sus_typ & SUS_RESET_PCI)
if (sus_typ & SUS_RESET_PCI) {
/* DMA is part of the southbridge so it responds to PCI reset. */
dma_reset();
dma_set_at(1);
device_reset_all(DEVICE_PCI);
}
if (sus_typ & SUS_RESET_CPU)
cpu_alt_reset = 0;
@@ -2387,6 +2393,14 @@ acpi_reset(void *priv)
dev->regs.gpi_val = 0xfff57fc1;
if (!strcmp(machine_get_internal_name(), "ficva503a") || !strcmp(machine_get_internal_name(), "6via90ap"))
dev->regs.gpi_val |= 0x00000004;
/*
TriGem Delhi-III second GPI word:
- Bit 7 = Save CMOS (must be set);
- Bit 6 = Password jumper (must be set);
- Bit 5 = Enable Setup (must be set).
*/
else if (!strcmp(machine_get_internal_name(), "delhi3"))
dev->regs.gpi_val |= 0x00008000;
}
if (acpi_power_on) {

View File

@@ -23,6 +23,7 @@ add_library(cdrom OBJECT
cdrom.c
cdrom_image.c
cdrom_image_viso.c
cdrom_mke.c
)
target_link_libraries(86Box PkgConfig::SNDFILE)

View File

@@ -32,6 +32,7 @@
#ifdef USE_CDROM_MITSUMI
#include <86box/cdrom_mitsumi.h>
#endif
#include <86box/cdrom_mke.h>
#include <86box/log.h>
#include <86box/plat.h>
#include <86box/plat_cdrom_ioctl.h>
@@ -121,8 +122,10 @@ static const struct {
// clang-format off
{ &cdrom_interface_none_device },
#ifdef USE_CDROM_MITSUMI
{ &mitsumi_cdrom_device },
{ &mitsumi_cdrom_device },
#endif
{ &mke_cdrom_noncreative_device },
{ &mke_cdrom_device },
{ NULL }
// clang-format on
};
@@ -292,10 +295,80 @@ msf_to_bcd(int *m, int *s, int *f)
*f = bin2bcd(*f);
}
static int
read_data(cdrom_t *dev, const uint32_t lba)
void
cdrom_compute_ecc_block(cdrom_t *dev, uint8_t *parity, const uint8_t *data,
uint32_t major_count, uint32_t minor_count,
uint32_t major_mult, uint32_t minor_inc, int m2f1)
{
int ret = 1;
uint32_t size = major_count * minor_count;
for (uint32_t major = 0; major < major_count; ++major) {
uint32_t index = (major >> 1) * major_mult + (major & 1);
uint8_t ecc_a = 0;
uint8_t ecc_b = 0;
for (uint32_t minor = 0; minor < minor_count; ++minor) {
uint8_t temp = data[index];
if (m2f1 && (index < 4))
temp = 0x00;
index += minor_inc;
if (index >= size)
index -= size;
ecc_a ^= temp;
ecc_b ^= temp;
ecc_a = dev->_F_LUT[ecc_a];
}
parity[major] = dev->_B_LUT[dev->_F_LUT[ecc_a] ^ ecc_b];
parity[major + major_count] = parity[major] ^ ecc_b;
}
}
static void
cdrom_generate_ecc_data(cdrom_t *dev, const uint8_t *data, int m2f1)
{
/* Compute ECC P code. */
cdrom_compute_ecc_block(dev, dev->p_parity, data, 86, 24, 2, 86, m2f1);
/* Compute ECC Q code. */
cdrom_compute_ecc_block(dev, dev->q_parity, data, 52, 43, 86, 88, m2f1);
}
static int
cdrom_is_sector_good(cdrom_t *dev, const uint8_t *b, const uint8_t mode2, const uint8_t form)
{
int ret = 1;
if (!mode2 || (form != 1)) {
if (mode2 && (form == 1)) {
const uint32_t crc = cdrom_crc32(0xffffffff, &(b[16]), 2056) ^ 0xffffffff;
ret = ret && (crc == (*(uint32_t *) &(b[2072])));
} else if (!mode2) {
const uint32_t crc = cdrom_crc32(0xffffffff, b, 2064) ^ 0xffffffff;
ret = ret && (crc == (*(uint32_t *) &(b[2064])));
}
cdrom_generate_ecc_data(dev, &(b[12]), mode2 && (form == 1));
ret = ret && !memcmp(dev->p_parity, &(b[2076]), 172);
ret = ret && !memcmp(dev->q_parity, &(b[2248]), 104);
}
return ret;
}
static int
read_data(cdrom_t *dev, const uint32_t lba, int check)
{
int ret = 1;
int form = 0;
if (dev->cached_sector != lba) {
dev->cached_sector = lba;
@@ -303,6 +376,25 @@ read_data(cdrom_t *dev, const uint32_t lba)
ret = dev->ops->read_sector(dev->local,
dev->raw_buffer[dev->cur_buf ^ 1], lba);
if ((ret > 0) && check) {
if (dev->mode2) {
if (dev->raw_buffer[dev->cur_buf ^ 1][0x000f] == 0x01)
/*
Use Mode 1, since evidently specification-violating
discs exist.
*/
dev->mode2 = 0;
else if (dev->raw_buffer[dev->cur_buf ^ 1][0x0012] ==
dev->raw_buffer[dev->cur_buf ^ 1][0x0016])
form = ((dev->raw_buffer[dev->cur_buf ^ 1][0x0012] &
0x20) >> 5) + 1;
} else if (dev->raw_buffer[dev->cur_buf ^ 1][0x000f] == 0x02)
dev->mode2 = 1;
if (!cdrom_is_sector_good(dev, dev->raw_buffer[dev->cur_buf ^ 1], dev->mode2, form))
ret = -1;
}
if (ret <= 0) {
memset(dev->raw_buffer[dev->cur_buf ^ 1], 0x00, 2448);
dev->cached_sector = -1;
@@ -322,7 +414,7 @@ cdrom_get_subchannel(cdrom_t *dev, const uint32_t lba,
if (lba != dev->cached_sector)
dev->cached_sector = -1;
(void) read_data(dev, lba);
(void) read_data(dev, lba, 0);
for (int i = 0; i < 12; i++)
for (int j = 0; j < 8; j++)
@@ -679,7 +771,7 @@ track_type_is_valid(UNUSED(const cdrom_t *dev), const int type, const int flags,
static int
read_audio(cdrom_t *dev, const uint32_t lba, uint8_t *b)
{
const int ret = read_data(dev, lba);
const int ret = read_data(dev, lba, 0);
memcpy(b, dev->raw_buffer[dev->cur_buf], 2352);
@@ -979,28 +1071,28 @@ cdrom_toc_dump(cdrom_t *dev)
uint8_t b[65536] = { 0 };
int len = cdrom_read_toc(dev, b, CD_TOC_RAW, 0, 0, 65536);
const char *fn2 = "d:\\86boxnew\\toc_cue.dmp";
FILE * f = fopen(fn2, "wb");
fwrite(b, 1, len, f);
fflush(f);
fclose(f);
FILE * fp = fopen(fn2, "wb");
fwrite(b, 1, len, fp);
fflush(fp);
fclose(fp);
cdrom_log(dev->log, "Written TOC of %i bytes to %s\n", len, fn2);
memset(b, 0x00, 65536);
len = cdrom_read_toc(dev, b, CD_TOC_NORMAL, 0, 0, 65536);
fn2 = "d:\\86boxnew\\toc_cue_cooked.dmp";
f = fopen(fn2, "wb");
fwrite(b, 1, len, f);
fflush(f);
fclose(f);
fp = fopen(fn2, "wb");
fwrite(b, 1, len, fp);
fflush(fp);
fclose(fp);
cdrom_log(dev->log, "Written cooked TOC of %i bytes to %s\n", len, fn2);
memset(b, 0x00, 65536);
len = cdrom_read_toc(dev, b, CD_TOC_SESSION, 0, 0, 65536);
fn2 = "d:\\86boxnew\\toc_cue_session.dmp";
f = fopen(fn2, "wb");
fwrite(b, 1, len, f);
fflush(f);
fclose(f);
fp = fopen(fn2, "wb");
fwrite(b, 1, len, fp);
fflush(fp);
fclose(fp);
cdrom_log(dev->log, "Written session TOC of %i bytes to %s\n", len, fn2);
}
#endif
@@ -1100,6 +1192,12 @@ cdrom_is_early(const int type)
return (cdrom_drive_types[type].scsi_std == 1);
}
int
cdrom_is_dvd(const int type)
{
return (cdrom_drive_types[type].is_dvd == 1);
}
int
cdrom_is_generic(const int type)
{
@@ -1151,6 +1249,26 @@ cdrom_get_type_count(void)
return count;
}
void
cdrom_generate_name_mke(const int type, char *name)
{
char elements[2][512] = { 0 };
memcpy(elements[0], cdrom_drive_types[type].model,
strlen(cdrom_drive_types[type].model) + 1);
char *s = strstr(elements[0], " ");
if (s != NULL)
s[0] = 0x00;
memcpy(elements[1], cdrom_drive_types[type].revision,
strlen(cdrom_drive_types[type].revision) + 1);
s = strstr(elements[1], " ");
if (s != NULL)
s[0] = 0x00;
sprintf(name, "%s%s", elements[0], elements[1]);
}
void
cdrom_get_identify_model(const int type, char *name, const int id)
{
@@ -1589,7 +1707,7 @@ cdrom_audio_track_search(cdrom_t *dev, const uint32_t pos,
dev->seek_pos = MSFtoLBA(ti.m, ti.s, ti.f) - 150;
else {
cdrom_log(dev->log, "Unable to get the starting position for "
"track %08X\n", ismsf & 0xff);
"track %08X\n", pos2 & 0xff);
cdrom_stop(dev);
}
break;
@@ -1707,7 +1825,7 @@ cdrom_audio_play_toshiba(cdrom_t *dev, const uint32_t pos, const int type)
dev->cd_end = MSFtoLBA(ti.m, ti.s, ti.f) - 150;
else {
cdrom_log(dev->log, "Unable to get the starting position for "
"track %08X\n", ismsf & 0xff);
"track %08X\n", pos2 & 0xff);
cdrom_stop(dev);
}
break;
@@ -1740,7 +1858,7 @@ cdrom_audio_scan(cdrom_t *dev, const uint32_t pos)
uint8_t ret = 0;
if (dev->cd_status & CD_STATUS_HAS_AUDIO) {
cdrom_log(dev->log, "Audio Scan: MSF = %06x, type = %02x\n", pos, type);
cdrom_log(dev->log, "Audio Scan: MSF = %06x\n", pos);
if (pos == 0xffffffff) {
cdrom_log(dev->log, "(Type 0) Search from current position\n");
@@ -2009,9 +2127,10 @@ cdrom_get_current_subcodeq_playstatus(cdrom_t *dev, uint8_t *b)
cdrom_get_current_subcodeq(dev, b);
switch (dev->cd_status) {
default: case CD_STATUS_EMPTY:
case CD_STATUS_DATA_ONLY: case CD_STATUS_DVD:
case CD_STATUS_STOPPED: case CD_STATUS_PLAYING_COMPLETED:
default: case CD_STATUS_EMPTY:
case CD_STATUS_DATA_ONLY: case CD_STATUS_DVD:
case CD_STATUS_STOPPED: case CD_STATUS_PLAYING_COMPLETED:
case CD_STATUS_DVD_REJECTED:
ret = 0x03;
break;
case CD_STATUS_HOLD:
@@ -2360,7 +2479,7 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, const int sector, const int
ecc_diff = 0;
}
if (dev->cd_status != CD_STATUS_EMPTY) {
if ((dev->cd_status != CD_STATUS_EMPTY) && (dev->cd_status != CD_STATUS_DVD_REJECTED)) {
uint8_t *temp_b;
uint8_t *b = temp_b = buffer;
int audio = 0;
@@ -2379,6 +2498,8 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, const int sector, const int
if (dm != CD_TRACK_NORMAL)
mode2 = 1;
dev->mode2 = mode2;
memset(dev->extra_buffer, 0, 296);
if ((cdrom_sector_flags & 0xf8) == 0x08) {
@@ -2405,7 +2526,7 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, const int sector, const int
else
ret = read_audio(dev, lba, temp_b);
} else {
ret = read_data(dev, lba);
ret = read_data(dev, lba, 1);
/* Return with error if we had one. */
if (ret > 0) {
@@ -2655,7 +2776,7 @@ cdrom_read_disc_information(const cdrom_t *dev, uint8_t *buffer)
buffer[ 3] = first; /* Number of First Track on Disc */
buffer[ 4] = sessions; /* Number of Sessions (LSB) */
buffer[ 5] = ls_first; /* First Track Number in Last Session (LSB) */
buffer[ 5] = ls_last; /* Last Track Number in Last Session (LSB) */
buffer[ 6] = ls_last; /* Last Track Number in Last Session (LSB) */
buffer[ 7] = 0x20; /* Unrestricted use */
buffer[ 8] = t[0].ps; /* Disc Type */
buffer[ 9] = 0x00; /* Number Of Sessions (MSB) */
@@ -2800,7 +2921,7 @@ cdrom_read_track_information(cdrom_t *dev, const uint8_t *cdb, uint8_t *buffer)
}
if (track->adr_ctl & 0x04) {
ret = read_data(dev, start);
ret = read_data(dev, start, 0);
mode = dev->raw_buffer[dev->cur_buf][3];
}
} else if (track->point != 0xa2)
@@ -2829,9 +2950,9 @@ uint8_t
cdrom_get_current_mode(cdrom_t *dev)
{
if (dev->cached_sector == -1)
(void) read_data(dev, dev->seek_pos);
(void) read_data(dev, dev->seek_pos, 0);
else
(void) read_data(dev, dev->cached_sector);
(void) read_data(dev, dev->cached_sector, 0);
return dev->raw_buffer[dev->cur_buf][3];
}
@@ -2864,7 +2985,7 @@ cdrom_update_status(cdrom_t *dev)
dev->cached_sector = -1;
dev->cdrom_capacity = dev->ops->get_last_block(dev->local);
if (dev->cd_status != CD_STATUS_EMPTY) {
if ((dev->cd_status != CD_STATUS_EMPTY) && (dev->cd_status != CD_STATUS_DVD_REJECTED)) {
/* Signal media change to the emulated machine. */
cdrom_insert(dev->id);
@@ -2906,9 +3027,14 @@ cdrom_load(cdrom_t *dev, const char *fn, const int skip_insert)
if ((dev->ops->is_empty != NULL) && dev->ops->is_empty(dev->local))
dev->cd_status = CD_STATUS_EMPTY;
else if (dev->ops->is_dvd(dev->local))
dev->cd_status = CD_STATUS_DVD;
else
else if (dev->ops->is_dvd(dev->local)) {
if (cdrom_is_dvd(dev->type))
dev->cd_status = CD_STATUS_DVD;
else {
warning("DVD image \"%s\" in a CD-only drive, reporting as empty\n", fn);
dev->cd_status = CD_STATUS_DVD_REJECTED;
}
} else
dev->cd_status = dev->ops->has_audio(dev->local) ? CD_STATUS_STOPPED :
CD_STATUS_DATA_ONLY;
@@ -2922,7 +3048,7 @@ cdrom_load(cdrom_t *dev, const char *fn, const int skip_insert)
cdrom_toc_dump(dev);
#endif
if (!skip_insert && (dev->cd_status != CD_STATUS_EMPTY)) {
if (!skip_insert && (dev->cd_status != CD_STATUS_EMPTY) && (dev->cd_status != CD_STATUS_DVD_REJECTED)) {
/* Signal media change to the emulated machine. */
cdrom_insert(dev->id);
@@ -3011,6 +3137,11 @@ cdrom_hard_reset(void)
cdrom_load(dev, dev->image_path, 0);
}
for (uint32_t j = 0; j < _LUT_SIZE; ++j) {
dev->_F_LUT[j] = (j << 1) ^ (j & 0x80 ? 0x11d : 0);
dev->_B_LUT[j ^ dev->_F_LUT[j]] = j;
}
}
}

View File

@@ -26,6 +26,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <sys/stat.h>
#ifndef _WIN32
# include <libgen.h>
@@ -84,17 +85,148 @@ typedef struct track_t {
track_index_t idx[3];
} track_t;
/*
MDS for DVD has the disc structure table - 4 byte pointer to BCA,
followed by the copyright, DMI, and layer pages.
*/
#pragma pack(push, 1)
typedef struct
{
uint8_t f1[4];
uint8_t f4[2048];
uint8_t f0[2048];
} layer_t;
typedef struct
{
layer_t layers[2];
} mds_disc_struct_t;
#pragma pack(pop)
#define dstruct_t mds_disc_struct_t
typedef struct cd_image_t {
cdrom_t *dev;
void *log;
int is_dvd;
int has_audio;
int has_dstruct;
int32_t tracks_num;
uint32_t bad_sectors_num;
track_t *tracks;
uint32_t *bad_sectors;
dstruct_t dstruct;
} cd_image_t;
typedef enum
{
CD = 0x00, /* CD-ROM */
CD_R = 0x01, /* CD-R */
CD_RW = 0x02, /* CD-RW */
DVD = 0x10, /* DVD-ROM */
DVD_MINUS_R = 0x12 /* DVD-R */
} mds_medium_type_t;
typedef enum
{
UNKNOWN = 0x00,
AUDIO = 0xa9, /* sector size = 2352 */
MODE1 = 0xaa, /* sector size = 2048 */
MODE2 = 0xab, /* sector size = 2336 */
MODE2_FORM1 = 0xac, /* sector size = 2048 */
MODE2_FORM2 = 0xad /* sector size = 2324 (+4) */
} mds_trk_mode_t;
typedef enum
{
NONE = 0x00, /* no subchannel */
PW_INTERLEAVED = 0x08 /* 96-byte PW subchannel, interleaved */
} mds_subch_mode_t;
#pragma pack(push, 1)
typedef struct
{
uint8_t file_sig[16];
uint8_t file_ver[2];
uint16_t medium_type;
uint16_t sess_num;
uint16_t pad[2];
uint16_t bca_data_len;
uint32_t pad0[2];
uint32_t bca_data_offs_offs;
uint32_t pad1[6];
uint32_t disc_struct_offs;
uint32_t pad2[3];
uint32_t sess_blocks_offs;
uint32_t dpm_blocks_offs;
} mds_hdr_t; /* 88 bytes */
typedef struct
{
int32_t sess_start;
int32_t sess_end;
uint16_t sess_id;
uint8_t all_blocks_num;
uint8_t non_track_blocks_num;
uint16_t first_trk;
uint16_t last_trk;
uint32_t pad;
uint32_t trk_blocks_offs;
} mds_sess_block_t; /* 24 bytes */
typedef struct
{
uint8_t trk_mode;
/* DiscImageCreator says this is the number of subchannels. */
uint8_t subch_mode;
uint8_t adr_ctl;
uint8_t track_id;
uint8_t point;
uint8_t m;
uint8_t s;
uint8_t f;
uint8_t zero;
uint8_t pm;
uint8_t ps;
uint8_t pf;
/* DiscImageCreator calls this the index offset. */
uint32_t ex_offs;
uint16_t sector_len;
/* DiscImageCreator says unknown1 followed by 17x zero. */
uint8_t pad0[18];
uint32_t start_sect;
uint64_t start_offs;
uint32_t files_num;
uint32_t footer_offs;
uint8_t pad1[24];
} mds_trk_block_t; /* 80 bytes */
/*
DiscImageCreator's interpretation here makes sense and essentially
matches libmirage's - Index 0 sectors followed by Index 1 sectors.
*/
typedef struct
{
uint32_t pregap;
uint32_t trk_sectors;
} mds_trk_ex_block_t; /* 8 bytes */
typedef struct
{
uint32_t fn_offs;
uint32_t fn_is_wide;
uint32_t pad;
uint32_t pad0;
} mds_footer_t; /* 16 bytes */
typedef struct
{
uint32_t type;
uint32_t pad[2];
uint32_t entries;
} mds_dpm_block_t;
#pragma pack(pop)
#ifdef ENABLE_IMAGE_LOG
int image_do_log = ENABLE_IMAGE_LOG;
@@ -284,6 +416,9 @@ bin_close(void *priv)
memset(tf->fn, 0x00, sizeof(tf->fn));
log_close(tf->log);
tf->log = NULL;
free(priv);
}
@@ -298,6 +433,11 @@ bin_init(const uint8_t id, const char *filename, int *error)
return NULL;
}
char n[1024] = { 0 };
sprintf(n, "CD-ROM %i Bin ", id + 1);
tf->log = log_open(n);
memset(tf->fn, 0x00, sizeof(tf->fn));
strncpy(tf->fn, filename, sizeof(tf->fn) - 1);
tf->fp = plat_fopen64(tf->fn, "rb");
@@ -314,11 +454,6 @@ bin_init(const uint8_t id, const char *filename, int *error)
tf->read = bin_read;
tf->get_length = bin_get_length;
tf->close = bin_close;
char n[1024] = { 0 };
sprintf(n, "CD-ROM %i Bin ", id + 1);
tf->log = log_open(n);
} else {
/* From the check above, error may still be non-zero if opening a directory.
* The error is set for viso to try and open the directory following this function.
@@ -326,8 +461,12 @@ bin_init(const uint8_t id, const char *filename, int *error)
if ((tf->fp != NULL) && ((stats.st_mode & S_IFMT) == S_IFDIR)) {
/* tf is freed by bin_close */
bin_close(tf);
} else
} else {
log_close(tf->log);
tf->log = NULL;
free(tf);
}
tf = NULL;
}
@@ -1183,7 +1322,7 @@ image_process(cd_image_t *img)
ct->point, j,
cit[ci->type + 2], ci->file_start * ct->sector_size);
image_log(img->log, " TOC data: %02X %02X %02X "
"%%02X %02X %02X %02X 02X %02X %02X %02X\n",
"%02X %02X %02X %02X %02X %02X %02X %02X\n",
ct->session, ct->attr, ct->tno, ct->point,
ct->extra[0], ct->extra[1], ct->extra[2], ct->extra[3],
(uint32_t) ((ci->start / 75) / 60),
@@ -1208,12 +1347,12 @@ image_set_track_subch_type(track_t *ct)
static int
image_load_iso(cd_image_t *img, const char *filename)
{
track_t *ct = NULL;
track_index_t *ci = NULL;
track_file_t *tf = NULL;
int success = 1;
int error = 1;
int is_viso = 0;
track_t *ct = NULL;
track_index_t *ci = NULL;
track_file_t *tf = NULL;
int success = 1;
int error = 1;
int is_viso = 0;
int sector_sizes[8] = { 2448, 2368, RAW_SECTOR_SIZE, 2336,
2332, 2328, 2324, COOKED_SECTOR_SIZE };
@@ -1308,8 +1447,12 @@ image_load_iso(cd_image_t *img, const char *filename)
if (success)
image_process(img);
else {
image_log(img->log, " [ISO ] Unable to open image or folder \"%s\"\n",
filename);
#ifdef ENABLE_IMAGE_LOG
log_warning(img->log, "Unable to open image or folder \"%s\"\n",
filename);
#else
warning("Unable to open image or folder \"%s\"\n", filename);
#endif
return 0;
}
@@ -1446,9 +1589,9 @@ image_load_cue(cd_image_t *img, const char *cuefile)
if (last_t != -1) {
/*
Important: This has to be done like this because pointers
change due to realloc.
change due to realloc.
*/
ct = &(img->tracks[t]);
ct = &(img->tracks[img->tracks_num - 1]);
for (int i = 2; i >= 0; i--) {
if (ct->idx[i].file == NULL)
@@ -1654,11 +1797,436 @@ image_load_cue(cd_image_t *img, const char *cuefile)
if (success)
image_process(img);
else {
image_log(img->log, " [CUE ] Unable to open Cue sheet \"%s\"\n", cuefile);
else
#ifdef ENABLE_IMAGE_LOG
log_warning(img->log, " [CUE ] Unable to open Cue sheet \"%s\"\n", cuefile);
#else
warning("Unable to open Cue sheet \"%s\"\n", cuefile);
#endif
return success;
}
// Converts UTF-16 string into UTF-8 string.
// If destination string is NULL returns total number of symbols that would've
// been written (without null terminator). However, when actually writing into
// destination string, it does include it. So, be sure to allocate extra byte
// for destination string.
// Params:
// u16_str - source UTF-16 string
// u16_str_len - length of source UTF-16 string
// u8_str - destination UTF-8 string
// u8_str_size - size of destination UTF-8 string in bytes
// Return value:
// 0 on success, -1 if encountered invalid surrogate pair, -2 if
// encountered buffer overflow or length of destination UTF-8 string in bytes
// (without including the null terminator).
long int utf16_to_utf8(const uint16_t *u16_str, size_t u16_str_len,
uint8_t *u8_str, size_t u8_str_size)
{
size_t i = 0, j = 0;
if (!u8_str) {
u8_str_size = u16_str_len * 4;
}
while (i < u16_str_len) {
uint32_t codepoint = u16_str[i++];
// check for surrogate pair
if (codepoint >= 0xD800 && codepoint <= 0xDBFF) {
uint16_t high_surr = codepoint;
uint16_t low_surr = u16_str[i++];
if (low_surr < 0xDC00 || low_surr > 0xDFFF)
return -1;
codepoint = ((high_surr - 0xD800) << 10) +
(low_surr - 0xDC00) + 0x10000;
}
if (codepoint < 0x80) {
if (j + 1 > u8_str_size) return -2;
if (u8_str) u8_str[j] = (char)codepoint;
j++;
} else if (codepoint < 0x800) {
if (j + 2 > u8_str_size) return -2;
if (u8_str) {
u8_str[j + 0] = 0xC0 | (codepoint >> 6);
u8_str[j + 1] = 0x80 | (codepoint & 0x3F);
}
j += 2;
} else if (codepoint < 0x10000) {
if (j + 3 > u8_str_size) return -2;
if (u8_str) {
u8_str[j + 0] = 0xE0 | (codepoint >> 12);
u8_str[j + 1] = 0x80 | ((codepoint >> 6) & 0x3F);
u8_str[j + 2] = 0x80 | (codepoint & 0x3F);
}
j += 3;
} else {
if (j + 4 > u8_str_size) return -2;
if (u8_str) {
u8_str[j + 0] = 0xF0 | (codepoint >> 18);
u8_str[j + 1] = 0x80 | ((codepoint >> 12) & 0x3F);
u8_str[j + 2] = 0x80 | ((codepoint >> 6) & 0x3F);
u8_str[j + 3] = 0x80 | (codepoint & 0x3F);
}
j += 4;
}
}
if (u8_str) {
if (j >= u8_str_size) return -2;
u8_str[j] = '\0';
}
return (long int)j;
}
static int
image_load_mds(cd_image_t *img, const char *mdsfile)
{
track_t *ct = NULL;
track_index_t *ci = NULL;
track_file_t *tf = NULL;
int is_viso = 0;
int last_t = -1;
int error;
char pathname[MAX_FILENAME_LENGTH];
char ofn[2048] = { 0 };
mds_hdr_t mds_hdr = { 0 };
mds_sess_block_t mds_sess_block = { 0 };
mds_trk_block_t mds_trk_block = { 0 };
mds_trk_ex_block_t mds_trk_ex_block = { 0 };
mds_footer_t mds_footer = { 0 };
mds_dpm_block_t mds_dpm_block = { 0 };
uint32_t mds_dpm_blocks_num = 0x00000000;
uint32_t mds_dpm_block_offs = 0x00000000;
img->tracks = NULL;
img->tracks_num = 0;
/* Get a copy of the filename into pathname, we need it later. */
memset(pathname, 0, MAX_FILENAME_LENGTH * sizeof(char));
path_get_dirname(pathname, mdsfile);
/* Open the file. */
FILE *fp = plat_fopen(mdsfile, "rb");
if (fp == NULL)
return 0;
int success = 0;
/*
Pass 1 - loading the MDS sheet.
*/
image_log(img->log, "Pass 1 (loading the Media Descriptor Sheet)...\n");
img->tracks_num = 0;
success = 2;
fseek(fp, 0, SEEK_SET);
fread(&mds_hdr, 1, sizeof(mds_hdr_t), fp);
if (memcmp(mds_hdr.file_sig, "MEDIA DESCRIPTOR", 16)) {
#ifdef ENABLE_IMAGE_LOG
log_warning(img->log, " [MDS ] \"%s\"\n is not an actual MDF file",
mdsfile);
#else
warning("\"%s\"\n is not an actual MDF file", mdsfile);
#endif
fclose(fp);
return 0;
}
if (mds_hdr.file_ver[0] == 0x02) {
#ifdef ENABLE_IMAGE_LOG
log_warning(img->log, " [MDS ] \"%s\" is a Daemon Tools encrypted MDS which is not supported\n",
mdsfile);
#else
warning("\"%s\" is a Daemon Tools encrypted MDS which is not supported\n", mdsfile);
#endif
fclose(fp);
return 0;
}
img->is_dvd = (mds_hdr.medium_type >= 0x10);
if (img->is_dvd) {
if (mds_hdr.disc_struct_offs != 0x00) {
fseek(fp, mds_hdr.disc_struct_offs, SEEK_SET);
fread(&(img->dstruct.layers[0]), 1, sizeof(layer_t), fp);
img->has_dstruct = 1;
if (((img->dstruct.layers[0].f0[2] & 0x60) >> 4) == 0x01) {
fseek(fp, mds_hdr.disc_struct_offs, SEEK_SET);
fread(&(img->dstruct.layers[1]), 1, sizeof(layer_t), fp);
img->has_dstruct++;
}
}
for (int t = 0; t < 3; t++) {
ct = image_insert_track(img, 1, 0xa0 + t);
ct->attr = DATA_TRACK;
ct->mode = 0;
ct->form = 0;
ct->tno = 0;
ct->subch_type = 0;
memset(ct->extra, 0x00, 4);
for (int i = 0; i < 3; i++) {
ci = &(ct->idx[i]);
ci->type = INDEX_NONE;
ci->start = 0;
ci->length = 0;
ci->file_start = 0;
ci->file_length = 0;
ci->file = NULL;
}
ci = &(ct->idx[1]);
if (t < 2)
ci->start = (0x01 * 60 * 75) + (0 * 75) + 0;
}
}
if (mds_hdr.dpm_blocks_offs != 0x00) {
fseek(fp, mds_hdr.dpm_blocks_offs, SEEK_SET);
fread(&mds_dpm_blocks_num, 1, sizeof(uint32_t), fp);
if (mds_dpm_blocks_num > 0) for (int b = 0; b < mds_dpm_blocks_num; b++) {
fseek(fp, mds_hdr.dpm_blocks_offs + 4 + (b * 4), SEEK_SET);
fread(&mds_dpm_block_offs, 1, sizeof(uint32_t), fp);
fseek(fp, mds_dpm_block_offs, SEEK_SET);
fread(&mds_dpm_block, 1, sizeof(mds_dpm_block_t), fp);
/* We currently only support the bad sectors block and not (yet) actual DPM. */
if (mds_dpm_block.type == 0x00000002) {
/* Bad sectors. */
img->bad_sectors_num = mds_dpm_block.entries;
img->bad_sectors = (uint32_t *) malloc(img->bad_sectors_num * sizeof(uint32_t));
fseek(fp, mds_dpm_block_offs + sizeof(mds_dpm_block_t), SEEK_SET);
fread(img->bad_sectors, 1, img->bad_sectors_num * sizeof(uint32_t), fp);
break;
}
}
}
for (int s = 0; s < mds_hdr.sess_num; s++) {
fseek(fp, mds_hdr.sess_blocks_offs + (s * sizeof(mds_sess_block_t)), SEEK_SET);
fread(&mds_sess_block, 1, sizeof(mds_sess_block_t), fp);
for (int t = 0; t < mds_sess_block.all_blocks_num; t++) {
fseek(fp, mds_sess_block.trk_blocks_offs + (t * sizeof(mds_trk_block_t)), SEEK_SET);
fread(&mds_trk_block, 1, sizeof(mds_trk_block_t), fp);
if (last_t != -1) {
/*
Important: This has to be done like this because pointers
change due to realloc.
*/
ct = &(img->tracks[img->tracks_num - 1]);
for (int i = 2; i >= 0; i--) {
if (ct->idx[i].file == NULL)
ct->idx[i].file = tf;
else
break;
}
}
last_t = mds_trk_block.point;
ct = image_insert_track(img, mds_sess_block.sess_id, mds_trk_block.point);
if (img->is_dvd) {
/* DVD images have no extra block - the extra block offset is the track length. */
memset(&mds_trk_ex_block, 0x00, sizeof(mds_trk_ex_block_t));
mds_trk_ex_block.pregap = 0x00000000;
mds_trk_ex_block.trk_sectors = mds_trk_block.ex_offs;
} else if (mds_trk_block.ex_offs != 0ULL) {
fseek(fp, mds_trk_block.ex_offs, SEEK_SET);
fread(&mds_trk_ex_block, 1, sizeof(mds_trk_ex_block), fp);
}
uint32_t astart = mds_trk_block.start_sect - mds_trk_ex_block.pregap;
uint32_t aend = astart + mds_trk_ex_block.pregap;
uint32_t aend2 = aend + mds_trk_ex_block.trk_sectors;
uint32_t astart2 = mds_trk_block.start_sect + mds_trk_ex_block.trk_sectors;
if (mds_trk_block.footer_offs != 0ULL) for (uint32_t ff = 0; ff < mds_trk_block.files_num; ff++) {
fseek(fp, mds_trk_block.footer_offs + (ff * sizeof(mds_footer_t)), SEEK_SET);
fread(&mds_footer, 1, sizeof(mds_footer_t), fp);
uint16_t wfn[2048] = { 0 };
char fn[2048] = { 0 };
fseek(fp, mds_footer.fn_offs, SEEK_SET);
if (mds_footer.fn_is_wide) {
int len = 0;
for (int i = 0; i < 256; i++) {
fread(&(wfn[i]), 1, 2, fp);
len++;
if (wfn[i] == 0x0000)
break;
}
(void) utf16_to_utf8(wfn, 2048, (uint8_t *) fn, 2048);
} else for (int i = 0; i < 512; i++) {
fread(&fn[i], 1, 1, fp);
if (fn[i] == 0x00)
break;
}
if (!stricmp(fn, "*.mdf")) {
strcpy(fn, mdsfile);
fn[strlen(mdsfile) - 3] = 'm';
fn[strlen(mdsfile) - 2] = 'd';
fn[strlen(mdsfile) - 1] = 'f';
}
char filename[2048] = { 0 };
if (!path_abs(fn))
path_append_filename(filename, pathname, fn);
else
strcpy(filename, fn);
if (strcmp(ofn, filename) != 0) {
tf = index_file_init(img->dev->id, filename, &error, &is_viso);
strcpy(ofn, filename);
}
}
ct->sector_size = mds_trk_block.sector_len;
ct->form = 0;
ct->tno = mds_trk_block.track_id;
ct->subch_type = mds_trk_block.subch_mode;
ct->extra[0] = mds_trk_block.m;
ct->extra[1] = mds_trk_block.s;
ct->extra[2] = mds_trk_block.f;
ct->extra[3] = mds_trk_block.zero;
/*
Note from DiscImageCreator:
I hexedited the track mode field with various values and fed it to Alchohol;
it seemed that high part of byte had no effect at all; only the lower one
affected the mode, in the following manner:
00: Mode 2, 01: Audio, 02: Mode 1, 03: Mode 2, 04: Mode 2 Form 1,
05: Mode 2 Form 2, 06: UKNONOWN, 07: Mode 2
08: Mode 2, 09: Audio, 0A: Mode 1, 0B: Mode 2, 0C: Mode 2 Form 1,
0D: Mode 2 Form 2, 0E: UKNONOWN, 0F: Mode 2
*/
ct->attr = ((mds_trk_block.trk_mode & 0x07) == 0x01) ?
AUDIO_TRACK : DATA_TRACK;
ct->mode = 0;
ct->form = 0;
if (((mds_trk_block.trk_mode & 0x07) != 0x01) &&
((mds_trk_block.trk_mode & 0x07) != 0x06))
ct->mode = ((mds_trk_block.trk_mode & 0x07) != 0x02) + 1;
if ((mds_trk_block.trk_mode & 0x06) == 0x04)
ct->form = (mds_trk_block.trk_mode & 0x07) - 0x03;
if (ct->attr == AUDIO_TRACK)
success = 1;
if (((ct->sector_size == 2336) || (ct->sector_size == 2332)) && (ct->mode == 2) && (ct->form == 1))
ct->skip = 8;
ci = &(ct->idx[0]);
if (ct->point < 0xa0) {
ci->start = astart + 150;
ci->length = mds_trk_ex_block.pregap;
}
ci->type = (ci->length > 0) ? INDEX_ZERO : INDEX_NONE;
ci->file_start = 0;
ci->file_length = 0;
ci->file = NULL;
ci = &(ct->idx[1]);
if ((mds_trk_block.point >= 1) && (mds_trk_block.point <= 99)) {
ci->start = aend + 150;
ci->length = mds_trk_ex_block.trk_sectors;
ci->type = INDEX_NORMAL;
ci->file_start = mds_trk_block.start_offs / ct->sector_size;
ci->file_length = ci->length;
ci->file = tf;
} else {
ci->start = (mds_trk_block.pm * 60 * 75) + (mds_trk_block.ps * 75) + mds_trk_block.pf;
ci->type = INDEX_NONE;
ci->file_start = 0;
ci->file_length = 0;
ci->file = NULL;
}
ci = &(ct->idx[2]);
if (ct->point < 0xa0) {
ci->start = aend2 + 150;
ci->length = astart2 - aend2;
}
ci->type = (ci->length > 0) ? INDEX_ZERO : INDEX_NONE;
ci->file_start = 0;
ci->file_length = 0;
ci->file = NULL;
if (img->is_dvd) {
ci = &(ct->idx[1]);
uint32_t total = ci->start + ci->length;
ci = &(img->tracks[2].idx[1]);
ci->start = total;
}
}
for (int i = 2; i >= 0; i--) {
if (ct->point >= 0xa0)
ci->type = INDEX_SPECIAL;
if (ct->idx[i].file == NULL)
ct->idx[i].file = tf;
else
break;
}
}
tf = NULL;
fclose(fp);
if (success) {
#ifdef ENABLE_IMAGE_LOG
image_log(img->log, "Final tracks list:\n");
for (int i = 0; i < img->tracks_num; i++) {
ct = &(img->tracks[i]);
for (int j = 0; j < 3; j++) {
ci = &(ct->idx[j]);
image_log(img->log, " [TRACK ] %02X INDEX %02X: [%8s, %016" PRIX64 "]\n",
ct->point, j,
cit[ci->type + 2], ci->file_start * ct->sector_size);
image_log(img->log, " TOC data: %02X %02X %02X "
"%02X %02X %02X %02X %02X %02X %02X %02X\n",
ct->session, ct->attr, ct->tno, ct->point,
ct->extra[0], ct->extra[1], ct->extra[2], ct->extra[3],
(uint32_t) ((ci->start / 75) / 60),
(uint32_t) ((ci->start / 75) % 60),
(uint32_t) (ci->start % 75));
}
}
#endif
} else
#ifdef ENABLE_IMAGE_LOG
log_warning(img->log, " [MDS ] Unable to open MDS sheet \"%s\"\n", mdsfile);
#else
warning("Unable to open MDS sheet \"%s\"\n", mdsfile);
#endif
return success;
}
@@ -1713,8 +2281,8 @@ image_get_track_info(const void *local, const uint32_t track,
}
if (ct != NULL) {
const uint32_t pos = end ? ct->idx[1].start :
(ct->idx[1].start + ct->idx[1].length);
const uint32_t pos = end ? (ct->idx[1].start + ct->idx[1].length) :
ct->idx[1].start;
ti->number = ct->point;
ti->attr = ct->attr;
@@ -1784,6 +2352,7 @@ image_read_sector(const void *local, uint8_t *buffer,
const uint32_t sector)
{
const cd_image_t *img = (const cd_image_t *) local;
cdrom_t *dev = (cdrom_t *) img->dev;
int m = 0;
int s = 0;
int f = 0;
@@ -1792,6 +2361,7 @@ image_read_sector(const void *local, uint8_t *buffer,
int track;
int index;
uint8_t q[16] = { 0x00 };
uint8_t *buf = buffer;
if (sector == 0xffffffff)
lba = img->dev->seek_pos;
@@ -1851,6 +2421,26 @@ image_read_sector(const void *local, uint8_t *buffer,
/* Index is not in the file, no read to fail here. */
ret = 1;
if ((ret > 0) && (trk->attr & 0x04) && ((idx->type < INDEX_NORMAL) || !track_is_raw)) {
uint32_t crc;
if ((trk->mode == 2) && (trk->form == 1)) {
crc = cdrom_crc32(0xffffffff, &(buf[16]), 2056) ^ 0xffffffff;
memcpy(&(buf[2072]), &crc, 4);
} else {
crc = cdrom_crc32(0xffffffff, buf, 2064) ^ 0xffffffff;
memcpy(&(buf[2064]), &crc, 4);
}
int m2f1 = (trk->mode == 2) && (trk->form == 1);
/* Compute ECC P code. */
cdrom_compute_ecc_block(dev, &(buf[2076]), &(buf[12]), 86, 24, 2, 86, m2f1);
/* Compute ECC Q code. */
cdrom_compute_ecc_block(dev, &(buf[2248]), &(buf[12]), 52, 43, 86, 88, m2f1);
}
if ((ret > 0) && ((idx->type < INDEX_NORMAL) || (trk->subch_type != 0x08))) {
buffer -= offset;
@@ -1945,7 +2535,27 @@ static int
image_read_dvd_structure(const void *local, const uint8_t layer, const uint8_t format,
uint8_t *buffer, uint32_t *info)
{
return 0;
const cd_image_t *img = (const cd_image_t *) local;
int ret = 0;
if ((img->has_dstruct > 0) && ((layer + 1) > img->has_dstruct)) {
switch (format) {
case 0x00:
memcpy(buffer + 4, img->dstruct.layers[layer].f0, 2048);
ret = 2048 + 2;
break;
case 0x01:
memcpy(buffer + 4, img->dstruct.layers[layer].f1, 4);
ret = 4 + 2;
break;
case 0x04:
memcpy(buffer + 4, img->dstruct.layers[layer].f4, 2048);
ret = 2048 + 2;
break;
}
}
return ret;
}
static int
@@ -1977,6 +2587,9 @@ image_close(void *local)
log_close(img->log);
img->log = NULL;
if (img->bad_sectors != NULL)
free(img->bad_sectors);
free(img);
}
}
@@ -2005,34 +2618,53 @@ image_open(cdrom_t *dev, const char *path)
if (img != NULL) {
int ret;
const int is_cue = ((ext == 4) && !stricmp(path + strlen(path) - ext + 1, "CUE"));
const int is_cue = ((ext == 4) && !stricmp(path + strlen(path) - ext + 1, "CUE"));
const int is_mds = ((ext == 4) && !stricmp(path + strlen(path) - ext + 1, "MDS"));
char n[1024] = { 0 };
img->dev = dev;
sprintf(n, "CD-ROM %i Image", dev->id + 1);
img->log = log_open(n);
if (is_cue) {
img->dev = dev;
if (is_mds) {
ret = image_load_mds(img, path);
if (ret >= 2)
img->has_audio = 0;
else if (ret)
img->has_audio = 1;
} else if (is_cue) {
ret = image_load_cue(img, path);
if (ret >= 2)
img->has_audio = 0;
else if (ret)
img->has_audio = 1;
if (ret >= 1)
img->is_dvd = 2;
} else {
ret = image_load_iso(img, path);
if (!ret) {
image_close(img);
img = NULL;
} else
if (ret) {
img->has_audio = 0;
img->is_dvd = 2;
}
}
if (ret) {
char n[1024] = { 0 };
sprintf(n, "CD-ROM %i Image", dev->id + 1);
img->log = log_open(n);
if (ret > 0) {
if (img->is_dvd == 2) {
uint32_t lb = image_get_last_block(img); /* Should be safer than previous way of doing it? */
img->is_dvd = (lb >= 524287); /* Minimum 1 GB total capacity as threshold for DVD. */
}
dev->ops = &image_ops;
} else {
log_warning(img->log, "Unable to load CD-ROM image: %s\n", path);
image_close(img);
img = NULL;
}
}

View File

@@ -446,24 +446,36 @@ static int
viso_fill_time(uint8_t *data, time_t time, int format, int longform)
{
uint8_t *p = data;
struct tm *time_s = localtime(&time);
if (!time_s) {
/* localtime will return NULL if the time_t is negative (Windows)
or way too far into 64-bit space (Linux). Fall back to epoch. */
time_t epoch = 0;
time_s = localtime(&epoch);
if (UNLIKELY(!time_s))
fatal("VISO: localtime(0) = NULL\n");
struct tm time_s_buf;
struct tm *time_s = NULL;
time_t epoch = 0;
/* Force year clamping if the timestamp is known to be outside the supported ranges. */
#ifdef _WIN32
if (localtime_s(&time_s_buf, &time) == 0)
time_s = &time_s_buf;
#else
time_s = localtime_r(&time, &time_s_buf);
#endif
if (!time_s) {
/* localtime may return NULL if time is negative or out of range */
#ifdef _WIN32
if (localtime_s(&time_s_buf, &epoch) == 0)
time_s = &time_s_buf;
#else
time_s = localtime_r(&epoch, &time_s_buf);
#endif
if (!time_s)
fatal("VISO: localtime fallback to epoch failed\n");
/* Force year clamping for out-of-range times */
if (time < (longform ? -62135596800LL : -2208988800LL)) /* 0001-01-01 00:00:00 : 1900-01-01 00:00:00 */
time_s->tm_year = -1901;
else if (time > (longform ? 253402300799LL : 5869583999LL)) /* 9999-12-31 23:59:59 : 2155-12-31 23:59:59 */
time_s->tm_year = 8100;
}
/* Clamp year to the supported ranges, and assume the
OS returns valid numbers in the other struct fields. */
/* Clamp year within supported ranges */
if (time_s->tm_year < (longform ? -1900 : 0)) {
time_s->tm_year = longform ? -1900 : 0;
time_s->tm_mon = time_s->tm_hour = time_s->tm_min = time_s->tm_sec = 0;
@@ -476,18 +488,18 @@ viso_fill_time(uint8_t *data, time_t time, int format, int longform)
time_s->tm_min = time_s->tm_sec = 59;
}
/* Convert timestamp. */
/* Convert timestamp */
if (longform) {
p += sprintf((char *) p, "%04u%02u%02u%02u%02u%02u00",
1900 + time_s->tm_year, 1 + time_s->tm_mon, time_s->tm_mday,
p += sprintf((char *)p, "%04u%02u%02u%02u%02u%02u00",
1900 + (unsigned)time_s->tm_year, 1 + time_s->tm_mon, time_s->tm_mday,
time_s->tm_hour, time_s->tm_min, time_s->tm_sec);
} else {
*p++ = time_s->tm_year; /* year since 1900 */
*p++ = 1 + time_s->tm_mon; /* month */
*p++ = time_s->tm_mday; /* day */
*p++ = time_s->tm_hour; /* hour */
*p++ = time_s->tm_min; /* minute */
*p++ = time_s->tm_sec; /* second */
*p++ = (uint8_t)time_s->tm_year; /* year since 1900 */
*p++ = (uint8_t)(1 + time_s->tm_mon); /* month */
*p++ = (uint8_t)time_s->tm_mday; /* day */
*p++ = (uint8_t)time_s->tm_hour; /* hour */
*p++ = (uint8_t)time_s->tm_min; /* minute */
*p++ = (uint8_t)time_s->tm_sec; /* second */
}
if (format & VISO_FORMAT_ISO)
*p++ = tz_offset; /* timezone (ISO only) */
@@ -782,9 +794,8 @@ viso_close(void *priv)
if (viso->entry_map)
free(viso->entry_map);
if (tf->log != NULL) {
}
if (tf->log != NULL)
log_close(tf->log);
free(viso);
}
@@ -1035,8 +1046,15 @@ next_dir:
the timezone offset for descriptors and file times to use. */
tzset();
time_t now = time(NULL);
if (viso->format & VISO_FORMAT_ISO) /* timezones are ISO only */
tz_offset = (now - mktime(gmtime(&now))) / (3600 / 4);
struct tm now_tm;
if (viso->format & VISO_FORMAT_ISO) { /* timezones are ISO only */
#ifdef _WIN32
gmtime_s(&now_tm, &now); // Windows: output first param, input second
#else
gmtime_r(&now, &now_tm); // POSIX: input first param, output second
#endif
tz_offset = (now - mktime(&now_tm)) / (3600 / 4);
}
/* Get root directory basename for the volume ID. */
const char *basename = path_get_filename(viso->root_dir->path);
@@ -1607,10 +1625,12 @@ end:
return &viso->tf;
} else {
image_viso_log(viso->tf.log, "Initialization failed\n");
if (data)
free(data);
viso_close(&viso->tf);
if (viso != NULL) {
image_viso_log(viso->tf.log, "Initialization failed\n");
if (data)
free(data);
viso_close(&viso->tf);
}
return NULL;
}
}

View File

@@ -8,11 +8,11 @@
*
* Mitsumi CD-ROM emulation for the ISA bus.
*
*
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Jasmine Iwanek, <jriwanek@gmail.com>
*
* Copyright 2022 Miran Grca.
* Copyright 2022 Miran Grca.
* Copyright 2024-2025 Jasmine Iwanek.
*/
#include <inttypes.h>
#include <stdarg.h>
@@ -33,10 +33,6 @@
#include <86box/plat.h>
#include <86box/sound.h>
#define MCD_DEFAULT_IOPORT 0x310
#define MCD_DEFAULT_IRQ 5
#define MCD_DEFAULT_DMA 5
#define RAW_SECTOR_SIZE 2352
#define COOKED_SECTOR_SIZE 2048
@@ -116,6 +112,8 @@ typedef struct mcd_t {
int cur_toc_track;
int pos;
int newstat;
cdrom_t *cdrom_dev;
} mcd_t;
#define CD_BCD(x) (((x) % 10) | (((x) / 10) << 4))
@@ -140,17 +138,15 @@ mitsumi_cdrom_log(const char *fmt, ...)
#endif
static int
mitsumi_cdrom_is_ready(const cdrom_t *dev)
mitsumi_cdrom_is_ready(const mcd_t *dev)
{
return (dev->image_path[0] != 0x00);
return (dev->cdrom_dev->image_path[0] != 0x00);
}
static void
mitsumi_cdrom_reset(mcd_t *dev)
{
cdrom_t *cdrom = calloc(1, sizeof(cdrom_t));
dev->stat = mitsumi_cdrom_is_ready(cdrom) ? (STAT_READY | STAT_CHANGE) : 0;
dev->stat = mitsumi_cdrom_is_ready(dev) ? (STAT_READY | STAT_CHANGE) : 0;
dev->cmdrd_count = 0;
dev->cmdbuf_count = 0;
dev->buf_count = 0;
@@ -168,12 +164,11 @@ mitsumi_cdrom_reset(mcd_t *dev)
static int
mitsumi_cdrom_read_sector(mcd_t *dev, int first)
{
cdrom_t *cdrom = calloc(1, sizeof(cdrom_t));
uint8_t status;
int ret = 0;
if (dev->drvmode == DRV_MODE_CDDA) {
status = cdrom_mitsumi_audio_play(cdrom, dev->readmsf, dev->readcount);
status = cdrom_mitsumi_audio_play(dev->cdrom_dev, dev->readmsf, dev->readcount);
if (status == 1)
return status;
else
@@ -187,15 +182,15 @@ mitsumi_cdrom_read_sector(mcd_t *dev, int first)
dev->data = 0;
return 0;
}
cdrom_stop(cdrom);
ret = cdrom_readsector_raw(cdrom, dev->buf, cdrom->seek_pos, 0, 2, 0x10, (int *) &dev->readcount, 0);
cdrom_stop(dev->cdrom_dev);
ret = cdrom_readsector_raw(dev->cdrom_dev, dev->buf, dev->cdrom_dev->seek_pos, 0, 2, 0x10, (int *) &dev->readcount, 0);
if (ret <= 0)
return 0;
if (dev->mode & 0x40) {
dev->buf[12] = CD_BCD((dev->readmsf >> 16) & 0xff);
dev->buf[13] = CD_BCD((dev->readmsf >> 8) & 0xff);
}
dev->readmsf = cdrom_lba_to_msf_accurate(cdrom->seek_pos + 1);
dev->readmsf = cdrom_lba_to_msf_accurate(dev->cdrom_dev->seek_pos + 1);
dev->buf_count = dev->dmalen + 1;
dev->buf_idx = 0;
dev->data = 1;
@@ -258,7 +253,6 @@ static void
mitsumi_cdrom_out(uint16_t port, uint8_t val, void *priv)
{
mcd_t *dev = (mcd_t *) priv;
cdrom_t *cdrom = calloc(1, sizeof(cdrom_t));
pclog("Mitsumi CD-ROM OUT=%03x, val=%02x\n", port, val);
switch (port & 1) {
@@ -340,19 +334,19 @@ mitsumi_cdrom_out(uint16_t port, uint8_t val, void *priv)
break;
}
if (!dev->cmdrd_count)
dev->stat = mitsumi_cdrom_is_ready(cdrom) ? (STAT_READY | (dev->change ? STAT_CHANGE : 0)) : 0;
dev->stat = mitsumi_cdrom_is_ready(dev) ? (STAT_READY | (dev->change ? STAT_CHANGE : 0)) : 0;
return;
}
dev->cmd = val;
dev->cmdbuf_idx = 0;
dev->cmdrd_count = 0;
dev->cmdbuf_count = 1;
dev->cmdbuf[0] = mitsumi_cdrom_is_ready(cdrom) ? (STAT_READY | (dev->change ? STAT_CHANGE : 0)) : 0;
dev->cmdbuf[0] = mitsumi_cdrom_is_ready(dev) ? (STAT_READY | (dev->change ? STAT_CHANGE : 0)) : 0;
dev->data = 0;
switch (val) {
case CMD_GET_INFO:
if (mitsumi_cdrom_is_ready(cdrom)) {
cdrom_get_track_buffer(cdrom, &(dev->cmdbuf[1]));
if (mitsumi_cdrom_is_ready(dev)) {
cdrom_get_track_buffer(dev->cdrom_dev, &(dev->cmdbuf[1]));
dev->cmdbuf_count = 10;
dev->readcount = 0;
} else {
@@ -361,7 +355,7 @@ mitsumi_cdrom_out(uint16_t port, uint8_t val, void *priv)
}
break;
case CMD_GET_Q:
if (mitsumi_cdrom_is_ready(cdrom)) {
if (mitsumi_cdrom_is_ready(dev)) {
cdrom_get_q(cdrom, &(dev->cmdbuf[1]), &dev->cur_toc_track, dev->mode & MODE_GET_TOC);
dev->cmdbuf_count = 11;
dev->readcount = 0;
@@ -378,7 +372,7 @@ mitsumi_cdrom_out(uint16_t port, uint8_t val, void *priv)
break;
case CMD_STOPCDDA:
case CMD_STOP:
cdrom_stop(cdrom);
cdrom_stop(dev->cdrom_dev);
dev->drvmode = DRV_MODE_STOP;
dev->cur_toc_track = 0;
break;
@@ -387,7 +381,7 @@ mitsumi_cdrom_out(uint16_t port, uint8_t val, void *priv)
break;
case CMD_READ1X:
case CMD_READ2X:
if (mitsumi_cdrom_is_ready(cdrom)) {
if (mitsumi_cdrom_is_ready(dev)) {
dev->readcount = 0;
dev->drvmode = (val == CMD_READ1X) ? DRV_MODE_CDDA : DRV_MODE_READ;
dev->cmdrd_count = 6;
@@ -403,7 +397,7 @@ mitsumi_cdrom_out(uint16_t port, uint8_t val, void *priv)
dev->cmdbuf_count = 3;
break;
case CMD_EJECT:
cdrom_stop(cdrom);
cdrom_stop(dev->cdrom_dev);
cdrom_eject(0);
dev->readcount = 0;
break;
@@ -434,10 +428,23 @@ mitsumi_cdrom_init(UNUSED(const device_t *info))
{
mcd_t *dev = calloc(1, sizeof(mcd_t));
dev->irq = MCD_DEFAULT_IRQ;
dev->dma = MCD_DEFAULT_DMA;
for (uint8_t i = 0; i < CDROM_NUM; i++) {
if (cdrom[i].bus_type == CDROM_BUS_MITSUMI) {
dev->cdrom_dev = &cdrom[i];
break;
}
}
io_sethandler(MCD_DEFAULT_IOPORT, 3,
if (!dev->cdrom_dev)
return NULL;
dev->cdrom_dev->priv = &dev;
uint16_t base = device_get_config_hex16("base");
dev->irq = device_get_config_int("irq");
dev->dma = device_get_config_int("dma");
io_sethandler(base, 3,
mitsumi_cdrom_in, NULL, NULL, mitsumi_cdrom_out, NULL, NULL, dev);
mitsumi_cdrom_reset(dev);
@@ -456,6 +463,64 @@ mitsumi_cdrom_close(void *priv)
}
}
static const device_config_t mitsumi_config[] = {
// clang-format off
{
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 0x310,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "300H", .value = 0x300 },
{ .description = "310H", .value = 0x310 },
{ .description = "320H", .value = 0x320 },
{ .description = "340H", .value = 0x340 },
{ .description = "350H", .value = 0x350 },
{ NULL }
},
.bios = { { 0 } }
},
{
.name = "irq",
.description = "IRQ",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 5,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "IRQ 3", .value = 3 },
{ .description = "IRQ 5", .value = 5 },
{ .description = "IRQ 9", .value = 9 },
{ .description = "IRQ 10", .value = 10 },
{ .description = "IRQ 11", .value = 11 },
{ .description = "" }
},
.bios = { { 0 } }
},
{
.name = "dma",
.description = "DMA",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 5,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "DMA 5", .value = 5 },
{ .description = "DMA 6", .value = 6 },
{ .description = "DMA 7", .value = 7 },
{ .description = "" }
},
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format off
};
const device_t mitsumi_cdrom_device = {
.name = "Mitsumi CD-ROM interface",
.internal_name = "mcd",
@@ -467,5 +532,5 @@ const device_t mitsumi_cdrom_device = {
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
.config = mitsumi_config
};

1078
src/cdrom/cdrom_mke.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -17,7 +17,9 @@
add_library(chipset OBJECT
82c100.c
acc2036.c
acc2168.c
cs8220.c
cs8230.c
ali1429.c
ali1435.c
@@ -39,12 +41,15 @@ add_library(chipset OBJECT
intel_i450kx.c
intel_sio.c
intel_piix.c
isa486c.c
../ioapic.c
neat.c
olivetti_eva.c
opti283.c
opti291.c
opti391.c
opti495.c
opti498.c
opti499.c
opti602.c
opti822.c
@@ -71,6 +76,7 @@ add_library(chipset OBJECT
sis_5572_usb.c
sis_5595_pmu.c
sis_55xx.c
sl82c461.c
via_vt82c49x.c
via_vt82c505.c
gc100.c
@@ -83,7 +89,3 @@ add_library(chipset OBJECT
vl82c480.c
wd76c10.c
)
if(OLIVETTI)
target_sources(chipset PRIVATE olivetti_eva.c)
endif()

346
src/chipset/acc2036.c Normal file
View File

@@ -0,0 +1,346 @@
/*
* 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.
*
* Implementation of the ACC 2036 chipset.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2025 Miran Grca.
*/
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include "cpu.h"
#include <86box/timer.h>
#include <86box/io.h>
#include <86box/device.h>
#include <86box/machine.h>
#include <86box/mem.h>
#include <86box/port_92.h>
#include <86box/plat_fallthrough.h>
#include <86box/plat_unused.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/chipset.h>
typedef struct {
uint32_t virt;
uint32_t phys;
mem_mapping_t mapping;
} ram_page_t;
typedef struct {
uint8_t reg;
uint8_t regs[32];
ram_page_t ram_mid_pages[24];
ram_page_t ems_pages[4];
} acc2036_t;
static uint8_t
acc2036_mem_read(uint32_t addr, void *priv)
{
ram_page_t *dev = (ram_page_t *) priv;
uint8_t ret = 0xff;
addr = (addr - dev->virt) + dev->phys;
if (addr < (mem_size << 10))
ret = ram[addr];
return ret;
}
static uint16_t
acc2036_mem_readw(uint32_t addr, void *priv)
{
ram_page_t *dev = (ram_page_t *) priv;
uint16_t ret = 0xffff;
addr = (addr - dev->virt) + dev->phys;
if (addr < (mem_size << 10))
ret = *(uint16_t *) &(ram[addr]);
return ret;
}
static void
acc2036_mem_write(uint32_t addr, uint8_t val, void *priv)
{
ram_page_t *dev = (ram_page_t *) priv;
addr = (addr - dev->virt) + dev->phys;
if (addr < (mem_size << 10))
ram[addr] = val;
}
static void
acc2036_mem_writew(uint32_t addr, uint16_t val, void *priv)
{
ram_page_t *dev = (ram_page_t *) priv;
addr = (addr - dev->virt) + dev->phys;
if (addr < (mem_size << 10))
*(uint16_t *) &(ram[addr]) = val;
}
static void
acc2036_recalc(acc2036_t *dev)
{
uint32_t ems_bases[4] = { 0x000c0000, 0x000c8000, 0x000d0000, 0x000e0000 };
int start_i = (ems_bases[dev->regs[0x0c] & 0x03] - 0x000a0000) >> 14;
int end_i = start_i + 3;
for (int i = 0; i < 24; i++) {
ram_page_t *rp = &dev->ram_mid_pages[i];
mem_mapping_disable(&rp->mapping);
}
for (int i = 0; i < 4; i++) {
ram_page_t *ep = &dev->ems_pages[i];
mem_mapping_disable(&ep->mapping);
}
for (int i = 0; i < 24; i++) {
ram_page_t *rp = &dev->ram_mid_pages[i];
if ((dev->regs[0x03] & 0x08) && (i >= start_i) && (i <= end_i)) {
/* EMS */
ram_page_t *ep = &dev->ems_pages[i - start_i];
mem_mapping_disable(&rp->mapping);
mem_mapping_set_addr(&ep->mapping, ep->virt, 0x000040000);
mem_mapping_set_exec(&ep->mapping, ram + ep->phys);
mem_set_mem_state_both(ep->virt, 0x00004000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
} else {
int master_write;
int master_read;
int bit;
int ew_flag;
int er_flag;
int flags;
uint8_t val;
mem_mapping_set_addr(&rp->mapping, rp->virt, 0x000040000);
mem_mapping_set_exec(&rp->mapping, ram + rp->phys);
if ((i >= 8) && (i <= 15)) {
/* 0C0000-0DFFFF */
master_write = dev->regs[0x02] & 0x08;
master_read = dev->regs[0x02] & 0x04;
bit = ((i - 8) >> 1);
val = dev->regs[0x0d] & (1 << bit);
if (i >= 12) {
ew_flag = (dev->regs[0x07] & 0x80) ? MEM_WRITE_EXTANY : MEM_WRITE_EXTERNAL;
er_flag = (dev->regs[0x07] & 0x80) ? MEM_READ_EXTANY : MEM_READ_EXTERNAL;
} else {
ew_flag = (dev->regs[0x07] & 0x40) ? MEM_WRITE_EXTANY : MEM_WRITE_EXTERNAL;
er_flag = (dev->regs[0x07] & 0x40) ? MEM_READ_EXTANY : MEM_READ_EXTERNAL;
}
flags = (val && master_write) ? MEM_WRITE_INTERNAL : ew_flag;
flags |= (val && master_read) ? MEM_READ_INTERNAL : er_flag;
mem_set_mem_state_both(rp->virt, 0x00004000, flags);
} else if (i > 15) {
/* 0E0000-0FFFFF */
master_write = dev->regs[0x02] & 0x02;
master_read = dev->regs[0x02] & 0x01;
bit = ((i - 8) >> 2);
val = dev->regs[0x0c] & (1 << bit);
if (i >= 20) {
ew_flag = MEM_WRITE_EXTANY;
er_flag = MEM_READ_EXTANY;
} else {
ew_flag = (dev->regs[0x0c] & 0x10) ? MEM_WRITE_EXTANY : MEM_WRITE_EXTERNAL;
er_flag = (dev->regs[0x0c] & 0x10) ? MEM_READ_EXTANY : MEM_READ_EXTERNAL;
}
flags = (val && master_write) ? MEM_WRITE_INTERNAL : ew_flag;
flags |= (val && master_read) ? MEM_READ_INTERNAL : er_flag;
mem_set_mem_state_both(rp->virt, 0x00004000, flags);
}
}
}
if (dev->regs[0x00] & 0x40)
mem_set_mem_state_both(0x00fe0000, 0x00010000, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
else
mem_set_mem_state_both(0x00fe0000, 0x00010000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
for (int i = 0x01; i <= 0x06; i++) {
uint32_t base = 0x00fe0000 - (i * 0x00010000);
if (dev->regs[i] & 0x40)
mem_set_mem_state_both(base, 0x00008000, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
else
mem_set_mem_state_both(base, 0x00008000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
if (dev->regs[i] & 0x80)
mem_set_mem_state_both(base + 0x00008000, 0x00008000, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
else
mem_set_mem_state_both(base + 0x00008000, 0x00008000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
}
mem_remap_top(0);
if (dev->regs[0x03] & 0x10) {
if (dev->regs[0x02] & 0x0c)
mem_remap_top(128);
else if (dev->regs[0x02] & 0x03)
mem_remap_top(256);
else
mem_remap_top(384);
}
flushmmucache_nopc();
}
static uint8_t
acc2036_in(uint16_t port, void *priv) {
acc2036_t *dev = (acc2036_t *) priv;
uint8_t reg = dev->reg - 0x20;
uint8_t ret = 0xff;
if (port & 0x0001) switch (dev->reg) {
default:
break;
case 0x20 ... 0x2e:
case 0x31 ... 0x3f:
ret = dev->regs[reg];
break;
} else
ret = dev->reg;
return ret;
}
static void
acc2036_out(uint16_t port, uint8_t val, void *priv) {
acc2036_t *dev = (acc2036_t *) priv;
uint8_t reg = dev->reg - 0x20;
if (port & 0x0001) switch (dev->reg) {
default:
break;
case 0x20 ... 0x23:
dev->regs[reg] = val;
acc2036_recalc(dev);
break;
case 0x24 ... 0x2b:
dev->regs[reg] = val;
dev->ems_pages[(reg - 0x04) >> 1].phys = ((dev->regs[reg & 0xfe] & 0x1f) << 19) |
((dev->regs[reg | 0x01] & 0x1f) << 14);
acc2036_recalc(dev);
break;
case 0x2c: case 0x2d:
dev->regs[reg] = val;
acc2036_recalc(dev);
break;
case 0x2e:
dev->regs[reg] = val | 0x10;
break;
case 0x31:
dev->regs[reg] = val;
mem_a20_alt = (val & 0x01);
mem_a20_recalc();
flushmmucache();
if (val & 0x02) {
softresetx86(); /* Pulse reset! */
cpu_set_edx();
flushmmucache();
}
break;
case 0x32 ... 0x3f:
dev->regs[reg] = val;
break;
} else
dev->reg = val;
}
static void
acc2036_close(void *priv)
{
acc2036_t *dev = (acc2036_t *) priv;
free(dev);
}
static void *
acc2036_init(UNUSED(const device_t *info))
{
acc2036_t *dev = (acc2036_t *) calloc(1, sizeof(acc2036_t));
for (int i = 0; i < 24; i++) {
ram_page_t *rp = &dev->ram_mid_pages[i];
rp->virt = 0x000a0000 + (i << 14);
rp->phys = 0x000a0000 + (i << 14);
mem_mapping_add(&rp->mapping, rp->virt, 0x00004000,
acc2036_mem_read, acc2036_mem_readw, NULL,
acc2036_mem_write, acc2036_mem_writew, NULL,
ram + rp->phys, MEM_MAPPING_INTERNAL, rp);
}
for (int i = 0; i < 4; i++) {
ram_page_t *ep = &dev->ems_pages[i];
ep->virt = 0x000d0000 + (i << 14);
ep->phys = 0x00000000 + (i << 14);
mem_mapping_add(&ep->mapping, ep->virt, 0x00004000,
acc2036_mem_read, acc2036_mem_readw, NULL,
acc2036_mem_write, acc2036_mem_writew, NULL,
ram + ep->phys, MEM_MAPPING_INTERNAL, ep);
mem_mapping_disable(&ep->mapping);
}
mem_mapping_disable(&ram_mid_mapping);
dev->regs[0x00] = 0x02;
dev->regs[0x0e] = 0x10;
dev->regs[0x11] = 0x01;
dev->regs[0x13] = 0x40;
dev->regs[0x15] = 0x40;
dev->regs[0x17] = 0x40;
dev->regs[0x19] = 0x40;
dev->regs[0x1b] = 0x40;
dev->regs[0x1c] = 0x22;
dev->regs[0x1d] = 0xc4;
dev->regs[0x1f] = 0x30;
acc2036_recalc(dev);
mem_a20_alt = 0x01;
mem_a20_recalc();
flushmmucache();
io_sethandler(0x00f2, 0x0002,
acc2036_in, NULL, NULL, acc2036_out, NULL, NULL, dev);
device_add(&port_92_device);
return dev;
}
const device_t acc2036_device = {
.name = "ACC 2036",
.internal_name = "acc2036",
.flags = 0,
.local = 0,
.init = acc2036_init,
.close = acc2036_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -61,91 +61,238 @@ ali1409_log(const char *fmt, ...)
#endif
typedef struct ali_1409_t {
uint8_t is_g;
uint8_t index;
uint8_t cfg_locked;
uint8_t reg_57h;
uint8_t regs[256];
uint8_t shadow[4];
uint8_t last_reg;
} ali1409_t;
/*
This here is because from the two BIOS'es I used to reverse engineer this,
it is unclear which of the two interpretations of the shadow RAM register
operation is correct.
The 16 kB interpretation appears to work fine right now but it may be wrong,
so I left the 32 kB interpretation in as well.
*/
#ifdef INTERPRETATION_32KB
#define SHADOW_SIZE 0x00008000
#else
#define SHADOW_SIZE 0x00004000
#endif
static void
ali1409_shadow_recalc(ali1409_t *dev)
{
uint32_t base = 0x000c0000;
for (uint8_t i = 0; i < 4; i++) {
uint8_t reg = 0x08 + i;
#ifdef INTERPRETATION_32KB
for (uint8_t j = 0; j < 4; j += 2) {
uint8_t mask = (0x03 << j);
#else
for (uint8_t j = 0; j < 4; j++) {
uint8_t mask = (0x01 << j);
#endif
uint8_t r_on = dev->regs[reg] & 0x10;
uint8_t w_on = dev->regs[reg] & 0x20;
uint8_t val = dev->regs[reg] & mask;
uint8_t xor = (dev->shadow[i] ^ dev->regs[reg]) & (mask | 0x30);
int read = r_on ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
int write = w_on ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
if (xor) {
#ifdef INTERPRETATION_32KB
switch (val >> j) {
case 0x00:
mem_set_mem_state_both(base, SHADOW_SIZE, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
break;
case 0x01:
mem_set_mem_state_both(base, SHADOW_SIZE, MEM_READ_EXTANY | write);
break;
case 0x02:
mem_set_mem_state_both(base, SHADOW_SIZE, read | write);
break;
case 0x03:
mem_set_mem_state_both(base, SHADOW_SIZE, read | MEM_WRITE_EXTANY);
break;
}
#else
switch (val >> j) {
case 0x00:
mem_set_mem_state_both(base, SHADOW_SIZE, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
break;
case 0x01:
mem_set_mem_state_both(base, SHADOW_SIZE, read | write);
break;
}
#endif
}
base += SHADOW_SIZE;
}
dev->shadow[i] = dev->regs[reg];
}
flushmmucache_nopc();
}
static void
ali1409_write(uint16_t addr, uint8_t val, void *priv)
{
ali1409_t *dev = (ali1409_t *) priv;
ali1409_log ("INPUT:addr %02x ,Value %02x \n" , addr , val);
ali1409_log("[%04X:%08X] [W] %04X = %02X\n", CS, cpu_state.pc, addr, val);
if (addr & 1) {
if (dev->cfg_locked) {
if (dev->last_reg == 0x14 && val == 0x09)
dev->cfg_locked = 0;
if (addr & 0x0001) {
if (dev->cfg_locked) {
if ((dev->last_reg == 0x14) && (val == 0x09))
dev->cfg_locked = 0;
dev->last_reg = val;
return;
}
dev->last_reg = val;
return;
}
if (dev->index == 0xff && val == 0xff)
dev->cfg_locked = 1;
else {
ali1409_log("Write reg %02x %02x %08x\n", dev->index, val, cs);
dev->regs[dev->index] = val;
/* It appears writing anything at all to register 0xFF locks it again. */
if (dev->index == 0xff)
dev->cfg_locked = 1;
else if (dev->index < 0x44) {
ali1409_log("[%04X:%08X] [W] Register %02X = %02X\n", CS, cpu_state.pc, dev->index, val);
switch (dev->index) {
case 0xa:
switch ((val >> 4) & 3) {
case 0:
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
break;
case 1:
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL);
break;
case 2:
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL);
break;
case 3:
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
break;
}
if (dev->index < 0x10) {
dev->regs[dev->index] = val;
/*
There are still a lot of unknown here, but unfortunately, this is
as far as I have been able to come with two BIOS'es that are
available (the Acer 100T and an AMI Color dated 07/07/91).
*/
switch (dev->index) {
case 0x02:
/*
- Bit 7: The RAS address hold time:
- 0: 1/2 T;
- 1: 1 T.
- Bits 6-4: The RAS precharge time:
- 0, 0, 0: 1.5 T;
- 0, 0, 1: 2 T;
- 0, 1, 0: 2.5 T;
- 0, 1, 1: 3 T;
- 1, 0, 0: 3.5 T;
- 1, 0, 1: 4 T;
- 1, 1, 0: Reserved;
- 1, 1, 1: Reserved.
- Bit 3: Early miss cycle:
- 0: Disabled;
- 1: Enabled.
*/
break;
case 0x03:
/*
- Bit 6: CAS pulse for read cycle:
- 0: 1 T;
- 1: 1.5 T or 2 T.
I can not get the 2.5 T or 3 T setting to apply so
I have no idea what bit governs that.
- Bits 5, 4: CAS pulse for write cycle:
- 0, 0: 0.5 T or 1 T;
- 0, 1: 1.5 T or 2 T;
- 1, 0: 2.5 T or 3 T;
- 1, 1: Reserved.
- Bit 3: CAS active for read cycle:
- 0: Disabled;
- 1: Enabled.
- Bit 2: CAS active for write cycle:
- 0: Disabled;
- 1: Enabled.
*/
break;
case 0x06:
/*
- Bits 6-4: Clock divider:
- 0, 0, 0: / 2;
- 0, 0, 1: / 4;
- 0, 1, 0: / 8;
- 0, 1, 1: Reserved;
- 1, 0, 0: / 3;
- 1, 0, 1: / 6;
- 1, 1, 0: / 5;
- 1, 1, 1: / 10.
*/
switch ((val >> 4) & 7) {
default:
case 3: /* Reserved */
cpu_set_isa_speed(7159091);
break;
case 0xb:
switch ((val >> 4) & 3) {
case 0:
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
break;
case 1:
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTANY);
break;
case 2:
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTANY| MEM_WRITE_INTERNAL);
break;
case 3:
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
break;
}
case 0:
cpu_set_isa_speed(cpu_busspeed / 2);
break;
case 1:
cpu_set_isa_speed(cpu_busspeed / 4);
break;
case 2:
cpu_set_isa_speed(cpu_busspeed / 8);
break;
case 4:
cpu_set_isa_speed(cpu_busspeed / 3);
break;
case 5:
cpu_set_isa_speed(cpu_busspeed / 6);
break;
case 6:
cpu_set_isa_speed(cpu_busspeed / 5);
break;
case 7:
cpu_set_isa_speed(cpu_busspeed / 10);
break;
}
break;
case 0x08 ... 0x0b:
ali1409_shadow_recalc(dev);
break;
case 0x0c:
/*
This appears to be turbo in bit 4 (1 = on, 0 = off),
and bus speed in the rest of the bits.
*/
break;
case 0x0d:
cpu_cache_ext_enabled = !!(val & 0x08);
cpu_update_waitstates();
break;
}
} else
dev->index = val;
}
}
} else
dev->index = val;
}
static uint8_t
ali1409_read(uint16_t addr, void *priv)
{
ali1409_log ("reading at %02X\n",addr);
const ali1409_t *dev = (ali1409_t *) priv;
uint8_t ret = 0xff;
if (dev->cfg_locked)
ret = 0xff;
if (addr & 1) {
if ((dev->index >= 0xc0 || dev->index == 0x20) && cpu_iscyrix)
ret = 0xff;
else if (addr & 0x0001) {
if (dev->index < 0x44)
ret = dev->regs[dev->index];
} else
ret = dev->index;
} else
ret = dev->index;
ali1409_log("[%04X:%08X] [R] %04X = %02X\n", CS, cpu_state.pc, addr, ret);
return ret;
}
@@ -166,17 +313,16 @@ ali1409_init(UNUSED(const device_t *info))
dev->cfg_locked = 1;
/* M1409 Ports:
22h Index Port
23h Data Port
*/
ali1409_log ("Bus speed: %i", cpu_busspeed);
ali1409_log("Bus speed: %i\n", cpu_busspeed);
io_sethandler(0x0022, 0x0002, ali1409_read, NULL, NULL, ali1409_write, NULL, NULL, dev);
io_sethandler(0x037f, 0x0001, ali1409_read, NULL, NULL, ali1409_write, NULL, NULL, dev);
io_sethandler(0x03f3, 0x0001, ali1409_read, NULL, NULL, ali1409_write, NULL, NULL, dev);
dev->regs[0x0f] = 0x08;
cpu_set_isa_speed(7159091);
cpu_cache_ext_enabled = 0;
cpu_update_waitstates();
return dev;
}

289
src/chipset/cs8220.c Normal file
View File

@@ -0,0 +1,289 @@
/*
* 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.
*
* Emulation of C&T CS8220 ("PC/AT") chipset.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2025 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include "cpu.h"
#include <86box/timer.h>
#include <86box/io.h>
#include <86box/device.h>
#include <86box/machine.h>
#include <86box/mem.h>
#include <86box/plat_fallthrough.h>
#include <86box/plat_unused.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/chipset.h>
typedef struct {
uint32_t virt;
uint32_t phys;
uint32_t size;
mem_mapping_t mapping;
} ram_bank_t;
typedef struct {
uint8_t regs[3];
ram_bank_t ram_banks[3];
} cs8220_t;
static uint8_t
cs8220_mem_read(uint32_t addr, void *priv)
{
ram_bank_t *dev = (ram_bank_t *) priv;
uint8_t ret = 0xff;
addr = (addr - dev->virt) + dev->phys;
if (addr < (mem_size << 10))
ret = ram[addr];
return ret;
}
static uint16_t
cs8220_mem_readw(uint32_t addr, void *priv)
{
ram_bank_t *dev = (ram_bank_t *) priv;
uint16_t ret = 0xffff;
addr = (addr - dev->virt) + dev->phys;
if (addr < (mem_size << 10))
ret = *(uint16_t *) &(ram[addr]);
return ret;
}
static void
cs8220_mem_write(uint32_t addr, uint8_t val, void *priv)
{
ram_bank_t *dev = (ram_bank_t *) priv;
addr = (addr - dev->virt) + dev->phys;
if (addr < (mem_size << 10))
ram[addr] = val;
}
static void
cs8220_mem_writew(uint32_t addr, uint16_t val, void *priv)
{
ram_bank_t *dev = (ram_bank_t *) priv;
addr = (addr - dev->virt) + dev->phys;
if (addr < (mem_size << 10))
*(uint16_t *) &(ram[addr]) = val;
}
static uint8_t
cs8220_in(uint16_t port, void *priv) {
cs8220_t *dev = (cs8220_t *) priv;
uint8_t ret = 0xff;
switch (port) {
case 0x00a4 ... 0x00a5:
ret = dev->regs[port & 0x0001];
break;
case 0x00ab:
ret = dev->regs[2];
break;
}
return ret;
}
static void
cs8220_out(uint16_t port, uint8_t val, void *priv) {
cs8220_t *dev = (cs8220_t *) priv;
switch (port) {
case 0x00a4:
dev->regs[0] = val;
mem_a20_alt = val & 0x40;
mem_a20_recalc();
break;
case 0x00a5:
dev->regs[1] = val;
if (val & 0x01) {
mem_mapping_set_addr(&dev->ram_banks[0].mapping, 0, 0x000040000);
mem_mapping_disable(&dev->ram_banks[1].mapping);
mem_mapping_disable(&dev->ram_banks[2].mapping);
} else {
mem_mapping_set_addr(&dev->ram_banks[0].mapping, 0, dev->ram_banks[0].size);
mem_mapping_enable(&dev->ram_banks[1].mapping);
mem_mapping_enable(&dev->ram_banks[2].mapping);
}
break;
case 0x00ab:
dev->regs[2] = val;
break;
}
}
static void
cs8220_close(void *priv)
{
cs8220_t *dev = (cs8220_t *) priv;
free(dev);
}
static void *
cs8220_init(UNUSED(const device_t *info))
{
cs8220_t *dev = (cs8220_t *) calloc(1, sizeof(cs8220_t));
mem_mapping_disable(&ram_low_mapping);
mem_mapping_disable(&ram_mid_mapping);
mem_mapping_disable(&ram_high_mapping);
/*
Dell System 200: 640 kB soldered on-board, any other RAM is expansion.
*/
if (!strcmp(machine_get_internal_name(), "dells200")) switch (mem_size) {
default:
dev->ram_banks[2].virt = 0x00100000;
dev->ram_banks[2].phys = 0x000a0000;
dev->ram_banks[2].size = (mem_size << 10) - 0x000a0000;
fallthrough;
case 640:
dev->ram_banks[0].virt = 0x00000000;
dev->ram_banks[0].phys = 0x00000000;
dev->ram_banks[0].size = 0x00080000;
dev->ram_banks[1].virt = 0x00080000;
dev->ram_banks[1].phys = 0x00080000;
dev->ram_banks[1].size = 0x00020000;
break;
/*
We are limited to steps of equal size, so we have to simulate some
memory expansions to work around the chipset's limits.
*/
} else switch (mem_size) {
case 256:
dev->ram_banks[0].virt = 0x00000000;
dev->ram_banks[0].phys = 0x00000000;
dev->ram_banks[0].size = 0x00020000;
dev->ram_banks[1].virt = 0x00020000;
dev->ram_banks[1].phys = 0x00020000;
dev->ram_banks[1].size = 0x00020000;
break;
case 384:
dev->ram_banks[0].virt = 0x00000000;
dev->ram_banks[0].phys = 0x00000000;
dev->ram_banks[0].size = 0x00020000;
/* Pretend there's a 128k expansion. */
dev->ram_banks[2].virt = 0x00020000;
dev->ram_banks[2].phys = 0x00020000;
dev->ram_banks[2].size = 0x00040000;
break;
case 512:
dev->ram_banks[0].virt = 0x00000000;
dev->ram_banks[0].phys = 0x00000000;
dev->ram_banks[0].size = 0x00080000;
break;
default:
dev->ram_banks[2].virt = 0x00100000;
dev->ram_banks[2].phys = 0x000a0000;
dev->ram_banks[2].size = (mem_size << 10) - 0x000a0000;
fallthrough;
case 640:
dev->ram_banks[0].virt = 0x00000000;
dev->ram_banks[0].phys = 0x00000000;
dev->ram_banks[0].size = 0x00080000;
dev->ram_banks[1].virt = 0x00080000;
dev->ram_banks[1].phys = 0x00080000;
dev->ram_banks[1].size = 0x00020000;
break;
case 768:
dev->ram_banks[0].virt = 0x00000000;
dev->ram_banks[0].phys = 0x00000000;
dev->ram_banks[0].size = 0x00080000;
dev->ram_banks[1].virt = 0x00080000;
dev->ram_banks[1].phys = 0x00080000;
dev->ram_banks[1].size = 0x00020000;
/* Pretend there's a 128k expansion. */
dev->ram_banks[2].virt = 0x00100000;
dev->ram_banks[2].phys = 0x00080000;
dev->ram_banks[2].size = 0x00020000;
break;
case 896:
dev->ram_banks[0].virt = 0x00000000;
dev->ram_banks[0].phys = 0x00000000;
dev->ram_banks[0].size = 0x00080000;
dev->ram_banks[1].virt = 0x00080000;
dev->ram_banks[1].phys = 0x00080000;
dev->ram_banks[1].size = 0x00020000;
/* Pretend there's a 256k expansion. */
dev->ram_banks[2].virt = 0x00100000;
dev->ram_banks[2].phys = 0x00080000;
dev->ram_banks[2].size = 0x00040000;
break;
case 1024:
dev->ram_banks[0].virt = 0x00000000;
dev->ram_banks[0].phys = 0x00000000;
dev->ram_banks[0].size = 0x00080000;
dev->ram_banks[1].virt = 0x00100000;
dev->ram_banks[1].phys = 0x00080000;
dev->ram_banks[1].size = 0x00080000;
break;
}
if (dev->ram_banks[0].size > 0x00000000)
mem_mapping_add(&dev->ram_banks[0].mapping, dev->ram_banks[0].virt, dev->ram_banks[0].size,
cs8220_mem_read, cs8220_mem_readw, NULL,
cs8220_mem_write, cs8220_mem_writew, NULL,
ram + dev->ram_banks[0].phys, MEM_MAPPING_INTERNAL, &(dev->ram_banks[0]));
if (dev->ram_banks[1].size > 0x00000000)
mem_mapping_add(&dev->ram_banks[1].mapping, dev->ram_banks[1].virt, dev->ram_banks[1].size,
cs8220_mem_read, cs8220_mem_readw, NULL,
cs8220_mem_write, cs8220_mem_writew, NULL,
ram + dev->ram_banks[1].phys, MEM_MAPPING_INTERNAL, &(dev->ram_banks[1]));
if (dev->ram_banks[2].size > 0x00000000)
mem_mapping_add(&dev->ram_banks[2].mapping, dev->ram_banks[2].virt, dev->ram_banks[2].size,
cs8220_mem_read, cs8220_mem_readw, NULL,
cs8220_mem_write, cs8220_mem_writew, NULL,
ram + dev->ram_banks[2].phys, MEM_MAPPING_INTERNAL, &(dev->ram_banks[2]));
io_sethandler(0x00a4, 0x0002,
cs8220_in, NULL, NULL, cs8220_out, NULL, NULL, dev);
io_sethandler(0x00ab, 0x0001,
cs8220_in, NULL, NULL, cs8220_out, NULL, NULL, dev);
return dev;
}
const device_t cs8220_device = {
.name = "C&T CS8220 (PC/AT)",
.internal_name = "cs8220",
.flags = 0,
.local = 0,
.init = cs8220_init,
.close = cs8220_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -1013,7 +1013,8 @@ i4x0_write(int func, int addr, uint8_t val, void *priv)
case INTEL_430TX:
if (!dev->smram_locked) {
i4x0_smram_handler_phase0(dev);
regs[0x71] = (regs[0x71] & 0x20) | (val & 0xdf);
regs[0x71] = (regs[0x71] & 0x60) | (val & 0x9f);
regs[0x71] &= (val & 0x40);
i4x0_smram_handler_phase1(dev);
}
break;
@@ -1041,9 +1042,11 @@ i4x0_write(int func, int addr, uint8_t val, void *priv)
regs[0x72] = (val & 0x7f);
else
regs[0x72] = (regs[0x72] & 0x87) | (val & 0x78);
dev->smram_locked = (val & 0x10);
if (dev->smram_locked)
regs[0x72] &= 0xbf;
if (val & 0x08) {
dev->smram_locked = (val & 0x10);
if (dev->smram_locked)
regs[0x72] &= 0xbf;
}
}
} else {
if (dev->smram_locked)
@@ -1577,6 +1580,8 @@ i4x0_reset(void *priv)
dev->regs[0x68 + i] = 0x00;
}
dev->smram_locked = 0;
if (dev->type >= INTEL_430FX) {
dev->regs[0x72] &= 0xef; /* Forcibly unlock the SMRAM register. */
i4x0_write(0, 0x72, 0x02, priv);
@@ -1656,7 +1661,12 @@ i4x0_init(const device_t *info)
regs[0x57] = 0x31;
regs[0x59] = 0x0f;
regs[0x60] = regs[0x61] = regs[0x62] = regs[0x63] = 0x02;
dev->max_drb = 3;
/* At the very least the 420ZX seems to read to 0x64, per the SB486PV. */
if (dev->type == INTEL_420ZX) {
regs[0x64] = 0x02;
dev->max_drb = 4;
} else
dev->max_drb = 3;
dev->drb_unit = 1;
dev->drb_default = 0x02;
break;

View File

@@ -59,7 +59,6 @@ typedef struct piix_io_trap_t {
} piix_io_trap_t;
typedef struct _piix_ {
uint8_t cur_readout_reg;
uint8_t rev;
uint8_t type;
uint8_t func_shift;
@@ -67,7 +66,6 @@ typedef struct _piix_ {
uint8_t pci_slot;
uint8_t no_mirq0;
uint8_t regs[4][256];
uint8_t readout_regs[256];
uint16_t func0_id;
uint16_t nvr_io_base;
uint16_t acpi_io_base;
@@ -157,6 +155,7 @@ piix_ide_handlers(piix_t *dev, int bus)
uint16_t side;
if (bus & 0x01) {
piix_log("Disabling primary IDE...\n");
ide_pri_disable();
if (dev->type == 5) {
@@ -172,11 +171,14 @@ piix_ide_handlers(piix_t *dev, int bus)
ide_set_side(0, side);
}
if ((dev->regs[1][0x04] & 0x01) && (dev->regs[1][0x41] & 0x80))
if ((dev->regs[1][0x04] & 0x01) && (dev->regs[1][0x41] & 0x80)) {
piix_log("Enabling primary IDE...\n");
ide_pri_enable();
}
}
if (bus & 0x02) {
piix_log("Disabling secondary IDE...\n");
ide_sec_disable();
if (dev->type == 5) {
@@ -192,8 +194,10 @@ piix_ide_handlers(piix_t *dev, int bus)
ide_set_side(1, side);
}
if ((dev->regs[1][0x04] & 0x01) && (dev->regs[1][0x43] & 0x80))
if ((dev->regs[1][0x04] & 0x01) && (dev->regs[1][0x43] & 0x80)) {
piix_log("Enabling secondary IDE...\n");
ide_sec_enable();
}
}
}
@@ -467,6 +471,13 @@ piix_write(int func, int addr, uint8_t val, void *priv)
uint8_t *fregs;
uint16_t base;
/* Dell OptiPlex Gn+ shows that register 02:FF is aliased in 01:FF. */
if ((dev->type == 4) && (func == 1) && (addr == 0xff))
func = 2;
if ((func == 1) || (addr == 0xf8) || (addr == 0xf9))
piix_log("[W] %02X:%02X = %02X\n", func, addr, val);
/* Return on unsupported function. */
if (dev->max_func > 0) {
if (func > dev->max_func)
@@ -738,6 +749,8 @@ piix_write(int func, int addr, uint8_t val, void *priv)
fregs[addr] = val;
break;
case 0xb0:
if (val & 0x10)
warning("Write %02X to B0\n", val);
if (dev->type == 4)
fregs[addr] = (fregs[addr] & 0x8c) | (val & 0x73);
else if (dev->type == 5)
@@ -747,6 +760,8 @@ piix_write(int func, int addr, uint8_t val, void *priv)
alt_access = !!(val & 0x20);
break;
case 0xb1:
if (val & 0x18)
warning("Write %02X to B1\n", val);
if (dev->type > 3)
fregs[addr] = val & 0xdf;
break;
@@ -925,6 +940,12 @@ piix_write(int func, int addr, uint8_t val, void *priv)
if (dev->type > 4)
fregs[addr] = val;
break;
case 0xf8:
case 0xf9:
/* Undocumented! */
if (dev->type == 4)
fregs[addr] = val;
break;
default:
break;
}
@@ -1171,6 +1192,10 @@ piix_read(int func, int addr, void *priv)
uint8_t ret = 0xff;
const uint8_t *fregs;
/* Dell OptiPlex Gn+ shows that register 02:FF is aliased in 01:FF. */
if ((dev->type == 4) && (func == 1) && (addr == 0xff))
func = 2;
if ((dev->type == 3) && (func == 2) && (dev->max_func == 1) && (addr >= 0x40))
ret = 0x00;
@@ -1185,31 +1210,6 @@ piix_read(int func, int addr, void *priv)
return ret;
}
static void
board_write(uint16_t port, uint8_t val, void *priv)
{
piix_t *dev = (piix_t *) priv;
if (port == 0x00e0)
dev->cur_readout_reg = val;
else if (port == 0x00e1)
dev->readout_regs[dev->cur_readout_reg] = val;
}
static uint8_t
board_read(uint16_t port, void *priv)
{
const piix_t *dev = (piix_t *) priv;
uint8_t ret = 0x64;
if (port == 0x00e0)
ret = dev->cur_readout_reg;
else if (port == 0x00e1)
ret = dev->readout_regs[dev->cur_readout_reg];
return ret;
}
static void
piix_reset_hard(piix_t *dev)
{
@@ -1226,7 +1226,7 @@ piix_reset_hard(piix_t *dev)
sff_set_slot(dev->bm[1], dev->pci_slot);
sff_set_irq_pin(dev->bm[1], PCI_INTA);
sff_set_irq_line(dev->bm[1], 14);
sff_set_irq_line(dev->bm[1], 15);
sff_set_irq_mode(dev->bm[1], IRQ_MODE_LEGACY);
}
@@ -1342,6 +1342,10 @@ piix_reset_hard(piix_t *dev)
fregs[0x45] = 0x55;
fregs[0x46] = 0x01;
}
if (dev->type == 4) {
fregs[0xf8] = 0x30;
fregs[0xf9] = 0x0f;
}
if ((dev->type == 1) && (dev->rev == 2))
dev->max_func = 0; /* It starts with IDE disabled, then enables it. */
else
@@ -1617,47 +1621,16 @@ piix_init(const device_t *info)
else
cpu_set_isa_pci_div(3);
dma_alias_set();
if (dev->type > 1)
dma_alias_set();
else
dma_alias_set_piix();
if (dev->type < 4)
pci_enable_mirq(0);
if (dev->type < 3)
pci_enable_mirq(1);
dev->readout_regs[0] = 0xff;
dev->readout_regs[1] = 0x40;
dev->readout_regs[2] = 0xff;
/* Port E1 register 01 (TODO: Find how multipliers > 3.0 are defined):
Bit 6: 1 = can boot, 0 = no;
Bit 7, 1 = multiplier (00 = 2.5, 01 = 2.0, 10 = 3.0, 11 = 1.5);
Bit 5, 4 = bus speed (00 = 50 MHz, 01 = 66 MHz, 10 = 60 MHz, 11 = ????):
Bit 7, 5, 4, 1: 0000 = 125 MHz, 0010 = 166 MHz, 0100 = 150 MHz, 0110 = ??? MHz;
0001 = 100 MHz, 0011 = 133 MHz, 0101 = 120 MHz, 0111 = ??? MHz;
1000 = 150 MHz, 1010 = 200 MHz, 1100 = 180 MHz, 1110 = ??? MHz;
1001 = 75 MHz, 1011 = 100 MHz, 1101 = 90 MHz, 1111 = ??? MHz */
if (cpu_busspeed <= 40000000)
dev->readout_regs[1] |= 0x30;
else if ((cpu_busspeed > 40000000) && (cpu_busspeed <= 50000000))
dev->readout_regs[1] |= 0x00;
else if ((cpu_busspeed > 50000000) && (cpu_busspeed <= 60000000))
dev->readout_regs[1] |= 0x20;
else if (cpu_busspeed > 60000000)
dev->readout_regs[1] |= 0x10;
if (cpu_dmulti <= 1.5)
dev->readout_regs[1] |= 0x82;
else if ((cpu_dmulti > 1.5) && (cpu_dmulti <= 2.0))
dev->readout_regs[1] |= 0x02;
else if ((cpu_dmulti > 2.0) && (cpu_dmulti <= 2.5))
dev->readout_regs[1] |= 0x00;
else if (cpu_dmulti > 2.5)
dev->readout_regs[1] |= 0x80;
io_sethandler(0x00e0, 0x0002, board_read, NULL, NULL, board_write, NULL, NULL, dev);
#if 0
device_add(&i8254_sec_device);
#endif

View File

@@ -355,7 +355,23 @@ sio_config_read(uint16_t port, UNUSED(void *priv))
ret = 0xff;
break;
case 5:
ret = 0xd3;
/*
Dell Dimension XPS P60 jumpers:
- Bit 5: Disable CMOS Setup (1 = yes, 0 = no).
Dell OptiPlex 560/L jumpers:
- Bit 1: Password (1 = disable, 0 = enable);
- Bit 5: Clear CMOS (1 = no, 0 = yes).
- Bits 7, 6: Board type:
- 0, 0 = L;
- 0, 1 = MT;
- 1, 0 = M;
- 1, 1 = M.
*/
if (!strcmp(machine_get_internal_name(), "opti560l"))
ret = 0x20;
else
ret = 0xd3;
switch (cpu_pci_speed) {
case 20000000:

131
src/chipset/isa486c.c Normal file
View File

@@ -0,0 +1,131 @@
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include "cpu.h"
#include <86box/io.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/plat_unused.h>
#include <86box/chipset.h>
typedef struct isa486c_t {
uint8_t regs[3];
} isa486c_t;
static void
isa486c_recalcmapping(isa486c_t *dev)
{
uint32_t shflags = 0;
uint32_t bases[5] = { 0x000c0000, 0x000c8000, 0x000d0000, 0x000d8000, 0x000e0000 };
uint32_t sizes[5] = { 0x00008000, 0x00008000, 0x00008000, 0x00008000, 0x00020000 };
if (dev->regs[1] & 0x20)
shflags = MEM_READ_EXTANY | MEM_WRITE_INTERNAL;
else
shflags = MEM_READ_INTERNAL | MEM_WRITE_EXTANY;
shadowbios = 0;
shadowbios_write = 0;
for (uint8_t i = 0; i < 5; i++)
if (dev->regs[1] & (1 << i)) {
if (i == 4) {
shadowbios = 1;
shadowbios_write = !!(dev->regs[1] & 0x20);
}
mem_set_mem_state_both(bases[i], sizes[i], shflags);
} else
mem_set_mem_state_both(bases[i], sizes[i], MEM_READ_EXTANY | MEM_WRITE_EXTANY);
flushmmucache_nopc();
}
static void
isa486c_write(uint16_t addr, uint8_t val, void *priv)
{
isa486c_t *dev = (isa486c_t *) priv;
switch (addr) {
case 0x0023:
dev->regs[0] = val;
break;
/*
Port 25h:
- Bit 0 = Video BIOS (C000-C7FF) shadow enabled;
- Bit 1 = C800-C8FF shadow enabled;
- Bit 2 = D000-D7FF shadow enabled;
- Bit 3 = D800-DFFF shadow enabled;
- Bit 4 = E000-FFFF shadow enabled (or F0000-FFFFF?);
- Bit 5 = If set, read from ROM, write to shadow;
- Bit 6 = KEN Video & BIOS enabled (cacheability!).
*/
case 0x0025:
dev->regs[1] = val;
isa486c_recalcmapping(dev);
break;
case 0x0027:
dev->regs[2] = val;
break;
}
}
static uint8_t
isa486c_read(uint16_t addr, void *priv)
{
isa486c_t *dev = (isa486c_t *) priv;
uint8_t ret = 0xff;
switch (addr) {
case 0x0023:
ret = dev->regs[0];
break;
case 0x0025:
ret = dev->regs[1];
break;
case 0x0027:
ret = dev->regs[2];
break;
}
return ret;
}
static void
isa486c_close(void *priv)
{
isa486c_t *dev = (isa486c_t *) priv;
free(dev);
}
static void *
isa486c_init(UNUSED(const device_t *info))
{
isa486c_t *dev = (isa486c_t *) calloc(1, sizeof(isa486c_t));
io_sethandler(0x0023, 0x0001, isa486c_read, NULL, NULL, isa486c_write, NULL, NULL, dev);
io_sethandler(0x0025, 0x0001, isa486c_read, NULL, NULL, isa486c_write, NULL, NULL, dev);
io_sethandler(0x0027, 0x0001, isa486c_read, NULL, NULL, isa486c_write, NULL, NULL, dev);
return dev;
}
const device_t isa486c_device = {
.name = "ASUS ISA-486C Gate Array",
.internal_name = "isa486c",
.flags = 0,
.local = 0,
.init = isa486c_init,
.close = isa486c_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -988,7 +988,7 @@ neat_read(uint16_t port, void *priv)
if ((dev->indx >= 0x60) && (dev->indx <= 0x6e))
ret = dev->regs[dev->indx];
else if (dev->indx == 0x6f)
ret = (dev->regs[dev->indx] & 0xfd) | ~(mem_a20_alt & 0x02);
ret = (dev->regs[dev->indx] & 0xfd) | ((~mem_a20_alt) & 0x02);
break;
default:

View File

@@ -73,26 +73,24 @@ olivetti_eva_write(uint16_t addr, uint8_t val, void *priv)
break;
case 0x069:
dev->reg_069 = val;
/*
* Unfortunately, if triggered, the BIOS remapping function fails causing
* a fatal error. Therefore, this code section is currently commented.
*/
#if 0
if (val & 1) {
mem_remap_top(0);
if (val == 0x01) {
/*
* Set the register to 7 or above for the BIOS to trigger the
* memory remapping function if shadowing is active.
*/
dev->reg_069 = 0x7;
dev->reg_069 = 0x07;
}
if (val & 8) {
if (val & 0x08) {
/*
* Activate shadowing for region e0000-fffff
*/
mem_remap_top(256);
mem_set_mem_state_both(0xa0000, 0x60000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
mem_set_mem_state_both(0xe0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
} else {
mem_remap_top(384);
mem_set_mem_state_both(0xe0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
}
#endif
break;
default:
break;
@@ -143,7 +141,7 @@ olivetti_eva_init(UNUSED(const device_t *info))
dev->reg_067 = 0x00;
/* RAM enable registers */
dev->reg_069 = 0x0;
dev->reg_069 = 0x00;
io_sethandler(0x0065, 0x0001, olivetti_eva_read, NULL, NULL, olivetti_eva_write, NULL, NULL, dev);
io_sethandler(0x0067, 0x0001, olivetti_eva_read, NULL, NULL, olivetti_eva_write, NULL, NULL, dev);
@@ -152,13 +150,6 @@ olivetti_eva_init(UNUSED(const device_t *info))
/* When shadowing is not enabled in BIOS, all upper memory is available as XMS */
mem_remap_top(384);
/*
* Default settings when NVRAM is cleared activate shadowing.
* Thus, to avoid boot errors, remap only 256k from UMB to XMS.
* Remove this block once BIOS memory remapping works.
*/
mem_remap_top(256);
return dev;
}

View File

@@ -16,6 +16,7 @@
* Copyright 2021 Tiseno100.
* Copyright 2021 Miran Grca.
*/
#include <math.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
@@ -158,7 +159,20 @@ opti283_shadow_recalc(opti283_t *dev)
rom = dev->regs[0x11] & (1 << ((i >> 2) + 4));
opti283_log("OPTI 283: %i/%08X: %i, %i, %i\n", i, base, (i >= 4) ? (1 << (i - 4)) : (1 << (i + 4)), (1 << (i >> 2)), (1 << ((i >> 2) + 4)));
if (sh_enable && rom) {
if (sh_copy) {
if (base >= 0x000e0000)
shadowbios_write |= 1;
if (base >= 0x000d0000)
dev->shadow_high |= 1;
if (base >= 0xe0000) {
mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL);
opti283_log("OPTI 283: %08X-%08X READ_EXTANY, WRITE_INTERNAL\n", base, base + 0x3fff);
} else {
mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL);
opti283_log("OPTI 283: %08X-%08X READ_EXTERNAL, WRITE_INTERNAL\n", base, base + 0x3fff);
}
} else if (sh_enable && rom) {
if (base >= 0x000e0000)
shadowbios |= 1;
if (base >= 0x000d0000)
@@ -171,13 +185,8 @@ opti283_shadow_recalc(opti283_t *dev)
if (base >= 0x000e0000)
shadowbios_write |= 1;
if (sh_copy) {
mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
opti283_log("OPTI 283: %08X-%08X READ_INTERNAL, WRITE_INTERNAL\n", base, base + 0x3fff);
} else {
mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL);
opti283_log("OPTI 283: %08X-%08X READ_INTERNAL, WRITE_EXTERNAL\n", base, base + 0x3fff);
}
mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
opti283_log("OPTI 283: %08X-%08X READ_INTERNAL, WRITE_INTERNAL\n", base, base + 0x3fff);
}
} else {
if (base >= 0xe0000) {
@@ -239,9 +248,21 @@ opti283_write(uint16_t addr, uint8_t val, void *priv)
dev->regs[dev->index] = (dev->regs[dev->index] & 0x80) | (val & 0x7f);
break;
case 0x14:
case 0x14: {
double bus_clk;
switch (val & 0x01) {
default:
case 0x00:
bus_clk = cpu_busspeed / 6.0;
break;
case 0x01:
bus_clk = cpu_busspeed / 4.0;
break;
}
cpu_set_isa_speed((int) round(bus_clk));
reset_on_hlt = !!(val & 0x40);
fallthrough;
}
case 0x11:
case 0x12:
case 0x13:
@@ -310,6 +331,8 @@ opti283_init(UNUSED(const device_t *info))
opti283_shadow_recalc(dev);
cpu_set_isa_speed((int) round(cpu_busspeed / 6.0));
device_add(&port_92_device);
return dev;

View File

@@ -8,14 +8,13 @@
*
* Implementation of the OPTi 82C493/82C495 chipset.
*
*
*
* Authors: Tiseno100,
* Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2008-2020 Tiseno100.
* Copyright 2016-2020 Miran Grca.
*/
#include <math.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
@@ -28,6 +27,7 @@
#include <86box/io.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/plat_fallthrough.h>
#include <86box/port_92.h>
#include <86box/chipset.h>
@@ -166,6 +166,27 @@ opti495_write(uint16_t addr, uint8_t val, void *priv)
case 0x26:
opti495_recalc(dev);
break;
case 0x25: {
double bus_clk;
switch (val & 0x03) {
default:
case 0x00:
bus_clk = cpu_busspeed / 6.0;
break;
case 0x01:
bus_clk = cpu_busspeed / 4.0;
break;
case 0x02:
bus_clk = cpu_busspeed / 3.0;
break;
case 0x03:
bus_clk = (cpu_busspeed * 2.0) / 5.0;
break;
}
cpu_set_isa_speed((int) round(bus_clk));
break;
}
}
}
@@ -259,6 +280,8 @@ opti495_init(const device_t *info)
io_sethandler(0x00e1, 0x0002, opti495_read, NULL, NULL, opti495_write, NULL, NULL, dev);
cpu_set_isa_speed((int) round(cpu_busspeed / 6.0));
return dev;
}
@@ -276,11 +299,25 @@ const device_t opti493_device = {
.config = NULL
};
const device_t opti495_device = {
const device_t opti495slc_device = {
.name = "OPTi 82C495",
.internal_name = "opti495",
.internal_name = "opti495slc",
.flags = 0,
.local = OPTI495XLC,
.local = OPTI495SLC,
.init = opti495_init,
.close = opti495_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t opti495sx_device = {
.name = "OPTi 82C495SX",
.internal_name = "opti495sx",
.flags = 0,
.local = OPTI495SX,
.init = opti495_init,
.close = opti495_close,
.reset = NULL,

360
src/chipset/opti498.c Normal file
View File

@@ -0,0 +1,360 @@
/*
* 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.
*
* Implementation of the OPTi 82C498 chipset.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2025 Miran Grca.
*/
#include <math.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include "cpu.h"
#include <86box/timer.h>
#include <86box/io.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/plat_fallthrough.h>
#include <86box/plat_unused.h>
#include <86box/port_92.h>
#include <86box/chipset.h>
#ifdef ENABLE_OPTI498_LOG
int opti498_do_log = ENABLE_OPTI498_LOG;
static void
opti498_log(const char *fmt, ...)
{
va_list ap;
if (opti498_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define opti498_log(fmt, ...)
#endif
typedef struct mem_remapping_t {
uint32_t phys;
uint32_t virt;
} mem_remapping_t;
typedef struct opti498_t {
uint8_t index;
/* 0x30 for 496/497, 0x70 for 498. */
uint8_t reg_base;
uint8_t shadow_high;
uint8_t regs[256];
mem_remapping_t mem_remappings[2];
mem_mapping_t mem_mappings[2];
} opti498_t;
static uint8_t
opti498_read_remapped_ram(uint32_t addr, void *priv)
{
const mem_remapping_t *dev = (mem_remapping_t *) priv;
return mem_read_ram((addr - dev->virt) + dev->phys, priv);
}
static uint16_t
opti498_read_remapped_ramw(uint32_t addr, void *priv)
{
const mem_remapping_t *dev = (mem_remapping_t *) priv;
return mem_read_ramw((addr - dev->virt) + dev->phys, priv);
}
static uint32_t
opti498_read_remapped_raml(uint32_t addr, void *priv)
{
const mem_remapping_t *dev = (mem_remapping_t *) priv;
return mem_read_raml((addr - dev->virt) + dev->phys, priv);
}
static void
opti498_write_remapped_ram(uint32_t addr, uint8_t val, void *priv)
{
const mem_remapping_t *dev = (mem_remapping_t *) priv;
mem_write_ram((addr - dev->virt) + dev->phys, val, priv);
}
static void
opti498_write_remapped_ramw(uint32_t addr, uint16_t val, void *priv)
{
const mem_remapping_t *dev = (mem_remapping_t *) priv;
mem_write_ramw((addr - dev->virt) + dev->phys, val, priv);
}
static void
opti498_write_remapped_raml(uint32_t addr, uint32_t val, void *priv)
{
const mem_remapping_t *dev = (mem_remapping_t *) priv;
mem_write_raml((addr - dev->virt) + dev->phys, val, priv);
}
static void
opti498_shadow_recalc(opti498_t *dev)
{
uint32_t base;
uint32_t rbase;
uint8_t sh_enable;
uint8_t sh_mode;
uint8_t rom;
uint8_t sh_copy;
shadowbios = shadowbios_write = 0;
dev->shadow_high = 0;
opti498_log("OPTI 498: %02X %02X %02X %02X\n", dev->regs[0x02], dev->regs[0x03], dev->regs[0x04], dev->regs[0x05]);
if (dev->regs[0x02] & 0x80) {
if (dev->regs[0x04] & 0x02) {
mem_set_mem_state_both(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
opti498_log("OPTI 498: F0000-FFFFF READ_EXTANY, WRITE_EXTANY\n");
} else {
shadowbios_write = 1;
mem_set_mem_state_both(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL);
opti498_log("OPTI 498: F0000-FFFFF READ_EXTANY, WRITE_INTERNAL\n");
}
} else {
shadowbios = 1;
mem_set_mem_state_both(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED);
opti498_log("OPTI 498: F0000-FFFFF READ_INTERNAL, WRITE_DISABLED\n");
}
sh_copy = dev->regs[0x02] & 0x08;
for (uint8_t i = 0; i < 12; i++) {
base = 0xc0000 + (i << 14);
if (i >= 4)
sh_enable = dev->regs[0x03] & (1 << (i - 4));
else
sh_enable = dev->regs[0x04] & (1 << (i + 4));
sh_mode = dev->regs[0x02] & (1 << (i >> 2));
rom = dev->regs[0x02] & (1 << ((i >> 2) + 4));
opti498_log("OPTI 498: %i/%08X: %i, %i, %i\n", i, base, (i >= 4) ? (1 << (i - 4)) : (1 << (i + 4)), (1 << (i >> 2)), (1 << ((i >> 2) + 4)));
if (sh_copy) {
if (base >= 0x000e0000)
shadowbios_write |= 1;
if (base >= 0x000d0000)
dev->shadow_high |= 1;
if (base >= 0xe0000) {
mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL);
opti498_log("OPTI 498: %08X-%08X READ_EXTANY, WRITE_INTERNAL\n", base, base + 0x3fff);
} else {
mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL);
opti498_log("OPTI 498: %08X-%08X READ_EXTERNAL, WRITE_INTERNAL\n", base, base + 0x3fff);
}
} else if (sh_enable && rom) {
if (base >= 0x000e0000)
shadowbios |= 1;
if (base >= 0x000d0000)
dev->shadow_high |= 1;
if (sh_mode) {
mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED);
opti498_log("OPTI 498: %08X-%08X READ_INTERNAL, WRITE_DISABLED\n", base, base + 0x3fff);
} else {
if (base >= 0x000e0000)
shadowbios_write |= 1;
mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
opti498_log("OPTI 498: %08X-%08X READ_INTERNAL, WRITE_INTERNAL\n", base, base + 0x3fff);
}
} else {
if (base >= 0xe0000) {
mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_DISABLED);
opti498_log("OPTI 498: %08X-%08X READ_EXTANY, WRITE_DISABLED\n", base, base + 0x3fff);
} else {
mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_DISABLED);
opti498_log("OPTI 498: %08X-%08X READ_EXTERNAL, WRITE_DISABLED\n", base, base + 0x3fff);
}
}
}
rbase = ((uint32_t) (dev->regs[0x05] & 0x3f)) << 20;
if (rbase > 0) {
dev->mem_remappings[0].virt = rbase;
mem_mapping_set_addr(&dev->mem_mappings[0], rbase, 0x00020000);
if (!dev->shadow_high) {
rbase += 0x00020000;
dev->mem_remappings[1].virt = rbase;
mem_mapping_set_addr(&dev->mem_mappings[1], rbase, 0x00020000);
} else
mem_mapping_disable(&dev->mem_mappings[1]);
} else {
mem_mapping_disable(&dev->mem_mappings[0]);
mem_mapping_disable(&dev->mem_mappings[1]);
}
flushmmucache_nopc();
}
static void
opti498_write(uint16_t addr, uint8_t val, void *priv)
{
opti498_t *dev = (opti498_t *) priv;
uint8_t reg = dev->index - dev->reg_base;
switch (addr) {
default:
break;
case 0x22:
dev->index = val;
break;
case 0x24:
opti498_log("OPTi 498: dev->regs[%02x] = %02x\n", dev->index, val);
if ((reg >= 0x00) && (reg <= 0x0b)) switch (reg) {
default:
break;
case 0x00:
dev->regs[reg] = (dev->regs[reg] & 0xc0) | (val & 0x3f);
break;
case 0x01:
case 0x07 ... 0x0b:
dev->regs[reg] = val;
break;
case 0x02:
case 0x03:
case 0x04:
case 0x05:
dev->regs[reg] = val;
opti498_shadow_recalc(dev);
break;
case 0x06: {
double bus_clk;
dev->regs[reg] = val;
switch (val & 0x03) {
default:
case 0x00:
bus_clk = cpu_busspeed / 8.0;
break;
case 0x01:
bus_clk = cpu_busspeed / 6.0;
break;
case 0x02:
bus_clk = cpu_busspeed / 5.0;
break;
case 0x03:
bus_clk = cpu_busspeed / 4.0;
break;
}
cpu_set_isa_speed((int) round(bus_clk));
reset_on_hlt = !!(val & 0x40);
break;
}
}
dev->index = 0xff;
break;
}
}
static uint8_t
opti498_read(uint16_t addr, void *priv)
{
opti498_t *dev = (opti498_t *) priv;
uint8_t reg = dev->index - dev->reg_base;
uint8_t ret = 0xff;
if (addr == 0x24) {
if ((reg >= 0x00) && (reg <= 0x0b))
ret = dev->regs[reg];
dev->index = 0xff;
}
return ret;
}
static void
opti498_close(void *priv)
{
opti498_t *dev = (opti498_t *) priv;
free(dev);
}
static void *
opti498_init(UNUSED(const device_t *info))
{
opti498_t *dev = (opti498_t *) calloc(1, sizeof(opti498_t));
dev->reg_base = info->local & 0xff;
io_sethandler(0x0022, 0x0001, opti498_read, NULL, NULL, opti498_write, NULL, NULL, dev);
io_sethandler(0x0024, 0x0001, opti498_read, NULL, NULL, opti498_write, NULL, NULL, dev);
dev->regs[0x00] = 0x1f;
dev->regs[0x01] = 0x8f;
dev->regs[0x02] = 0xf0;
dev->regs[0x07] = 0x70;
dev->regs[0x09] = 0x70;
dev->mem_remappings[0].phys = 0x000a0000;
dev->mem_remappings[1].phys = 0x000d0000;
mem_mapping_add(&dev->mem_mappings[0], 0, 0x00020000,
opti498_read_remapped_ram, opti498_read_remapped_ramw, opti498_read_remapped_raml,
opti498_write_remapped_ram, opti498_write_remapped_ramw, opti498_write_remapped_raml,
&ram[dev->mem_remappings[0].phys], MEM_MAPPING_INTERNAL, &dev->mem_remappings[0]);
mem_mapping_disable(&dev->mem_mappings[0]);
mem_mapping_add(&dev->mem_mappings[1], 0, 0x00020000,
opti498_read_remapped_ram, opti498_read_remapped_ramw, opti498_read_remapped_raml,
opti498_write_remapped_ram, opti498_write_remapped_ramw, opti498_write_remapped_raml,
&ram[dev->mem_remappings[1].phys], MEM_MAPPING_INTERNAL, &dev->mem_remappings[1]);
mem_mapping_disable(&dev->mem_mappings[1]);
opti498_shadow_recalc(dev);
cpu_set_isa_speed((int) round(cpu_busspeed / 8.0));
device_add(&port_92_device);
return dev;
}
const device_t opti498_device = {
.name = "OPTi 82C498",
.internal_name = "opti498",
.flags = 0,
.local = 0x70,
.init = opti498_init,
.close = opti498_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -16,6 +16,7 @@
* Copyright 2008-2020 Tiseno100.
* Copyright 2016-2020 Miran Grca.
*/
#include <math.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
@@ -148,9 +149,28 @@ opti499_write(uint16_t addr, uint8_t val, void *priv)
default:
break;
case 0x20:
case 0x20: {
double coeff = (val & 0x10) ? 1.0 : 2.0;
double bus_clk;
switch (dev->regs[0x25] & 0x03) {
default:
case 0x00:
bus_clk = (cpu_busspeed * coeff) / 6.0;
break;
case 0x01:
bus_clk = (cpu_busspeed * coeff) / 5.0;
break;
case 0x02:
bus_clk = (cpu_busspeed * coeff) / 4.0;
break;
case 0x03:
bus_clk = (cpu_busspeed * coeff) / 3.0;
break;
}
cpu_set_isa_speed((int) round(bus_clk));
reset_on_hlt = !(val & 0x02);
break;
}
case 0x21:
cpu_cache_ext_enabled = !!(dev->regs[0x21] & 0x10);
@@ -163,6 +183,28 @@ opti499_write(uint16_t addr, uint8_t val, void *priv)
case 0x2d:
opti499_recalc(dev);
break;
case 0x25: {
double coeff = (dev->regs[0x20] & 0x10) ? 1.0 : 2.0;
double bus_clk;
switch (val & 0x03) {
default:
case 0x00:
bus_clk = (cpu_busspeed * coeff) / 8.0;
break;
case 0x01:
bus_clk = (cpu_busspeed * coeff) / 6.0;
break;
case 0x02:
bus_clk = (cpu_busspeed * coeff) / 5.0;
break;
case 0x03:
bus_clk = (cpu_busspeed * coeff) / 4.0;
break;
}
cpu_set_isa_speed((int) round(bus_clk));
break;
}
}
}
@@ -229,6 +271,8 @@ opti499_reset(void *priv)
cpu_update_waitstates();
opti499_recalc(dev);
cpu_set_isa_speed((int) round((cpu_busspeed * 2.0) / 6.0));
}
static void

View File

@@ -16,6 +16,7 @@
* Copyright 2008-2020 Tiseno100.
* Copyright 2016-2020 Miran Grca.
*/
#include <math.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
@@ -182,6 +183,27 @@ opti895_write(uint16_t addr, uint8_t val, void *priv)
smram_state_change(dev->smram, 0, !!(val & 0x80));
break;
case 0x25: {
double bus_clk;
switch (val & 0x03) {
default:
case 0x00:
bus_clk = cpu_busspeed / 6.0;
break;
case 0x01:
bus_clk = cpu_busspeed / 5.0;
break;
case 0x02:
bus_clk = cpu_busspeed / 4.0;
break;
case 0x03:
bus_clk = cpu_busspeed / 3.0;
break;
}
cpu_set_isa_speed((int) round(bus_clk));
break;
}
case 0xe0:
if (!(val & 0x01))
dev->forced_green = 0;
@@ -294,6 +316,8 @@ opti895_init(const device_t *info)
smram_enable(dev->smram, 0x00030000, 0x000b0000, 0x00010000, 0, 1);
cpu_set_isa_speed((int) round(cpu_busspeed / 6.0));
return dev;
}

View File

@@ -840,7 +840,7 @@ recalc_sltptr(scamp_t *dev)
recalc_ems(dev);
}
} else {
for (uint8_t i = 0; i < (sltptr / EMS_PGSIZE); i++)
for (uint32_t i = 0; i < (sltptr / EMS_PGSIZE); i++)
scamp_mem_update_state(dev, i * EMS_PGSIZE, EMS_PGSIZE, 0x00, MEM_FMASK_SLOTBUS);
for (uint8_t i = (sltptr / EMS_PGSIZE); i < 40; i++)
@@ -1177,7 +1177,7 @@ scamp_init(UNUSED(const device_t *info))
dev->mem_flags[i] = MEM_FLAG_READ | MEM_FLAG_WRITE;
scamp_mem_update_state(dev, i * EMS_PGSIZE, EMS_PGSIZE, 0x00, MEM_FMASK_RW);
if (i >= 60)
if (i >= 56)
scamp_mem_update_state(dev, i * EMS_PGSIZE, EMS_PGSIZE, MEM_FLAG_ROMCS, MEM_FMASK_ROMCS);
}
}

View File

@@ -259,7 +259,7 @@ sis_5511_host_to_pci_write(int addr, uint8_t val, void *priv)
case 0x7a: /* DRAM Bank Register 2-1 */
case 0x7c: /* DRAM Bank Register 3-0 */
case 0x7e: /* DRAM Bank Register 3-1 */
spd_write_drbs(dev->pci_conf, 0x70, 0x7e, 0x82);
spd_write_drbs(dev->pci_conf, 0x70, 0x7e, 0x02);
break;
case 0x71: /* DRAM Bank Register 0-0 */

View File

@@ -15,6 +15,7 @@
*
* Copyright 2019-2020 Miran Grca.
*/
#include <math.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
@@ -33,6 +34,7 @@
#include <86box/mem.h>
#include <86box/smram.h>
#include <86box/pic.h>
#include <86box/plat_fallthrough.h>
#include <86box/keyboard.h>
#include <86box/machine.h>
#include <86box/chipset.h>
@@ -82,6 +84,14 @@ static uint8_t ram_471[64] = { 0x00, 0x00, 0x01, 0x01, 0x02, 0x20, 0x09, 0x09,
0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,
0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d };
static uint8_t ram_asus[64] = { 0x00, 0x00, 0x01, 0x10, 0x10, 0x20, 0x03, 0x11,
0x11, 0x05, 0x05, 0x12, 0x12, 0x13, 0x13, 0x13,
0x13, 0x21, 0x06, 0x14, 0x14, 0x15, 0x15, 0x15,
0x15, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
0x1d, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17,
0x17, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f };
static uint8_t ram_tg486g[64] = { 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11,
0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13,
0x13, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15,
@@ -162,17 +172,32 @@ sis_85c471_get_row(ram_bank_t *dev, uint32_t addr)
uint32_t ret = 0x00000000;
switch (dev->virt_size) {
case 0x04000000:
ret = (addr >> 14) & 0x00000fff;
break;
case 0x01000000:
ret = (addr >> 13) & 0x000007ff;
case 0x00100000:
case 0x00200000:
ret |= (addr >> 13) & 0x00000001;
ret |= ((addr >> 12) & 0x00000001) << 1;
ret |= ((addr >> 14) & 0x0000003f) << 2;
ret |= ((addr >> 11) & 0x00000001) << 8;
ret |= ((addr >> 20) & 0x00000001) << 9;
ret |= ((addr >> 22) & 0x00000001) << 10;
ret |= ((addr >> 24) & 0x00000001) << 11;
break;
case 0x00400000:
ret = (addr >> 12) & 0x000003ff;
case 0x00800000:
ret |= (addr >> 13) & 0x00000001;
ret |= ((addr >> 12) & 0x00000001) << 1;
ret |= ((addr >> 14) & 0x000000ff) << 2;
ret |= ((addr >> 22) & 0x00000001) << 10;
ret |= ((addr >> 24) & 0x00000001) << 11;
break;
case 0x00100000:
ret = (addr >> 11) & 0x000001ff;
case 0x01000000:
case 0x02000000:
case 0x04000000:
ret |= (addr >> 13) & 0x00000001;
ret |= ((addr >> 22) & 0x00000001) << 1;
ret |= ((addr >> 14) & 0x000000ff) << 2;
ret |= ((addr >> 23) & 0x00000001) << 10;
ret |= ((addr >> 24) & 0x00000001) << 11;
break;
}
@@ -185,17 +210,31 @@ sis_85c471_get_col(ram_bank_t *dev, uint32_t addr)
uint32_t ret = 0x00000000;
switch (dev->virt_size) {
case 0x04000000:
ret = (addr >> 2) & 0x00000fff;
break;
case 0x01000000:
ret = (addr >> 2) & 0x000007ff;
case 0x00100000:
case 0x00200000:
ret |= (addr >> 3) & 0x00000001;
ret |= ((addr >> 2) & 0x00000001) << 1;
ret |= ((addr >> 4) & 0x0000003f) << 2;
ret |= ((addr >> 10) & 0x00000001) << 8;
ret |= ((addr >> 21) & 0x00000001) << 9;
ret |= ((addr >> 23) & 0x00000001) << 10;
ret |= ((addr >> 25) & 0x00000001) << 11;
break;
case 0x00400000:
ret = (addr >> 2) & 0x000003ff;
case 0x00800000:
ret |= (addr >> 3) & 0x00000001;
ret |= ((addr >> 2) & 0x00000001) << 1;
ret |= ((addr >> 4) & 0x000000ff) << 2;
ret |= ((addr >> 23) & 0x00000001) << 10;
ret |= ((addr >> 25) & 0x00000001) << 11;
break;
case 0x00100000:
ret = (addr >> 2) & 0x000001ff;
case 0x01000000:
case 0x02000000:
case 0x04000000:
ret |= (addr >> 3) & 0x00000001;
ret |= ((addr >> 2) & 0x00000001) << 1;
ret |= ((addr >> 4) & 0x000001ff) << 2;
ret |= ((addr >> 25) & 0x00000001) << 11;
break;
}
@@ -208,17 +247,26 @@ sis_85c471_set_row(ram_bank_t *dev, uint32_t addr)
uint32_t ret = 0x00000000;
switch (dev->phys_size) {
case 0x04000000:
ret = (addr & 0x00000fff) << 14;
case 0x00100000:
ret = (addr & 0x1ff) << 11;
break;
case 0x01000000:
ret = (addr & 0x000007ff) << 13;
case 0x00200000:
ret = (addr & 0x3ff) << 11;
break;
case 0x00400000:
ret = (addr & 0x000003ff) << 12;
ret = (addr & 0x3ff) << 12;
break;
case 0x00100000:
ret = (addr & 0x000002ff) << 11;
case 0x00800000:
ret = (addr & 0x7ff) << 12;
break;
case 0x01000000:
ret = (addr & 0x7ff) << 13;
break;
case 0x02000000:
ret = (addr & 0xfff) << 13;
break;
case 0x04000000:
ret = (addr & 0xfff) << 14;
break;
}
@@ -231,23 +279,28 @@ sis_85c471_set_col(ram_bank_t *dev, uint32_t addr)
uint32_t ret = 0x00000000;
switch (dev->phys_size) {
case 0x04000000:
ret = (addr & 0x00000fff) << 2;
break;
case 0x01000000:
ret = (addr & 0x000007ff) << 2;
case 0x00100000:
case 0x00200000:
ret = (addr & 0x1ff) << 2;
break;
case 0x00400000:
ret = (addr & 0x000003ff) << 2;
case 0x00800000:
ret = (addr & 0x3ff) << 2;
break;
case 0x00100000:
ret = (addr & 0x000002ff) << 2;
case 0x01000000:
case 0x02000000:
ret = (addr & 0x7ff) << 2;
break;
case 0x04000000:
ret = (addr & 0xfff) << 2;
break;
}
return ret;
}
uint8_t reg09 = 0x00;
static uint8_t
sis_85c471_read_ram(uint32_t addr, void *priv)
{
@@ -255,12 +308,10 @@ sis_85c471_read_ram(uint32_t addr, void *priv)
uint32_t rel = addr - dev->virt_base;
uint8_t ret = 0xff;
if ((dev->virt_size == 0x01000000) && (dev->phys_size == 0x00400000)) {
uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel));
uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel));
uint32_t dw = rel & 0x00000003;
rel = row | col | dw;
}
uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel));
uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel));
uint32_t dw = rel & 0x00000003;
rel = row | col | dw;
addr = (rel + dev->phys_base);
@@ -277,12 +328,10 @@ sis_85c471_read_ramw(uint32_t addr, void *priv)
uint32_t rel = addr - dev->virt_base;
uint16_t ret = 0xffff;
if ((dev->virt_size == 0x01000000) && (dev->phys_size == 0x00400000)) {
uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel));
uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel));
uint32_t dw = rel & 0x00000003;
rel = row | col | dw;
}
uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel));
uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel));
uint32_t dw = rel & 0x00000003;
rel = row | col | dw;
addr = (rel + dev->phys_base);
@@ -299,12 +348,10 @@ sis_85c471_read_raml(uint32_t addr, void *priv)
uint32_t rel = addr - dev->virt_base;
uint32_t ret = 0xffffffff;
if ((dev->virt_size == 0x01000000) && (dev->phys_size == 0x00400000)) {
uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel));
uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel));
uint32_t dw = rel & 0x00000003;
rel = row | col | dw;
}
uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel));
uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel));
uint32_t dw = rel & 0x00000003;
rel = row | col | dw;
addr = (rel + dev->phys_base);
@@ -320,12 +367,10 @@ sis_85c471_write_ram(uint32_t addr, uint8_t val, void *priv)
ram_bank_t *dev = (ram_bank_t *) priv;
uint32_t rel = addr - dev->virt_base;
if ((dev->virt_size == 0x01000000) && (dev->phys_size == 0x00400000)) {
uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel));
uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel));
uint32_t dw = rel & 0x00000003;
rel = row | col | dw;
}
uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel));
uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel));
uint32_t dw = rel & 0x00000003;
rel = row | col | dw;
addr = (rel + dev->phys_base);
@@ -339,12 +384,10 @@ sis_85c471_write_ramw(uint32_t addr, uint16_t val, void *priv)
ram_bank_t *dev = (ram_bank_t *) priv;
uint32_t rel = addr - dev->virt_base;
if ((dev->virt_size == 0x01000000) && (dev->phys_size == 0x00400000)) {
uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel));
uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel));
uint32_t dw = rel & 0x00000003;
rel = row | col | dw;
}
uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel));
uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel));
uint32_t dw = rel & 0x00000003;
rel = row | col | dw;
addr = (rel + dev->phys_base);
@@ -358,12 +401,10 @@ sis_85c471_write_raml(uint32_t addr, uint32_t val, void *priv)
ram_bank_t *dev = (ram_bank_t *) priv;
uint32_t rel = addr - dev->virt_base;
if ((dev->virt_size == 0x01000000) && (dev->phys_size == 0x00400000)) {
uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel));
uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel));
uint32_t dw = rel & 0x00000003;
rel = row | col | dw;
}
uint32_t row = sis_85c471_set_row(dev, sis_85c471_get_row(dev, rel));
uint32_t col = sis_85c471_set_col(dev, sis_85c471_get_col(dev, rel));
uint32_t dw = rel & 0x00000003;
rel = row | col | dw;
addr = (rel + dev->phys_base);
@@ -492,6 +533,8 @@ sis_85c471_banks_split(uint32_t *b_ex, uint32_t *banks)
static void
sis_85c471_banks_recalc(sis_85c4xx_t *dev)
{
reg09 = dev->regs[0x09];
for (uint8_t i = 0; i < 8; i++)
mem_mapping_disable(&dev->ram_banks[i].mapping);
@@ -553,13 +596,6 @@ sis_85c4xx_out(uint16_t port, uint8_t val, void *priv)
switch (rel_reg) {
case 0x00:
if (val & 0x01) {
kbc_at_set_fast_reset(0);
cpu_cpurst_on_sr = 1;
} else {
kbc_at_set_fast_reset(1);
cpu_cpurst_on_sr = 0;
}
break;
case 0x01:
@@ -572,7 +608,7 @@ sis_85c4xx_out(uint16_t port, uint8_t val, void *priv)
case 0x08:
if (valxor)
sis_85c4xx_recalcmapping(dev);
if (rel_reg == 0x08)
if ((rel_reg == 0x08) && dev->is_471)
flushmmucache();
break;
@@ -587,6 +623,41 @@ sis_85c4xx_out(uint16_t port, uint8_t val, void *priv)
sis_85c4xx_recalcremap(dev);
break;
case 0x10:
if (dev->reg_base == 0x50) {
double bus_clk;
switch (val & 0xe0) {
default:
case 0x00:
bus_clk = 7159091.0;
break;
case 0x02:
bus_clk = cpu_busspeed / 10.0;
break;
case 0x04:
bus_clk = cpu_busspeed / 8.0;
break;
case 0x06:
bus_clk = cpu_busspeed / 6.0;
break;
case 0x80:
bus_clk = cpu_busspeed / 5.0;
break;
case 0xa0:
bus_clk = cpu_busspeed / 4.0;
break;
case 0xc0:
bus_clk = cpu_busspeed / 3.0;
break;
case 0xe0:
bus_clk = cpu_busspeed / 2.0;
break;
}
cpu_set_isa_speed((int) round(bus_clk));
}
break;
case 0x13:
if (dev->is_471 && (valxor & 0xf0)) {
smram_disable(dev->smram);
@@ -694,17 +765,25 @@ sis_85c4xx_reset(void *priv)
if (dev->is_471) {
dev->regs[0x09] = 0x40;
if (mem_size_mb >= 64) {
if (!strcmp(machine_get_internal_name(), "vli486sv2g")) {
if (mem_size_mb == 64)
dev->regs[0x09] |= 0x1f;
else
dev->regs[0x09] |= ram_asus[mem_size_mb];
} else if (mem_size_mb >= 64) {
if ((mem_size_mb >= 64) && (mem_size_mb < 68))
dev->regs[0x09] |= 0x33;
if ((mem_size_mb >= 68) && (mem_size_mb < 72))
else if ((mem_size_mb >= 68) && (mem_size_mb < 72))
dev->regs[0x09] |= 0x2b;
if ((mem_size_mb >= 72) && (mem_size_mb < 80))
else if ((mem_size_mb >= 72) && (mem_size_mb < 80))
dev->regs[0x09] |= 0x2d;
if ((mem_size_mb >= 80) && (mem_size_mb < 96))
else if ((mem_size_mb >= 80) && (mem_size_mb < 96))
dev->regs[0x09] |= 0x2f;
else if ((mem_size_mb >= 96) && (mem_size_mb < 128))
dev->regs[0x09] |= 0x34;
else
dev->regs[0x09] |= 0x29;
dev->regs[0x09] |= 0x35;
} else if (!strcmp(machine_get_internal_name(), "tg486g"))
dev->regs[0x09] |= ram_tg486g[mem_size_mb];
else
@@ -761,6 +840,9 @@ sis_85c4xx_reset(void *priv)
dev->force_flush = 1;
sis_85c4xx_recalcmapping(dev);
if (dev->reg_base == 0x50)
cpu_set_isa_speed((int) round(7159091.0));
}
static void

362
src/chipset/sl82c461.c Normal file
View File

@@ -0,0 +1,362 @@
/*
* 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.
*
* Implementation of the Symphony SL82C461 (Haydn II) chipset.
*
* Symphony SL82C461 Configuration Registers (WARNING: May be inaccurate!):
*
* - Register 00h:
* - Bit 6: External cache present (if clear, AMI BIOS'es will not
* allow enabling external cache).
*
* - Register 01h:
* - Bit 0: Fast Gate A20 Enable (Handler mostly).
* Is it? Enabling/disabling fast gate A20 doesn't appear
* to do much to any register at all.
*
* - Register 02h:
* - Bit 0: Optional Chipset Turbo Pin;
* - Bits 4-2:
* - 000 = CLK2/3;
* - 001 = CLK2/4;
* - 010 = CLK2/5;
* - 011 = 7.159 MHz (ATCLK2);
* - 100 = CLK2/6;
* - 110 = CLK2/2.5;
* - 111 = CLK2/2.
*
* - Register 06h:
* - Bit 2: Decoupled Refresh Option.
*
* - Register 08h:
* - Bits 3, 2: I/O Recovery Time (SYSCLK):
* - 0, 0 = 0;
* - 1, 1 = 12.
* - Bit 1: Extended ALE.
*
* - Register 25h:
* Bit 7 here causes AMI 111192 CMOS Setup to return 7168 KB RAM
* instead of 6912 KB. This is 256 KB off. Relocation?
* Also, returning bit 5 clear instead of set, causes the AMI BIOS
* to set bits 0,1 of register 45h to 1,0 instead of 0,1.
*
* - Register 2Dh:
* - Bit 7: Enable 256KB Memory Relocation;
* - Bit 6: Enable 384KB Memory Relocation, bit 7 must also be set.
*
* - Register 2Eh:
* - Bit 7: CC000-CFFFF Shadow Read Enable;
* - Bit 6: CC000-CFFFF Shadow Write Enable;
* - Bit 5: C8000-CBFFF Shadow Read Enable;
* - Bit 4: C8000-CBFFF Shadow Write Enable;
* - Bit 3: C4000-C7FFF Shadow Read Enable;
* - Bit 2: C4000-C7FFF Shadow Write Enable;
* - Bit 1: C0000-C3FFF Shadow Read Enable;
* - Bit 0: C0000-C3FFF Shadow Write Enable.
*
* - Register 2Fh:
* - Bit 7: DC000-DFFFF Shadow Read Enable;
* - Bit 6: DC000-DFFFF Shadow Write Enable;
* - Bit 5: D8000-DBFFF Shadow Read Enable;
* - Bit 4: D8000-DBFFF Shadow Write Enable;
* - Bit 3: D4000-D7FFF Shadow Read Enable;
* - Bit 2: D4000-D7FFF Shadow Write Enable;
* - Bit 1: D0000-D3FFF Shadow Read Enable;
* - Bit 0: D0000-D3FFF Shadow Write Enable.
*
* - Register 30h:
* - Bit 7: E0000-EFFFF Shadow Read Enable;
* - Bit 6: E0000-EFFFF Shadow Write Enable.
*
* - Register 31h:
* - Bit 7: F0000-FFFFF Shadow Read Enable;
* - Bit 6: F0000-FFFFF Shadow Write Enable.
*
* - Register 33h (NOTE: Waitstates also affect register 32h):
* - Bits 3, 0:
* - 0,0 = 0 W/S;
* - 1,0 = 1 W/S;
* - 1,1 = 2 W/S.
*
* - Register 40h:
* - Bit 3: External Cache Enabled (0 = yes, 1 = no);
* I also see bits 5, 4, 3 of register 44h affected:
* - 38h (so all 3 set) when cache is disabled;
* - 00h (all 3 clear) when it's enabled.
*
* - Register 45h:
* - Bit 3: Video Shadow RAM Cacheable;
* - Bit 4: Adapter Shadow RAM Cacheable;
* - Bit 5: BIOS Shadow RAM Cacheable.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Tiseno100,
*
* Copyright 2025 Miran Grca.
* Copyright 2021-2025 Tiseno100.
*/
#include <math.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include "cpu.h"
#include <86box/timer.h>
#include <86box/io.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/chipset.h>
typedef struct {
uint8_t index;
uint8_t regs[256];
uint8_t shadow[4];
} sl82c461_t;
#ifdef ENABLE_SL82C461_LOG
int sl82c461_do_log = ENABLE_SL82C461_LOG;
static void
sl82c461_log(const char *fmt, ...)
{
va_list ap;
if (sl82c461_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define sl82c461_log(fmt, ...)
#endif
static void
sl82c461_recalcmapping(sl82c461_t *dev)
{
int do_shadow = 0;
for (uint32_t i = 0; i < 8; i += 2) {
if ((dev->regs[0x2e] ^ dev->shadow[0x00]) & (3 << i)) {
uint32_t base = 0x000c0000 + ((i >> 1) << 14);
uint32_t read = ((dev->regs[0x2e] >> i) & 0x02) ? MEM_READ_INTERNAL :
MEM_READ_EXTANY;
uint32_t write = ((dev->regs[0x2e] >> i) & 0x01) ? MEM_WRITE_INTERNAL :
MEM_WRITE_EXTANY;
mem_set_mem_state_both(base, 0x00004000, read | write);
do_shadow++;
}
if ((dev->regs[0x2f] ^ dev->shadow[0x01]) & (3 << i)) {
uint32_t base = 0x000d0000 + ((i >> 1) << 14);
uint32_t read = ((dev->regs[0x2f] >> i) & 0x02) ? MEM_READ_INTERNAL :
MEM_READ_EXTANY;
uint32_t write = ((dev->regs[0x2f] >> i) & 0x01) ? MEM_WRITE_INTERNAL :
MEM_WRITE_EXTANY;
mem_set_mem_state_both(base, 0x00004000, read | write);
do_shadow++;
}
}
if ((dev->regs[0x30] ^ dev->shadow[0x02]) & 0xc0) {
uint32_t base = 0x000e0000;
uint32_t read = ((dev->regs[0x30] >> 6) & 0x02) ? MEM_READ_INTERNAL :
MEM_READ_EXTANY;
uint32_t write = ((dev->regs[0x30] >> 6) & 0x01) ? MEM_WRITE_INTERNAL :
MEM_WRITE_EXTANY;
mem_set_mem_state_both(base, 0x00010000, read | write);
do_shadow++;
}
if ((dev->regs[0x31] ^ dev->shadow[0x03]) & 0xc0) {
uint32_t base = 0x000f0000;
uint32_t read = ((dev->regs[0x31] >> 6) & 0x02) ? MEM_READ_INTERNAL :
MEM_READ_EXTANY;
uint32_t write = ((dev->regs[0x31] >> 6) & 0x01) ? MEM_WRITE_INTERNAL :
MEM_WRITE_EXTANY;
shadowbios = !!((dev->regs[0x31] >> 6) & 0x02);
shadowbios_write = !!((dev->regs[0x31] >> 6) & 0x01);
mem_set_mem_state_both(base, 0x00010000, read | write);
do_shadow++;
}
if (do_shadow) {
memcpy(dev->shadow, &(dev->regs[0x2e]), 4 * sizeof(uint8_t));
flushmmucache_nopc();
}
}
static void
sl82c461_write(uint16_t addr, uint8_t val, void *priv)
{
sl82c461_t *dev = (sl82c461_t *) priv;
sl82c461_log("[%04X:%08X] [W] %04X = %02X\n", CS, cpu_state.pc, addr, val);
if (addr & 0x0001) {
dev->regs[dev->index] = val;
switch (dev->index) {
case 0x01:
/* NOTE: This is to be verified. */
mem_a20_alt = val & 1;
mem_a20_recalc();
break;
case 0x02: {
double bus_clk;
switch (val & 0x1c) {
case 0x00:
bus_clk = cpu_busspeed / 3.0;
break;
case 0x04:
bus_clk = cpu_busspeed / 4.0;
break;
case 0x08:
bus_clk = cpu_busspeed / 5.0;
break;
default:
case 0x0c:
bus_clk = 7159091.0;
break;
case 0x10:
bus_clk = cpu_busspeed / 6.0;
break;
case 0x18:
bus_clk = cpu_busspeed / 2.5;
break;
case 0x1c:
bus_clk = cpu_busspeed / 2.0;
break;
}
cpu_set_isa_speed((int) round(bus_clk));
break;
} case 0x2d:
switch (val & 0xc0) {
case 0xc0:
mem_remap_top(384);
break;
case 0x80:
mem_remap_top(256);
break;
default:
case 0x00:
mem_remap_top(0);
break;
}
break;
case 0x2e ... 0x31:
sl82c461_recalcmapping(dev);
break;
case 0x33:
switch (val & 0x09) {
default:
case 0x00:
cpu_waitstates = 0;
break;
case 0x08:
cpu_waitstates = 1;
break;
case 0x09:
cpu_waitstates = 2;
break;
}
cpu_update_waitstates();
break;
case 0x40:
cpu_cache_ext_enabled = !(val & 0x08);
cpu_update_waitstates();
break;
}
} else
dev->index = val;
}
static uint8_t
sl82c461_read(uint16_t addr, void *priv)
{
sl82c461_t *dev = (sl82c461_t *) priv;
uint8_t ret = 0x00;
if (addr & 0x0001)
if (dev->index == 0x00)
ret = dev->regs[dev->index] | 0x40;
else
ret = dev->regs[dev->index];
else
ret = dev->index;
sl82c461_log("[%04X:%08X] [R] %04X = %02X\n", CS, cpu_state.pc, addr, ret);
return ret;
}
static void
sl82c461_close(void *priv)
{
sl82c461_t *dev = (sl82c461_t *) priv;
free(dev);
}
static void *
sl82c461_init(const device_t *info)
{
sl82c461_t *dev = (sl82c461_t *) calloc(1, sizeof(sl82c461_t));
dev->regs[0x00] = 0x40;
dev->regs[0x02] = 0x0c;
dev->regs[0x40] = 0x08;
memset(dev->shadow, 0xff, 4 * sizeof(uint8_t));
mem_a20_alt = 0x00;
mem_a20_recalc();
cpu_set_isa_speed(7159091.0);
sl82c461_recalcmapping(dev);
cpu_waitstates = 0;
cpu_cache_ext_enabled = 0;
cpu_update_waitstates();
io_sethandler(0x00a8, 2,
sl82c461_read, NULL, NULL,
sl82c461_write, NULL, NULL, dev);
return dev;
}
const device_t sl82c461_device = {
.name = "Symphony SL82C461 (Haydn II)",
.internal_name = "sis_85c471",
.flags = 0,
.local = 0,
.init = sl82c461_init,
.close = sl82c461_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -80,10 +80,12 @@ typedef struct stpc_serial_t {
} stpc_serial_t;
typedef struct stpc_lpt_t {
uint8_t unlocked;
uint8_t offset;
uint8_t reg1;
uint8_t reg4;
uint8_t unlocked;
uint8_t offset;
uint8_t reg1;
uint8_t reg4;
lpt_t *lpt;
} stpc_lpt_t;
#ifdef ENABLE_STPC_LOG
@@ -977,22 +979,22 @@ stpc_lpt_handlers(stpc_lpt_t *dev, uint8_t val)
{
const uint8_t new_addr = (val & 0x03);
lpt1_remove();
lpt_port_remove(dev->lpt);
switch (new_addr) {
case 0x1:
stpc_log("STPC: Remapping parallel port to LPT3\n");
lpt1_setup(LPT_MDA_ADDR);
lpt_port_setup(dev->lpt, LPT_MDA_ADDR);
break;
case 0x2:
stpc_log("STPC: Remapping parallel port to LPT1\n");
lpt1_setup(LPT1_ADDR);
lpt_port_setup(dev->lpt, LPT1_ADDR);
break;
case 0x3:
stpc_log("STPC: Remapping parallel port to LPT2\n");
lpt1_setup(LPT2_ADDR);
lpt_port_setup(dev->lpt, LPT2_ADDR);
break;
default:
@@ -1063,6 +1065,8 @@ stpc_lpt_init(UNUSED(const device_t *info))
stpc_lpt_t *dev = (stpc_lpt_t *) calloc(1, sizeof(stpc_lpt_t));
dev->lpt = device_add_inst(&lpt_port_device, 1);
stpc_lpt_reset(dev);
io_sethandler(0x3f0, 2,

View File

@@ -270,6 +270,8 @@ hb4_smram(hb4_t *dev)
}
umc_smram_recalc(dev->smram_base >> 12, 1);
flushmmucache();
}
static void
@@ -398,55 +400,6 @@ hb4_close(void *priv)
free(dev);
}
static void
ims8848_write(uint16_t addr, uint8_t val, void *priv)
{
hb4_t *dev = (hb4_t *) priv;
switch (addr) {
case 0x22:
dev->idx = val;
break;
case 0x23:
if (((val & 0x0f) == ((dev->idx >> 4) & 0x0f)) && ((val & 0xf0) == ((dev->idx << 4) & 0xf0)))
dev->access_data = 1;
break;
case 0x24:
if (dev->access_data)
dev->access_data = 0;
break;
default:
break;
}
}
static uint8_t
ims8848_read(uint16_t addr, void *priv)
{
uint8_t ret = 0xff;
hb4_t *dev = (hb4_t *) priv;
switch (addr) {
case 0x22:
ret = dev->idx;
break;
case 0x23:
ret = (dev->idx >> 4) | (dev->idx << 4);
break;
case 0x24:
if (dev->access_data) {
ret = dev->pci_conf[dev->idx];
dev->access_data = 0;
}
break;
default:
break;
}
return ret;
}
static void *
hb4_init(UNUSED(const device_t *info))
{
@@ -463,8 +416,6 @@ hb4_init(UNUSED(const device_t *info))
dev->smram_base = 0x000a0000;
hb4_reset(dev);
io_sethandler(0x0022, 0x0003, ims8848_read, NULL, NULL, ims8848_write, NULL, NULL, dev);
return dev;
}

View File

@@ -24,14 +24,16 @@
#include <86box/timer.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/machine.h>
#include <86box/mem.h>
#include <86box/nmi.h>
#include <86box/port_92.h>
#include <86box/chipset.h>
typedef struct vl82c480_t {
uint8_t idx;
uint8_t regs[256];
uint8_t idx;
uint8_t regs[256];
uint32_t banks[4];
} vl82c480_t;
static int
@@ -59,7 +61,7 @@ vl82c480_shflags(uint8_t access)
}
static void
vl82c480_recalc(vl82c480_t *dev)
vl82c480_recalc_shadow(vl82c480_t *dev)
{
uint32_t base;
uint8_t access;
@@ -69,8 +71,8 @@ vl82c480_recalc(vl82c480_t *dev)
for (uint8_t i = 0; i < 6; i++) {
for (uint8_t j = 0; j < 8; j += 2) {
base = 0x000a0000 + (i << 16) + (j << 13);
access = (dev->regs[0x0d + i] >> j) & 3;
base = 0x000a0000 + (i << 16) + (j << 13);
access = (dev->regs[0x0d + i] >> j) & 3;
mem_set_mem_state(base, 0x4000, vl82c480_shflags(access));
shadowbios |= ((base >= 0xe0000) && (access & 0x02));
shadowbios_write |= ((base >= 0xe0000) && (access & 0x01));
@@ -80,6 +82,37 @@ vl82c480_recalc(vl82c480_t *dev)
flushmmucache();
}
static void
vl82c480_recalc_banks(vl82c480_t *dev)
{
uint32_t sizes[8] = { 0, 0, 1024, 2048, 4096, 8192, 16384, 32768 };
uint8_t shifts[4] = { 0, 4, 0, 4 };
uint8_t regs[4] = { 0x02, 0x02, 0x03, 0x03 };
uint32_t total = 0;
for (uint8_t i = 0; i < 4; i++) {
uint8_t shift = shifts[i];
uint8_t reg = regs[i];
uint8_t cfg = (dev->regs[reg] >> shift) & 0x7;
uint32_t size = sizes[cfg];
total += MIN(dev->banks[i], size);
}
if (total > 1024) {
mem_mapping_set_addr(&ram_low_mapping, 0x00000000, 0x000a0000);
mem_mapping_set_addr(&ram_high_mapping, 0x00100000, (total - 1024) << 10);
} else {
if (total >= 1024)
mem_mapping_set_addr(&ram_low_mapping, 0x00000000, 0x000a0000);
else
mem_mapping_disable(&ram_low_mapping);
mem_mapping_disable(&ram_high_mapping);
}
flushmmucache();
}
static void
vl82c480_write(uint16_t addr, uint8_t val, void *priv)
{
@@ -91,11 +124,18 @@ vl82c480_write(uint16_t addr, uint8_t val, void *priv)
break;
case 0xed:
if (dev->idx >= 0x01 && dev->idx <= 0x24) {
if (((dev->idx >= 0x01) && (dev->idx <= 0x19)) ||
((dev->idx >= 0x20) && (dev->idx <= 0x24))) {
switch (dev->idx) {
default:
dev->regs[dev->idx] = val;
break;
case 0x02: case 0x03:
dev->regs[dev->idx] = val;
if (!strcmp(machine_get_internal_name(), "martin") ||
!strcmp(machine_get_internal_name(), "prolineamt"))
vl82c480_recalc_banks(dev);
break;
case 0x04:
if (dev->regs[0x00] == 0x98)
dev->regs[dev->idx] = (dev->regs[dev->idx] & 0x08) | (val & 0xf7);
@@ -108,14 +148,9 @@ vl82c480_write(uint16_t addr, uint8_t val, void *priv)
case 0x07:
dev->regs[dev->idx] = (dev->regs[dev->idx] & 0x40) | (val & 0xbf);
break;
case 0x0d:
case 0x0e:
case 0x0f:
case 0x10:
case 0x11:
case 0x12:
case 0x0d ... 0x12:
dev->regs[dev->idx] = val;
vl82c480_recalc(dev);
vl82c480_recalc_shadow(dev);
break;
}
}
@@ -124,8 +159,8 @@ vl82c480_write(uint16_t addr, uint8_t val, void *priv)
/* TODO: This is actually Fast A20 disable. */
#if 0
case 0xee:
if (mem_a20_alt)
outb(0x92, inb(0x92) & ~2);
mem_a20_alt = 0x00;
mem_a20_recalc();
break;
#endif
@@ -146,14 +181,16 @@ vl82c480_read(uint16_t addr, void *priv)
break;
case 0xed:
ret = dev->regs[dev->idx];
if (((dev->idx >= 0x01) && (dev->idx <= 0x19)) ||
((dev->idx >= 0x20) && (dev->idx <= 0x24)))
ret = dev->regs[dev->idx];
break;
/* TODO: This is actually Fast A20 enable. */
#if 0
case 0xee:
if (!mem_a20_alt)
outb(0x92, inb(0x92) | 2);
mem_a20_alt = 0x02;
mem_a20_recalc();
break;
#endif
@@ -180,7 +217,12 @@ vl82c480_close(void *priv)
static void *
vl82c480_init(const device_t *info)
{
vl82c480_t *dev = (vl82c480_t *) calloc(1, sizeof(vl82c480_t));
vl82c480_t *dev = (vl82c480_t *) calloc(1, sizeof(vl82c480_t));
uint32_t sizes[8] = { 0, 0, 1024, 2048, 4096, 8192, 16384, 32768 };
uint32_t ms = mem_size;
uint8_t min_i = !strcmp(machine_get_internal_name(), "prolineamt") ? 1 : 0;
uint8_t min_j = !strcmp(machine_get_internal_name(), "prolineamt") ? 4 : 2;
uint8_t max_j = !strcmp(machine_get_internal_name(), "prolineamt") ? 8 : 7;
dev->regs[0x00] = info->local;
dev->regs[0x01] = 0xff;
@@ -191,9 +233,31 @@ vl82c480_init(const device_t *info)
dev->regs[0x07] = 0x21;
dev->regs[0x08] = 0x38;
if (!strcmp(machine_get_internal_name(), "prolineamt")) {
dev->banks[0] = 4096;
/* Bank 0 is ignored if 64 MB is installed. */
if (ms != 65536)
ms -= 4096;
}
if (ms > 0) for (uint8_t i = min_i; i < 4; i++) {
for (uint8_t j = min_j; j < max_j; j++) {
if (ms >= sizes[j])
dev->banks[i] = sizes[j];
else
break;
}
ms -= dev->banks[i];
if ((ms == 0) || (dev->banks[i] == 0))
break;
}
io_sethandler(0x00ec, 0x0004, vl82c480_read, NULL, NULL, vl82c480_write, NULL, NULL, dev);
device_add(&port_92_device);
device_add(&port_92_pci_device);
return dev;
}

View File

@@ -113,9 +113,9 @@ typedef struct
mem_mapping_t ram_mapping;
nvr_t *nvr;
fdc_t *fdc;
serial_t *uart[2];
fdc_t *fdc;
serial_t *uart[2];
lpt_t *lpt;
} wd76c10_t;
static uint32_t bank_sizes[4] = { 0x00020000, /* 64 Kbit X 16 = 1024 Kbit = 128 kB, 8x 8 */
@@ -841,7 +841,7 @@ wd76c10_pf_loc_recalc(wd76c10_t *dev)
uint8_t ems_page;
uint32_t base;
for (uint8_t i = (0x031 + pf_loc); i <= (0x037 + pf_loc); i++) {
for (uint16_t i = (0x031 + pf_loc); i <= (0x037 + pf_loc); i++) {
ems_page = (i - 0x10) & 0xf7;
dev->mem_pages[i] = ems_page;
base = ((uint32_t) i) << 14;
@@ -911,19 +911,19 @@ wd76c10_ser_par_cs_recalc(wd76c10_t *dev)
}
/* LPT */
lpt1_remove();
lpt_port_remove(dev->lpt);
switch ((dev->ser_par_cs >> 9) & 0x03) {
case 1:
lpt1_setup(LPT_MDA_ADDR);
lpt1_irq(LPT1_IRQ);
lpt_port_setup(dev->lpt, LPT_MDA_ADDR);
lpt_port_irq(dev->lpt, LPT1_IRQ);
break;
case 2:
lpt1_setup(LPT1_ADDR);
lpt1_irq(LPT1_IRQ);
lpt_port_setup(dev->lpt, LPT1_ADDR);
lpt_port_irq(dev->lpt, LPT1_IRQ);
break;
case 3:
lpt1_setup(LPT2_ADDR);
lpt1_irq(LPT1_IRQ);
lpt_port_setup(dev->lpt, LPT2_ADDR);
lpt_port_irq(dev->lpt, LPT1_IRQ);
break;
}
}
@@ -1173,8 +1173,8 @@ wd76c10_inw(uint16_t port, void *priv)
case 0xd072:
ret = (serial_read(0x0002, dev->uart[0]) & 0xc0) << 8;
ret |= (serial_read(0x0002, dev->uart[1]) & 0xc0) << 6;
ret |= (lpt_read_port(0, 0x0002) & 0x0f) << 8;
ret |= lpt_read_port(0, 0x0000);
ret |= (lpt_read_port(dev->lpt, 0x0002) & 0x0f) << 8;
ret |= lpt_read_port(dev->lpt, 0x0000);
break;
case 0xe072:
@@ -1188,7 +1188,7 @@ wd76c10_inw(uint16_t port, void *priv)
break;
case 0xfc72:
ret = ((lpt_read_status(0) & 0x20) >> 2);
ret = ((lpt_read_status(dev->lpt) & 0x20) >> 2);
ret |= (((uint16_t) dma_m) << 4);
ret |= dev->toggle;
dev->toggle ^= 0x8000;
@@ -1303,6 +1303,7 @@ wd76c10_init(UNUSED(const device_t *info))
dev->nvr = device_add(&amstrad_megapc_nvr_device);
dev->uart[0] = device_add_inst(&ns16450_device, 1);
dev->uart[1] = device_add_inst(&ns16450_device, 2);
dev->lpt = device_add_inst(&lpt_port_device, 1);
dev->fdc = device_add(&fdc_at_device);
device_add(&ide_isa_device);

View File

@@ -3875,19 +3875,31 @@ FP_LOAD_IMM_Q(uint64_t v)
static __inline void
FP_FCHS(void)
{
addbyte(0x48); /* MOVABS RAX, 0x8000000000000000 */
addbyte(0xb8);
addquad(0x8000000000000000);
addbyte(0x66); /* MOVQ XMM15, RAX */
addbyte(0x4c);
addbyte(0x0f);
addbyte(0x6e);
addbyte(0xf8);
addbyte(0x48); /* XOR RAX, RAX */
addbyte(0x31);
addbyte(0xc0);
addbyte(0x8b); /*MOV EAX, TOP*/
addbyte(0x45);
addbyte((uint8_t) cpu_state_offset(TOP));
addbyte(0xf2); /*SUBSD XMM0, XMM0*/
addbyte(0xf3); /*MOVQ XMM0, ST[EAX*8]*/
addbyte(0x0f);
addbyte(0x5c);
addbyte(0xc0);
addbyte(0xf2); /*SUBSD XMM0, ST[EAX*8]*/
addbyte(0x0f);
addbyte(0x5c);
addbyte(0x7e);
addbyte(0x44);
addbyte(0xc5);
addbyte((uint8_t) cpu_state_offset(ST));
addbyte(0x66); /* PXOR XMM0, XMM15 */
addbyte(0x41);
addbyte(0x0F);
addbyte(0xEF);
addbyte(0xC7);
addbyte(0x80); /*AND tag[EAX], ~TAG_UINT64*/
addbyte(0x64);
addbyte(0x05);

View File

@@ -818,6 +818,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p
int over = 0;
int pc_off = 0;
int test_modrm = 1;
int in_lock = 0;
int c;
uint32_t op87 = 0x00000000;
@@ -956,6 +957,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p
break;
case 0xf0: /*LOCK*/
in_lock = 0;
break;
case 0xf2: /*REPNE*/
@@ -1013,6 +1015,9 @@ generate_call:
STORE_IMM_ADDR_L((uintptr_t) &x87_op, op87);
}
if (in_lock && ((opcode == 0x90) || (opcode == 0xec)))
goto codegen_skip;
if (recomp_op_table && recomp_op_table[(opcode | op_32) & 0x1ff]) {
uint32_t new_pc = recomp_op_table[(opcode | op_32) & 0x1ff](opcode, fetchdat, op_32, op_pc, block);
if (new_pc) {
@@ -1040,7 +1045,13 @@ generate_call:
}
}
op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask];
codegen_skip:
if (in_lock && ((opcode == 0x90) || (opcode == 0xec)))
/* This is always ILLEGAL. */
op = x86_dynarec_opcodes_3DNOW[0xff];
else
op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask];
if (op_ssegs != last_ssegs) {
last_ssegs = op_ssegs;
addbyte(0xC6); /*MOVB $0,(ssegs)*/

View File

@@ -1857,6 +1857,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p
int over = 0;
int pc_off = 0;
int test_modrm = 1;
int in_lock = 0;
int c;
uint32_t op87 = 0x00000000;
@@ -1996,6 +1997,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p
break;
case 0xf0: /*LOCK*/
in_lock = 1;
break;
case 0xf2: /*REPNE*/
@@ -2054,6 +2056,9 @@ generate_call:
STORE_IMM_ADDR_L((uintptr_t) &x87_op, op87);
}
if (in_lock && ((opcode == 0x90) || (opcode == 0xec)))
goto codegen_skip;
if (recomp_op_table && recomp_op_table[(opcode | op_32) & 0x1ff]) {
uint32_t new_pc = recomp_op_table[(opcode | op_32) & 0x1ff](opcode, fetchdat, op_32, op_pc, block);
if (new_pc) {
@@ -2080,7 +2085,13 @@ generate_call:
}
}
op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask];
codegen_skip:
if (in_lock && ((opcode == 0x90) || (opcode == 0xec)))
/* This is always ILLEGAL. */
op = x86_dynarec_opcodes_3DNOW[0xff];
else
op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask];
if (op_ssegs != last_ssegs) {
last_ssegs = op_ssegs;

View File

@@ -395,6 +395,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p
int over = 0;
int test_modrm = 1;
int pc_off = 0;
int in_lock = 0;
uint32_t next_pc = 0;
uint16_t op87 = 0x0000;
#ifdef DEBUG_EXTRA
@@ -556,6 +557,7 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p
break;
case 0xf0: /*LOCK*/
in_lock = 1;
break;
case 0xf2: /*REPNE*/
@@ -675,6 +677,9 @@ generate_call:
goto codegen_skip;
#endif
if (in_lock && ((opcode == 0x90) || (opcode == 0xec)))
goto codegen_skip;
if (recomp_op_table && recomp_op_table[(opcode | op_32) & recomp_opcode_mask]) {
uint32_t new_pc = recomp_op_table[(opcode | op_32) & recomp_opcode_mask](block, ir, opcode, fetchdat, op_32, op_pc);
if (new_pc) {
@@ -692,13 +697,17 @@ generate_call:
}
}
// codegen_skip:
codegen_skip:
if ((op_table == x86_dynarec_opcodes_REPNE || op_table == x86_dynarec_opcodes_REPE) && !op_table[opcode | op_32]) {
op_table = x86_dynarec_opcodes;
recomp_op_table = recomp_opcodes;
}
op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask];
if (in_lock && ((opcode == 0x90) || (opcode == 0xec)))
/* This is always ILLEGAL. */
op = x86_dynarec_opcodes_3DNOW[0xff];
else
op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask];
if (!test_modrm || (op_table == x86_dynarec_opcodes && opcode_modrm[opcode]) || (op_table == x86_dynarec_opcodes_0f && opcode_0f_modrm[opcode]) || (op_table == x86_dynarec_opcodes_3DNOW)) {
int stack_offset = 0;
@@ -737,8 +746,7 @@ generate_call:
uop_MOV_PTR(ir, IREG_ea_seg, (void *) op_ea_seg);
if (op_ssegs != last_op_ssegs)
uop_MOV_IMM(ir, IREG_ssegs, op_ssegs);
uop_LOAD_FUNC_ARG_IMM(ir, 0, fetchdat);
uop_CALL_INSTRUCTION_FUNC(ir, op);
uop_CALL_INSTRUCTION_FUNC(ir, op, fetchdat);
codegen_flags_changed = 0;
codegen_mark_code_present(block, cs + cpu_state.pc, 8);

View File

@@ -218,6 +218,7 @@ codegen_CALL_FUNC_RESULT(codeblock_t *block, uop_t *uop)
static int
codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop)
{
host_arm64_mov_imm(block, REG_ARG0, uop->imm_data);
host_arm64_call(block, uop->p);
host_arm64_CBNZ(block, REG_X0, (uintptr_t) codegen_exit_rout);

View File

@@ -286,6 +286,7 @@ codegen_CALL_FUNC_RESULT(codeblock_t *block, uop_t *uop)
static int
codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop)
{
host_arm_MOV_IMM(block, REG_ARG0, uop->imm_data);
host_arm_call(block, uop->p);
host_arm_TST_REG(block, REG_R0, REG_R0);
host_arm_BNE(block, (uintptr_t) codegen_exit_rout);

File diff suppressed because it is too large Load Diff

View File

@@ -219,6 +219,11 @@ codegen_CALL_FUNC_RESULT(codeblock_t *block, uop_t *uop)
static int
codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop)
{
# if _WIN64
host_x86_MOV32_REG_IMM(block, REG_ECX, uop->imm_data);
# else
host_x86_MOV32_REG_IMM(block, REG_EDI, uop->imm_data);
# endif
host_x86_CALL(block, uop->p);
host_x86_TEST32_REG(block, REG_EAX, REG_EAX);
host_x86_JNZ(block, codegen_exit_rout);
@@ -631,9 +636,10 @@ codegen_FCHS(codeblock_t *block, uop_t *uop)
int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real);
if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) {
host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a);
host_x86_PXOR_XREG_XREG(block, dest_reg, dest_reg);
host_x86_SUBSD_XREG_XREG(block, dest_reg, REG_XMM_TEMP);
host_x86_MOVQ_XREG_XREG(block, dest_reg, src_reg_a);
host_x86_MOV64_REG_IMM(block, REG_RCX, 0x8000000000000000);
host_x86_MOVQ_XREG_REG(block, REG_XMM_TEMP, REG_RCX);
host_x86_PXOR_XREG_XREG(block, dest_reg, REG_XMM_TEMP);
}
# ifdef RECOMPILER_DEBUG
else

View File

@@ -221,6 +221,7 @@ codegen_CALL_FUNC_RESULT(codeblock_t *block, uop_t *uop)
static int
codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop)
{
host_x86_MOV32_STACK_IMM(block, STACK_ARG0, uop->imm_data);
host_x86_CALL(block, uop->p);
host_x86_TEST32_REG(block, REG_EAX, REG_EAX);
host_x86_JNZ(block, codegen_exit_rout);

View File

@@ -38,7 +38,7 @@ codegen_ir_set_unroll(int count, int start, int first_instruction)
static void
duplicate_uop(ir_data_t *ir, uop_t *uop, int offset)
{
uop_t *new_uop = uop_alloc(ir, uop->type);
uop_t *new_uop = uop_alloc_unroll(ir, uop->type);
if (!ir_reg_is_invalid(uop->src_reg_a))
new_uop->src_reg_a = codegen_reg_read(uop->src_reg_a.reg);

View File

@@ -41,8 +41,8 @@
#define UOP_LOAD_FUNC_ARG_2_IMM (UOP_TYPE_PARAMS_IMM | 0x0a | UOP_TYPE_BARRIER)
#define UOP_LOAD_FUNC_ARG_3_IMM (UOP_TYPE_PARAMS_IMM | 0x0b | UOP_TYPE_BARRIER)
#define UOP_CALL_FUNC (UOP_TYPE_PARAMS_POINTER | 0x10 | UOP_TYPE_BARRIER)
/*UOP_CALL_INSTRUCTION_FUNC - call instruction handler at p, check return value and exit block if non-zero*/
#define UOP_CALL_INSTRUCTION_FUNC (UOP_TYPE_PARAMS_POINTER | 0x11 | UOP_TYPE_BARRIER)
/*UOP_CALL_INSTRUCTION_FUNC - call instruction handler at p with fetchdat, check return value and exit block if non-zero*/
#define UOP_CALL_INSTRUCTION_FUNC (UOP_TYPE_PARAMS_POINTER | UOP_TYPE_PARAMS_IMM | 0x11 | UOP_TYPE_BARRIER)
#define UOP_STORE_P_IMM (UOP_TYPE_PARAMS_IMM | 0x12)
#define UOP_STORE_P_IMM_8 (UOP_TYPE_PARAMS_IMM | 0x13)
/*UOP_LOAD_SEG - load segment in src_reg_a to segment p via loadseg(), check return value and exit block if non-zero*/
@@ -377,6 +377,34 @@ uop_alloc(ir_data_t *ir, uint32_t uop_type)
uop->jump_dest_uop = -1;
uop->jump_list_next = -1;
if (uop_type & (UOP_TYPE_BARRIER | UOP_TYPE_ORDER_BARRIER))
dirty_ir_regs[0] = dirty_ir_regs[1] = ~0ULL;
return uop;
}
static inline uop_t *
uop_alloc_unroll(ir_data_t *ir, uint32_t uop_type)
{
uop_t *uop;
if (ir->wr_pos >= UOP_NR_MAX)
fatal("Exceeded uOP max\n");
uop = &ir->uops[ir->wr_pos++];
uop->is_a16 = 0;
uop->dest_reg_a = invalid_ir_reg;
uop->src_reg_a = invalid_ir_reg;
uop->src_reg_b = invalid_ir_reg;
uop->src_reg_c = invalid_ir_reg;
uop->pc = cpu_state.oldpc;
uop->jump_dest_uop = -1;
uop->jump_list_next = -1;
if (uop_type & (UOP_TYPE_BARRIER | UOP_TYPE_ORDER_BARRIER))
codegen_reg_mark_as_required();
@@ -662,7 +690,7 @@ uop_gen_reg_src2_pointer(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int sr
#define uop_CALL_FUNC(ir, p) uop_gen_pointer(UOP_CALL_FUNC, ir, p)
#define uop_CALL_FUNC_RESULT(ir, dst_reg, p) uop_gen_reg_dst_pointer(UOP_CALL_FUNC_RESULT, ir, dst_reg, p)
#define uop_CALL_INSTRUCTION_FUNC(ir, p) uop_gen_pointer(UOP_CALL_INSTRUCTION_FUNC, ir, p)
#define uop_CALL_INSTRUCTION_FUNC(ir, p, imm) uop_gen_pointer_imm(UOP_CALL_INSTRUCTION_FUNC, ir, p, imm)
#define uop_CMP_IMM_JZ(ir, src_reg, imm, p) uop_gen_reg_src_pointer_imm(UOP_CMP_IMM_JZ, ir, src_reg, p, imm)

View File

@@ -390,6 +390,8 @@ ropPUSHF(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNUS
uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc);
uop_CALL_FUNC(ir, flags_rebuild);
sp_reg = LOAD_SP_WITH_OFFSET(ir, -2);
uop_AND_IMM(ir, IREG_flags, IREG_flags, 0x7fd5);
uop_OR_IMM(ir, IREG_flags, IREG_flags, 0x0002);
uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_flags);
SUB_SP(ir, 2);
@@ -406,6 +408,8 @@ ropPUSHFD(UNUSED(codeblock_t *block), ir_data_t *ir, UNUSED(uint8_t opcode), UNU
uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc);
uop_CALL_FUNC(ir, flags_rebuild);
uop_AND_IMM(ir, IREG_flags, IREG_flags, 0x7fd5);
uop_OR_IMM(ir, IREG_flags, IREG_flags, 0x0002);
if (cpu_CR4_mask & CR4_VME)
uop_AND_IMM(ir, IREG_temp0_W, IREG_eflags, 0x3c);
else if (CPUID)

View File

@@ -34,6 +34,8 @@ typedef struct host_reg_set_t {
static host_reg_set_t host_reg_set;
static host_reg_set_t host_fp_reg_set;
uint64_t dirty_ir_regs[2] = { 0, 0 };
enum {
REG_BYTE,
REG_WORD,
@@ -184,15 +186,36 @@ struct
[IREG_temp1d] = { REG_DOUBLE, (void *) 48, REG_FP, REG_VOLATILE },
};
static const uint8_t native_requested_sizes[9][8] =
{
[REG_BYTE][IREG_SIZE_B >> IREG_SIZE_SHIFT] = 1,
[REG_FPU_ST_BYTE][IREG_SIZE_B >> IREG_SIZE_SHIFT] = 1,
[REG_WORD][IREG_SIZE_W >> IREG_SIZE_SHIFT] = 1,
[REG_DWORD][IREG_SIZE_L >> IREG_SIZE_SHIFT] = 1,
[REG_QWORD][IREG_SIZE_D >> IREG_SIZE_SHIFT] = 1,
[REG_FPU_ST_QWORD][IREG_SIZE_D >> IREG_SIZE_SHIFT] = 1,
[REG_DOUBLE][IREG_SIZE_D >> IREG_SIZE_SHIFT] = 1,
[REG_FPU_ST_DOUBLE][IREG_SIZE_D >> IREG_SIZE_SHIFT] = 1,
[REG_QWORD][IREG_SIZE_Q >> IREG_SIZE_SHIFT] = 1,
[REG_FPU_ST_QWORD][IREG_SIZE_Q >> IREG_SIZE_SHIFT] = 1,
[REG_DOUBLE][IREG_SIZE_Q >> IREG_SIZE_SHIFT] = 1,
[REG_FPU_ST_DOUBLE][IREG_SIZE_Q >> IREG_SIZE_SHIFT] = 1,
[REG_POINTER][(sizeof(void *) == 4) ? (IREG_SIZE_L >> IREG_SIZE_SHIFT) : (IREG_SIZE_Q >> IREG_SIZE_SHIFT)] = 1
};
void
codegen_reg_mark_as_required(void)
{
for (uint8_t reg = 0; reg < IREG_COUNT; reg++) {
/* This used to start from IREG_EAX, now only starts from IREG_ESP since the first 4 registers are never optimized out. */
/* It also no longer iterates through volatile registers unnecessarily. */
for (uint8_t reg = IREG_ESP; reg < IREG_temp0; reg++) {
int last_version = reg_last_version[reg];
if (last_version > 0 && ireg_data[reg].is_volatile == REG_PERMANENT)
if (last_version > 0)
reg_version[reg][last_version].flags |= REG_FLAGS_REQUIRED;
}
dirty_ir_regs[0] = dirty_ir_regs[1] = 0;
}
int
@@ -201,29 +224,7 @@ reg_is_native_size(ir_reg_t ir_reg)
int native_size = ireg_data[IREG_GET_REG(ir_reg.reg)].native_size;
int requested_size = IREG_GET_SIZE(ir_reg.reg);
switch (native_size) {
case REG_BYTE:
case REG_FPU_ST_BYTE:
return (requested_size == IREG_SIZE_B);
case REG_WORD:
return (requested_size == IREG_SIZE_W);
case REG_DWORD:
return (requested_size == IREG_SIZE_L);
case REG_QWORD:
case REG_FPU_ST_QWORD:
case REG_DOUBLE:
case REG_FPU_ST_DOUBLE:
return ((requested_size == IREG_SIZE_D) || (requested_size == IREG_SIZE_Q));
case REG_POINTER:
if (sizeof(void *) == 4)
return (requested_size == IREG_SIZE_L);
return (requested_size == IREG_SIZE_Q);
default:
fatal("get_reg_is_native_size: unknown native size %i\n", native_size);
}
return 0;
return native_requested_sizes[native_size][requested_size >> IREG_SIZE_SHIFT];
}
void
@@ -256,6 +257,8 @@ codegen_reg_reset(void)
host_fp_reg_set.locked = 0;
host_fp_reg_set.nr_regs = CODEGEN_HOST_FP_REGS;
dirty_ir_regs[0] = dirty_ir_regs[1] = 0;
for (c = 0; c < IREG_COUNT; c++) {
reg_last_version[c] = 0;
reg_version[c][0].refcount = 0;

View File

@@ -16,59 +16,45 @@
#define IREG_SIZE_Q (5 << IREG_SIZE_SHIFT)
enum {
IREG_EAX = 0,
IREG_ECX = 1,
IREG_EDX = 2,
IREG_EBX = 3,
IREG_ESP = 4,
IREG_EBP = 5,
IREG_ESI = 6,
IREG_EDI = 7,
IREG_EAX,
IREG_ECX,
IREG_EDX,
IREG_EBX,
IREG_ESP,
IREG_EBP,
IREG_ESI,
IREG_EDI,
IREG_flags_op = 8,
IREG_flags_res = 9,
IREG_flags_op1 = 10,
IREG_flags_op2 = 11,
IREG_flags_op,
IREG_flags_res,
IREG_flags_op1,
IREG_flags_op2,
IREG_pc = 12,
IREG_oldpc = 13,
IREG_pc,
IREG_oldpc,
IREG_eaaddr = 14,
IREG_ea_seg = 15,
IREG_op32 = 16,
IREG_ssegsx = 17,
IREG_eaaddr,
IREG_ea_seg,
IREG_op32,
IREG_ssegsx,
IREG_rm_mod_reg = 18,
IREG_rm_mod_reg,
IREG_acycs = 19,
IREG_cycles = 20,
IREG_cycles,
IREG_CS_base = 21,
IREG_DS_base = 22,
IREG_ES_base = 23,
IREG_FS_base = 24,
IREG_GS_base = 25,
IREG_SS_base = 26,
IREG_CS_base,
IREG_DS_base,
IREG_ES_base,
IREG_FS_base,
IREG_GS_base,
IREG_SS_base,
IREG_CS_seg = 27,
IREG_DS_seg = 28,
IREG_ES_seg = 29,
IREG_FS_seg = 30,
IREG_GS_seg = 31,
IREG_SS_seg = 32,
/*Temporary registers are stored on the stack, and are not guaranteed to
be preserved across uOPs. They will not be written back if they will
not be read again.*/
IREG_temp0 = 33,
IREG_temp1 = 34,
IREG_temp2 = 35,
IREG_temp3 = 36,
IREG_FPU_TOP = 37,
IREG_temp0d = 38,
IREG_temp1d = 39,
IREG_CS_seg,
IREG_DS_seg,
IREG_ES_seg,
IREG_FS_seg,
IREG_GS_seg,
IREG_SS_seg,
/*FPU stack registers are physical registers. Use IREG_ST() / IREG_tag()
to access.
@@ -76,66 +62,79 @@ enum {
used directly to index the stack. When it is clear, the difference
between the current value of TOP and the value when the block was
first compiled will be added to adjust for any changes in TOP.*/
IREG_ST0 = 40,
IREG_ST1 = 41,
IREG_ST2 = 42,
IREG_ST3 = 43,
IREG_ST4 = 44,
IREG_ST5 = 45,
IREG_ST6 = 46,
IREG_ST7 = 47,
IREG_ST0,
IREG_ST1,
IREG_ST2,
IREG_ST3,
IREG_ST4,
IREG_ST5,
IREG_ST6,
IREG_ST7,
IREG_tag0 = 48,
IREG_tag1 = 49,
IREG_tag2 = 50,
IREG_tag3 = 51,
IREG_tag4 = 52,
IREG_tag5 = 53,
IREG_tag6 = 54,
IREG_tag7 = 55,
IREG_tag0,
IREG_tag1,
IREG_tag2,
IREG_tag3,
IREG_tag4,
IREG_tag5,
IREG_tag6,
IREG_tag7,
IREG_ST0_i64 = 56,
IREG_ST1_i64 = 57,
IREG_ST2_i64 = 58,
IREG_ST3_i64 = 59,
IREG_ST4_i64 = 60,
IREG_ST5_i64 = 61,
IREG_ST6_i64 = 62,
IREG_ST7_i64 = 63,
IREG_ST0_i64,
IREG_ST1_i64,
IREG_ST2_i64,
IREG_ST3_i64,
IREG_ST4_i64,
IREG_ST5_i64,
IREG_ST6_i64,
IREG_ST7_i64,
IREG_MM0x = 64,
IREG_MM1x = 65,
IREG_MM2x = 66,
IREG_MM3x = 67,
IREG_MM4x = 68,
IREG_MM5x = 69,
IREG_MM6x = 70,
IREG_MM7x = 71,
IREG_MM0x,
IREG_MM1x,
IREG_MM2x,
IREG_MM3x,
IREG_MM4x,
IREG_MM5x,
IREG_MM6x,
IREG_MM7x,
IREG_NPXCx = 72,
IREG_NPXSx = 73,
IREG_NPXCx,
IREG_NPXSx,
IREG_flagsx = 74,
IREG_eflagsx = 75,
IREG_flagsx,
IREG_eflagsx,
IREG_CS_limit_low = 76,
IREG_DS_limit_low = 77,
IREG_ES_limit_low = 78,
IREG_FS_limit_low = 79,
IREG_GS_limit_low = 80,
IREG_SS_limit_low = 81,
IREG_CS_limit_low,
IREG_DS_limit_low,
IREG_ES_limit_low,
IREG_FS_limit_low,
IREG_GS_limit_low,
IREG_SS_limit_low,
IREG_CS_limit_high = 82,
IREG_DS_limit_high = 83,
IREG_ES_limit_high = 84,
IREG_FS_limit_high = 85,
IREG_GS_limit_high = 86,
IREG_SS_limit_high = 87,
IREG_CS_limit_high,
IREG_DS_limit_high,
IREG_ES_limit_high,
IREG_FS_limit_high,
IREG_GS_limit_high,
IREG_SS_limit_high,
IREG_eaa16 = 88,
IREG_x87_op = 89,
IREG_eaa16,
IREG_x87_op,
IREG_COUNT = 90,
IREG_FPU_TOP,
/*Temporary registers are stored on the stack, and are not guaranteed to
be preserved across uOPs. They will not be written back if they will
not be read again.*/
IREG_temp0,
IREG_temp1,
IREG_temp2,
IREG_temp3,
IREG_temp0d,
IREG_temp1d,
IREG_COUNT,
IREG_INVALID = 255,
@@ -279,6 +278,7 @@ ireg_seg_limit_high(x86seg *seg)
}
extern uint8_t reg_last_version[IREG_COUNT];
extern uint64_t dirty_ir_regs[2];
/*This version of the register must be calculated, regardless of whether it is
apparently required or not. Do not optimise out.*/
@@ -363,10 +363,12 @@ codegen_reg_write(int reg, int uop_nr)
int last_version = reg_last_version[IREG_GET_REG(reg)];
reg_version_t *version;
#ifndef RELEASE_BUILD
if (IREG_GET_REG(reg) == IREG_INVALID)
fatal("codegen_reg_write - IREG_INVALID\n");
#endif
if (dirty_ir_regs[(IREG_GET_REG(reg) >> 6) & 3] & (1ull << ((uint64_t)IREG_GET_REG(reg) & 0x3full))) {
dirty_ir_regs[(IREG_GET_REG(reg) >> 6) & 3] &= ~(1ull << ((uint64_t)IREG_GET_REG(reg) & 0x3full));
if ((IREG_GET_REG(reg) > IREG_EBX && IREG_GET_REG(reg) < IREG_temp0) && last_version > 0) {
reg_version[IREG_GET_REG(reg)][last_version].flags |= REG_FLAGS_REQUIRED;
}
}
ireg.reg = reg;
ireg.version = last_version + 1;
@@ -376,12 +378,8 @@ codegen_reg_write(int reg, int uop_nr)
}
reg_last_version[IREG_GET_REG(reg)]++;
#ifndef RELEASE_BUILD
if (!reg_last_version[IREG_GET_REG(reg)])
fatal("codegen_reg_write - version overflow\n");
else
#endif
if (reg_last_version[IREG_GET_REG(reg)] > REG_VERSION_MAX)
if (reg_last_version[IREG_GET_REG(reg)] > REG_VERSION_MAX)
CPU_BLOCK_END();
if (reg_last_version[IREG_GET_REG(reg)] > max_version_refcount)
max_version_refcount = reg_last_version[IREG_GET_REG(reg)];

File diff suppressed because it is too large Load Diff

View File

@@ -739,7 +739,7 @@ exec386_dynarec(int32_t cycs)
uint64_t oldtsc;
uint64_t delta;
int32_t cyc_period = cycs / 2000; /*5us*/
int32_t cyc_period = cycs / (force_10ms ? 2000 : 200); /*5us*/
# ifdef USE_ACYCS
acycs = 0;

View File

@@ -264,6 +264,7 @@ opVPCEXT(uint32_t fetchdat)
uint8_t b2;
uint16_t cent;
time_t now;
struct tm tm_buf;
struct tm *tm = NULL;
if (!is_vpc) /* only emulate this on Virtual PC machines */
@@ -282,7 +283,16 @@ opVPCEXT(uint32_t fetchdat)
/* 0f 3f 03 xx opcodes are mostly related to the host clock, so fetch it now */
if (b1 == 0x03) {
(void) time(&now);
tm = localtime(&now);
#ifdef _WIN32
if (localtime_s(&tm_buf, &now) == 0)
tm = &tm_buf;
#else
tm = localtime_r(&now, &tm_buf);
#endif
if (!tm)
fatal("localtime() failed for host clock\n");
}
if ((b1 == 0x07) && (b2 == 0x0b)) {

File diff suppressed because it is too large Load Diff

View File

@@ -4264,7 +4264,7 @@ cpu_write(uint16_t addr, uint8_t val, UNUSED(void *priv))
cyrix_addr = val;
else if (addr < 0xf1) switch (cyrix_addr) {
default:
if (cyrix_addr >= 0xc0)
if ((cyrix_addr >= 0xc0) && (cyrix_addr != 0xff))
fatal("Writing unimplemented Cyrix register %02X\n", cyrix_addr);
break;

View File

@@ -381,7 +381,7 @@ typedef struct {
MMX_REG MM[8];
#ifdef USE_NEW_DYNAREC
# if defined(__APPLE__) && defined(__aarch64__)
# if (defined(__APPLE__) && defined(__aarch64__)) || defined(__aarch64__)
uint64_t old_fp_control;
uint64_t new_fp_control;
# else

View File

@@ -688,6 +688,23 @@ const cpu_family_t cpu_families[] = {
.cache_write_cycles = 0,
.atclk_div = 1
},
{
.name = "8",
.cpu_type = CPU_V20,
.fpus = fpus_8088,
.rspeed = 8000000,
.multi = 1,
.voltage = 5000,
.edx_reset = 0,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 0,
.mem_write_cycles = 0,
.cache_read_cycles = 0,
.cache_write_cycles = 0,
.atclk_div = 1
},
{
.name = "10",
.cpu_type = CPU_V20,
@@ -911,10 +928,10 @@ const cpu_family_t cpu_families[] = {
.internal_name = "necv30",
.cpus = (const CPU[]) {
{
.name = "5",
.name = "7.16",
.cpu_type = CPU_V30,
.fpus = fpus_80186,
.rspeed = 5000000,
.rspeed = 7159092,
.multi = 1,
.voltage = 5000,
.edx_reset = 0,
@@ -944,6 +961,23 @@ const cpu_family_t cpu_families[] = {
.cache_write_cycles = 0,
.atclk_div = 1
},
{
.name = "9.54",
.cpu_type = CPU_V30,
.fpus = fpus_80186,
.rspeed = 9545456,
.multi = 1,
.voltage = 5000,
.edx_reset = 0,
.cpuid_model = 0,
.cyrix_id = 0,
.cpu_flags = 0,
.mem_read_cycles = 0,
.mem_write_cycles = 0,
.cache_read_cycles = 0,
.cache_write_cycles = 0,
.atclk_div = 1
},
{
.name = "10",
.cpu_type = CPU_V30,

View File

@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=============================================================================*/
#include <stddef.h>
#include <stdint.h>
#include "primitiveTypes.h"
@@ -64,7 +65,7 @@ void softfloat_shiftRightJam256M(const uint64_t *aPtr, uint32_t dist, uint64_t *
{
uint64_t wordJam;
uint32_t wordDist;
uint64_t *ptr;
uint64_t *ptr = NULL;
uint8_t i, innerDist;
wordJam = 0;
@@ -89,7 +90,7 @@ void softfloat_shiftRightJam256M(const uint64_t *aPtr, uint32_t dist, uint64_t *
aPtr,
innerDist,
zPtr + indexMultiwordLoBut(4, wordDist)
);
);
if (! wordDist) goto wordJam;
} else {
aPtr += indexWordLo(4 - wordDist);

View File

@@ -326,7 +326,6 @@ reset_common(int hard)
resetreadlookup();
makemod1table();
cpu_set_edx();
mmu_perm = 4;
}
x86seg_reset();
#ifdef USE_DYNAREC

View File

@@ -121,6 +121,7 @@ opPUSHF(UNUSED(uint32_t fetchdat))
temp = (cpu_state.flags & ~I_FLAG) | 0x3000;
if (cpu_state.eflags & VIF_FLAG)
temp |= I_FLAG;
temp = (temp & 0x7fd5) | 2;
PUSH_W(temp);
} else {
x86gpf(NULL, 0);
@@ -128,6 +129,7 @@ opPUSHF(UNUSED(uint32_t fetchdat))
}
} else {
flags_rebuild();
cpu_state.flags = (cpu_state.flags & 0x7fd5) | 2;
PUSH_W(cpu_state.flags);
}
CLOCK_CYCLES(4);
@@ -149,6 +151,7 @@ opPUSHFD(UNUSED(uint32_t fetchdat))
else
tempw = cpu_state.eflags & 4;
flags_rebuild();
cpu_state.flags = (cpu_state.flags & 0x7fd5) | 2;
PUSH_L(cpu_state.flags | (tempw << 16));
CLOCK_CYCLES(4);
PREFETCH_RUN(4, 1, -1, 0, 0, 0, 1, 0);
@@ -160,23 +163,11 @@ opPOPF_186(UNUSED(uint32_t fetchdat))
{
uint16_t tempw;
if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) {
x86gpf(NULL, 0);
return 1;
}
tempw = POP_W();
if (cpu_state.abrt)
return 1;
if (!(msw & 1))
cpu_state.flags = (cpu_state.flags & 0x7000) | (tempw & 0x0fd5) | 2;
else if (!(CPL))
cpu_state.flags = (tempw & 0x7fd5) | 2;
else if (IOPLp)
cpu_state.flags = (cpu_state.flags & 0x3000) | (tempw & 0x4fd5) | 2;
else
cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2;
cpu_state.flags = (cpu_state.flags & 0x7000) | (tempw & 0x0fd5) | 2;
flags_extract();
#ifdef USE_DEBUG_REGS_486
rf_flag_no_clear = 1;

View File

@@ -121,6 +121,7 @@ opPUSHF(UNUSED(uint32_t fetchdat))
temp = (cpu_state.flags & ~I_FLAG) | 0x3000;
if (cpu_state.eflags & VIF_FLAG)
temp |= I_FLAG;
temp = (temp & 0x7fd5) | 2;
PUSH_W(temp);
} else {
x86gpf(NULL, 0);
@@ -128,6 +129,7 @@ opPUSHF(UNUSED(uint32_t fetchdat))
}
} else {
flags_rebuild();
cpu_state.flags = (cpu_state.flags & 0x7fd5) | 2;
PUSH_W(cpu_state.flags);
}
CLOCK_CYCLES(4);
@@ -149,6 +151,7 @@ opPUSHFD(UNUSED(uint32_t fetchdat))
else
tempw = cpu_state.eflags & 4;
flags_rebuild();
cpu_state.flags = (cpu_state.flags & 0x7fd5) | 2;
PUSH_L(cpu_state.flags | (tempw << 16));
CLOCK_CYCLES(4);
PREFETCH_RUN(4, 1, -1, 0, 0, 0, 1, 0);
@@ -160,23 +163,11 @@ opPOPF_186(UNUSED(uint32_t fetchdat))
{
uint16_t tempw;
if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) {
x86gpf(NULL, 0);
return 1;
}
tempw = POP_W();
if (cpu_state.abrt)
return 1;
if (!(msw & 1))
cpu_state.flags = (cpu_state.flags & 0x7000) | (tempw & 0x0fd5) | 2;
else if (!(CPL))
cpu_state.flags = (tempw & 0x7fd5) | 2;
else if (IOPLp)
cpu_state.flags = (cpu_state.flags & 0x3000) | (tempw & 0x4fd5) | 2;
else
cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2;
cpu_state.flags = (cpu_state.flags & 0x7000) | (tempw & 0x0fd5) | 2;
flags_extract();
rf_flag_no_clear = 1;

View File

@@ -753,7 +753,7 @@ opLOCK(uint32_t fetchdat)
return 0;
cpu_state.pc++;
ILLEGAL_ON((fetchdat & 0xff) == 0x90);
ILLEGAL_ON(((fetchdat & 0xff) == 0x90) || ((fetchdat & 0xff) == 0xec));
CLOCK_CYCLES(4);
PREFETCH_PREFIX();

View File

@@ -22,12 +22,12 @@
}
#define MMX_ENTER() \
if (!cpu_has_feature(CPU_FEATURE_MMX)) { \
if (!cpu_has_feature(CPU_FEATURE_MMX) || (cr0 & 0x4)) { \
cpu_state.pc = cpu_state.oldpc; \
x86illegal(); \
return 1; \
} \
if (cr0 & 0xc) { \
if (cr0 & 0x8) { \
x86_int(7); \
return 1; \
} \

View File

@@ -201,8 +201,6 @@ opMOV_CRx_r_a16(uint32_t fetchdat)
cr0 = cpu_state.regs[cpu_rm].l;
if (cpu_16bitbus)
cr0 |= 0x10;
if (!(cr0 & 0x80000000))
mmu_perm = 4;
if (hascache && !(cr0 & (1 << 30)))
cpu_cache_int_enabled = 1;
else
@@ -267,8 +265,6 @@ opMOV_CRx_r_a32(uint32_t fetchdat)
cr0 = cpu_state.regs[cpu_rm].l;
if (cpu_16bitbus)
cr0 |= 0x10;
if (!(cr0 & 0x80000000))
mmu_perm = 4;
if (hascache && !(cr0 & (1 << 30)))
cpu_cache_int_enabled = 1;
else

View File

@@ -193,8 +193,6 @@ opMOV_CRx_r_a16(uint32_t fetchdat)
cr0 = cpu_state.regs[cpu_rm].l;
if (cpu_16bitbus)
cr0 |= 0x10;
if (!(cr0 & 0x80000000))
mmu_perm = 4;
if (hascache && !(cr0 & (1 << 30)))
cpu_cache_int_enabled = 1;
else
@@ -255,8 +253,6 @@ opMOV_CRx_r_a32(uint32_t fetchdat)
cr0 = cpu_state.regs[cpu_rm].l;
if (cpu_16bitbus)
cr0 |= 0x10;
if (!(cr0 & 0x80000000))
mmu_perm = 4;
if (hascache && !(cr0 & (1 << 30)))
cpu_cache_int_enabled = 1;
else

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

@@ -349,12 +349,6 @@ device_reset_all(uint32_t match_flags)
devices[c]->reset(device_priv[c]);
}
}
#ifdef UNCOMMENT_LATER
/* TODO: Actually convert the LPT devices to device_t's. */
if ((match_flags == DEVICE_ALL) || (match_flags == DEVICE_PCI))
lpt_reset();
#endif
}
void *
@@ -390,42 +384,18 @@ device_get_priv(const device_t *dev)
int
device_available(const device_t *dev)
{
if (dev != NULL) {
const device_config_t *config = dev->config;
if (config != NULL) {
while (config->type != CONFIG_END) {
if (config->type == CONFIG_BIOS) {
int roms_present = 0;
const device_config_bios_t *bios = (const device_config_bios_t *) config->bios;
/* Go through the ROM's in the device configuration. */
while ((bios != NULL) &&
(bios->name != NULL) &&
(bios->internal_name != NULL) &&
(bios->files_no != 0)) {
int i = 0;
for (uint8_t bf = 0; bf < bios->files_no; bf++)
i += !!rom_present(bios->files[bf]);
if (i == bios->files_no)
roms_present++;
bios++;
}
return (roms_present ? -1 : 0);
}
config++;
}
}
int ret = machine_device_available(dev);
if (ret == 0) {
/* No CONFIG_BIOS field present, use the classic available(). */
if (dev->available != NULL)
return (dev->available());
ret = (dev->available());
else
return 1;
}
ret = (dev != NULL);
} else
ret = (ret == -1);
/* A NULL device is never available. */
return 0;
return ret;
}
uint8_t
@@ -493,7 +463,6 @@ device_get_bios_local(const device_t *dev, const char *internal_name)
(bios->name != NULL) &&
(bios->internal_name != NULL) &&
(bios->files_no != 0)) {
printf("Internal name was: %s", internal_name);
if (!strcmp(internal_name, bios->internal_name))
return bios->local;
bios++;
@@ -690,9 +659,9 @@ device_get_name(const device_t *dev, int bus, char *name)
fbus = strstr(tname, sbus);
if (fbus == tname)
strcat(name, tname + strlen(sbus) + 1);
/* Special case to not strip the "oPCI" from "Ensoniq AudioPCI" or
the "-ISA" from "AMD PCnet-ISA". */
else if ((fbus == NULL) || (*(fbus - 1) == 'o') || (*(fbus - 1) == '-') || (*(fbus - 2) == 'r'))
/* Special case to not strip the "oPCI" from "Ensoniq AudioPCI",
the "-ISA" from "AMD PCnet-ISA" or the " PCI" from "CMD PCI-064x". */
else if ((fbus == NULL) || (*(fbus - 1) == 'o') || (*(fbus - 1) == '-') || (*(fbus - 2) == 'r') || ((fbus[0] == 'P') && (fbus[1] == 'C') && (fbus[2] == 'I') && (fbus[3] == '-')))
strcat(name, tname);
else {
strncat(name, tname, fbus - tname - 1);
@@ -921,8 +890,14 @@ device_is_valid(const device_t *device, int mch)
{
int ret = 1;
if ((device != NULL) && ((device->flags & DEVICE_BUS) != 0))
ret = machine_has_bus(mch, device->flags & DEVICE_BUS);
if ((device != NULL) && ((device->flags & DEVICE_BUS) != 0)) {
/* Hide PCI devices on machines with only an internal PCI bus. */
if ((device->flags & DEVICE_PCI) &&
machine_has_flags(mch, MACHINE_PCI_INTERNAL))
ret = 0;
else
ret = machine_has_bus(mch, device->flags & DEVICE_BUS);
}
return ret;
}
@@ -969,6 +944,36 @@ machine_get_config_string(char *str)
return ret;
}
int
machine_device_available(const device_t *dev)
{
if (dev != NULL) {
const device_config_t *config = dev->config;
if ((config != NULL) && (config->type == CONFIG_BIOS)) {
int roms_present = 0;
const device_config_bios_t *bios = (const device_config_bios_t *) config->bios;
/* Go through the ROM's in the device configuration. */
while ((bios != NULL) &&
(bios->name != NULL) &&
(bios->internal_name != NULL) &&
(bios->files_no != 0)) {
int i = 0;
for (uint8_t bf = 0; bf < bios->files_no; bf++)
i += !!rom_present(bios->files[bf]);
if (i == bios->files_no)
roms_present++;
bios++;
}
return (roms_present ? -1 : -2);
}
}
/* NULL device or no CONFIG_BIOS field, return 0. */
return 0;
}
const device_t *
device_context_get_device(void)
{

View File

@@ -22,6 +22,7 @@ add_library(dev OBJECT
cartridge.c
cassette.c
clock_ics9xxx.c
dell_jumper.c
hasp.c
hwm.c
hwm_gl518sm.c
@@ -32,19 +33,22 @@ add_library(dev OBJECT
i2c_gpio.c
ibm_5161.c
isamem.c
isarom.c
isartc.c
isapnp.c
kbc_at.c
kbc_at_dev.c
kbc_xt.c
keyboard.c
keyboard_at.c
keyboard_xt.c
../lpt.c
lpt.c
mouse.c
mouse_bus.c
mouse_microtouch_touchscreen.c
mouse_ps2.c
mouse_serial.c
mouse_upc.c
nec_mate_unk.c
novell_cardkey.c
pci_bridge.c
@@ -55,6 +59,7 @@ add_library(dev OBJECT
smbus_ali7101.c
smbus_piix4.c
smbus_sis5595.c
tulip_jumper.c
unittester.c
)

View File

@@ -152,10 +152,11 @@ pc_cas_del(pc_cassette_t *cas)
}
int
pc_cas_set_fname(pc_cassette_t *cas, const char *fname)
pc_cas_set_fname(pc_cassette_t *cas, char *fname)
{
unsigned n;
const char *ext;
int offs = 0;
if (cas->close)
fclose(cas->fp);
@@ -176,6 +177,13 @@ pc_cas_set_fname(pc_cassette_t *cas, const char *fname)
return 0;
}
if (strstr(fname, "wp://") == fname) {
offs = 5;
cassette_ui_writeprot = 1;
}
fname += offs;
cas->fp = plat_fopen(fname, "r+b");
if (cas->fp == NULL)
@@ -197,10 +205,10 @@ pc_cas_set_fname(pc_cassette_t *cas, const char *fname)
n = strlen(fname);
cas->fname = malloc((n + 1) * sizeof(char));
cas->fname = malloc((n + offs + 1) * sizeof(char));
if (cas->fname != NULL)
memcpy(cas->fname, fname, (n + 1) * sizeof(char));
memcpy(cas->fname, fname - offs, (n + offs + 1) * sizeof(char));
if (n > 4) {
ext = fname + (n - 4);
@@ -216,6 +224,8 @@ pc_cas_set_fname(pc_cassette_t *cas, const char *fname)
pc_cas_set_pcm(cas, 0);
}
ui_sb_update_icon_wp(SB_CASSETTE, cassette_ui_writeprot);
return 0;
}

175
src/device/dell_jumper.c Normal file
View File

@@ -0,0 +1,175 @@
/*
* 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.
*
* Implementation of the Dell 486 and 586 Jumper Readout.
*
* Register 0x02:
* - Bit 0: ATX power: 1 = off, 0 = on.
*
* Register 0x05:
* - Appears to be: 0x02 = On-board audio enabled;
* 0x07 = On-board audio disabled.
*
* Register 0x07:
* - Bit 0: On-board NIC: 1 = present, 0 = absent;
* - Bit 1: On-board audio: 1 = present, 0 = absent;
* - Bits 4-2:
* - 0, 0, 0 = GXL;
* - 0, 0, 1 = GL+;
* - 0, 1, 0 = GXMT;
* - 0, 1, 1 = GMT+;
* - 1, 0, 0 = GXM;
* - 1, 0, 1 = GM+;
* - 1, 1, 0 = WS;
* - 1, 1, 1 = GWS+.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2025 Miran Grca.
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include "cpu.h"
#include <86box/timer.h>
#include <86box/io.h>
#include <86box/device.h>
#include <86box/machine.h>
#include <86box/sound.h>
#include <86box/chipset.h>
#include <86box/plat.h>
#include <86box/plat_unused.h>
typedef struct dell_jumper_t {
uint8_t index;
uint8_t regs[256];
} dell_jumper_t;
#ifdef ENABLE_DELL_JUMPER_LOG
int dell_jumper_do_log = ENABLE_DELL_JUMPER_LOG;
static void
dell_jumper_log(const char *fmt, ...)
{
va_list ap;
if (dell_jumper_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define dell_jumper_log(fmt, ...)
#endif
static void
dell_jumper_write(uint16_t addr, uint8_t val, void *priv)
{
dell_jumper_t *dev = (dell_jumper_t *) priv;
dell_jumper_log("Dell Jumper: Write %02x\n", val);
if (addr & 1) switch (dev->index) {
default:
dev->regs[dev->index] = val;
break;
case 0x02:
dev->regs[dev->index] = val;
if (val & 0x04)
/* Soft power off. */
plat_power_off();
break;
case 0x05:
dev->regs[dev->index] = (dev->regs[dev->index] & 0x02) | (val & 0xfd);
if (machine_snd != NULL) switch (val & 0x05) {
default:
case 0x05:
sb_vibra16s_onboard_relocate_base(0x0000, machine_snd);
break;
case 0x00:
sb_vibra16s_onboard_relocate_base(0x0220, machine_snd);
break;
}
break;
case 0x07:
break;
} else
dev->index = val;
}
static uint8_t
dell_jumper_read(uint16_t addr, void *priv)
{
const dell_jumper_t *dev = (dell_jumper_t *) priv;
uint8_t ret = 0xff;
dell_jumper_log("Dell Jumper: Read %02x\n", dev->jumper);
if (addr & 1)
ret = dev->regs[dev->index];
else
ret = dev->index;
return ret;
}
static void
dell_jumper_reset(void *priv)
{
dell_jumper_t *dev = (dell_jumper_t *) priv;
dev->index = 0x00;
memset(dev->regs, 0x00, 256);
if (sound_card_current[0] == SOUND_INTERNAL)
/* GXL, on-board audio present, on-board NIC absent. */
dev->regs[0x07] = 0x02;
else
/* GXL, on-board audio absent, on-board NIC absent. */
dev->regs[0x07] = 0x00;
}
static void
dell_jumper_close(void *priv)
{
dell_jumper_t *dev = (dell_jumper_t *) priv;
free(dev);
}
static void *
dell_jumper_init(const device_t *info)
{
dell_jumper_t *dev = (dell_jumper_t *) calloc(1, sizeof(dell_jumper_t));
dell_jumper_reset(dev);
io_sethandler(0x00e8, 0x0002, dell_jumper_read, NULL, NULL, dell_jumper_write, NULL, NULL, dev);
return dev;
}
const device_t dell_jumper_device = {
.name = "Dell Jumper Readout",
.internal_name = "dell_jumper",
.flags = 0,
.local = 0,
.init = dell_jumper_init,
.close = dell_jumper_close,
.reset = dell_jumper_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -27,8 +27,9 @@
#include <stdarg.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/lpt.h>
#include <86box/timer.h>
#include <86box/device.h>
#include <86box/lpt.h>
#define HASP_BYTEARRAY(...) \
{ \
@@ -334,13 +335,16 @@ hasp_close(void *priv)
}
const lpt_device_t lpt_hasp_savquest_device = {
.name = "Protection Dongle for Savage Quest",
.internal_name = "dongle_savquest",
.init = hasp_init_savquest,
.close = hasp_close,
.write_data = hasp_write_data,
.write_ctrl = NULL,
.read_data = NULL,
.read_status = hasp_read_status,
.read_ctrl = NULL
.name = "Protection Dongle for Savage Quest",
.internal_name = "dongle_savquest",
.init = hasp_init_savquest,
.close = hasp_close,
.write_data = hasp_write_data,
.write_ctrl = NULL,
.autofeed = NULL,
.strobe = NULL,
.read_status = hasp_read_status,
.read_ctrl = NULL,
.epp_write_data = NULL,
.epp_request_read = NULL
};

View File

@@ -107,6 +107,7 @@
#define ISAMEM_BRAT_CARD 14
#define ISAMEM_EV165A_CARD 15
#define ISAMEM_LOTECH_EMS_CARD 16
#define ISAMEM_MPLUS2_CARD 17
#define ISAMEM_DEBUG 0
@@ -495,6 +496,7 @@ isamem_init(const device_t *info)
case ISAMEM_SYSTEMCARD_CARD: /* Microsoft SystemCard */
case ISAMEM_P5PAK_CARD: /* Paradise Systems 5-PAK */
case ISAMEM_A6PAK_CARD: /* AST SixPakPlus */
case ISAMEM_MPLUS2_CARD: /* AST MegaPlus II */
dev->total_size = device_get_config_int("size");
dev->start_addr = device_get_config_int("start");
tot = dev->total_size;
@@ -1391,10 +1393,10 @@ static const device_config_t ems5150_config[] = {
.spinner = { 0 },
.selection = {
{ .description = "Disabled", .value = 0x0000 },
{ .description = "Board 1", .value = 0x0208 },
{ .description = "Board 2", .value = 0x020a },
{ .description = "Board 3", .value = 0x020c },
{ .description = "Board 4", .value = 0x020e },
{ .description = "208H", .value = 0x0208 },
{ .description = "20AH", .value = 0x020a },
{ .description = "20CH", .value = 0x020c },
{ .description = "20EH", .value = 0x020e },
{ .description = "" }
},
.bios = { { 0 } }
@@ -2094,6 +2096,54 @@ static const device_t iab_device = {
};
#endif /* USE_ISAMEM_IAB */
static const device_config_t mplus2_config[] = {
// clang-format off
{
.name = "size",
.description = "Memory Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 64,
.file_filter = "",
.spinner = {
.min = 0,
.max = 512,
.step = 64
},
.selection = { { 0 } }
},
{
.name = "start",
.description = "Start Address",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 256,
.file_filter = "",
.spinner = {
.min = 64,
.max = 576,
.step = 64
},
.selection = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_t mplus2_device = {
.name = "AST MegaPlus II",
.internal_name = "mplus2",
.flags = DEVICE_ISA,
.local = ISAMEM_MPLUS2_CARD,
.init = isamem_init,
.close = isamem_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = mplus2_config
};
static const struct {
const device_t *dev;
} boards[] = {
@@ -2127,6 +2177,7 @@ static const struct {
{ &iab_device },
#endif /* USE_ISAMEM_IAB */
{ &lotech_ems_device },
{ &mplus2_device },
{ NULL }
// clang-format on
};
@@ -2165,12 +2216,12 @@ isamem_get_internal_name(int board)
}
int
isamem_get_from_internal_name(const char *s)
isamem_get_from_internal_name(const char *str)
{
int c = 0;
while (boards[c].dev != NULL) {
if (!strcmp(boards[c].dev->internal_name, s))
if (!strcmp(boards[c].dev->internal_name, str))
return c;
c++;
}

706
src/device/isarom.c Normal file
View File

@@ -0,0 +1,706 @@
/*
* 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.
*
* Implementation of ISA ROM card Expansions.
*
* Authors: Jasmine Iwanek, <jriwanek@gmail.com>
*
* Copyright 2025 Jasmine Iwanek.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/io.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/rom.h>
#include <86box/nvr.h>
#include <86box/isarom.h>
enum {
ISAROM_CARD = 0,
ISAROM_CARD_DUAL,
ISAROM_CARD_QUAD,
ISAROM_CARD_LBA_ENHANCER
};
#define BIOS_LBA_ENHANCER "roms/hdd/misc/lbaenhancer.bin"
#ifdef ENABLE_ISAROM_LOG
int isarom_do_log = ENABLE_ISAROM_LOG;
static void
isarom_log(const char *fmt, ...)
{
va_list ap;
if (isarom_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define isarom_log(fmt, ...)
#endif
typedef struct isarom_t {
struct {
rom_t rom;
uint32_t addr;
const char *fn;
uint32_t size;
uint32_t len;
char nvr_path[64];
uint8_t writable;
} socket[4];
uint8_t inst;
uint8_t type;
} isarom_t;
static inline uint8_t
get_limit(uint8_t type)
{
switch (type) {
case ISAROM_CARD_DUAL:
return 2;
case ISAROM_CARD_QUAD:
return 4;
default:
return 1;
}
}
static inline void
isarom_save_nvr(char *path, uint8_t *data, size_t size)
{
if (path[0] == 0x00)
return;
FILE *fp = nvr_fopen(path, "wb");
if (fp) {
fwrite(data, 1, size, fp);
fclose(fp);
}
}
void
isarom_close(void *priv)
{
isarom_t *dev = (isarom_t *) priv;
if (!priv)
return;
for (uint8_t i = 0; i < get_limit(dev->type); i++) {
if (dev->socket[i].writable) {
isarom_log("isarom[%u]: saving NVR for socket %u -> %s (%u bytes)\n",
dev->inst, i, dev->socket[i].nvr_path, dev->socket[i].size);
isarom_save_nvr(dev->socket[i].nvr_path, dev->socket[i].rom.rom, dev->socket[i].size);
}
}
free(dev);
}
static void *
isarom_init(const device_t *info)
{
isarom_t *dev = (isarom_t *) calloc(1, sizeof(isarom_t));
if (!dev)
return NULL;
dev->inst = device_get_instance();
dev->type = (uint8_t) info->local;
isarom_log("isarom[%u]: initializing device (type=%u)\n", dev->inst, dev->type);
for (uint8_t i = 0; i < get_limit(dev->type); i++) {
char str[22];
char suffix[4] = "";
if (i > 0)
snprintf(suffix, sizeof(suffix), "%d", i + 1);
snprintf(str, sizeof(str), "bios_addr%s", suffix);
dev->socket[i].addr = device_get_config_hex20(str);
switch (dev->type) {
case ISAROM_CARD_LBA_ENHANCER:
dev->socket[i].fn = BIOS_LBA_ENHANCER;
dev->socket[i].size = 0x4000;
break;
default:
snprintf(str, sizeof(str), "bios_fn%s", suffix);
dev->socket[i].fn = device_get_config_string(str);
snprintf(str, sizeof(str), "bios_size%s", suffix);
dev->socket[i].size = device_get_config_int(str);
snprintf(str, sizeof(str), "rom_writes_enabled%s", suffix);
if (device_get_config_int(str))
dev->socket[i].writable = 1;
break;
}
/* Note: 2K is the smallest ROM I've found, but 86Box's memory granularity is 4K, the number
below is fine as we'll end up allocating no less than 4K due to the device config limits. */
dev->socket[i].len = (dev->socket[i].size > 0) ? ((dev->socket[i].size - 1) | MEM_GRANULARITY_MASK) : 0;
isarom_log("isarom[%u]: socket %u: addr=0x%05X size=%u writable=%u fn=%s\n",
dev->inst, i, dev->socket[i].addr, dev->socket[i].size,
dev->socket[i].writable, dev->socket[i].fn ? dev->socket[i].fn : "(null)");
if ((dev->socket[i].addr != 0) && (dev->socket[i].fn != NULL)) {
rom_init(&dev->socket[i].rom,
dev->socket[i].fn,
dev->socket[i].addr,
dev->socket[i].size,
dev->socket[i].len,
0,
MEM_MAPPING_EXTERNAL);
isarom_log("isarom[%u]: ROM initialized for socket %u\n", dev->inst, i);
if (dev->socket[i].writable) {
mem_mapping_set_write_handler(&dev->socket[i].rom.mapping, rom_write, rom_writew, rom_writel);
snprintf(dev->socket[i].nvr_path, sizeof(dev->socket[i].nvr_path), "isarom_%i_%i.nvr", dev->inst, i + 1);
FILE *fp = nvr_fopen(dev->socket[i].nvr_path, "rb");
if (fp != NULL) {
(void) !fread(dev->socket[i].rom.rom, 1, dev->socket[i].size, fp);
fclose(fp);
isarom_log("isarom[%u]: loaded %zu bytes from %s\n", dev->inst, read_bytes, dev->socket[i].nvr_path);
} else
isarom_log("isarom[%u]: NVR not found, skipping load (%s)\n", dev->inst, dev->socket[i].nvr_path);
}
}
}
return dev;
}
static int
isarom_lba_enhancer_available(void)
{
return rom_present(BIOS_LBA_ENHANCER);
}
#define BIOS_FILE_FILTER "ROM files (*.bin *.rom)|*.bin,*.rom"
#define BIOS_ADDR_SELECTION { \
{ "Disabled", 0x00000 }, \
{ "C000H", 0xc0000 }, \
{ "C200H", 0xc2000 }, \
{ "C400H", 0xc4000 }, \
{ "C600H", 0xc6000 }, \
{ "C800H", 0xc8000 }, \
{ "CA00H", 0xca000 }, \
{ "CC00H", 0xcc000 }, \
{ "CE00H", 0xce000 }, \
{ "D000H", 0xd0000 }, \
{ "D200H", 0xd2000 }, \
{ "D400H", 0xd4000 }, \
{ "D600H", 0xd6000 }, \
{ "D800H", 0xd8000 }, \
{ "DA00H", 0xda000 }, \
{ "DC00H", 0xdc000 }, \
{ "DE00H", 0xde000 }, \
{ "E000H", 0xe0000 }, \
{ "E200H", 0xe2000 }, \
{ "E400H", 0xe4000 }, \
{ "E600H", 0xe6000 }, \
{ "E800H", 0xe8000 }, \
{ "EA00H", 0xea000 }, \
{ "EC00H", 0xec000 }, \
{ "EE00H", 0xee000 }, \
{ "", 0 } \
}
#define BIOS_SIZE_SELECTION { \
{ "4K", 4096 }, \
{ "8K", 8192 }, \
{ "16K", 16384 }, \
{ "32K", 32768 }, \
{ "64K", 65536 }, \
{ "", 0 } \
}
// clang-format off
static const device_config_t isarom_config[] = {
{
.name = "bios_fn",
.description = "BIOS file",
.type = CONFIG_FNAME,
.default_string = NULL,
.default_int = 0,
.file_filter = BIOS_FILE_FILTER,
.spinner = { 0 },
.selection = { },
.bios = { { 0 } }
},
{
.name = "bios_addr",
.description = "BIOS address",
.type = CONFIG_HEX20,
.default_string = NULL,
.default_int = 0x00000,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_ADDR_SELECTION,
.bios = { { 0 } }
},
{
.name = "bios_size",
.description = "BIOS size",
.type = CONFIG_INT,
.default_string = NULL,
.default_int = 8192,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_SIZE_SELECTION,
.bios = { { 0 } }
},
{
.name = "rom_writes_enabled",
.description = "Enable BIOS extension ROM Writes",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
static const device_config_t isarom_dual_config[] = {
{
.name = "bios_fn",
.description = "BIOS file (ROM #1)",
.type = CONFIG_FNAME,
.default_string = NULL,
.default_int = 0,
.file_filter = BIOS_FILE_FILTER,
.spinner = { 0 },
.selection = { },
.bios = { { 0 } }
},
{
.name = "bios_addr",
.description = "BIOS address (ROM #1)",
.type = CONFIG_HEX20,
.default_string = NULL,
.default_int = 0x00000,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_ADDR_SELECTION,
.bios = { { 0 } }
},
{
.name = "bios_size",
.description = "BIOS size (ROM #1)",
.type = CONFIG_INT,
.default_string = NULL,
.default_int = 8192,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_SIZE_SELECTION,
.bios = { { 0 } }
},
{
.name = "rom_writes_enabled",
.description = "Enable BIOS extension ROM Writes (ROM #1)",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{
.name = "bios_fn2",
.description = "BIOS file (ROM #2)",
.type = CONFIG_FNAME,
.default_string = NULL,
.default_int = 0,
.file_filter = BIOS_FILE_FILTER,
.spinner = { 0 },
.selection = { },
.bios = { { 0 } }
},
{
.name = "bios_addr2",
.description = "BIOS address (ROM #2)",
.type = CONFIG_HEX20,
.default_string = NULL,
.default_int = 0x00000,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_ADDR_SELECTION,
.bios = { { 0 } }
},
{
.name = "bios_size2",
.description = "BIOS size (ROM #2)",
.type = CONFIG_INT,
.default_string = NULL,
.default_int = 8192,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_SIZE_SELECTION,
.bios = { { 0 } }
},
{
.name = "rom_writes_enabled2",
.description = "Enable BIOS extension ROM Writes (ROM #2)",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
static const device_config_t isarom_quad_config[] = {
{
.name = "bios_fn",
.description = "BIOS file (ROM #1)",
.type = CONFIG_FNAME,
.default_string = NULL,
.default_int = 0,
.file_filter = BIOS_FILE_FILTER,
.spinner = { 0 },
.selection = { },
.bios = { { 0 } }
},
{
.name = "bios_addr",
.description = "BIOS address (ROM #1)",
.type = CONFIG_HEX20,
.default_string = NULL,
.default_int = 0x00000,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_ADDR_SELECTION,
.bios = { { 0 } }
},
{
.name = "bios_size",
.description = "BIOS size (ROM #1)",
.type = CONFIG_INT,
.default_string = NULL,
.default_int = 8192,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_SIZE_SELECTION,
.bios = { { 0 } }
},
{
.name = "rom_writes_enabled",
.description = "Enable BIOS extension ROM Writes (ROM #1)",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{
.name = "bios_fn2",
.description = "BIOS file (ROM #2)",
.type = CONFIG_FNAME,
.default_string = NULL,
.default_int = 0,
.file_filter = BIOS_FILE_FILTER,
.spinner = { 0 },
.selection = { },
.bios = { { 0 } }
},
{
.name = "bios_addr2",
.description = "BIOS address (ROM #2)",
.type = CONFIG_HEX20,
.default_string = NULL,
.default_int = 0x00000,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_ADDR_SELECTION,
.bios = { { 0 } }
},
{
.name = "bios_size2",
.description = "BIOS size (ROM #2)",
.type = CONFIG_INT,
.default_string = NULL,
.default_int = 8192,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_SIZE_SELECTION,
.bios = { { 0 } }
},
{
.name = "rom_writes_enabled2",
.description = "Enable BIOS extension ROM Writes (ROM #2)",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{
.name = "bios_fn3",
.description = "BIOS file (ROM #3)",
.type = CONFIG_FNAME,
.default_string = NULL,
.default_int = 0,
.file_filter = BIOS_FILE_FILTER,
.spinner = { 0 },
.selection = { },
.bios = { { 0 } }
},
{
.name = "bios_addr3",
.description = "BIOS address (ROM #3)",
.type = CONFIG_HEX20,
.default_string = NULL,
.default_int = 0x00000,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_ADDR_SELECTION,
.bios = { { 0 } }
},
{
.name = "bios_size3",
.description = "BIOS size (ROM #3)",
.type = CONFIG_INT,
.default_string = NULL,
.default_int = 8192,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_SIZE_SELECTION,
.bios = { { 0 } }
},
{
.name = "rom_writes_enabled3",
.description = "Enable BIOS extension ROM Writes (ROM #3)",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{
.name = "bios_fn4",
.description = "BIOS file (ROM #4)",
.type = CONFIG_FNAME,
.default_string = NULL,
.default_int = 0,
.file_filter = BIOS_FILE_FILTER,
.spinner = { 0 },
.selection = { },
.bios = { { 0 } }
},
{
.name = "bios_addr4",
.description = "BIOS address (ROM #4)",
.type = CONFIG_HEX20,
.default_string = NULL,
.default_int = 0x00000,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_ADDR_SELECTION,
.bios = { { 0 } }
},
{
.name = "bios_size4",
.description = "BIOS size (ROM #4)",
.type = CONFIG_INT,
.default_string = NULL,
.default_int = 8192,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_SIZE_SELECTION,
.bios = { { 0 } }
},
{
.name = "rom_writes_enabled4",
.description = "Enable BIOS extension ROM Writes (ROM #4)",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
static const device_config_t lba_enhancer_config[] = {
{
.name = "bios_addr",
.description = "BIOS address",
.type = CONFIG_HEX20,
.default_string = NULL,
.default_int = 0xc8000,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "C800H", .value = 0xc8000 },
{ .description = "CC00H", .value = 0xcc000 },
{ .description = "D000H", .value = 0xd0000 },
{ .description = "D400H", .value = 0xd4000 },
{ .description = "D800H", .value = 0xd8000 },
{ .description = "DC00H", .value = 0xdc000 },
{ .description = "" }
},
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
// clang-format on
static const device_t isarom_device = {
.name = "Generic ISA ROM Board",
.internal_name = "isarom",
.flags = DEVICE_ISA,
.local = ISAROM_CARD,
.init = isarom_init,
.close = isarom_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = isarom_config
};
static const device_t isarom_dual_device = {
.name = "Generic Dual ISA ROM Board",
.internal_name = "isarom_dual",
.flags = DEVICE_ISA,
.local = ISAROM_CARD_DUAL,
.init = isarom_init,
.close = isarom_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = isarom_dual_config
};
static const device_t isarom_quad_device = {
.name = "Generic Quad ISA ROM Board",
.internal_name = "isarom_quad",
.flags = DEVICE_ISA,
.local = ISAROM_CARD_QUAD,
.init = isarom_init,
.close = isarom_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = isarom_quad_config
};
static const device_t lba_enhancer_device = {
.name = "Vision Systems LBA Enhancer",
.internal_name = "lba_enhancer",
.flags = DEVICE_ISA,
.local = ISAROM_CARD_LBA_ENHANCER,
.init = isarom_init,
.close = isarom_close,
.reset = NULL,
.available = isarom_lba_enhancer_available,
.speed_changed = NULL,
.force_redraw = NULL,
.config = lba_enhancer_config
};
static const struct {
const device_t *dev;
} boards[] = {
// clang-format off
{ &device_none },
{ &isarom_device },
{ &isarom_dual_device },
{ &isarom_quad_device },
{ &lba_enhancer_device },
{ NULL }
// clang-format on
};
void
isarom_reset(void)
{
for (uint8_t i = 0; i < ISAROM_MAX; i++) {
if (isarom_type[i] == 0)
continue;
/* Add the device instance to the system. */
device_add_inst(boards[isarom_type[i]].dev, i + 1);
}
}
const char *
isarom_get_name(int board)
{
if (boards[board].dev == NULL)
return NULL;
return (boards[board].dev->name);
}
const char *
isarom_get_internal_name(int board)
{
return device_get_internal_name(boards[board].dev);
}
int
isarom_get_from_internal_name(const char *str)
{
int c = 0;
while (boards[c].dev != NULL) {
if (!strcmp(boards[c].dev->internal_name, str))
return c;
c++;
}
/* Not found. */
return 0;
}
const device_t *
isarom_get_device(int board)
{
/* Add the device instance to the system. */
return boards[board].dev;
}
int
isarom_has_config(int board)
{
if (boards[board].dev == NULL)
return 0;
return (boards[board].dev->config ? 1 : 0);
}

View File

@@ -89,10 +89,11 @@
#define ISARTC_P5PAK 2
#define ISARTC_A6PAK 3
#define ISARTC_VENDEX 4
#define ISARTC_MPLUS2 5
#define ISARTC_MM58167 10
#define ISARTC_ROM_MM58167_1 "roms/rtc/glatick/GLaTICK_0.8.5_NS_RP.ROM"
#define ISARTC_ROM_MM58167_2 "roms/rtc/glatick/GLaTICK_0.8.5_86B.ROM"
#define ISARTC_ROM_MM58167_1 "roms/rtc/glatick/GLaTICK_0.8.8_NS_86B.ROM" /* Generic 58167, AST or EV-170 */
#define ISARTC_ROM_MM58167_2 "roms/rtc/glatick/GLaTICK_0.8.8_NS_86B2.ROM" /* PII-147 */
#define ISARTC_DEBUG 0
@@ -409,6 +410,7 @@ mm67_read(uint16_t port, void *priv)
break;
case MM67_AL_MSEC:
case MM67_MSEC:
ret = dev->nvr.regs[reg] & 0xf0;
break;
@@ -416,6 +418,10 @@ mm67_read(uint16_t port, void *priv)
ret = dev->nvr.regs[reg] & 0x0f;
break;
case MM67_DOW:
ret = dev->nvr.regs[reg] & 0x07;
break;
default:
ret = dev->nvr.regs[reg];
break;
@@ -532,8 +538,8 @@ isartc_init(const device_t *info)
switch (dev->board) {
case ISARTC_MM58167: /* Generic MM58167 RTC */
{
int rom_addr = device_get_config_hex20("bios_addr");
if (rom_addr != -1)
uint32_t rom_addr = device_get_config_hex20("bios_addr");
if (rom_addr != 0)
rom_init(&dev->rom, ISARTC_ROM_MM58167_1,
rom_addr, 0x0800, 0x7ff, 0, MEM_MAPPING_EXTERNAL);
@@ -563,8 +569,9 @@ isartc_init(const device_t *info)
dev->year = MM67_AL_HUNTEN; /* year, NON STANDARD */
break;
case ISARTC_P5PAK: /* Paradise Systems 5PAK */
case ISARTC_A6PAK: /* AST SixPakPlus */
case ISARTC_P5PAK: /* Paradise Systems 5PAK */
case ISARTC_A6PAK: /* AST SixPakPlus */
case ISARTC_MPLUS2: /* AST MegaPlus II */
dev->flags |= FLAG_YEAR80;
dev->base_addr = 0x02c0;
dev->base_addrsz = 32;
@@ -786,6 +793,42 @@ static const device_t a6pak_device = {
.config = a6pak_config
};
static const device_config_t mplus2_config[] = {
// clang-format off
{
.name = "irq",
.description = "IRQ",
.type = CONFIG_SELECTION,
.default_string = "",
.default_int = -1,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ "Disabled", -1 },
{ "IRQ2", 2 },
{ "IRQ3", 3 },
{ "IRQ5", 5 },
{ "" }
},
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_t mplus2_device = {
.name = "AST MegaPlus II",
.internal_name = "mplus2",
.flags = DEVICE_ISA,
.local = ISARTC_MPLUS2,
.init = isartc_init,
.close = isartc_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = mplus2_config
};
static const device_config_t mm58167_config[] = {
// clang-format off
{
@@ -823,14 +866,14 @@ static const device_config_t mm58167_config[] = {
},
{
.name = "bios_addr",
.description = "BIOS Address",
.description = "BIOS address",
.type = CONFIG_HEX20,
.default_string = NULL,
.default_int = 0xcc000,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "Disabled", .value = -1 },
{ .description = "Disabled", .value = 0x00000 },
{ .description = "C800H", .value = 0xc8000 },
{ .description = "CA00H", .value = 0xca000 },
{ .description = "CC00H", .value = 0xcc000 },
@@ -897,6 +940,7 @@ static const struct {
{ &pii147_device },
{ &p5pak_device },
{ &a6pak_device },
{ &mplus2_device },
{ &mm58167_device },
{ NULL }
// clang-format on
@@ -919,12 +963,12 @@ isartc_get_internal_name(int board)
}
int
isartc_get_from_internal_name(char *s)
isartc_get_from_internal_name(const char *str)
{
int c = 0;
while (boards[c].dev != NULL) {
if (!strcmp(boards[c].dev->internal_name, s))
if (!strcmp(boards[c].dev->internal_name, str))
return c;
c++;
}

File diff suppressed because it is too large Load Diff

View File

@@ -8,11 +8,9 @@
*
* AT / PS/2 attached device emulation.
*
*
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2023 Miran Grca.
* Copyright 2023-2025 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
@@ -22,23 +20,9 @@
#define HAVE_STDARG_H
#include <wchar.h>
#include <86box/86box.h>
#include "cpu.h"
#include <86box/timer.h>
#include <86box/io.h>
#include <86box/pic.h>
#include <86box/pit.h>
#include <86box/ppi.h>
#include <86box/mem.h>
#include <86box/device.h>
#include <86box/machine.h>
#include <86box/m_at_t3100e.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/sound.h>
#include <86box/snd_speaker.h>
#include <86box/video.h>
#include <86box/keyboard.h>
#include <86box/plat_fallthrough.h>
#include <86box/keyboard.h>
#ifdef ENABLE_KBC_AT_DEV_LOG
int kbc_at_dev_do_log = ENABLE_KBC_AT_DEV_LOG;
@@ -58,7 +42,7 @@ kbc_at_dev_log(const char *fmt, ...)
# define kbc_at_dev_log(fmt, ...)
#endif
static void
void
kbc_at_dev_queue_reset(atkbc_dev_t *dev, uint8_t reset_main)
{
if (reset_main) {
@@ -95,10 +79,6 @@ kbc_at_dev_queue_add(atkbc_dev_t *dev, uint8_t val, uint8_t main)
dev->cmd_queue[dev->cmd_queue_end] = val;
dev->cmd_queue_end = (dev->cmd_queue_end + 1) & 0xf;
}
/* TODO: This should be done on actual send to host. */
if (val != 0xfe)
dev->last_scan_code = val;
}
static void
@@ -123,6 +103,8 @@ kbc_at_dev_poll(void *priv)
(dev->queue_start != dev->queue_end)) {
kbc_at_dev_log("%s: %02X (DATA) on channel 1\n", dev->name, dev->queue[dev->queue_start]);
dev->port->out_new = dev->queue[dev->queue_start];
if (dev->port->out_new != 0xfe)
dev->last_scan_code = dev->port->out_new;
dev->queue_start = (dev->queue_start + 1) & dev->fifo_mask;
}
if (dev->ignore || !(*dev->scan) || dev->port->wantcmd)
@@ -143,6 +125,8 @@ kbc_at_dev_poll(void *priv)
if ((dev->port->out_new == -1) && (dev->cmd_queue_start != dev->cmd_queue_end)) {
kbc_at_dev_log("%s: %02X (CMD ) on channel 1\n", dev->name, dev->cmd_queue[dev->cmd_queue_start]);
dev->port->out_new = dev->cmd_queue[dev->cmd_queue_start];
if (dev->port->out_new != 0xfe)
dev->last_scan_code = dev->port->out_new;
dev->cmd_queue_start = (dev->cmd_queue_start + 1) & 0xf;
}
if (dev->cmd_queue_start == dev->cmd_queue_end)
@@ -166,6 +150,8 @@ kbc_at_dev_poll(void *priv)
if ((dev->port->out_new == -1) && (dev->cmd_queue_start != dev->cmd_queue_end)) {
kbc_at_dev_log("%s: %02X (CMD ) on channel 1\n", dev->name, dev->cmd_queue[dev->cmd_queue_start]);
dev->port->out_new = dev->cmd_queue[dev->cmd_queue_start];
if (dev->port->out_new != 0xfe)
dev->last_scan_code = dev->port->out_new;
dev->cmd_queue_start = (dev->cmd_queue_start + 1) & 0xf;
}
if (dev->cmd_queue_start == dev->cmd_queue_end)

903
src/device/kbc_xt.c Normal file
View File

@@ -0,0 +1,903 @@
/*
* 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.
*
* Implementation of the XT-style keyboard.
*
*
*
* Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
* EngiNerd, <webmaster.crrc@yahoo.it>
*
* Copyright 2008-2019 Sarah Walker.
* Copyright 2016-2019 Miran Grca.
* Copyright 2017-2019 Fred N. van kempen.
* Copyright 2020 EngiNerd.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#define HAVE_STDARG_H
#include <wchar.h>
#include <86box/86box.h>
#include <86box/device.h>
#include "cpu.h"
#include <86box/timer.h>
#include <86box/fdd.h>
#include <86box/machine.h>
#include <86box/m_xt_t1000.h>
#include <86box/cassette.h>
#include <86box/io.h>
#include <86box/pic.h>
#include <86box/pit.h>
#include <86box/ppi.h>
#include <86box/mem.h>
#include <86box/rom.h>
#include <86box/sound.h>
#include <86box/snd_speaker.h>
#include <86box/video.h>
#include <86box/keyboard.h>
#define STAT_PARITY 0x80
#define STAT_RTIMEOUT 0x40
#define STAT_TTIMEOUT 0x20
#define STAT_LOCK 0x10
#define STAT_CD 0x08
#define STAT_SYSFLAG 0x04
#define STAT_IFULL 0x02
#define STAT_OFULL 0x01
/* Keyboard Types */
enum {
KBD_TYPE_PC81 = 0,
KBD_TYPE_PC82,
KBD_TYPE_XT82,
KBD_TYPE_XT86,
KBD_TYPE_COMPAQ,
KBD_TYPE_TANDY,
KBD_TYPE_TOSHIBA,
KBD_TYPE_VTECH,
KBD_TYPE_OLIVETTI,
KBD_TYPE_ZENITH,
KBD_TYPE_PRAVETZ,
KBD_TYPE_HYUNDAI,
KBD_TYPE_FE2010,
KBD_TYPE_XTCLONE
};
typedef struct xtkbd_t {
int want_irq;
int blocked;
int tandy;
uint8_t pa;
uint8_t pb;
uint8_t pd;
uint8_t cfg;
uint8_t clock;
uint8_t key_waiting;
uint8_t type;
uint8_t pravetz_flags;
uint8_t cpu_speed;
pc_timer_t send_delay_timer;
} xtkbd_t;
static uint8_t key_queue[16];
static int key_queue_start = 0;
static int key_queue_end = 0;
static int is_tandy = 0;
static int is_t1x00 = 0;
static int is_amstrad = 0;
#ifdef ENABLE_KEYBOARD_XT_LOG
int keyboard_xt_do_log = ENABLE_KEYBOARD_XT_LOG;
static void
kbd_log(const char *fmt, ...)
{
va_list ap;
if (keyboard_xt_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define kbd_log(fmt, ...)
#endif
static uint8_t
get_fdd_switch_settings(void)
{
uint8_t fdd_count = 0;
for (uint8_t i = 0; i < FDD_NUM; i++) {
if (fdd_get_flags(i))
fdd_count++;
}
if (!fdd_count)
return 0x00;
else
return ((fdd_count - 1) << 6) | 0x01;
}
static uint8_t
get_videomode_switch_settings(void)
{
if (video_is_mda())
return 0x30;
else if (video_is_cga())
return 0x20; /* 0x10 would be 40x25 */
else
return 0x00;
}
static void
kbd_poll(void *priv)
{
xtkbd_t *kbd = (xtkbd_t *) priv;
timer_advance_u64(&kbd->send_delay_timer, 1000 * TIMER_USEC);
if (!(kbd->pb & 0x40) && (kbd->type != KBD_TYPE_TANDY))
return;
if (kbd->want_irq) {
kbd->want_irq = 0;
kbd->pa = kbd->key_waiting;
kbd->blocked = 1;
picint(2);
#ifdef ENABLE_KEYBOARD_XT_LOG
kbd_log("XTkbd: kbd_poll(): keyboard_xt : take IRQ\n");
#endif
}
if ((key_queue_start != key_queue_end) && !kbd->blocked) {
kbd->key_waiting = key_queue[key_queue_start];
kbd_log("XTkbd: reading %02X from the key queue at %i\n",
kbd->key_waiting, key_queue_start);
key_queue_start = (key_queue_start + 1) & 0x0f;
kbd->want_irq = 1;
}
}
static void
kbd_adddata(uint16_t val)
{
/* Test for T1000 'Fn' key (Right Alt / Right Ctrl) */
if (is_t1x00) {
if (keyboard_recv(0x138) || keyboard_recv(0x11d)) { /* 'Fn' pressed */
t1000_syskey(0x00, 0x04, 0x00); /* Set 'Fn' indicator */
switch (val) {
case 0x45: /* Num Lock => toggle numpad */
t1000_syskey(0x00, 0x00, 0x10);
break;
case 0x47: /* Home => internal display */
t1000_syskey(0x40, 0x00, 0x00);
break;
case 0x49: /* PgDn => turbo on */
t1000_syskey(0x80, 0x00, 0x00);
break;
case 0x4D: /* Right => toggle LCD font */
t1000_syskey(0x00, 0x00, 0x20);
break;
case 0x4F: /* End => external display */
t1000_syskey(0x00, 0x40, 0x00);
break;
case 0x51: /* PgDn => turbo off */
t1000_syskey(0x00, 0x80, 0x00);
break;
case 0x54: /* SysRQ => toggle window */
t1000_syskey(0x00, 0x00, 0x08);
break;
default:
break;
}
} else
t1000_syskey(0x04, 0x00, 0x00); /* Reset 'Fn' indicator */
}
key_queue[key_queue_end] = val;
kbd_log("XTkbd: %02X added to key queue at %i\n",
val, key_queue_end);
key_queue_end = (key_queue_end + 1) & 0x0f;
}
void
kbd_adddata_process(uint16_t val, void (*adddata)(uint16_t val))
{
uint8_t num_lock = 0;
uint8_t shift_states = 0;
if (!adddata)
return;
keyboard_get_states(NULL, &num_lock, NULL, NULL);
shift_states = keyboard_get_shift() & STATE_LSHIFT;
if (is_amstrad)
num_lock = !num_lock;
/* If NumLock is on, invert the left shift state so we can always check for
the the same way flag being set (and with NumLock on that then means it
is actually *NOT* set). */
if (num_lock)
shift_states ^= STATE_LSHIFT;
switch (val) {
case FAKE_LSHIFT_ON:
/* If NumLock is on, fake shifts are sent when shift is *NOT* presed,
if NumLock is off, fake shifts are sent when shift is pressed. */
if (shift_states) {
/* Send fake shift. */
adddata(num_lock ? 0x2a : 0xaa);
}
break;
case FAKE_LSHIFT_OFF:
if (shift_states) {
/* Send fake shift. */
adddata(num_lock ? 0xaa : 0x2a);
}
break;
default:
adddata(val);
break;
}
}
static void
kbd_adddata_ex(uint16_t val)
{
kbd_adddata_process(val, kbd_adddata);
}
static void
kbd_write(uint16_t port, uint8_t val, void *priv)
{
xtkbd_t *kbd = (xtkbd_t *) priv;
uint8_t bit;
uint8_t set;
uint8_t new_clock;
switch (port) {
case 0x61: /* Keyboard Control Register (aka Port B) */
if (!(val & 0x80) || (kbd->type == KBD_TYPE_HYUNDAI)) {
new_clock = !!(val & 0x40);
if (!kbd->clock && new_clock) {
key_queue_start = key_queue_end = 0;
kbd->want_irq = 0;
kbd->blocked = 0;
kbd_adddata(0xaa);
}
}
kbd->pb = val;
if (!(kbd->pb & 0x80) || (kbd->type == KBD_TYPE_HYUNDAI))
kbd->clock = !!(kbd->pb & 0x40);
ppi.pb = val;
timer_process();
if (((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) ||
(kbd->type == KBD_TYPE_PRAVETZ)) && (cassette != NULL))
pc_cas_set_motor(cassette, (kbd->pb & 0x08) == 0);
speaker_update();
speaker_gated = val & 1;
speaker_enable = val & 2;
if (speaker_enable)
was_speaker_enable = 1;
pit_devs[0].set_gate(pit_devs[0].data, 2, val & 1);
if (val & 0x80) {
kbd->pa = 0;
kbd->blocked = 0;
picintc(2);
}
#ifdef ENABLE_KEYBOARD_XT_LOG
if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_PRAVETZ))
kbd_log("XTkbd: Cassette motor is %s\n", !(val & 0x08) ? "ON" : "OFF");
#endif
break;
case 0x62: /* Switch Register (aka Port C) */
#ifdef ENABLE_KEYBOARD_XT_LOG
if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_PRAVETZ))
kbd_log("XTkbd: Cassette IN is %i\n", !!(val & 0x10));
#endif
if (kbd->type == KBD_TYPE_FE2010) {
kbd_log("XTkbd: Switch register in is %02X\n", val);
if (!(kbd->cfg & 0x08))
kbd->pd = (kbd->pd & 0x30) | (val & 0xcf);
}
break;
case 0x63:
if (kbd->type == KBD_TYPE_FE2010) {
kbd_log("XTkbd: Configuration register in is %02X\n", val);
if (!(kbd->cfg & 0x08))
kbd->cfg = val;
}
break;
case 0xc0 ... 0xcf: /* Pravetz Flags */
kbd_log("XTkbd: Port %02X out: %02X\n", port, val);
if (kbd->type == KBD_TYPE_PRAVETZ) {
bit = (port >> 1) & 0x07;
set = (port & 0x01) << bit;
kbd->pravetz_flags = (kbd->pravetz_flags & ~(1 << bit)) | set;
}
break;
case 0x1f0:
kbd_log("XTkbd: Port %04X out: %02X\n", port, val);
if (kbd->type == KBD_TYPE_VTECH) {
kbd->cpu_speed = val;
cpu_dynamic_switch(kbd->cpu_speed >> 7);
}
break;
default:
break;
}
}
static uint8_t
kbd_read(uint16_t port, void *priv)
{
const xtkbd_t *kbd = (xtkbd_t *) priv;
uint8_t ret = 0xff;
switch (port) {
case 0x60: /* Keyboard Data Register (aka Port A) */
if ((kbd->pb & 0x80) && ((kbd->type == KBD_TYPE_PC81) ||
(kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_PRAVETZ) ||
(kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86) ||
(kbd->type == KBD_TYPE_XTCLONE) || (kbd->type == KBD_TYPE_COMPAQ) ||
(kbd->type == KBD_TYPE_ZENITH) || (kbd->type == KBD_TYPE_HYUNDAI) ||
(kbd->type == KBD_TYPE_VTECH))) {
if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) ||
(kbd->type == KBD_TYPE_XTCLONE) || (kbd->type == KBD_TYPE_COMPAQ) ||
(kbd->type == KBD_TYPE_PRAVETZ) || (kbd->type == KBD_TYPE_HYUNDAI))
ret = (kbd->pd & ~0x02) | (hasfpu ? 0x02 : 0x00);
else if ((kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86) ||
(kbd->type == KBD_TYPE_VTECH))
/* According to Ruud on the PCem forum, this is supposed to
return 0xFF on the XT. */
ret = 0xff;
else if (kbd->type == KBD_TYPE_ZENITH) {
/* Zenith Data Systems Z-151
* SW1 switch settings:
* bits 6-7: floppy drive number
* bits 4-5: video mode
* bit 2-3: base memory size
* bit 1: fpu enable
* bit 0: fdc enable
*/
ret = get_fdd_switch_settings();
ret |= get_videomode_switch_settings();
/* Base memory size should always be 64k */
ret |= 0x0c;
if (hasfpu)
ret |= 0x02;
}
} else
ret = kbd->pa;
break;
case 0x61: /* Keyboard Control Register (aka Port B) */
ret = kbd->pb;
break;
case 0x62: /* Switch Register (aka Port C) */
if (kbd->type == KBD_TYPE_FE2010) {
if (kbd->pb & 0x04) /* PB2 */
ret = (kbd->pd & 0x0d) | (hasfpu ? 0x02 : 0x00);
else
ret = kbd->pd >> 4;
} else if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) ||
(kbd->type == KBD_TYPE_PRAVETZ)) {
if (kbd->pb & 0x04) /* PB2 */
switch (mem_size + isa_mem_size) {
case 64:
case 48:
case 32:
case 16:
ret = 0x00;
break;
default:
ret = (((mem_size + isa_mem_size) - 64) / 32) & 0x0f;
break;
}
else
ret = (((mem_size + isa_mem_size) - 64) / 32) >> 4;
} else if ((kbd->type == KBD_TYPE_OLIVETTI) ||
(kbd->type == KBD_TYPE_ZENITH)) {
/* Olivetti M19 or Zenith Data Systems Z-151 */
if (kbd->pb & 0x04) /* PB2 */
ret = kbd->pd & 0xbf;
else
ret = kbd->pd >> 4;
} else {
if (kbd->pb & 0x08) /* PB3 */
ret = kbd->pd >> 4;
else
ret = (kbd->pd & 0x0d) | (hasfpu ? 0x02 : 0x00);
}
ret |= (ppispeakon ? 0x20 : 0);
/* This is needed to avoid error 131 (cassette error).
This is serial read: bit 5 = clock, bit 4 = data, cassette header is 256 x 0xff. */
if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) ||
(kbd->type == KBD_TYPE_PRAVETZ)) {
if (cassette == NULL)
ret |= (ppispeakon ? 0x10 : 0);
else
ret |= (pc_cas_get_inp(cassette) ? 0x10 : 0);
}
if (kbd->type == KBD_TYPE_TANDY)
ret |= (tandy1k_eeprom_read() ? 0x10 : 0);
break;
case 0x63: /* Keyboard Configuration Register (aka Port D) */
if ((kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86) ||
(kbd->type == KBD_TYPE_XTCLONE) || (kbd->type == KBD_TYPE_COMPAQ) ||
(kbd->type == KBD_TYPE_TOSHIBA) || (kbd->type == KBD_TYPE_HYUNDAI) ||
(kbd->type == KBD_TYPE_VTECH))
ret = kbd->pd;
break;
case 0xc0: /* Pravetz Flags */
if (kbd->type == KBD_TYPE_PRAVETZ)
ret = kbd->pravetz_flags;
kbd_log("XTkbd: Port %02X in : %02X\n", port, ret);
break;
case 0x1f0:
if (kbd->type == KBD_TYPE_VTECH)
ret = kbd->cpu_speed;
kbd_log("XTkbd: Port %04X in : %02X\n", port, ret);
break;
default:
break;
}
return ret;
}
static void
kbd_reset(void *priv)
{
xtkbd_t *kbd = (xtkbd_t *) priv;
kbd->want_irq = 0;
kbd->blocked = 0;
kbd->pa = 0x00;
kbd->pb = 0x00;
kbd->pravetz_flags = 0x00;
keyboard_scan = 1;
key_queue_start = 0;
key_queue_end = 0;
}
void
keyboard_set_is_amstrad(int ams)
{
is_amstrad = ams;
}
static void *
kbd_init(const device_t *info)
{
xtkbd_t *kbd;
kbd = (xtkbd_t *) calloc(1, sizeof(xtkbd_t));
io_sethandler(0x0060, 4,
kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd);
keyboard_send = kbd_adddata_ex;
kbd->type = info->local;
if (kbd->type == KBD_TYPE_VTECH)
kbd->cpu_speed = (!!cpu) << 2;
kbd_reset(kbd);
if (kbd->type == KBD_TYPE_PRAVETZ)
io_sethandler(0x00c0, 16,
kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd);
if (kbd->type == KBD_TYPE_VTECH)
io_sethandler(0x01f0, 1,
kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd);
key_queue_start = key_queue_end = 0;
video_reset(gfxcard[0]);
if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) ||
(kbd->type == KBD_TYPE_PRAVETZ) || (kbd->type == KBD_TYPE_XT82) ||
(kbd->type <= KBD_TYPE_XT86) || (kbd->type == KBD_TYPE_XTCLONE) ||
(kbd->type == KBD_TYPE_COMPAQ) || (kbd->type == KBD_TYPE_TOSHIBA) ||
(kbd->type == KBD_TYPE_OLIVETTI) || (kbd->type == KBD_TYPE_HYUNDAI) ||
(kbd->type == KBD_TYPE_VTECH) || (kbd->type == KBD_TYPE_FE2010)) {
/* DIP switch readout: bit set = OFF, clear = ON. */
if (kbd->type == KBD_TYPE_OLIVETTI)
/* Olivetti M19
* Jumpers J1, J2 - monitor type.
* 01 - mono (high-res)
* 10 - color (low-res, disables 640x400x2 mode)
* 00 - autoswitching
*/
kbd->pd |= 0x00;
else
/* Switches 7, 8 - floppy drives. */
kbd->pd = get_fdd_switch_settings();
/* Switches 5, 6 - video card type */
kbd->pd |= get_videomode_switch_settings();
/* Switches 3, 4 - memory size. */
if ((kbd->type == KBD_TYPE_XT86) || (kbd->type == KBD_TYPE_XTCLONE) ||
(kbd->type == KBD_TYPE_HYUNDAI) || (kbd->type == KBD_TYPE_COMPAQ) ||
(kbd->type == KBD_TYPE_TOSHIBA) || (kbd->type == KBD_TYPE_FE2010)) {
switch (mem_size) {
case 256:
kbd->pd |= 0x00;
break;
case 512:
kbd->pd |= 0x04;
break;
case 576:
kbd->pd |= 0x08;
break;
case 640:
default:
kbd->pd |= 0x0c;
break;
}
} else if ((kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_VTECH)) {
switch (mem_size) {
case 64: /* 1x64k */
kbd->pd |= 0x00;
break;
case 128: /* 2x64k */
kbd->pd |= 0x04;
break;
case 192: /* 3x64k */
kbd->pd |= 0x08;
break;
case 256: /* 4x64k */
default:
kbd->pd |= 0x0c;
break;
}
} else if (kbd->type == KBD_TYPE_PC82) {
switch (mem_size) {
#ifdef PC82_192K_3BANK
case 192: /* 3x64k, not supported by stock BIOS due to bugs */
kbd->pd |= 0x08;
break;
#else
case 192: /* 2x64k + 2x32k */
#endif
case 64: /* 4x16k */
case 96: /* 2x32k + 2x16k */
case 128: /* 4x32k */
case 160: /* 2x64k + 2x16k */
case 224: /* 3x64k + 1x32k */
case 256: /* 4x64k */
default:
kbd->pd |= 0x0c;
break;
}
} else { /* really just the PC '81 */
switch (mem_size) {
case 16: /* 1x16k */
kbd->pd |= 0x00;
break;
case 32: /* 2x16k */
kbd->pd |= 0x04;
break;
case 48: /* 3x16k */
kbd->pd |= 0x08;
break;
case 64: /* 4x16k */
default:
kbd->pd |= 0x0c;
break;
}
}
/* Switch 2 - 8087 FPU. */
if (hasfpu)
kbd->pd |= 0x02;
} else if (kbd->type == KBD_TYPE_ZENITH) {
/* Zenith Data Systems Z-151
* SW2 switch settings:
* bit 7: monitor frequency
* bits 5-6: autoboot (00-11 resident monitor, 10 hdd, 01 fdd)
* bits 0-4: installed memory
*/
kbd->pd = 0x20;
switch (mem_size) {
case 128:
kbd->pd |= 0x02;
break;
case 192:
kbd->pd |= 0x04;
break;
case 256:
kbd->pd |= 0x06;
break;
case 320:
kbd->pd |= 0x08;
break;
case 384:
kbd->pd |= 0x0a;
break;
case 448:
kbd->pd |= 0x0c;
break;
case 512:
kbd->pd |= 0x0e;
break;
case 576:
kbd->pd |= 0x10;
break;
case 640:
default:
kbd->pd |= 0x12;
break;
}
}
timer_add(&kbd->send_delay_timer, kbd_poll, kbd, 1);
is_tandy = (kbd->type == KBD_TYPE_TANDY);
is_t1x00 = (kbd->type == KBD_TYPE_TOSHIBA);
if (keyboard_type == KEYBOARD_TYPE_INTERNAL)
keyboard_set_table(scancode_xt);
else
keyboard_add_device();
is_amstrad = 0;
return kbd;
}
static void
kbd_close(void *priv)
{
xtkbd_t *kbd = (xtkbd_t *) priv;
/* Stop the timer. */
timer_disable(&kbd->send_delay_timer);
/* Disable scanning. */
keyboard_scan = 0;
keyboard_send = NULL;
io_removehandler(0x0060, 4,
kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd);
free(kbd);
}
const device_t kbc_pc_device = {
.name = "IBM PC Keyboard Controller (1981)",
.internal_name = "kbc_pc",
.flags = 0,
.local = KBD_TYPE_PC81,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t kbc_pc82_device = {
.name = "IBM PC Keyboard Controller (1982)",
.internal_name = "kbc_pc82",
.flags = 0,
.local = KBD_TYPE_PC82,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t kbc_pravetz_device = {
.name = "Pravetz Keyboard Controller",
.internal_name = "kbc_pravetz",
.flags = 0,
.local = KBD_TYPE_PRAVETZ,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t kbc_xt_device = {
.name = "XT (1982) Keyboard Controller",
.internal_name = "kbc_xt",
.flags = 0,
.local = KBD_TYPE_XT82,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t kbc_xt86_device = {
.name = "XT (1986) Keyboard Controller",
.internal_name = "kbc_xt86",
.flags = 0,
.local = KBD_TYPE_XT86,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t kbc_xt_compaq_device = {
.name = "Compaq Portable Keyboard Controller",
.internal_name = "kbc_xt_compaq",
.flags = 0,
.local = KBD_TYPE_COMPAQ,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t kbc_tandy_device = {
.name = "Tandy 1000 Keyboard Controller",
.internal_name = "kbc_tandy",
.flags = 0,
.local = KBD_TYPE_TANDY,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t kbc_xt_t1x00_device = {
.name = "Toshiba T1x00 Keyboard Controller",
.internal_name = "kbc_xt_t1x00",
.flags = 0,
.local = KBD_TYPE_TOSHIBA,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t kbc_xt_lxt3_device = {
.name = "VTech Laser Turbo XT Keyboard Controller",
.internal_name = "kbc_xt_lxt",
.flags = 0,
.local = KBD_TYPE_VTECH,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t kbc_xt_olivetti_device = {
.name = "Olivetti XT Keyboard Controller",
.internal_name = "kbc_xt_olivetti",
.flags = 0,
.local = KBD_TYPE_OLIVETTI,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t kbc_xt_zenith_device = {
.name = "Zenith XT Keyboard Controller",
.internal_name = "kbc_xt_zenith",
.flags = 0,
.local = KBD_TYPE_ZENITH,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t kbc_xt_hyundai_device = {
.name = "Hyundai XT Keyboard Controller",
.internal_name = "kbc_xt_hyundai",
.flags = 0,
.local = KBD_TYPE_HYUNDAI,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t kbc_xt_fe2010_device = {
.name = "Faraday FE2010 XT Keyboard Controller",
.internal_name = "kbc_xt_fe2010",
.flags = 0,
.local = KBD_TYPE_FE2010,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t kbc_xtclone_device = {
.name = "XT (Clone) Keyboard Controller",
.internal_name = "kbc_xtclone",
.flags = 0,
.local = KBD_TYPE_XTCLONE,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -27,6 +27,7 @@
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/machine.h>
#include <86box/device.h>
#include <86box/keyboard.h>
#include <86box/plat.h>
@@ -36,6 +37,38 @@ uint16_t scancode_map[768] = { 0 };
int keyboard_scan;
typedef struct keyboard_t {
const device_t *device;
} keyboard_t;
int keyboard_type = 0;
static const device_t keyboard_internal_device = {
.name = "Internal",
.internal_name = "internal",
.flags = 0,
.local = KEYBOARD_TYPE_INTERNAL,
.init = NULL,
.close = NULL,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
static keyboard_t keyboard_devices[] = {
// clang-format off
{ &keyboard_internal_device },
{ &keyboard_pc_xt_device },
{ &keyboard_at_device },
{ &keyboard_ax_device },
{ &keyboard_ps2_device },
{ &keyboard_ps55_device },
{ NULL }
// clang-format on
};
#ifdef ENABLE_KBC_AT_LOG
int kbc_at_do_log = ENABLE_KBC_AT_LOG;
@@ -64,10 +97,12 @@ static int keydelay[512];
#endif
static scancode *scan_table; /* scancode table for keyboard */
static uint8_t caps_lock = 0;
static uint8_t num_lock = 0;
static uint8_t scroll_lock = 0;
static uint8_t shift = 0;
static volatile uint8_t caps_lock = 0;
static volatile uint8_t num_lock = 0;
static volatile uint8_t scroll_lock = 0;
static volatile uint8_t kana_lock = 0;
static volatile uint8_t kbd_in_reset = 0;
static uint8_t shift = 0;
static int key5576mode = 0;
@@ -105,10 +140,12 @@ static scconvtbl scconv55_8a[18 + 1] =
void
keyboard_init(void)
{
num_lock = 0;
caps_lock = 0;
scroll_lock = 0;
shift = 0;
num_lock = 0;
caps_lock = 0;
scroll_lock = 0;
kana_lock = 0;
shift = 0;
kbd_in_reset = 0;
memset(recv_key, 0x00, sizeof(recv_key));
memset(recv_key_ui, 0x00, sizeof(recv_key));
@@ -236,6 +273,9 @@ key_process(uint16_t scan, int down)
void
keyboard_input(int down, uint16_t scan)
{
if (kbd_in_reset)
return;
/* Special case for E1 1D, translate it to 0100 - special case. */
if ((scan >> 8) == 0xe1) {
if ((scan & 0xff) == 0x1d)
@@ -310,13 +350,16 @@ keyboard_input(int down, uint16_t scan)
shift &= ~0x80;
break;
case 0x03a: /* Caps Lock */
caps_lock ^= 1;
if (!(machine_has_bus(machine, MACHINE_AT) > 0))
caps_lock ^= 1;
break;
case 0x045:
num_lock ^= 1;
if (!(machine_has_bus(machine, MACHINE_AT) > 0))
num_lock ^= 1;
break;
case 0x046:
scroll_lock ^= 1;
if (!(machine_has_bus(machine, MACHINE_AT) > 0))
scroll_lock ^= 1;
break;
default:
@@ -338,9 +381,9 @@ void
keyboard_all_up(void)
{
for (unsigned short i = 0; i < 0x200; i++) {
if (recv_key_ui[i]) {
if (recv_key_ui[i])
recv_key_ui[i] = 0;
}
if (recv_key[i]) {
recv_key[i] = 0;
key_process(i, 0);
@@ -348,6 +391,18 @@ keyboard_all_up(void)
}
}
void
keyboard_set_in_reset(uint8_t in_reset)
{
kbd_in_reset = in_reset;
}
uint8_t
keyboard_get_in_reset(void)
{
return kbd_in_reset;
}
static uint8_t
keyboard_do_break(uint16_t scan)
{
@@ -367,11 +422,12 @@ keyboard_do_break(uint16_t scan)
Caps Lock, Num Lock, and Scroll Lock when receving the "Set keyboard LEDs"
command. */
void
keyboard_update_states(uint8_t cl, uint8_t nl, uint8_t sl)
keyboard_update_states(uint8_t cl, uint8_t nl, uint8_t sl, uint8_t kl)
{
caps_lock = cl;
num_lock = nl;
scroll_lock = sl;
kana_lock = kl;
}
uint8_t
@@ -381,7 +437,7 @@ keyboard_get_shift(void)
}
void
keyboard_get_states(uint8_t *cl, uint8_t *nl, uint8_t *sl)
keyboard_get_states(uint8_t *cl, uint8_t *nl, uint8_t *sl, uint8_t *kl)
{
if (cl)
*cl = caps_lock;
@@ -389,6 +445,8 @@ keyboard_get_states(uint8_t *cl, uint8_t *nl, uint8_t *sl)
*nl = num_lock;
if (sl)
*sl = scroll_lock;
if (kl)
*kl = kana_lock;
}
/* Called by the UI to update the states of Caps Lock, Num Lock, and Scroll Lock. */
@@ -432,7 +490,7 @@ keyboard_set_states(uint8_t cl, uint8_t nl, uint8_t sl)
}
}
keyboard_update_states(cl, nl, sl);
keyboard_update_states(cl, nl, sl, kana_lock);
}
int
@@ -491,3 +549,57 @@ convert_scan_code(uint16_t scan_code)
return scan_code;
}
const char *
keyboard_get_name(int keyboard)
{
return (keyboard_devices[keyboard].device->name);
}
const char *
keyboard_get_internal_name(int keyboard)
{
return device_get_internal_name(keyboard_devices[keyboard].device);
}
int
keyboard_get_from_internal_name(char *s)
{
int c = 0;
while (keyboard_devices[c].device != NULL) {
if (!strcmp((char *) keyboard_devices[c].device->internal_name, s))
return c;
c++;
}
return 0;
}
int
keyboard_has_config(int keyboard)
{
if (keyboard_devices[keyboard].device == NULL)
return 0;
return (keyboard_devices[keyboard].device->config ? 1 : 0);
}
const device_t *
keyboard_get_device(int keyboard)
{
return (keyboard_devices[keyboard].device);
}
/* Return number of MOUSE types we know about. */
int
keyboard_get_ndev(void)
{
return ((sizeof(keyboard_devices) / sizeof(keyboard_t)) - 1);
}
void
keyboard_add_device(void)
{
device_add(keyboard_devices[keyboard_type].device);
}

File diff suppressed because it is too large Load Diff

View File

@@ -35,60 +35,8 @@
#include <86box/machine.h>
#include <86box/m_xt_t1000.h>
#include <86box/cassette.h>
#include <86box/io.h>
#include <86box/pic.h>
#include <86box/pit.h>
#include <86box/ppi.h>
#include <86box/mem.h>
#include <86box/rom.h>
#include <86box/sound.h>
#include <86box/snd_speaker.h>
#include <86box/video.h>
#include <86box/keyboard.h>
#define STAT_PARITY 0x80
#define STAT_RTIMEOUT 0x40
#define STAT_TTIMEOUT 0x20
#define STAT_LOCK 0x10
#define STAT_CD 0x08
#define STAT_SYSFLAG 0x04
#define STAT_IFULL 0x02
#define STAT_OFULL 0x01
/* Keyboard Types */
enum {
KBD_TYPE_PC81 = 0,
KBD_TYPE_PC82,
KBD_TYPE_XT82,
KBD_TYPE_XT86,
KBD_TYPE_COMPAQ,
KBD_TYPE_TANDY,
KBD_TYPE_TOSHIBA,
KBD_TYPE_VTECH,
KBD_TYPE_OLIVETTI,
KBD_TYPE_ZENITH,
KBD_TYPE_PRAVETZ,
KBD_TYPE_HYUNDAI,
KBD_TYPE_XTCLONE
};
typedef struct xtkbd_t {
int want_irq;
int blocked;
int tandy;
uint8_t pa;
uint8_t pb;
uint8_t pd;
uint8_t clock;
uint8_t key_waiting;
uint8_t type;
uint8_t pravetz_flags;
uint8_t cpu_speed;
pc_timer_t send_delay_timer;
} xtkbd_t;
/*XT keyboard has no escape scancodes, and no scancodes beyond 53*/
const scancode scancode_xt[512] = {
// clang-format off
@@ -607,779 +555,66 @@ const scancode scancode_xt[512] = {
// clang-format on
};
static uint8_t key_queue[16];
static int key_queue_start = 0;
static int key_queue_end = 0;
static int is_tandy = 0;
static int is_t1x00 = 0;
static int is_amstrad = 0;
#ifdef ENABLE_KEYBOARD_XT_LOG
int keyboard_xt_do_log = ENABLE_KEYBOARD_XT_LOG;
static void
kbd_log(const char *fmt, ...)
{
va_list ap;
if (keyboard_xt_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define kbd_log(fmt, ...)
#endif
static uint8_t
get_fdd_switch_settings(void)
{
uint8_t fdd_count = 0;
for (uint8_t i = 0; i < FDD_NUM; i++) {
if (fdd_get_flags(i))
fdd_count++;
}
if (!fdd_count)
return 0x00;
else
return ((fdd_count - 1) << 6) | 0x01;
}
static uint8_t
get_videomode_switch_settings(void)
{
if (video_is_mda())
return 0x30;
else if (video_is_cga())
return 0x20; /* 0x10 would be 40x25 */
else
return 0x00;
}
static void
kbd_poll(void *priv)
{
xtkbd_t *kbd = (xtkbd_t *) priv;
timer_advance_u64(&kbd->send_delay_timer, 1000 * TIMER_USEC);
if (!(kbd->pb & 0x40) && (kbd->type != KBD_TYPE_TANDY))
return;
if (kbd->want_irq) {
kbd->want_irq = 0;
kbd->pa = kbd->key_waiting;
kbd->blocked = 1;
picint(2);
#ifdef ENABLE_KEYBOARD_XT_LOG
kbd_log("XTkbd: kbd_poll(): keyboard_xt : take IRQ\n");
#endif
}
if ((key_queue_start != key_queue_end) && !kbd->blocked) {
kbd->key_waiting = key_queue[key_queue_start];
kbd_log("XTkbd: reading %02X from the key queue at %i\n",
kbd->key_waiting, key_queue_start);
key_queue_start = (key_queue_start + 1) & 0x0f;
kbd->want_irq = 1;
}
}
static void
kbd_adddata(uint16_t val)
{
/* Test for T1000 'Fn' key (Right Alt / Right Ctrl) */
if (is_t1x00) {
if (keyboard_recv(0x138) || keyboard_recv(0x11d)) { /* 'Fn' pressed */
t1000_syskey(0x00, 0x04, 0x00); /* Set 'Fn' indicator */
switch (val) {
case 0x45: /* Num Lock => toggle numpad */
t1000_syskey(0x00, 0x00, 0x10);
break;
case 0x47: /* Home => internal display */
t1000_syskey(0x40, 0x00, 0x00);
break;
case 0x49: /* PgDn => turbo on */
t1000_syskey(0x80, 0x00, 0x00);
break;
case 0x4D: /* Right => toggle LCD font */
t1000_syskey(0x00, 0x00, 0x20);
break;
case 0x4F: /* End => external display */
t1000_syskey(0x00, 0x40, 0x00);
break;
case 0x51: /* PgDn => turbo off */
t1000_syskey(0x00, 0x80, 0x00);
break;
case 0x54: /* SysRQ => toggle window */
t1000_syskey(0x00, 0x00, 0x08);
break;
default:
break;
}
} else
t1000_syskey(0x04, 0x00, 0x00); /* Reset 'Fn' indicator */
}
key_queue[key_queue_end] = val;
kbd_log("XTkbd: %02X added to key queue at %i\n",
val, key_queue_end);
key_queue_end = (key_queue_end + 1) & 0x0f;
}
void
kbd_adddata_process(uint16_t val, void (*adddata)(uint16_t val))
{
uint8_t num_lock = 0;
uint8_t shift_states = 0;
if (!adddata)
return;
keyboard_get_states(NULL, &num_lock, NULL);
shift_states = keyboard_get_shift() & STATE_LSHIFT;
if (is_amstrad)
num_lock = !num_lock;
/* If NumLock is on, invert the left shift state so we can always check for
the the same way flag being set (and with NumLock on that then means it
is actually *NOT* set). */
if (num_lock)
shift_states ^= STATE_LSHIFT;
switch (val) {
case FAKE_LSHIFT_ON:
/* If NumLock is on, fake shifts are sent when shift is *NOT* presed,
if NumLock is off, fake shifts are sent when shift is pressed. */
if (shift_states) {
/* Send fake shift. */
adddata(num_lock ? 0x2a : 0xaa);
}
break;
case FAKE_LSHIFT_OFF:
if (shift_states) {
/* Send fake shift. */
adddata(num_lock ? 0xaa : 0x2a);
}
break;
default:
adddata(val);
break;
}
}
static void
kbd_adddata_ex(uint16_t val)
{
kbd_adddata_process(val, kbd_adddata);
}
static void
kbd_write(uint16_t port, uint8_t val, void *priv)
{
xtkbd_t *kbd = (xtkbd_t *) priv;
uint8_t bit;
uint8_t set;
uint8_t new_clock;
switch (port) {
case 0x61: /* Keyboard Control Register (aka Port B) */
if (!(val & 0x80) || (kbd->type == KBD_TYPE_HYUNDAI)) {
new_clock = !!(val & 0x40);
if (!kbd->clock && new_clock) {
key_queue_start = key_queue_end = 0;
kbd->want_irq = 0;
kbd->blocked = 0;
kbd_adddata(0xaa);
}
}
kbd->pb = val;
if (!(kbd->pb & 0x80) || (kbd->type == KBD_TYPE_HYUNDAI))
kbd->clock = !!(kbd->pb & 0x40);
ppi.pb = val;
timer_process();
if (((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) ||
(kbd->type == KBD_TYPE_PRAVETZ)) && (cassette != NULL))
pc_cas_set_motor(cassette, (kbd->pb & 0x08) == 0);
speaker_update();
speaker_gated = val & 1;
speaker_enable = val & 2;
if (speaker_enable)
was_speaker_enable = 1;
pit_devs[0].set_gate(pit_devs[0].data, 2, val & 1);
if (val & 0x80) {
kbd->pa = 0;
kbd->blocked = 0;
picintc(2);
}
#ifdef ENABLE_KEYBOARD_XT_LOG
if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_PRAVETZ))
kbd_log("XTkbd: Cassette motor is %s\n", !(val & 0x08) ? "ON" : "OFF");
#endif
break;
#ifdef ENABLE_KEYBOARD_XT_LOG
case 0x62: /* Switch Register (aka Port C) */
if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_PRAVETZ))
kbd_log("XTkbd: Cassette IN is %i\n", !!(val & 0x10));
break;
#endif
case 0xc0 ... 0xcf: /* Pravetz Flags */
kbd_log("XTkbd: Port %02X out: %02X\n", port, val);
if (kbd->type == KBD_TYPE_PRAVETZ) {
bit = (port >> 1) & 0x07;
set = (port & 0x01) << bit;
kbd->pravetz_flags = (kbd->pravetz_flags & ~(1 << bit)) | set;
}
break;
case 0x1f0:
kbd_log("XTkbd: Port %04X out: %02X\n", port, val);
if (kbd->type == KBD_TYPE_VTECH) {
kbd->cpu_speed = val;
cpu_dynamic_switch(kbd->cpu_speed >> 7);
}
break;
default:
break;
}
}
static uint8_t
kbd_read(uint16_t port, void *priv)
{
const xtkbd_t *kbd = (xtkbd_t *) priv;
uint8_t ret = 0xff;
switch (port) {
case 0x60: /* Keyboard Data Register (aka Port A) */
if ((kbd->pb & 0x80) && ((kbd->type == KBD_TYPE_PC81) ||
(kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_PRAVETZ) ||
(kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86) ||
(kbd->type == KBD_TYPE_XTCLONE) || (kbd->type == KBD_TYPE_COMPAQ) ||
(kbd->type == KBD_TYPE_ZENITH) || (kbd->type == KBD_TYPE_HYUNDAI) ||
(kbd->type == KBD_TYPE_VTECH))) {
if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) ||
(kbd->type == KBD_TYPE_XTCLONE) || (kbd->type == KBD_TYPE_COMPAQ) ||
(kbd->type == KBD_TYPE_PRAVETZ) || (kbd->type == KBD_TYPE_HYUNDAI))
ret = (kbd->pd & ~0x02) | (hasfpu ? 0x02 : 0x00);
else if ((kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86) ||
(kbd->type == KBD_TYPE_VTECH))
/* According to Ruud on the PCem forum, this is supposed to
return 0xFF on the XT. */
ret = 0xff;
else if (kbd->type == KBD_TYPE_ZENITH) {
/* Zenith Data Systems Z-151
* SW1 switch settings:
* bits 6-7: floppy drive number
* bits 4-5: video mode
* bit 2-3: base memory size
* bit 1: fpu enable
* bit 0: fdc enable
*/
ret = get_fdd_switch_settings();
ret |= get_videomode_switch_settings();
/* Base memory size should always be 64k */
ret |= 0x0c;
if (hasfpu)
ret |= 0x02;
}
} else
ret = kbd->pa;
break;
case 0x61: /* Keyboard Control Register (aka Port B) */
ret = kbd->pb;
break;
case 0x62: /* Switch Register (aka Port C) */
if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) ||
(kbd->type == KBD_TYPE_PRAVETZ)) {
if (kbd->pb & 0x04) /* PB2 */
switch (mem_size + isa_mem_size) {
case 64:
case 48:
case 32:
case 16:
ret = 0x00;
break;
default:
ret = (((mem_size + isa_mem_size) - 64) / 32) & 0x0f;
break;
}
else
ret = (((mem_size + isa_mem_size) - 64) / 32) >> 4;
} else if ((kbd->type == KBD_TYPE_OLIVETTI) ||
(kbd->type == KBD_TYPE_ZENITH)) {
/* Olivetti M19 or Zenith Data Systems Z-151 */
if (kbd->pb & 0x04) /* PB2 */
ret = kbd->pd & 0xbf;
else
ret = kbd->pd >> 4;
} else {
if (kbd->pb & 0x08) /* PB3 */
ret = kbd->pd >> 4;
else
ret = (kbd->pd & 0x0d) | (hasfpu ? 0x02 : 0x00);
}
ret |= (ppispeakon ? 0x20 : 0);
/* This is needed to avoid error 131 (cassette error).
This is serial read: bit 5 = clock, bit 4 = data, cassette header is 256 x 0xff. */
if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) ||
(kbd->type == KBD_TYPE_PRAVETZ)) {
if (cassette == NULL)
ret |= (ppispeakon ? 0x10 : 0);
else
ret |= (pc_cas_get_inp(cassette) ? 0x10 : 0);
}
if (kbd->type == KBD_TYPE_TANDY)
ret |= (tandy1k_eeprom_read() ? 0x10 : 0);
break;
case 0x63: /* Keyboard Configuration Register (aka Port D) */
if ((kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_XT86) ||
(kbd->type == KBD_TYPE_XTCLONE) || (kbd->type == KBD_TYPE_COMPAQ) ||
(kbd->type == KBD_TYPE_TOSHIBA) || (kbd->type == KBD_TYPE_HYUNDAI) ||
(kbd->type == KBD_TYPE_VTECH))
ret = kbd->pd;
break;
case 0xc0: /* Pravetz Flags */
if (kbd->type == KBD_TYPE_PRAVETZ)
ret = kbd->pravetz_flags;
kbd_log("XTkbd: Port %02X in : %02X\n", port, ret);
break;
case 0x1f0:
if (kbd->type == KBD_TYPE_VTECH)
ret = kbd->cpu_speed;
kbd_log("XTkbd: Port %04X in : %02X\n", port, ret);
break;
default:
break;
}
return ret;
}
static void
kbd_reset(void *priv)
{
xtkbd_t *kbd = (xtkbd_t *) priv;
kbd->want_irq = 0;
kbd->blocked = 0;
kbd->pa = 0x00;
kbd->pb = 0x00;
kbd->pravetz_flags = 0x00;
keyboard_scan = 1;
key_queue_start = 0;
key_queue_end = 0;
}
void
keyboard_set_is_amstrad(int ams)
{
is_amstrad = ams;
}
typedef struct {
int type;
} kbd_t;
static void *
kbd_init(const device_t *info)
{
xtkbd_t *kbd;
kbd_t *dev = (kbd_t *) calloc(1, sizeof(kbd_t));
kbd = (xtkbd_t *) calloc(1, sizeof(xtkbd_t));
dev->type = info->local;
io_sethandler(0x0060, 4,
kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd);
keyboard_send = kbd_adddata_ex;
kbd->type = info->local;
if (kbd->type == KBD_TYPE_VTECH)
kbd->cpu_speed = (!!cpu) << 2;
kbd_reset(kbd);
if (kbd->type == KBD_TYPE_PRAVETZ)
io_sethandler(0x00c0, 16,
kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd);
if (kbd->type == KBD_TYPE_VTECH)
io_sethandler(0x01f0, 1,
kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd);
if (dev->type == KBD_83_KEY)
keyboard_set_table(scancode_xt);
else
keyboard_set_table(scancode_set1);
key_queue_start = key_queue_end = 0;
video_reset(gfxcard[0]);
if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) ||
(kbd->type == KBD_TYPE_PRAVETZ) || (kbd->type == KBD_TYPE_XT82) ||
(kbd->type <= KBD_TYPE_XT86) || (kbd->type == KBD_TYPE_XTCLONE) ||
(kbd->type == KBD_TYPE_COMPAQ) || (kbd->type == KBD_TYPE_TOSHIBA) ||
(kbd->type == KBD_TYPE_OLIVETTI) || (kbd->type == KBD_TYPE_HYUNDAI) ||
(kbd->type == KBD_TYPE_VTECH)) {
/* DIP switch readout: bit set = OFF, clear = ON. */
if (kbd->type == KBD_TYPE_OLIVETTI)
/* Olivetti M19
* Jumpers J1, J2 - monitor type.
* 01 - mono (high-res)
* 10 - color (low-res, disables 640x400x2 mode)
* 00 - autoswitching
*/
kbd->pd |= 0x00;
else
/* Switches 7, 8 - floppy drives. */
kbd->pd = get_fdd_switch_settings();
/* Switches 5, 6 - video card type */
kbd->pd |= get_videomode_switch_settings();
/* Switches 3, 4 - memory size. */
if ((kbd->type == KBD_TYPE_XT86) || (kbd->type == KBD_TYPE_XTCLONE) ||
(kbd->type == KBD_TYPE_HYUNDAI) || (kbd->type == KBD_TYPE_COMPAQ) ||
(kbd->type == KBD_TYPE_TOSHIBA)) {
switch (mem_size) {
case 256:
kbd->pd |= 0x00;
break;
case 512:
kbd->pd |= 0x04;
break;
case 576:
kbd->pd |= 0x08;
break;
case 640:
default:
kbd->pd |= 0x0c;
break;
}
} else if ((kbd->type == KBD_TYPE_XT82) || (kbd->type == KBD_TYPE_VTECH)) {
switch (mem_size) {
case 64: /* 1x64k */
kbd->pd |= 0x00;
break;
case 128: /* 2x64k */
kbd->pd |= 0x04;
break;
case 192: /* 3x64k */
kbd->pd |= 0x08;
break;
case 256: /* 4x64k */
default:
kbd->pd |= 0x0c;
break;
}
} else if (kbd->type == KBD_TYPE_PC82) {
switch (mem_size) {
#ifdef PC82_192K_3BANK
case 192: /* 3x64k, not supported by stock BIOS due to bugs */
kbd->pd |= 0x08;
break;
#else
case 192: /* 2x64k + 2x32k */
#endif
case 64: /* 4x16k */
case 96: /* 2x32k + 2x16k */
case 128: /* 4x32k */
case 160: /* 2x64k + 2x16k */
case 224: /* 3x64k + 1x32k */
case 256: /* 4x64k */
default:
kbd->pd |= 0x0c;
break;
}
} else { /* really just the PC '81 */
switch (mem_size) {
case 16: /* 1x16k */
kbd->pd |= 0x00;
break;
case 32: /* 2x16k */
kbd->pd |= 0x04;
break;
case 48: /* 3x16k */
kbd->pd |= 0x08;
break;
case 64: /* 4x16k */
default:
kbd->pd |= 0x0c;
break;
}
}
/* Switch 2 - 8087 FPU. */
if (hasfpu)
kbd->pd |= 0x02;
} else if (kbd->type == KBD_TYPE_ZENITH) {
/* Zenith Data Systems Z-151
* SW2 switch settings:
* bit 7: monitor frequency
* bits 5-6: autoboot (00-11 resident monitor, 10 hdd, 01 fdd)
* bits 0-4: installed memory
*/
kbd->pd = 0x20;
switch (mem_size) {
case 128:
kbd->pd |= 0x02;
break;
case 192:
kbd->pd |= 0x04;
break;
case 256:
kbd->pd |= 0x06;
break;
case 320:
kbd->pd |= 0x08;
break;
case 384:
kbd->pd |= 0x0a;
break;
case 448:
kbd->pd |= 0x0c;
break;
case 512:
kbd->pd |= 0x0e;
break;
case 576:
kbd->pd |= 0x10;
break;
case 640:
default:
kbd->pd |= 0x12;
break;
}
}
timer_add(&kbd->send_delay_timer, kbd_poll, kbd, 1);
keyboard_set_table(scancode_xt);
is_tandy = (kbd->type == KBD_TYPE_TANDY);
is_t1x00 = (kbd->type == KBD_TYPE_TOSHIBA);
is_amstrad = 0;
return kbd;
return dev;
}
static void
kbd_close(void *priv)
{
xtkbd_t *kbd = (xtkbd_t *) priv;
/* Stop the timer. */
timer_disable(&kbd->send_delay_timer);
/* Disable scanning. */
keyboard_scan = 0;
keyboard_send = NULL;
io_removehandler(0x0060, 4,
kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd);
kbd_t *kbd = (kbd_t *) priv;
free(kbd);
}
const device_t keyboard_pc_device = {
.name = "IBM PC Keyboard (1981)",
.internal_name = "keyboard_pc",
.flags = 0,
.local = KBD_TYPE_PC81,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
static const device_config_t keyboard_pc_xt_config[] = {
// clang-format off
{
.name = "keys",
.description = "Keys",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = KBD_83_KEY,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "83", .value = KBD_83_KEY },
{ .description = "101 (ANSI)", .value = KBD_101_KEY },
{ .description = "102 (ISO)", .value = KBD_102_KEY }
},
.bios = { { 0 } }
},
{
.name = "", .description = "", .type = CONFIG_END
}
// clang-format on
};
const device_t keyboard_pc82_device = {
.name = "IBM PC Keyboard (1982)",
.internal_name = "keyboard_pc82",
.flags = 0,
.local = KBD_TYPE_PC82,
const device_t keyboard_pc_xt_device = {
.name = "PC/XT Keyboard",
.internal_name = "keyboard_pc_xt",
.flags = DEVICE_XT_KBC,
.local = 0,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t keyboard_pravetz_device = {
.name = "Pravetz Keyboard",
.internal_name = "keyboard_pravetz",
.flags = 0,
.local = KBD_TYPE_PRAVETZ,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t keyboard_xt_device = {
.name = "XT (1982) Keyboard",
.internal_name = "keyboard_xt",
.flags = 0,
.local = KBD_TYPE_XT82,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t keyboard_xt86_device = {
.name = "XT (1986) Keyboard",
.internal_name = "keyboard_xt86",
.flags = 0,
.local = KBD_TYPE_XT86,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t keyboard_xt_compaq_device = {
.name = "Compaq Portable Keyboard",
.internal_name = "keyboard_xt_compaq",
.flags = 0,
.local = KBD_TYPE_COMPAQ,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t keyboard_tandy_device = {
.name = "Tandy 1000 Keyboard",
.internal_name = "keyboard_tandy",
.flags = 0,
.local = KBD_TYPE_TANDY,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t keyboard_xt_t1x00_device = {
.name = "Toshiba T1x00 Keyboard",
.internal_name = "keyboard_xt_t1x00",
.flags = 0,
.local = KBD_TYPE_TOSHIBA,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
#ifdef USE_LASERXT
const device_t keyboard_xt_lxt3_device = {
.name = "VTech Laser Turbo XT Keyboard",
.internal_name = "keyboard_xt_lxt",
.flags = 0,
.local = KBD_TYPE_VTECH,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
#endif /* USE_LASERXT */
const device_t keyboard_xt_olivetti_device = {
.name = "Olivetti XT Keyboard",
.internal_name = "keyboard_xt_olivetti",
.flags = 0,
.local = KBD_TYPE_OLIVETTI,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t keyboard_xt_zenith_device = {
.name = "Zenith XT Keyboard",
.internal_name = "keyboard_xt_zenith",
.flags = 0,
.local = KBD_TYPE_ZENITH,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t keyboard_xt_hyundai_device = {
.name = "Hyundai XT Keyboard",
.internal_name = "keyboard_x_hyundai",
.flags = 0,
.local = KBD_TYPE_HYUNDAI,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t keyboard_xtclone_device = {
.name = "XT (Clone) Keyboard",
.internal_name = "keyboard_xtclone",
.flags = 0,
.local = KBD_TYPE_XTCLONE,
.init = kbd_init,
.close = kbd_close,
.reset = kbd_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
.config = keyboard_pc_xt_config
};

945
src/device/lpt.c Normal file
View File

@@ -0,0 +1,945 @@
/* Copyright holders: Sarah Walker
see COPYING for more details
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/io.h>
#include <86box/fifo.h>
#include <86box/timer.h>
#include <86box/device.h>
#include <86box/dma.h>
#include <86box/lpt.h>
#include <86box/pic.h>
#include <86box/sound.h>
#include <86box/prt_devs.h>
#include <86box/thread.h>
#include <86box/device.h>
#include <86box/machine.h>
#include <86box/network.h>
static int next_inst = 0;
int lpt_3bc_used = 0;
lpt_port_t lpt_ports[PARALLEL_MAX];
lpt_device_t lpt_devs[PARALLEL_MAX];
const lpt_device_t lpt_none_device = {
.name = "None",
.internal_name = "none",
.init = NULL,
.close = NULL,
.write_data = NULL,
.write_ctrl = NULL,
.read_status = NULL,
.read_ctrl = NULL
};
static const struct {
const lpt_device_t *device;
} lpt_devices[] = {
// clang-format off
{ &lpt_none_device },
{ &dss_device },
{ &lpt_dac_device },
{ &lpt_dac_stereo_device },
{ &lpt_prt_text_device },
{ &lpt_prt_escp_device },
{ &lpt_prt_ps_device },
#ifdef USE_PCL
{ &lpt_prt_pcl_device },
#endif
{ &lpt_plip_device },
{ &lpt_hasp_savquest_device },
{ NULL }
// clang-format on
};
#ifdef ENABLE_LPT_LOG
int lpt_do_log = ENABLE_LPT_LOG;
static void
lpt_log(const char *fmt, ...)
{
va_list ap;
if (lpt_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define lpt_log(fmt, ...)
#endif
const device_t *
lpt_device_getdevice(const int id)
{
return (device_t *) lpt_devices[id].device->cfgdevice;
}
int
lpt_device_has_config(const int id)
{
int c = 0;
const device_t *dev = (device_t *) lpt_devices[id].device->cfgdevice;
const device_config_t *config;
if (dev == NULL)
return 0;
if (dev->config == NULL)
return 0;
config = dev->config;
while (config->type != CONFIG_END) {
c++;
config++;
}
return (c > 0) ? 1 : 0;
}
const char *
lpt_device_get_name(const int id)
{
if (lpt_devices[id].device == NULL)
return NULL;
return lpt_devices[id].device->name;
}
const char *
lpt_device_get_internal_name(const int id)
{
if (lpt_devices[id].device == NULL)
return NULL;
return lpt_devices[id].device->internal_name;
}
int
lpt_device_get_from_internal_name(const char *str)
{
int c = 0;
while (lpt_devices[c].device != NULL) {
if (!strcmp(lpt_devices[c].device->internal_name, str))
return c;
c++;
}
return 0;
}
void
lpt_devices_init(void)
{
for (uint8_t i = 0; i < PARALLEL_MAX; i++) {
lpt_t *dev = lpt_devs[i].lpt;
if (lpt_devices[lpt_ports[i].device].device != NULL) {
memcpy(&(lpt_devs[i]), (lpt_device_t *) lpt_devices[lpt_ports[i].device].device, sizeof(lpt_device_t));
if (lpt_devs[i].init)
lpt_devs[i].priv = lpt_devs[i].init(dev);
} else
memset(&(lpt_devs[i]), 0x00, sizeof(lpt_device_t));
lpt_devs[i].lpt = dev;
}
}
void
lpt_devices_close(void)
{
for (uint8_t i = 0; i < PARALLEL_MAX; i++) {
if (lpt_devs[i].close)
lpt_devs[i].close(lpt_devs[i].priv);
memset(&(lpt_devs[i]), 0x00, sizeof(lpt_device_t));
}
}
static uint8_t
lpt_get_ctrl_raw(const lpt_t *dev)
{
uint8_t ret;
if (dev->dt && dev->dt->read_ctrl && dev->dt->priv)
ret = (dev->dt->read_ctrl(dev->dt->priv) & 0xef) | dev->enable_irq;
else
ret = 0xc0 | dev->ctrl | dev->enable_irq;
return ret & 0xdf;
}
static uint8_t
lpt_is_epp(const lpt_t *dev)
{
return (dev->epp || ((dev->ecp) && ((dev->ecr & 0xe0) == 0x80)));
}
static uint8_t
lpt_get_ctrl(const lpt_t *dev)
{
uint8_t ret = lpt_get_ctrl_raw(dev);
if (!dev->ecp && !dev->epp)
ret |= 0x20;
return ret;
}
static void
lpt_write_fifo(lpt_t *dev, const uint8_t val, const uint8_t tag)
{
if (!fifo_get_full(dev->fifo)) {
fifo_write_evt_tagged(tag, val, dev->fifo);
if (!timer_is_enabled(&dev->fifo_out_timer))
timer_set_delay_u64(&dev->fifo_out_timer, (uint64_t) ((1000000.0 / 2500000.0) * (double) TIMER_USEC));
}
}
static void
lpt_ecp_update_irq(lpt_t *dev)
{
if (!(dev->ecr & 0x04) && ((dev->fifo_stat | dev->dma_stat) & 0x04))
picintlevel(1 << dev->irq, &dev->irq_state);
else
picintclevel(1 << dev->irq, &dev->irq_state);
}
static void
lpt_autofeed(lpt_t *dev, const uint8_t val)
{
if (dev->dt && dev->dt->autofeed && dev->dt->priv)
dev->dt->autofeed(val, dev->dt->priv);
dev->autofeed = val;
}
static void
lpt_strobe(lpt_t *dev, const uint8_t val)
{
if (dev->dt && dev->dt->strobe && dev->dt->priv)
dev->dt->strobe(dev->strobe, val, dev->dt->priv);
dev->strobe = val;
}
static void
lpt_fifo_out_callback(void *priv)
{
lpt_t *dev = (lpt_t *) priv;
switch (dev->state) {
default:
break;
case LPT_STATE_READ_DMA:
;
int ret = 0xff;
if (dev->dma == 0xff)
ret = DMA_NODATA;
else
ret = dma_channel_read(dev->dma);
lpt_log("DMA %02X: %08X\n", dev->dma, ret);
if (ret != DMA_NODATA) {
fifo_write_evt_tagged(0x01, (uint8_t) (ret & 0xff), dev->fifo);
if (ret & DMA_OVER)
/* Internal flag to indicate we have finished the DMA reads. */
dev->dma_stat = 0x08;
}
timer_advance_u64(&dev->fifo_out_timer,
(uint64_t) ((1000000.0 / 2500000.0) * (double) TIMER_USEC));
if (dev->dma_stat || fifo_get_full(dev->fifo))
dev->state = LPT_STATE_WRITE_FIFO;
break;
case LPT_STATE_WRITE_FIFO:
if (!fifo_get_empty(dev->fifo)) {
uint8_t tag = 0x00;
const uint8_t val = fifo_read_evt_tagged(&tag, dev->fifo);
lpt_log("FIFO: %02X, TAG = %02X\n", val, tag);
/* We do not currently support sending commands. */
if (tag == 0x01) {
if (dev->dt && dev->dt->write_data && dev->dt->priv)
dev->dt->write_data(val, dev->dt->priv);
lpt_strobe(dev, 1);
lpt_strobe(dev, 0);
}
}
if (dev->ecr & 0x08) {
if (fifo_get_empty(dev->fifo)) {
if (dev->dma_stat) {
/* Now actually set the external flag. */
dev->dma_stat = 0x04;
dev->state = LPT_STATE_IDLE;
lpt_ecp_update_irq(dev);
lpt_autofeed(dev, 0);
} else {
dev->state = LPT_STATE_READ_DMA;
timer_advance_u64(&dev->fifo_out_timer,
(uint64_t) ((1000000.0 / 2500000.0) * (double) TIMER_USEC));
}
} else
timer_advance_u64(&dev->fifo_out_timer,
(uint64_t) ((1000000.0 / 2500000.0) * (double) TIMER_USEC));
} else if (!fifo_get_empty(dev->fifo))
timer_advance_u64(&dev->fifo_out_timer,
(uint64_t) ((1000000.0 / 2500000.0) * (double) TIMER_USEC));
else
lpt_autofeed(dev, 0);
break;
}
}
void
lpt_write(const uint16_t port, const uint8_t val, void *priv)
{
lpt_t *dev = (lpt_t *) priv;
uint16_t mask = 0x0407;
lpt_log("[W] %04X = %02X\n", port, val);
/* This is needed so the parallel port at 3BC works. */
if (dev->addr & 0x0004)
mask = 0x0403;
switch (port & mask) {
case 0x0000:
if (dev->ecp) {
if ((dev->ecr & 0xe0) == 0x60)
/* AFIFO */
lpt_write_fifo(dev, val, 0x00);
else if (!(dev->ecr & 0xc0) && (!(dev->ecr & 0x20) || !(lpt_get_ctrl_raw(dev) & 0x20)) &&
dev->dt && dev->dt->write_data && dev->dt->priv)
/* DATAR */
dev->dt->write_data(val, dev->dt->priv);
dev->dat = val;
} else {
/* DTR */
if ((!dev->ext || !(lpt_get_ctrl_raw(dev) & 0x20)) && dev->dt &&
dev->dt->write_data && dev->dt->priv)
dev->dt->write_data(val, dev->dt->priv);
dev->dat = val;
}
break;
case 0x0001:
break;
case 0x0002:
if (dev->dt && dev->dt->write_ctrl && dev->dt->priv) {
if (dev->ecp)
dev->dt->write_ctrl((val & 0xfc) | dev->autofeed | dev->strobe, dev->dt->priv);
else
dev->dt->write_ctrl(val, dev->dt->priv);
}
dev->ctrl = val;
dev->enable_irq = val & 0x10;
if (!(val & 0x10) && (dev->irq != 0xff))
picintc(1 << dev->irq);
dev->irq_state = 0;
break;
case 0x0003:
if (lpt_is_epp(dev)) {
if (dev->dt && dev->dt->epp_write_data && dev->dt->priv)
dev->dt->epp_write_data(1, val, dev->dt->priv);
}
break;
case 0x0004 ... 0x0007:
if (lpt_is_epp(dev)) {
if (dev->dt && dev->dt->epp_write_data && dev->dt->priv)
dev->dt->epp_write_data(0, val, dev->dt->priv);
}
break;
case 0x0400: case 0x0404:
switch (dev->ecr >> 5) {
default:
break;
case 2:
lpt_write_fifo(dev, val, 0x01);
break;
case 3:
if (!(lpt_get_ctrl_raw(dev) & 0x20))
lpt_write_fifo(dev, val, 0x01);
break;
case 6:
/* TFIFO */
if (!fifo_get_full(dev->fifo))
fifo_write_evt(val, dev->fifo);
break;
}
break;
case 0x0402: case 0x0406:
if (!(val & 0x0c))
lpt_autofeed(dev, 0x00);
else
lpt_autofeed(dev, 0x02);
if ((dev->ecr & 0x04) && !(val & 0x04)) {
dev->dma_stat = 0x00;
fifo_reset(dev->fifo);
if (val & 0x08) {
dev->state = LPT_STATE_READ_DMA;
dev->fifo_stat = 0x00;
if (!timer_is_enabled(&dev->fifo_out_timer))
timer_set_delay_u64(&dev->fifo_out_timer, (uint64_t) ((1000000.0 / 2500000.0) * (double) TIMER_USEC));
} else {
dev->state = LPT_STATE_WRITE_FIFO;
if (lpt_get_ctrl_raw(dev) & 0x20)
dev->fifo_stat = fifo_get_ready(dev->fifo) ? 0x04 : 0x00;
else
dev->fifo_stat = fifo_get_ready(dev->fifo) ? 0x00 : 0x04;
}
} else if ((val & 0x04) && !(dev->ecr & 0x04)) {
if (timer_is_enabled(&dev->fifo_out_timer))
timer_disable(&dev->fifo_out_timer);
dev->state = LPT_STATE_IDLE;
}
dev->ecr = val;
lpt_ecp_update_irq(dev);
break;
default:
break;
}
}
static void
lpt_fifo_d_ready_evt(void *priv)
{
lpt_t *dev = (lpt_t *) priv;
if (!(dev->ecr & 0x08)) {
if (lpt_get_ctrl_raw(dev) & 0x20)
dev->fifo_stat = fifo_get_ready(dev->fifo) ? 0x04 : 0x00;
else
dev->fifo_stat = fifo_get_ready(dev->fifo) ? 0x00 : 0x04;
}
lpt_ecp_update_irq(dev);
}
void
lpt_write_to_fifo(void *priv, const uint8_t val)
{
lpt_t *dev = (lpt_t *) priv;
if (dev->ecp) {
if (((dev->ecr & 0xe0) == 0x20) && (lpt_get_ctrl_raw(dev) & 0x20))
dev->dat = val;
else if (((dev->ecr & 0xe0) == 0x60) && (lpt_get_ctrl_raw(dev) & 0x20) &&
!fifo_get_full(dev->fifo))
fifo_write_evt_tagged(0x01, val, dev->fifo);
if (((dev->ecr & 0x0c) == 0x08) && (dev->dma != 0xff)) {
const int ret = dma_channel_write(dev->dma, val);
if (ret & DMA_OVER)
dev->dma_stat |= 0x04;
}
} else {
if (dev->ext && (lpt_get_ctrl_raw(dev) & 0x20))
dev->dat = val;
}
}
void
lpt_write_to_dat(void *priv, const uint8_t val)
{
lpt_t *dev = (lpt_t *) priv;
dev->dat = val;
}
static uint8_t
lpt_read_fifo(const lpt_t *dev)
{
uint8_t ret = 0xff;
if (!fifo_get_empty(dev->fifo))
ret = fifo_read(dev->fifo);
return ret;
}
uint8_t
lpt_read_status(lpt_t *dev)
{
uint8_t low_bits = 0x07;
uint8_t ret;
if (dev->ext) {
low_bits = 0x03 | (dev->irq_state ? 0x00 : 0x04);
if (dev->irq != 0xff)
picintclevel(1 << dev->irq, &dev->irq_state);
dev->irq_state = 0;
}
if (dev->epp || dev->ecp) {
low_bits = lpt_is_epp(dev) ? 0x02 : 0x03;
if (lpt_get_ctrl_raw(dev) & 0x10)
low_bits |= (dev->irq_state ? 0x00 : 0x04);
else
low_bits |= 0x04;
}
if (dev->dt && dev->dt->read_status && dev->dt->priv)
ret = (dev->dt->read_status(dev->dt->priv) & 0xf8) | low_bits;
else
ret = 0xd8 | low_bits;
return ret;
}
uint8_t
lpt_read(const uint16_t port, void *priv)
{
lpt_t *dev = (lpt_t *) priv;
uint16_t mask = 0x0407;
uint8_t ret = 0xff;
/* This is needed so the parallel port at 3BC works. */
if (dev->addr & 0x0004)
mask = 0x0403;
switch (port & mask) {
case 0x0000:
if (dev->ecp) {
if (!(dev->ecr & 0xc0))
ret = dev->dat;
} else {
/* DTR */
ret = dev->dat;
}
break;
case 0x0001:
ret = lpt_read_status(dev);
break;
case 0x0002:
ret = lpt_get_ctrl(dev);
if (dev->ecp)
ret = (ret & 0xfc) | (dev->ctrl & 0x03);
break;
case 0x0003:
if (lpt_is_epp(dev)) {
if (dev->dt && dev->dt->epp_request_read && dev->dt->priv)
dev->dt->epp_request_read(1, dev->dt->priv);
ret = dev->dat;
}
break;
case 0x0004 ... 0x0007:
if (lpt_is_epp(dev)) {
if (dev->dt && dev->dt->epp_request_read && dev->dt->priv)
dev->dt->epp_request_read(0, dev->dt->priv);
ret = dev->dat;
}
break;
case 0x0400: case 0x0404:
switch (dev->ecr >> 5) {
default:
break;
case 3:
if (lpt_get_ctrl_raw(dev) & 0x20)
ret = lpt_read_fifo(dev);
break;
case 6:
/* TFIFO */
if (!fifo_get_empty(dev->fifo))
ret = fifo_read_evt(dev->fifo);
break;
case 7:
/* CNFGA */
ret = dev->cnfga_readout;
break;
}
break;
case 0x0401: case 0x0405:
if ((dev->ecr & 0xe0) == 0xe0) {
/* CNFGB */
ret = 0x08;
ret |= (dev->irq_state ? 0x40 : 0x00);
ret |= ((dev->irq == 0x05) ? 0x30 : 0x00);
if ((dev->dma >= 1) && (dev->dma <= 3))
ret |= dev->dma;
}
break;
case 0x0402: case 0x0406:
ret = dev->ecr | dev->fifo_stat | (dev->dma_stat & 0x04);
ret |= (fifo_get_full(dev->fifo) ? 0x02 : 0x00);
ret |= (fifo_get_empty(dev->fifo) ? 0x01 : 0x00);
break;
default:
break;
}
lpt_log("[R] %04X = %02X\n", port, ret);
return ret;
}
uint8_t
lpt_read_port(lpt_t *dev, const uint16_t reg)
{
return lpt_read(reg, dev);
}
void
lpt_irq(void *priv, const int raise)
{
lpt_t *dev = (lpt_t *) priv;
if (dev->enable_irq) {
if (dev->irq != 0xff) {
if (dev->ext) {
if (raise)
picintlevel(1 << dev->irq, &dev->irq_state);
else
picintclevel(1 << dev->irq, &dev->irq_state);
} else {
if (raise)
picint(1 << dev->irq);
else
picintc(1 << dev->irq);
}
}
if (!dev->ext || (dev->irq == 0xff))
dev->irq_state = raise;
} else {
if (dev->irq != 0xff) {
if (dev->ext)
picintclevel(1 << dev->irq, &dev->irq_state);
else
picintc(1 << dev->irq);
}
dev->irq_state = 0;
}
}
void
lpt_set_ext(lpt_t *dev, const uint8_t ext)
{
if (lpt_ports[dev->id].enabled)
dev->ext = ext;
}
void
lpt_set_ecp(lpt_t *dev, const uint8_t ecp)
{
if (lpt_ports[dev->id].enabled)
dev->ecp = ecp;
}
void
lpt_set_epp(lpt_t *dev, const uint8_t epp)
{
if (lpt_ports[dev->id].enabled)
dev->epp = epp;
}
void
lpt_set_lv2(lpt_t *dev, const uint8_t lv2)
{
if (lpt_ports[dev->id].enabled)
dev->lv2 = lv2;
}
void
lpt_set_fifo_threshold(lpt_t *dev, const int threshold)
{
if (lpt_ports[dev->id].enabled)
fifo_set_trigger_len(dev->fifo, threshold);
}
void
lpt_set_cnfga_readout(lpt_t *dev, const uint8_t cnfga_readout)
{
if (lpt_ports[dev->id].enabled)
dev->cnfga_readout = cnfga_readout;
}
void
lpt_port_setup(lpt_t *dev, const uint16_t port)
{
if (lpt_ports[dev->id].enabled) {
if ((dev->addr != 0x0000) && (dev->addr != 0xffff)) {
io_removehandler(dev->addr, 0x0007, lpt_read, NULL, NULL, lpt_write, NULL, NULL, dev);
io_removehandler(dev->addr + 0x0400, 0x0007, lpt_read, NULL, NULL, lpt_write, NULL, NULL, dev);
}
if ((port != 0x0000) && (port != 0xffff)) {
lpt_log("Set handler: %04X-%04X\n", port, port + 0x0003);
io_sethandler(port, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, dev);
if (dev->epp)
io_sethandler(port + 0x0003, 0x0005, lpt_read, NULL, NULL, lpt_write, NULL, NULL, dev);
if (dev->ecp || dev->lv2) {
io_sethandler(port + 0x0400, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, dev);
if (dev->epp)
io_sethandler(port + 0x0404, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, dev);
}
}
dev->addr = port;
} else
dev->addr = 0xffff;
}
void
lpt_port_irq(lpt_t *dev, const uint8_t irq)
{
if (lpt_ports[dev->id].enabled)
dev->irq = irq;
else
dev->irq = 0xff;
lpt_log("Port %i IRQ = %02X\n", dev->id, irq);
}
void
lpt_port_dma(lpt_t *dev, const uint8_t dma)
{
if (lpt_ports[dev->id].enabled)
dev->dma = dma;
else
dev->dma = 0xff;
lpt_log("Port %i DMA = %02X\n", dev->id, dma);
}
void
lpt_port_remove(lpt_t *dev)
{
if (lpt_ports[dev->id].enabled && (dev->addr != 0xffff)) {
io_removehandler(dev->addr, 0x0007, lpt_read, NULL, NULL, lpt_write, NULL, NULL, dev);
io_removehandler(dev->addr + 0x0400, 0x0007, lpt_read, NULL, NULL, lpt_write, NULL, NULL, dev);
dev->addr = 0xffff;
}
}
void
lpt1_remove_ams(lpt_t *dev)
{
if (dev->enabled)
io_removehandler(dev->addr + 1, 0x0002, lpt_read, NULL, NULL, lpt_write, NULL, NULL, dev);
}
void
lpt_speed_changed(void *priv)
{
lpt_t *dev = (lpt_t *) priv;
if (timer_is_enabled(&dev->fifo_out_timer)) {
timer_disable(&dev->fifo_out_timer);
timer_set_delay_u64(&dev->fifo_out_timer, (uint64_t) ((1000000.0 / 2500000.0) * (double) TIMER_USEC));
}
}
void
lpt_port_zero(lpt_t *dev)
{
lpt_t temp = { 0 };
temp.irq = dev->irq;
temp.id = dev->id;
temp.dt = dev->dt;
temp.fifo = dev->fifo;
temp.fifo_out_timer = dev->fifo_out_timer;
if (lpt_ports[dev->id].enabled)
lpt_port_remove(dev);
memset(dev, 0x00, sizeof(lpt_t));
dev->addr = 0xffff;
dev->irq = temp.irq;
dev->id = temp.id;
dev->dt = temp.dt;
dev->fifo = temp.fifo;
dev->fifo_out_timer = temp.fifo_out_timer;
if (machine_has_bus(machine, MACHINE_BUS_MCA))
dev->ext = 1;
}
static void
lpt_close(void *priv)
{
lpt_t *dev = (lpt_t *) priv;
if (lpt_ports[dev->id].enabled) {
fifo_close(dev->fifo);
dev->fifo = NULL;
timer_disable(&dev->fifo_out_timer);
}
free(dev);
}
static void
lpt_reset(void *priv)
{
lpt_t *dev = (lpt_t *) priv;
if (lpt_ports[dev->id].enabled)
if (timer_is_enabled(&dev->fifo_out_timer))
timer_disable(&dev->fifo_out_timer);
lpt_port_zero(dev);
if (lpt_ports[dev->id].enabled) {
if (dev->irq_state) {
if (dev->irq == 0xff)
dev->irq_state = 0x00;
else {
picintclevel(dev->irq, &dev->irq_state);
picintc(dev->irq);
}
}
dev->enable_irq = 0x00;
dev->ext = !!(machine_has_bus(machine, MACHINE_BUS_MCA));
dev->epp = 0;
dev->ecp = 0;
dev->ecr = 0x15;
dev->dat = 0xff;
dev->fifo_stat = 0x00;
dev->dma_stat = 0x00;
}
}
static void *
lpt_init(const device_t *info)
{
lpt_t *dev = (lpt_t *) calloc(1, sizeof(lpt_t));
int orig_inst = next_inst;
const uint16_t default_ports[PARALLEL_MAX] = { LPT1_ADDR, LPT2_ADDR, LPT_MDA_ADDR, LPT4_ADDR };
const uint8_t default_irqs[PARALLEL_MAX] = { LPT1_IRQ, LPT2_IRQ, LPT_MDA_IRQ, LPT4_IRQ };
if (info->local & 0xFFF00000)
next_inst = PARALLEL_MAX - 1;
dev->id = next_inst;
if (lpt_ports[next_inst].enabled || (info->local & 0xFFF00000)) {
lpt_log("Adding parallel port %i...\n", next_inst);
dev->dt = &(lpt_devs[next_inst]);
dev->dt->lpt = dev;
dev->fifo = NULL;
memset(&dev->fifo_out_timer, 0x00, sizeof(pc_timer_t));
lpt_port_zero(dev);
dev->addr = 0xffff;
dev->irq = 0xff;
dev->dma = 0xff;
dev->enable_irq = 0x00;
dev->ext = 0;
dev->epp = 0;
dev->ecp = 0;
dev->ecr = 0x15;
dev->cnfga_readout = 0x14;
if (lpt_ports[dev->id].enabled) {
if (info->local & 0xfff00000) {
lpt_port_setup(dev, info->local >> 20);
lpt_port_irq(dev, (info->local >> 16) & 0xF);
next_inst = orig_inst;
} else {
if ((dev->id == 2) && (lpt_3bc_used)) {
lpt_port_setup(dev, LPT1_ADDR);
lpt_port_irq(dev, LPT1_IRQ);
} else {
lpt_port_setup(dev, default_ports[dev->id]);
lpt_port_irq(dev, default_irqs[dev->id]);
}
}
dev->fifo = fifo16_init();
fifo_set_trigger_len(dev->fifo, 8);
fifo_set_d_ready_evt(dev->fifo, lpt_fifo_d_ready_evt);
fifo_set_priv(dev->fifo, dev);
timer_add(&dev->fifo_out_timer, lpt_fifo_out_callback, dev, 0);
}
}
if (!(info->local & 0xfff00000))
next_inst++;
return dev;
}
void
lpt_set_next_inst(int ni)
{
next_inst = ni;
}
void
lpt_set_3bc_used(int is_3bc_used)
{
lpt_3bc_used = is_3bc_used;
}
void
lpt_standalone_init(void)
{
while (next_inst < (PARALLEL_MAX - 1))
device_add_inst(&lpt_port_device, next_inst + 1);
};
const device_t lpt_port_device = {
.name = "Parallel Port",
.internal_name = "lpt",
.flags = 0,
.local = 0,
.init = lpt_init,
.close = lpt_close,
.reset = lpt_reset,
.available = NULL,
.speed_changed = lpt_speed_changed,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -83,24 +83,29 @@ static const device_t mouse_internal_device = {
static mouse_t mouse_devices[] = {
// clang-format off
{ &mouse_none_device },
{ &mouse_internal_device },
{ &mouse_logibus_device },
{ &mouse_msinport_device },
{ &mouse_none_device },
{ &mouse_internal_device },
{ &mouse_logibus_device },
{ &mouse_msinport_device },
#ifdef USE_GENIBUS
{ &mouse_genibus_device },
{ &mouse_genibus_device },
#endif
{ &mouse_mssystems_device },
{ &mouse_mssystems_bus_device },
{ &mouse_msserial_device },
{ &mouse_msserial_ballpoint_device },
{ &mouse_ltserial_device },
{ &mouse_ps2_device },
#ifdef USE_STANDALONE_QUICKPORT
{ &mouse_upc_standalone_device },
#endif
{ &mouse_mssystems_device },
{ &mouse_mssystems_bus_device },
{ &mouse_msserial_device },
{ &mouse_ltserial_device },
{ &mouse_ps2_device },
#ifdef USE_WACOM
{ &mouse_wacom_device },
{ &mouse_wacom_artpad_device },
{ &mouse_wacom_device },
{ &mouse_wacom_artpad_device },
#endif
{ &mouse_mtouch_device },
{ NULL }
{ &mouse_mtouch_device },
{ NULL }
// clang-format on
};

View File

@@ -10,7 +10,7 @@
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2023 Miran Grca.
* Copyright 2023-2025 Miran Grca.
*/
#include <stdarg.h>
#include <stdatomic.h>
@@ -21,7 +21,6 @@
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include "cpu.h"
#include <86box/device.h>
#include <86box/keyboard.h>
#include <86box/mouse.h>
@@ -333,13 +332,13 @@ ps2_poll(void *priv)
atkbc_dev_t *dev = (atkbc_dev_t *) priv;
int packet_size = (dev->flags & FLAG_INTMODE) ? 4 : 3;
int cond = (!mouse_capture && !video_fullscreen) || (!mouse_scan || !mouse_state_changed()) ||
((dev->mode == MODE_STREAM) && (kbc_at_dev_queue_pos(dev, 1) >= (FIFO_SIZE - packet_size)));
int cond = (mouse_capture || video_fullscreen) && mouse_scan && (dev->mode == MODE_STREAM) &&
mouse_state_changed() && (kbc_at_dev_queue_pos(dev, 1) < (FIFO_SIZE - packet_size));
if (!cond && (dev->mode == MODE_STREAM))
if (cond)
ps2_report_coordinates(dev, 1);
return cond;
return !cond;
}
/*
@@ -353,6 +352,9 @@ mouse_ps2_init(const device_t *info)
atkbc_dev_t *dev = kbc_at_dev_init(DEV_AUX);
int i;
if (info->local & MOUSE_TYPE_QPORT)
device_context(&mouse_upc_standalone_device);
dev->name = info->name;
dev->type = info->local;
@@ -382,6 +384,9 @@ mouse_ps2_init(const device_t *info)
mouse_set_poll(ps2_poll, dev);
if (info->local & MOUSE_TYPE_QPORT)
device_context_restore();
/* Return our private data to the I/O layer. */
return dev;
}

View File

@@ -50,7 +50,7 @@ enum {
FORMAT_MM_SERIES = 0x13,
FORMAT_PB_3BYTE,
FORMAT_PB_5BYTE,
FORMAT_MSYSTEMS = 0x15, /* Alias for FORMAT_PB_5BYTE. */
FORMAT_MSYSTEMS = 0x15, /* Alias for FORMAT_PB_5BYTE. */
FORMAT_MS,
FORMAT_HEX,
FORMAT_MS_4BYTE,
@@ -59,45 +59,46 @@ enum {
};
typedef struct mouse_t {
const char *name; /* name of this device */
const char *name; /* name of this device */
uint8_t id[252];
uint8_t buf[256];
uint8_t id[252];
uint8_t buf[256];
uint8_t flags; /* device flags */
uint8_t but;
uint8_t rts_toggle;
uint8_t status;
uint8_t format;
uint8_t prompt;
uint8_t flags; /* device flags */
uint8_t but;
uint8_t rts_toggle;
uint8_t status;
uint8_t format;
uint8_t prompt;
uint8_t continuous;
uint8_t ib;
uint8_t command;
uint8_t buf_len;
uint8_t report_mode;
uint8_t id_len;
uint8_t buf_pos;
uint8_t rev;
uint8_t continuous;
uint8_t ib;
uint8_t command;
uint8_t buf_len;
uint8_t report_mode;
uint8_t id_len;
uint8_t buf_pos;
uint8_t rev;
int8_t type; /* type of this device */
int8_t port;
int8_t type; /* type of this device */
int8_t port;
int state;
int state;
int bps;
int rps;
int bps;
int default_bps;
int rps;
double transmit_period;
double report_period;
double cur_period;
double min_bit_period;
double acc_time;
double host_transmit_period;
double transmit_period;
double report_period;
double cur_period;
double min_bit_period;
double acc_time;
double host_transmit_period;
pc_timer_t timer;
pc_timer_t timer;
serial_t * serial;
serial_t *serial;
} mouse_t;
#define FLAG_INPORT 0x80 /* device is MS InPort */
@@ -128,7 +129,7 @@ mouse_serial_log(const char *fmt, ...)
static void
sermouse_set_period(mouse_t *dev, double period)
{
dev->cur_period = period; /* Needed for the recalculation of the timings. */
dev->cur_period = period; /* Needed for the recalculation of the timings. */
timer_stop(&dev->timer);
@@ -160,7 +161,7 @@ sermouse_transmit_byte(mouse_t *dev, int do_next)
static void
sermouse_transmit(mouse_t *dev, int len, int from_report, int to_report)
{
dev->state = to_report ? STATE_TRANSMIT_REPORT : STATE_TRANSMIT;
dev->state = to_report ? STATE_TRANSMIT_REPORT : STATE_TRANSMIT;
dev->buf_pos = 0;
dev->buf_len = len;
@@ -186,7 +187,7 @@ sermouse_report_msystems(mouse_t *dev)
{
int delta_x = 0;
int delta_y = 0;
int b = mouse_get_buttons_ex();
int b = mouse_get_buttons_ex();
mouse_subtract_coords(&delta_x, &delta_y, NULL, NULL, -128, 127, 1, 0);
@@ -195,12 +196,12 @@ sermouse_report_msystems(mouse_t *dev)
if (dev->but >= 3)
dev->buf[0] |= (b & 0x04) ? 0x00 : 0x02; /* middle button */
else
dev->buf[0] |= 0x02; /* middle button */
dev->buf[0] |= 0x02; /* middle button */
dev->buf[0] |= (b & 0x02) ? 0x00 : 0x01; /* right button */
dev->buf[1] = delta_x;
dev->buf[2] = delta_y;
dev->buf[3] = delta_x; /* same as byte 1 */
dev->buf[4] = delta_y; /* same as byte 2 */
dev->buf[3] = delta_x; /* same as byte 1 */
dev->buf[4] = delta_y; /* same as byte 2 */
return 5;
}
@@ -210,7 +211,7 @@ sermouse_report_3bp(mouse_t *dev)
{
int delta_x = 0;
int delta_y = 0;
int b = mouse_get_buttons_ex();
int b = mouse_get_buttons_ex();
mouse_subtract_coords(&delta_x, &delta_y, NULL, NULL, -128, 127, 1, 0);
@@ -218,7 +219,7 @@ sermouse_report_3bp(mouse_t *dev)
dev->buf[0] |= (b & 0x01) ? 0x04 : 0x00; /* left button */
if (dev->but >= 3)
dev->buf[0] |= (b & 0x04) ? 0x02 : 0x00; /* middle button */
dev->buf[0] |= (b & 0x02) ? 0x01 : 0x00; /* right button */
dev->buf[0] |= (b & 0x02) ? 0x01 : 0x00; /* right button */
dev->buf[1] = delta_x;
dev->buf[2] = delta_y;
@@ -230,7 +231,7 @@ sermouse_report_mmseries(mouse_t *dev)
{
int delta_x = 0;
int delta_y = 0;
int b = mouse_get_buttons_ex();
int b = mouse_get_buttons_ex();
mouse_subtract_coords(&delta_x, &delta_y, NULL, NULL, -127, 127, 1, 0);
@@ -243,7 +244,7 @@ sermouse_report_mmseries(mouse_t *dev)
dev->buf[0] |= (b & 0x01) ? 0x04 : 0x00; /* left button */
if (dev->but >= 3)
dev->buf[0] |= (b & 0x04) ? 0x02 : 0x00; /* middle button */
dev->buf[0] |= (b & 0x02) ? 0x01 : 0x00; /* right button */
dev->buf[0] |= (b & 0x02) ? 0x01 : 0x00; /* right button */
dev->buf[1] = ABS(delta_x) & 0x7f;
dev->buf[2] = ABS(delta_y) & 0x7f;
mouse_serial_log("MM series mouse report: %02X %02X %02X\n", dev->buf[0], dev->buf[1], dev->buf[2]);
@@ -256,7 +257,7 @@ sermouse_report_bp1(mouse_t *dev, int abs)
{
int delta_x = 0;
int delta_y = 0;
int b = mouse_get_buttons_ex();
int b = mouse_get_buttons_ex();
mouse_subtract_coords(&delta_x, &delta_y, NULL, NULL, -2048, 2047, 1, abs);
@@ -264,7 +265,7 @@ sermouse_report_bp1(mouse_t *dev, int abs)
dev->buf[0] |= (b & 0x01) ? 0x10 : 0x00; /* left button */
if (dev->but >= 3)
dev->buf[0] |= (b & 0x04) ? 0x08 : 0x00; /* middle button */
dev->buf[0] |= (b & 0x02) ? 0x04 : 0x00; /* right button */
dev->buf[0] |= (b & 0x02) ? 0x04 : 0x00; /* right button */
dev->buf[1] = (delta_x & 0x3f);
dev->buf[2] = ((delta_x >> 6) & 0x3f);
dev->buf[3] = (delta_y & 0x3f);
@@ -277,17 +278,17 @@ static uint8_t
sermouse_report_ms(mouse_t *dev)
{
uint8_t len;
int delta_x = 0;
int delta_y = 0;
int delta_z = 0;
int b = mouse_get_buttons_ex();
int delta_x = 0;
int delta_y = 0;
int delta_z = 0;
int b = mouse_get_buttons_ex();
mouse_subtract_coords(&delta_x, &delta_y, NULL, NULL, -128, 127, 0, 0);
mouse_subtract_z(&delta_z, -8, 7, 1);
dev->buf[0] = 0x40;
dev->buf[0] |= (((delta_y >> 6) & 0x03) << 2);
dev->buf[0] |= ((delta_x >> 6) & 0x03);
dev->buf[0] |= ((((delta_y & 0xFF) >> 6) & 0x03) << 2);
dev->buf[0] |= (((delta_x & 0xFF) >> 6) & 0x03);
if (b & 0x01)
dev->buf[0] |= 0x20;
if (b & 0x02)
@@ -295,7 +296,16 @@ sermouse_report_ms(mouse_t *dev)
dev->buf[1] = delta_x & 0x3f;
dev->buf[2] = delta_y & 0x3f;
mouse_serial_log("Microsoft serial mouse report: %02X %02X %02X\n", dev->buf[0], dev->buf[1], dev->buf[2]);
if (dev->but == 3) {
if (dev->type == MOUSE_TYPE_MSBPOINT) {
len = 4;
dev->buf[3] = 0;
if (b & 0x4)
dev->buf[3] |= 0x8;
if (b & 0x8)
dev->buf[3] |= 0x4;
dev->buf[3] |= !!(delta_y < 0) ? 0x2 : 0;
dev->buf[3] |= !!(delta_x < 0) ? 0x1 : 0;
} else if (dev->but == 3) {
len = 3;
if (dev->format == FORMAT_MS) {
if (b & 0x04) {
@@ -325,18 +335,18 @@ sermouse_report_ms(mouse_t *dev)
static uint8_t
sermouse_report_hex(mouse_t *dev)
{
char ret[6] = { 0, 0, 0, 0, 0, 0 };
uint8_t but = 0x00;
int delta_x = 0;
int delta_y = 0;
int b = mouse_get_buttons_ex();
char ret[6] = { 0, 0, 0, 0, 0, 0 };
uint8_t but = 0x00;
int delta_x = 0;
int delta_y = 0;
int b = mouse_get_buttons_ex();
mouse_subtract_coords(&delta_x, &delta_y, NULL, NULL, -128, 127, 1, 0);
but |= (b & 0x01) ? 0x04 : 0x00; /* left button */
if (dev->but >= 3)
but |= (b & 0x04) ? 0x02 : 0x00; /* middle button */
but |= (b & 0x02) ? 0x01 : 0x00; /* right button */
but |= (b & 0x02) ? 0x01 : 0x00; /* right button */
sprintf(ret, "%01X%02X%02X", but & 0x0f, (int8_t) delta_x, (int8_t) delta_y);
@@ -441,14 +451,14 @@ ltsermouse_set_report_period(mouse_t *dev, int rps)
sermouse_set_period(dev, 0.0);
dev->report_period = 0.0;
dev->continuous = 1;
dev->continuous = 1;
} else {
#if 0
if (rps > dev->max_rps)
rps = dev->max_rps;
#endif
dev->continuous = 0;
dev->continuous = 0;
dev->report_period = 1000000.0 / ((double) rps);
/* Actual spacing between reports. */
}
@@ -470,21 +480,22 @@ ltsermouse_update_report_period(mouse_t *dev)
}
static void
ltsermouse_switch_baud_rate(mouse_t *dev, int next_state)
ltsermouse_switch_baud_rate(mouse_t *dev, int next_state, int prompt_off)
{
double word_lens[FORMATS_NUM] = {
[FORMAT_BP1_ABS] = 7.0 + 1.0, /* 7 data bits + even parity */
[FORMAT_BP1_REL] = 7.0 + 1.0, /* 7 data bits + even parity */
[FORMAT_MM_SERIES] = 8.0 + 1.0, /* 8 data bits + odd parity */
[FORMAT_PB_3BYTE] = 8.0, /* 8 data bits + no parity */
[FORMAT_PB_5BYTE] = 8.0, /* 8 data bits + no parity */
[FORMAT_MS] = 7.0, /* 7 datas bits + no parity */
[FORMAT_HEX] = 8.0, /* 8 data bits + no parity */
[FORMAT_MS_4BYTE] = 7.0, /* 7 datas bits + no parity */
[FORMAT_MS_WHEEL] = 7.0 }; /* 7 datas bits + no parity */
[FORMAT_BP1_ABS] = 7.0 + 1.0, /* 7 data bits + even parity */
[FORMAT_BP1_REL] = 7.0 + 1.0, /* 7 data bits + even parity */
[FORMAT_MM_SERIES] = 8.0 + 1.0, /* 8 data bits + odd parity */
[FORMAT_PB_3BYTE] = 8.0, /* 8 data bits + no parity */
[FORMAT_PB_5BYTE] = 8.0, /* 8 data bits + no parity */
[FORMAT_MS] = 7.0, /* 7 datas bits + no parity */
[FORMAT_HEX] = 8.0, /* 8 data bits + no parity */
[FORMAT_MS_4BYTE] = 7.0, /* 7 datas bits + no parity */
[FORMAT_MS_WHEEL] = 7.0 /* 7 datas bits + no parity */
};
double word_len = word_lens[dev->format];
word_len += 1.0 + 2.0; /* 1 start bit + 2 stop bits */
word_len += 1.0 + 2.0; /* 1 start bit + 2 stop bits */
#if 0
dev->max_rps = (int) floor(((double) dev->bps) / (word_len * num_words));
@@ -506,7 +517,7 @@ ltsermouse_switch_baud_rate(mouse_t *dev, int next_state)
ltsermouse_set_report_period(dev, dev->rps);
if (!dev->continuous && (next_state != STATE_BAUD_RATE)) {
if (dev->prompt)
if (dev->prompt && prompt_off)
ltsermouse_set_prompt_mode(dev, 0);
sermouse_transmit_report(dev, 0);
@@ -531,18 +542,19 @@ sermouse_next_state(mouse_t *dev)
static void
ltsermouse_process_command(mouse_t *dev)
{
int cmd_to_rps[9] = { 10, 20, 35, 70, 150, 0, -1, 100, 50 };
int b;
int cmd_to_rps[9] = { 10, 20, 35, 70, 150, 0, -1, 100, 50 };
int b;
uint8_t format_codes[FORMATS_NUM] = {
[FORMAT_BP1_ABS] = 0x0c,
[FORMAT_BP1_REL] = 0x06,
[FORMAT_MM_SERIES] = 0x0a,
[FORMAT_PB_3BYTE] = 0x00,
[FORMAT_PB_5BYTE] = 0x02,
[FORMAT_MS] = 0x0e,
[FORMAT_HEX] = 0x04,
[FORMAT_MS_4BYTE] = 0x08, /* Guess */
[FORMAT_MS_WHEEL] = 0x08 }; /* Guess */
[FORMAT_BP1_ABS] = 0x0c,
[FORMAT_BP1_REL] = 0x06,
[FORMAT_MM_SERIES] = 0x0a,
[FORMAT_PB_3BYTE] = 0x00,
[FORMAT_PB_5BYTE] = 0x02,
[FORMAT_MS] = 0x0e,
[FORMAT_HEX] = 0x04,
[FORMAT_MS_4BYTE] = 0x08, /* Guess */
[FORMAT_MS_WHEEL] = 0x08 /* Guess */
};
const char *copr = "\r\n(C) " COPYRIGHT_YEAR " 86Box, Revision 3.0";
mouse_serial_log("ltsermouse_process_command(): %02X\n", dev->ib);
@@ -551,13 +563,13 @@ ltsermouse_process_command(mouse_t *dev)
switch (dev->command) {
case 0x20:
/* Auto Baud Selection */
dev->bps = (int) floor(1000000.0 / dev->host_transmit_period);
dev->bps = (int) floor(1000000.0 / dev->host_transmit_period);
dev->transmit_period = dev->host_transmit_period;
dev->buf[0] = 0x06;
sermouse_transmit(dev, 1, 0, 0);
ltsermouse_switch_baud_rate(dev, STATE_BAUD_RATE);
ltsermouse_switch_baud_rate(dev, STATE_BAUD_RATE, 0);
break;
case 0x4a: /* Report Rate Selection commands */
@@ -569,7 +581,7 @@ ltsermouse_process_command(mouse_t *dev)
case 0x4e:
case 0x4f:
dev->report_mode = dev->command;
dev->rps = cmd_to_rps[dev->command - 0x4a];
dev->rps = cmd_to_rps[dev->command - 0x4a];
ltsermouse_update_report_period(dev);
break;
@@ -593,16 +605,16 @@ ltsermouse_process_command(mouse_t *dev)
/* Absolute Bit Pad One Packed Binary Format */
mouse_clear_coords();
fallthrough;
case 0x42: /* Relative Bit Pad One Packed Binary Format */
case 0x53: /* MM Series Data Format */
case 0x54: /* Three Byte Packed Binary Format */
case 0x55: /* Five Byte Packed Binary Format (Mouse Systems-compatible) */
case 0x56: /* Microsoft Compatible Format */
case 0x57: /* Hexadecimal Format */
case 0x58: /* Microsoft Compatible Format (3+1 byte 3-button, from the FreeBSD source code) */
case 0x42: /* Relative Bit Pad One Packed Binary Format */
case 0x53: /* MM Series Data Format */
case 0x54: /* Three Byte Packed Binary Format */
case 0x55: /* Five Byte Packed Binary Format (Mouse Systems-compatible) */
case 0x56: /* Microsoft Compatible Format */
case 0x57: /* Hexadecimal Format */
case 0x58: /* Microsoft Compatible Format (3+1 byte 3-button, from the FreeBSD source code) */
if ((dev->rev >= 0x02) && ((dev->command != 0x58) || (dev->rev > 0x04))) {
dev->format = dev->command & 0x1f;
ltsermouse_switch_baud_rate(dev, sermouse_next_state(dev));
ltsermouse_switch_baud_rate(dev, sermouse_next_state(dev), 0);
}
break;
@@ -620,7 +632,7 @@ ltsermouse_process_command(mouse_t *dev)
break;
case 0x05:
/* Diagnostic */
b = mouse_get_buttons_ex();
b = mouse_get_buttons_ex();
dev->buf[0] = ((b & 0x01) << 2) | ((b & 0x06) >> 1);
dev->buf[1] = dev->buf[2] = 0x00;
sermouse_transmit(dev, 3, 0, 0);
@@ -630,7 +642,7 @@ ltsermouse_process_command(mouse_t *dev)
if (dev->rev >= 0x20) {
/* Format and Revision Number */
dev->buf[0] = format_codes[dev->format];
dev->buf[0] |= 0x10; /* Revision 3.0, 0x00 would be Revision 2.0 */
dev->buf[0] |= 0x10; /* Revision 3.0, 0x00 would be Revision 2.0 */
sermouse_transmit(dev, 1, 0, 0);
}
break;
@@ -676,7 +688,7 @@ ltsermouse_process_data(mouse_t *dev)
{
mouse_serial_log("ltsermouse_process_data(): %02X (command = %02X)\n", dev->ib, dev->command);
switch(dev->command) {
switch (dev->command) {
case 0x2a:
switch (dev->ib) {
default:
@@ -694,7 +706,7 @@ ltsermouse_process_data(mouse_t *dev)
dev->bps = 9600;
break;
}
ltsermouse_switch_baud_rate(dev, (dev->prompt || dev->continuous) ? STATE_IDLE : STATE_TRANSMIT_REPORT);
ltsermouse_switch_baud_rate(dev, (dev->prompt || dev->continuous) ? STATE_IDLE : STATE_TRANSMIT_REPORT, 0);
break;
default:
dev->state = STATE_IDLE;
@@ -707,25 +719,32 @@ sermouse_reset(mouse_t *dev, int callback)
{
sermouse_set_period(dev, 0.0);
dev->bps = 1200;
dev->rps = 0;
if (dev->default_bps)
dev->bps = dev->default_bps;
else
dev->bps = 1200;
dev->rps = 0;
dev->prompt = 0;
if (dev->id[0] == 'H')
dev->format = FORMAT_MSYSTEMS;
else switch (dev->but) {
default:
case 2:
dev->format = FORMAT_MS;
break;
case 3:
dev->format = (dev->type == MOUSE_TYPE_LT3BUTTON) ? FORMAT_MS : FORMAT_MS_4BYTE;
break;
case 4:
dev->format = FORMAT_MS_WHEEL;
break;
}
else
switch (dev->but) {
default:
case 2:
dev->format = FORMAT_MS;
break;
case 3:
dev->format = (dev->type == MOUSE_TYPE_LT3BUTTON) ? FORMAT_MS : FORMAT_MS_4BYTE;
break;
case 4:
dev->format = FORMAT_MS_WHEEL;
break;
case 5:
dev->format = FORMAT_MS;
break;
}
ltsermouse_switch_baud_rate(dev, callback ? STATE_TRANSMIT : STATE_IDLE);
ltsermouse_switch_baud_rate(dev, callback ? STATE_TRANSMIT : STATE_IDLE, 1);
}
static void
@@ -840,7 +859,7 @@ sermouse_close(void *priv)
static void *
sermouse_init(const device_t *info)
{
mouse_t *dev;
mouse_t *dev = (mouse_t *) calloc(1, sizeof(mouse_t));
void (*rcr_callback)(struct serial_s *serial, void *priv);
void (*dev_write)(struct serial_s *serial, void *priv, uint8_t data);
void (*transmit_period_callback)(struct serial_s *serial, void *priv,
@@ -850,34 +869,42 @@ sermouse_init(const device_t *info)
uintptr_t irqbase = ((device_get_config_int("irq") << 16) |
(device_get_config_hex16("addr") << 20)) |
ns16450_device.local;
device_add_params(&ns16450_device, (void*)irqbase);
device_add_params(&ns16450_device, (void *) irqbase);
}
dev = (mouse_t *) calloc(1, sizeof(mouse_t));
dev->name = info->name;
dev->but = device_get_config_int("buttons");
dev->rev = device_get_config_int("revision");
dev->but = (info->local == MOUSE_TYPE_MSBPOINT) ? 5 : device_get_config_int("buttons");
if (info->local == 0)
dev->rts_toggle = 1;
if ((info->local == 0) || (info->local == MOUSE_TYPE_MSBPOINT))
dev->rts_toggle = 1;
else
dev->rts_toggle = device_get_config_int("rts_toggle");
dev->rts_toggle = device_get_config_int("rts_toggle");
if (dev->but > 2)
dev->flags |= FLAG_3BTN;
if (info->local == MOUSE_TYPE_MSYSTEMS || info->local == MOUSE_TYPE_MSYSTEMSB) {
dev->format = 0;
dev->type = info->local;
dev->id_len = 1;
dev->id[0] = 'H';
if (info->local == MOUSE_TYPE_MSBPOINT) {
dev->format = 7;
dev->status = 0x0f;
dev->type = MOUSE_TYPE_MSBPOINT;
dev->id_len = 1;
dev->id[0] = 'B';
dev->flags &= ~FLAG_3BTN;
} else if ((info->local == MOUSE_TYPE_MSYSTEMS) || (info->local == MOUSE_TYPE_MSYSTEMSB)) {
dev->format = 0;
dev->type = info->local;
dev->id_len = 1;
dev->id[0] = 'H';
} else {
dev->format = 7;
dev->status = 0x0f;
dev->id_len = 1;
dev->id[0] = 'M';
if (info->local)
dev->rev = device_get_config_int("revision");
dev->format = 7;
dev->status = 0x0f;
dev->id_len = 1;
dev->id[0] = 'M';
if (info->local == 1) {
/* Logitech Serial Mouse */
dev->rev = device_get_config_int("revision");
dev->default_bps = device_get_config_int("default_baud");
}
switch (dev->but) {
default:
case 2:
@@ -900,8 +927,8 @@ sermouse_init(const device_t *info)
dev->port = (info->local == MOUSE_TYPE_MSYSTEMSB) ? (SERIAL_MAX - 1) : device_get_config_int("port");
/* Attach a serial port to the mouse. */
rcr_callback = dev->rts_toggle ? sermouse_callback : NULL;
dev_write = (info->local == 1) ? ltsermouse_write : NULL;
rcr_callback = dev->rts_toggle ? sermouse_callback : NULL;
dev_write = (info->local == 1) ? ltsermouse_write : NULL;
transmit_period_callback = (info->local == 1) ? ltsermouse_transmit_period : NULL;
dev->serial = serial_attach_ex(dev->port, rcr_callback, dev_write,
@@ -923,25 +950,28 @@ sermouse_init(const device_t *info)
return dev;
}
#define SERMOUSE_PORT_CONFIG_COMMON \
{ \
.name = "port", \
.description = "Serial Port", \
.type = CONFIG_SELECTION, \
.default_string = NULL, \
.default_int = 0, \
.file_filter = NULL, \
.spinner = { 0 }, \
.selection = { \
{ .description = "COM1", .value = 0 }, \
{ .description = "COM2", .value = 1 }, \
{ .description = "COM3", .value = 2 }, \
{ .description = "COM4", .value = 3 }, \
{ .description = "" } \
}, \
.bios = { { 0 } } \
}
static const device_config_t msssermouse_config[] = {
// clang-format off
{
.name = "port",
.description = "Serial Port",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "COM1", .value = 0 },
{ .description = "COM2", .value = 1 },
{ .description = "COM3", .value = 2 },
{ .description = "COM4", .value = 3 },
{ .description = "" }
},
.bios = { { 0 } }
},
// clang-format off
SERMOUSE_PORT_CONFIG_COMMON,
{
.name = "buttons",
.description = "Buttons",
@@ -969,7 +999,7 @@ static const device_config_t msssermouse_config[] = {
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
// clang-format on
};
static const device_config_t mssbusmouse_config[] = {
@@ -1042,27 +1072,11 @@ static const device_config_t mssbusmouse_config[] = {
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
};
static const device_config_t mssermouse_config[] = {
// clang-format off
{
.name = "port",
.description = "Serial Port",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "COM1", .value = 0 },
{ .description = "COM2", .value = 1 },
{ .description = "COM3", .value = 2 },
{ .description = "COM4", .value = 3 },
{ .description = "" }
},
.bios = { { 0 } }
},
// clang-format off
SERMOUSE_PORT_CONFIG_COMMON,
{
.name = "buttons",
.description = "Buttons",
@@ -1080,28 +1094,19 @@ static const device_config_t mssermouse_config[] = {
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
// clang-format on
};
static const device_config_t msballpoint_config[] = {
// clang-format off
SERMOUSE_PORT_CONFIG_COMMON,
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_config_t ltsermouse_config[] = {
// clang-format off
{
.name = "port",
.description = "Serial Port",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "COM1", .value = 0 },
{ .description = "COM2", .value = 1 },
{ .description = "COM3", .value = 2 },
{ .description = "COM4", .value = 3 },
{ .description = "" }
},
.bios = { { 0 } }
},
// clang-format off
SERMOUSE_PORT_CONFIG_COMMON,
{
.name = "buttons",
.description = "Buttons",
@@ -1134,19 +1139,36 @@ static const device_config_t ltsermouse_config[] = {
},
.bios = { { 0 } }
},
{
.name = "default_baud",
.description = "Default Baud rate",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 1200,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "1200", .value = 1200 },
{ .description = "2400", .value = 2400 },
{ .description = "4800", .value = 4800 },
{ .description = "9600", .value = 9600 },
{ .description = "" }
},
.bios = { { 0 } }
},
{
.name = "rts_toggle",
.description = "RTS toggle",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.default_int = 1,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
// clang-format on
};
const device_t mouse_mssystems_device = {
@@ -1191,6 +1213,20 @@ const device_t mouse_msserial_device = {
.config = mssermouse_config
};
const device_t mouse_msserial_ballpoint_device = {
.name = "Microsoft Serial BallPoint",
.internal_name = "msballpoint",
.flags = DEVICE_COM,
.local = MOUSE_TYPE_MSBPOINT,
.init = sermouse_init,
.close = sermouse_close,
.reset = NULL,
.available = NULL,
.speed_changed = sermouse_speed_changed,
.force_redraw = NULL,
.config = msballpoint_config
};
const device_t mouse_ltserial_device = {
.name = "Logitech Serial Mouse",
.internal_name = "ltserial",

444
src/device/mouse_upc.c Normal file
View File

@@ -0,0 +1,444 @@
/*
* 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.
*
* Implementation of the Chips & Technologies F82C710 Universal
* Peripheral Controller (UPC) PS/2 mouse port.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2025 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#define HAVE_STDARG_H
#include <wchar.h>
#include <86box/86box.h>
#include "cpu.h"
#include "x86seg.h"
#include <86box/device.h>
#include <86box/timer.h>
#include <86box/io.h>
#include <86box/pic.h>
#include <86box/keyboard.h>
#include <86box/mouse.h>
#define STAT_DEV_IDLE 0x01
#define STAT_RX_FULL 0x02
#define STAT_TX_IDLE 0x04
#define STAT_RESET 0x08
#define STAT_INTS_ON 0x10
#define STAT_ERROR_FLAG 0x20
#define STAT_CLEAR 0x40
#define STAT_ENABLE 0x80
typedef struct mouse_upc_t {
uint8_t status;
uint8_t ib;
uint8_t ob;
uint8_t state;
uint8_t ctrl_queue_start;
uint8_t ctrl_queue_end;
uint8_t handler_enable[2];
uint16_t mdata_addr;
uint16_t mstat_addr;
uint16_t irq;
uint16_t base_addr[2];
/* Local copies of the pointers to both ports for easier swapping (AMI '5' MegaKey). */
kbc_at_port_t *port;
/* Main timers. */
pc_timer_t poll_timer;
pc_timer_t dev_poll_timer;
struct {
uint8_t (*read)(uint16_t port, void *priv);
void (*write)(uint16_t port, uint8_t val, void *priv);
} handlers[2];
void *mouse_ps2;
} mouse_upc_t;
enum {
STATE_MAIN_IBF, /* UPC checking if the input buffer is full. */
STATE_MAIN, /* UPC checking if the auxiliary has anything to send. */
STATE_OUT, /* UPC is sending multiple bytes. */
STATE_SEND, /* UPC is sending command to the auxiliary device. */
STATE_SCAN /* UPC is waiting for the auxiliary command response. */
};
#ifdef ENABLE_MOUSE_UPC_LOG
int mouse_upc_do_log = ENABLE_MOUSE_UPC_LOG;
static void
mouse_upc_log(const char *fmt, ...)
{
va_list ap;
if (mouse_upc_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define mouse_upc_log(fmt, ...)
#endif
static void
mouse_upc_send_to_ob(mouse_upc_t *dev, uint8_t val)
{
dev->status = (dev->status & ~STAT_DEV_IDLE) | STAT_RX_FULL;
if (dev->status & STAT_INTS_ON) {
picint_common(1 << dev->irq, 0, 0, NULL);
picint_common(1 << dev->irq, 0, 1, NULL);
}
dev->ob = val;
}
static void
set_enable_aux(mouse_upc_t *dev, uint8_t enable)
{
dev->status &= ~STAT_ENABLE;
dev->status |= (enable ? STAT_ENABLE : 0x00);
}
static void
mouse_upc_ibf_process(mouse_upc_t *dev)
{
/* IBF set, process both commands and data. */
dev->status |= STAT_TX_IDLE;
dev->state = STATE_MAIN_IBF;
set_enable_aux(dev, 1);
if (dev->port != NULL) {
dev->port->wantcmd = 1;
dev->port->dat = dev->ib;
dev->state = STATE_SEND;
}
}
/*
Correct Procedure:
1. Controller asks the device (keyboard or auxiliary device) for a byte.
2. The device, unless it's in the reset or command states, sees if there's anything to give it,
and if yes, begins the transfer.
3. The controller checks if there is a transfer, if yes, transfers the byte and sends it to the host,
otherwise, checks the next device, or if there is no device left to check, checks if IBF is full
and if yes, processes it.
*/
static int
mouse_upc_scan(mouse_upc_t *dev)
{
if ((dev->port != NULL) && (dev->port->out_new != -1)) {
mouse_upc_log("UPC Mouse: %02X coming\n", dev->port->out_new & 0xff);
mouse_upc_send_to_ob(dev, dev->port->out_new);
dev->port->out_new = -1;
dev->state = STATE_MAIN_IBF;
return 1;
}
return 0;
}
static void
mouse_upc_poll(void *priv)
{
mouse_upc_t *dev = (mouse_upc_t *) priv;
timer_advance_u64(&dev->poll_timer, (100ULL * TIMER_USEC));
switch (dev->state) {
case STATE_MAIN_IBF:
default:
if (!(dev->status & STAT_TX_IDLE))
mouse_upc_ibf_process(dev);
else if (!(dev->status & STAT_RX_FULL)) {
if (dev->status & STAT_ENABLE)
dev->state = STATE_MAIN;
}
break;
case STATE_MAIN:
if (!(dev->status & STAT_TX_IDLE))
mouse_upc_ibf_process(dev);
else {
(void) mouse_upc_scan(dev);
dev->state = STATE_MAIN_IBF;
}
break;
case STATE_SEND:
if (!dev->port->wantcmd)
dev->state = STATE_SCAN;
break;
case STATE_SCAN:
(void) mouse_upc_scan(dev);
break;
}
}
static void
mouse_upc_dev_poll(void *priv)
{
mouse_upc_t *dev = (mouse_upc_t *) priv;
timer_advance_u64(&dev->dev_poll_timer, (100ULL * TIMER_USEC));
if ((dev->port != NULL) && (dev->port->priv != NULL))
dev->port->poll(dev->port->priv);
}
static void
mouse_upc_port_1_write(uint16_t port, uint8_t val, void *priv)
{
mouse_upc_t *dev = (mouse_upc_t *) priv;
mouse_upc_log("UPC Mouse: [%04X:%08X] write(%04X) = %02X\n", CS, cpu_state.pc, port, val);
if ((dev->status & STAT_TX_IDLE) && (dev->status & STAT_ENABLE)) {
dev->ib = val;
dev->status &= ~STAT_TX_IDLE;
}
}
static void
mouse_upc_port_2_write(uint16_t port, uint8_t val, void *priv)
{
mouse_upc_t *dev = (mouse_upc_t *) priv;
mouse_upc_log("UPC Mouse: [%04X:%08X] write(%04X) = %02X\n", CS, cpu_state.pc, port, val);
dev->status = (dev->status & 0x27) | (val & 0xd8);
if (dev->status & (STAT_CLEAR | STAT_RESET)) {
/* TODO: Silently reset the mouse. */
}
}
static uint8_t
mouse_upc_port_1_read(uint16_t port, void *priv)
{
mouse_upc_t *dev = (mouse_upc_t *) priv;
uint8_t ret = 0xff;
cycles -= ISA_CYCLES(8);
ret = dev->ob;
dev->ob = 0xff;
dev->status &= ~STAT_RX_FULL;
dev->status |= STAT_DEV_IDLE;
mouse_upc_log("UPC Mouse: [%04X:%08X] read (%04X) = %02X\n", CS, cpu_state.pc, port, ret);
return ret;
}
static uint8_t
mouse_upc_port_2_read(uint16_t port, void *priv)
{
mouse_upc_t *dev = (mouse_upc_t *) priv;
uint8_t ret = 0xff;
cycles -= ISA_CYCLES(8);
ret = dev->status;
mouse_upc_log("UPC Mouse: [%04X:%08X] read (%04X) = %02X\n", CS, cpu_state.pc, port, ret);
return ret;
}
static void
mouse_upc_reset(void *priv)
{
mouse_upc_t *dev = (mouse_upc_t *) priv;
dev->status = STAT_DEV_IDLE | STAT_TX_IDLE;
dev->ob = 0xff;
dev->state = STATE_MAIN_IBF;
}
static void
mouse_upc_close(void *priv)
{
mouse_upc_t *dev = (mouse_upc_t *) priv;
/* Stop timers. */
timer_disable(&dev->dev_poll_timer);
timer_disable(&dev->poll_timer);
if (kbc_at_ports[1] != NULL) {
free(kbc_at_ports[1]);
kbc_at_ports[1] = NULL;
}
free(dev);
}
void
mouse_upc_port_handler(int num, int set, uint16_t port, void *priv)
{
mouse_upc_t *dev = (mouse_upc_t *) priv;
if (dev->handler_enable[num] && (dev->base_addr[num] != 0x0000))
io_removehandler(dev->base_addr[num], 1,
dev->handlers[num].read, NULL, NULL,
dev->handlers[num].write, NULL, NULL, priv);
dev->handler_enable[num] = set;
dev->base_addr[num] = port;
if (dev->handler_enable[num] && (dev->base_addr[num] != 0x0000))
io_sethandler(dev->base_addr[num], 1,
dev->handlers[num].read, NULL, NULL,
dev->handlers[num].write, NULL, NULL, priv);
}
void
mouse_upc_handler(int set, uint16_t port, void *priv)
{
mouse_upc_port_handler(0, set, port, priv);
mouse_upc_port_handler(1, set, port + 0x0001, priv);
}
void
mouse_upc_set_irq(int num, uint16_t irq, void *priv)
{
mouse_upc_t *dev = (mouse_upc_t *) priv;
if (dev->irq != 0xffff)
picintc(1 << dev->irq);
dev->irq = irq;
}
static void *
mouse_upc_init_common(int standalone, int irq)
{
mouse_upc_t *dev;
dev = (mouse_upc_t *) calloc(1, sizeof(mouse_upc_t));
mouse_upc_reset(dev);
dev->handlers[0].read = mouse_upc_port_1_read;
dev->handlers[0].write = mouse_upc_port_1_write;
dev->handlers[1].read = mouse_upc_port_2_read;
dev->handlers[1].write = mouse_upc_port_2_write;
dev->irq = irq;
if (kbc_at_ports[1] == NULL) {
kbc_at_ports[1] = (kbc_at_port_t *) calloc(1, sizeof(kbc_at_port_t));
kbc_at_ports[1]->out_new = -1;
}
dev->port = kbc_at_ports[1];
timer_add(&dev->poll_timer, mouse_upc_poll, dev, 1);
timer_add(&dev->dev_poll_timer, mouse_upc_dev_poll, dev, 1);
if (standalone) {
mouse_upc_handler(1, 0x02d4, dev);
dev->mouse_ps2 = device_add_params(&mouse_ps2_device, (void *) (uintptr_t) MOUSE_TYPE_PS2_QPORT);
}
return dev;
}
static void *
mouse_upc_init(const device_t *info)
{
void *dev = NULL;
if (info->local == 1)
dev = mouse_upc_init_common(1, device_get_config_int("irq"));
else
dev = mouse_upc_init_common(0, info->local);
return dev;
}
static const device_config_t upc_config[] = {
// clang-format off
{
.name = "irq",
.description = "IRQ",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 12,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "IRQ 12", .value = 12 },
{ .description = "IRQ 2/9", .value = 2 },
{ .description = "" }
},
.bios = { { 0 } }
},
{
.name = "buttons",
.description = "Buttons",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 2,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "Two", .value = 2 },
{ .description = "Three", .value = 3 },
{ .description = "Wheel", .value = 4 },
{ .description = "Five + Wheel", .value = 5 },
{ .description = "Five + 2 Wheels", .value = 6 },
{ .description = "" }
},
.bios = { { 0 } }
},
{
.name = "", .description = "", .type = CONFIG_END
}
// clang-format on
};
const device_t mouse_upc_device = {
.name = "PS/2 QuickPort Mouse (F82C710)",
.internal_name = "mouse_upc",
.flags = DEVICE_ISA,
.local = 0,
.init = mouse_upc_init,
.close = mouse_upc_close,
.reset = mouse_upc_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const device_t mouse_upc_standalone_device = {
.name = "PS/2 QuickPort Mouse",
.internal_name = "mouse_upc_standalone",
.flags = DEVICE_ISA,
.local = 1,
.init = mouse_upc_init,
.close = mouse_upc_close,
.reset = mouse_upc_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = upc_config
};

View File

@@ -37,24 +37,29 @@ novell_cardkey_read(uint16_t port, void *priv)
novell_cardkey_t* cardkey = (novell_cardkey_t*)priv;
uint8_t val = 0x00;
switch (port) {
/* Byte 5 high nibble + byte 4 high nibble */
case 0x23A:
val = (((cardkey->serial_number_str[11] > 'A') ? ((cardkey->serial_number_str[11] - 'A') + 10) : (cardkey->serial_number_str[11] - '0')) << 4) | (((cardkey->serial_number_str[9] > 'A') ? ((cardkey->serial_number_str[9] - 'A') + 10) : (cardkey->serial_number_str[9] - '0')) << 4);
break;
case 0x23B:
val = (((cardkey->serial_number_str[10] > 'A') ? ((cardkey->serial_number_str[10] - 'A') + 10) : (cardkey->serial_number_str[10] - '0')) << 4) | (((cardkey->serial_number_str[8] > 'A') ? ((cardkey->serial_number_str[8] - 'A') + 10) : (cardkey->serial_number_str[8] - '0')) << 4);
break;
/* Byte 5 low nibble + byte 4 low nibble */
case 0x23B:
val = (((cardkey->serial_number_str[11] > 'A') ? ((cardkey->serial_number_str[11] - 'A') + 10) : (cardkey->serial_number_str[11] - '0')) << 4) | (((cardkey->serial_number_str[9] > 'A') ? ((cardkey->serial_number_str[9] - 'A') + 10) : (cardkey->serial_number_str[9] - '0')) << 4);
break;
/* Byte 2 low nibble + byte 1 low nibble */
case 0x23C:
val = ((cardkey->serial_number_str[4] - '0') << 4) | ((cardkey->serial_number_str[2] - '0'));
val = ((cardkey->serial_number_str[5] - '0') << 4) | ((cardkey->serial_number_str[3] - '0'));
break;
/* Byte 0 high nibble + byte 3 low nibble*/
case 0x23D:
val = ((cardkey->serial_number_str[1] - '0') << 4) | ((cardkey->serial_number_str[6] - '0'));
break;
case 0x23E:
val = ((cardkey->serial_number_str[0] - '0') << 4) | ((cardkey->serial_number_str[7] - '0'));
break;
/* Byte 0 low nibble + byte 3 high nibble */
case 0x23E:
val = ((cardkey->serial_number_str[1] - '0') << 4) | ((cardkey->serial_number_str[6] - '0'));
break;
/* Byte 1 high nibble + byte 2 high nibble*/
case 0x23F:
val = ((cardkey->serial_number_str[3] - '0') << 4) | ((cardkey->serial_number_str[5] - '0'));
val = ((cardkey->serial_number_str[2] - '0') << 4) | ((cardkey->serial_number_str[4] - '0'));
break;
}
return val ^ 0xFF;
@@ -109,8 +114,8 @@ static const device_config_t keycard_config[] = {
};
const device_t novell_keycard_device = {
.name = "Novell Netware 2.x Key Card",
.internal_name = "mssystems",
.name = "Novell NetWare 2.x Key Card",
.internal_name = "novellkeycard",
.flags = DEVICE_ISA,
.local = 0,
.init = novell_cardkey_init,

View File

@@ -30,8 +30,10 @@
#include <86box/mem.h>
#include <86box/device.h>
#include <86box/pci.h>
#include <86box/plat_fallthrough.h>
#define PCI_BRIDGE_DEC_21150 0x10110022
#define PCI_BRIDGE_DEC_21152 0x10110024
#define AGP_BRIDGE_ALI_M5243 0x10b95243
#define AGP_BRIDGE_ALI_M5247 0x10b95247
#define AGP_BRIDGE_INTEL_440LX 0x80867181
@@ -85,6 +87,14 @@ pci_bridge_set_ctl(void *priv, uint8_t ctl)
dev->ctl = ctl;
}
uint8_t
pci_bridge_get_bus_index(void *priv)
{
pci_bridge_t *dev = (pci_bridge_t *) priv;
return dev->bus_index;
}
static void
pci_bridge_write(int func, int addr, uint8_t val, void *priv)
{
@@ -242,12 +252,15 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv)
case 0x40:
if (dev->local == PCI_BRIDGE_DEC_21150)
val &= 0x32;
else if (dev->local == PCI_BRIDGE_DEC_21152)
val &= 0x12;
break;
case 0x41:
if (AGP_BRIDGE_VIA(dev->local))
val &= 0x7e;
else if (dev->local == PCI_BRIDGE_DEC_21150)
else if ((dev->local == PCI_BRIDGE_DEC_21150) ||
(dev->local == PCI_BRIDGE_DEC_21152))
val &= 0x07;
break;
@@ -257,18 +270,22 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv)
break;
case 0x43:
if (dev->local == PCI_BRIDGE_DEC_21150)
if ((dev->local == PCI_BRIDGE_DEC_21150) ||
(dev->local == PCI_BRIDGE_DEC_21152))
val &= 0x03;
break;
case 0x64:
if (dev->local == PCI_BRIDGE_DEC_21150)
if ((dev->local == PCI_BRIDGE_DEC_21150) ||
(dev->local == PCI_BRIDGE_DEC_21152))
val &= 0x7e;
break;
case 0x69:
if (dev->local == PCI_BRIDGE_DEC_21150)
val &= 0x3f;
else if (dev->local == PCI_BRIDGE_DEC_21152)
val = (val & 0x01) | 0x3e;
break;
case 0x86:
@@ -302,6 +319,15 @@ pci_bridge_write(int func, int addr, uint8_t val, void *priv)
break;
case 0xe0:
if (AGP_BRIDGE_ALI(dev->local)) {
if (!(dev->ctl & 0x20))
return;
} else if (dev->local == PCI_BRIDGE_DEC_21152)
val &= 0x03;
else
return;
break;
case 0xe1:
if (AGP_BRIDGE_ALI(dev->local)) {
if (!(dev->ctl & 0x20))
@@ -399,6 +425,14 @@ pci_bridge_reset(void *priv)
/* command and status */
switch (dev->local) {
case PCI_BRIDGE_DEC_21152:
dev->regs[0x08] = 0x03;
dev->regs[0x34] = 0xdc;
dev->regs[0x69] = 0x3e;
dev->regs[0xdc] = 0x01;
dev->regs[0xde] = 0x01;
dev->regs[0xe2] = 0x80;
fallthrough;
case PCI_BRIDGE_DEC_21150:
dev->regs[0x06] = 0x80;
dev->regs[0x07] = 0x02;
@@ -487,8 +521,8 @@ static void *
pci_bridge_init(const device_t *info)
{
uint8_t interrupts[4];
uint8_t interrupt_count;
uint8_t interrupt_mask;
uint8_t add_type;
uint8_t slot_count;
pci_bridge_t *dev = (pci_bridge_t *) calloc(1, sizeof(pci_bridge_t));
@@ -499,22 +533,27 @@ pci_bridge_init(const device_t *info)
pci_bridge_reset(dev);
pci_add_bridge(AGP_BRIDGE(dev->local), pci_bridge_read, pci_bridge_write, dev, &dev->slot);
interrupt_count = sizeof(interrupts);
interrupt_mask = interrupt_count - 1;
interrupt_mask = sizeof(interrupts) - 1;
if (dev->slot < 32) {
for (uint8_t i = 0; i < interrupt_count; i++)
for (uint8_t i = 0; i <= interrupt_mask; i++)
interrupts[i] = pci_get_int(dev->slot, PCI_INTA + i);
}
pci_bridge_log("PCI Bridge %d: upstream bus %02X slot %02X interrupts %02X %02X %02X %02X\n",
dev->bus_index, (dev->slot >> 5) & 0xff, dev->slot & 31, interrupts[0],
interrupts[1], interrupts[2], interrupts[3]);
if (info->local == PCI_BRIDGE_DEC_21150)
if (info->local == PCI_BRIDGE_DEC_21150) {
slot_count = 9; /* 9 bus masters */
else
add_type = PCI_ADD_NORMAL;
} else if (info->local == PCI_BRIDGE_DEC_21152) {
slot_count = 0; /* 4 bus masters, but slots are added by the Dell machines */
add_type = PCI_ADD_BRIDGE;
} else {
slot_count = 1; /* AGP bridges always have 1 slot */
add_type = PCI_ADD_AGPBRIDGE;
}
pci_add_bridge(add_type, pci_bridge_read, pci_bridge_write, dev, &dev->slot);
for (uint8_t i = 0; i < slot_count; i++) {
/* Interrupts for bridge slots are assigned in round-robin: ABCD, BCDA, CDAB and so on. */
@@ -547,6 +586,20 @@ const device_t dec21150_device = {
.config = NULL
};
const device_t dec21152_device = {
.name = "DEC 21152 PCI Bridge",
.internal_name = "dec21152",
.flags = DEVICE_PCI,
.local = PCI_BRIDGE_DEC_21152,
.init = pci_bridge_init,
.close = NULL,
.reset = pci_bridge_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
/* AGP bridges */
const device_t ali5243_agp_device = {
.name = "ALi M5243 AGP Bridge",

View File

@@ -30,11 +30,14 @@
#include "cpu.h"
uint8_t postcard_codes[POSTCARDS_NUM];
char postcard_diags[5] = { 0 };
static uint16_t postcard_port;
static uint8_t postcard_written[POSTCARDS_NUM];
static uint8_t postcard_ports_num = 1;
static uint8_t postcard_prev_codes[POSTCARDS_NUM];
static uint8_t postcard_dell_mode = 0;
static char postcard_prev_diags[5] = { 0 };
#define UISTR_LEN 32
static char postcard_str[UISTR_LEN]; /* UI output string */
@@ -98,12 +101,22 @@ postcard_setui(void)
break;
}
} else {
char dell_diags[11] = { 0 };
if (postcard_dell_mode) {
if (!postcard_written[1])
snprintf(dell_diags, sizeof(dell_diags), " ---- ----");
else if (postcard_written[1] == 1)
snprintf(dell_diags, sizeof(dell_diags), " %s ----", postcard_diags);
else
snprintf(dell_diags, sizeof(dell_diags), " %s %s", postcard_diags, postcard_prev_diags);
}
if (!postcard_written[0])
snprintf(postcard_str, sizeof(postcard_str), "POST: -- --");
snprintf(postcard_str, sizeof(postcard_str), "POST: -- --%s", dell_diags);
else if (postcard_written[0] == 1)
snprintf(postcard_str, sizeof(postcard_str), "POST: %02X --", postcard_codes[0]);
snprintf(postcard_str, sizeof(postcard_str), "POST: %02X --%s", postcard_codes[0], dell_diags);
else
snprintf(postcard_str, sizeof(postcard_str), "POST: %02X %02X", postcard_codes[0], postcard_prev_codes[0]);
snprintf(postcard_str, sizeof(postcard_str), "POST: %02X %02X%s", postcard_codes[0], postcard_prev_codes[0], dell_diags);
}
ui_sb_bugui(postcard_str);
@@ -122,6 +135,9 @@ postcard_reset(void)
memset(postcard_codes, 0x00, POSTCARDS_NUM * sizeof(uint8_t));
memset(postcard_prev_codes, 0x00, POSTCARDS_NUM * sizeof(uint8_t));
memset(postcard_diags, 0x00, 5 * sizeof(char));
memset(postcard_prev_diags, 0x00, 5 * sizeof(char));
postcard_setui();
}
@@ -140,6 +156,35 @@ postcard_write(uint16_t port, uint8_t val, UNUSED(void *priv))
postcard_setui();
}
static int
postcard_cmp_diags(uint32_t val)
{
int ret = 0;
char *pv = (char *) &val;
for (int i = 0; i < 4; i++)
ret = ret || (pv[i] != postcard_diags[3 - i]);
return ret;
}
static void
postcard_writel(uint16_t port, uint32_t val, UNUSED(void *priv))
{
char *pv = (char *) &val;
if (postcard_written[1] && !postcard_cmp_diags(val))
return;
*(uint32_t *) postcard_prev_diags = *(uint32_t *) postcard_diags;
for (int i = 0; i < 4; i++)
postcard_diags[i] = pv[3 - i];
if (postcard_written[1] < 2)
postcard_written[1]++;
postcard_setui();
}
static void *
postcard_init(UNUSED(const device_t *info))
{
@@ -147,17 +192,22 @@ postcard_init(UNUSED(const device_t *info))
if (machine_has_bus(machine, MACHINE_BUS_MCA))
postcard_port = 0x680; /* MCA machines */
else if (strstr(machines[machine].name, " PS/2 ") || strstr(machine_getname_ex(machine), " PS/1 "))
else if (strstr(machines[machine].name, " PS/2 ") ||
strstr(machine_getname_ex(machine), " PS/1 "))
postcard_port = 0x190; /* ISA PS/2 machines */
else if (strstr(machines[machine].name, " IBM XT "))
postcard_port = 0x60; /* IBM XT */
else if (strstr(machines[machine].name, " IBM PCjr")) {
postcard_port = 0x10; /* IBM PCjr */
postcard_ports_num = 3; /* IBM PCjr error ports 11h and 12h */
} else if (strstr(machines[machine].name, " Compaq ") && !machine_has_bus(machine, MACHINE_BUS_PCI))
} else if (strstr(machines[machine].name, " Compaq ") &&
!strstr(machines[machine].name, " Presario ") &&
!strstr(machines[machine].name, " ProSignia "))
postcard_port = 0x84; /* ISA Compaq machines */
else if (strstr(machines[machine].name, "Olivetti"))
postcard_port = 0x378; /* Olivetti machines */
else if (!strcmp(machines[machine].internal_name, "isa486c"))
postcard_port = 0x5080; /* ASUS ISA-486C */
else
postcard_port = 0x80; /* AT and clone machines */
postcard_log("POST card initializing on port %04Xh\n", postcard_port);
@@ -168,6 +218,12 @@ postcard_init(UNUSED(const device_t *info))
io_sethandler(postcard_port, postcard_ports_num,
NULL, NULL, NULL, postcard_write, NULL, NULL, NULL);
postcard_dell_mode = strstr(machines[machine].name, " Dell ") &&
(machine_get_chipset(machine) >= MACHINE_CHIPSET_INTEL_430FX);
if (postcard_dell_mode)
io_sethandler(is486 ? 0x00e0 : 0x00e4, 0x0001,
NULL, NULL, NULL, NULL, NULL, postcard_writel, NULL);
return postcard_write;
}

View File

@@ -746,6 +746,14 @@ serial_read(uint16_t addr, void *priv)
return ret;
}
uint8_t
serial_get_shadow(serial_t *dev)
{
uint8_t ret = dev->fcr;
return ret;
}
void
serial_remove(serial_t *dev)
{

View File

@@ -13,7 +13,7 @@
* Jasmine Iwanek <jasmine@iwanek.co.uk>
*
* Copyright 2021 Andreas J. Reichel.
* Copyright 2021-2022 Jasmine Iwanek.
* Copyright 2021-2025 Jasmine Iwanek.
*/
#include <stdarg.h>
@@ -222,10 +222,15 @@ serial_passthrough_dev_init(const device_t *info)
}
const char *serpt_mode_names[SERPT_MODES_MAX] = {
[SERPT_MODE_VCON] = "vcon",
[SERPT_MODE_TCPSRV] = "tcpsrv",
[SERPT_MODE_TCPCLNT] = "tcpclnt",
[SERPT_MODE_HOSTSER] = "hostser",
#ifdef _WIN32
[SERPT_MODE_NPIPE_SRV] = "npipesrv",
[SERPT_MODE_NPIPE_CLNT] = "npipeclnt",
#else
[SERPT_MODE_VCON] = "vcon",
#endif
[SERPT_MODE_TCP_SRV] = "tcpsrv",
[SERPT_MODE_TCP_CLNT] = "tcpclnt",
[SERPT_MODE_HOSTSER] = "hostser",
};
// clang-format off
@@ -240,19 +245,17 @@ static const device_config_t serial_passthrough_config[] = {
.spinner = { 0 },
.selection = {
#ifdef _WIN32
{ .description = "Named Pipe (Server)", .value = SERPT_MODE_VCON },
#if 0 /* TODO */
{ .description = "Named Pipe (Client)", .value = SERPT_MODE_VCON },
#endif
{ .description = "Named Pipe (Server)", .value = SERPT_MODE_NPIPE_SRV },
{ .description = "Named Pipe (Client)", .value = SERPT_MODE_NPIPE_CLNT },
#else /* _WIN32 */
{ .description = "Pseudo Terminal/Virtual Console", .value = SERPT_MODE_VCON },
{ .description = "Pseudo Terminal/Virtual Console", .value = SERPT_MODE_VCON },
#endif /* _WIN32 */
#if 0 /* TODO */
{ .description = "TCP Server", .value = SERPT_MODE_TCPSRV },
{ .description = "TCP Client", .value = SERPT_MODE_TCPCLNT },
{ .description = "TCP Server", .value = SERPT_MODE_TCP_SRV },
{ .description = "TCP Client", .value = SERPT_MODE_TCP_CLNT },
#endif
{ .description = "Host Serial Passthrough", .value = SERPT_MODE_HOSTSER },
{ .description = "" }
{ .description = "Host Serial Passthrough", .value = SERPT_MODE_HOSTSER },
{ .description = "" }
},
.bios = { { 0 } }
},

103
src/device/tulip_jumper.c Normal file
View File

@@ -0,0 +1,103 @@
/*
* 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.
*
* Implementation of the Tulip Jumper Readout.
*
* Bits 7-5 = board number, 0-5 valid, 6, 7 invalid.
*
* Authors: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2025 Miran Grca.
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include "cpu.h"
#include <86box/timer.h>
#include <86box/io.h>
#include <86box/device.h>
#include <86box/machine.h>
#include <86box/sound.h>
#include <86box/chipset.h>
#include <86box/plat.h>
#include <86box/plat_unused.h>
typedef struct tulip_jumper_t {
uint8_t jumper;
} tulip_jumper_t;
#ifdef ENABLE_TULIP_JUMPER_LOG
int tulip_jumper_do_log = ENABLE_TULIP_JUMPER_LOG;
static void
tulip_jumper_log(const char *fmt, ...)
{
va_list ap;
if (tulip_jumper_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define tulip_jumper_log(fmt, ...)
#endif
static uint8_t
tulip_jumper_read(uint16_t addr, void *priv)
{
const tulip_jumper_t *dev = (tulip_jumper_t *) priv;
uint8_t ret = 0xff;
tulip_jumper_log("Tulip Jumper: Read %02x\n", dev->jumper);
ret = dev->jumper;
return ret;
}
static void
tulip_jumper_close(void *priv)
{
tulip_jumper_t *dev = (tulip_jumper_t *) priv;
free(dev);
}
static void *
tulip_jumper_init(const device_t *info)
{
tulip_jumper_t *dev = (tulip_jumper_t *) calloc(1, sizeof(tulip_jumper_t));
/* Return board number 05. */
dev->jumper = 0xbf;
io_sethandler(0x0d80, 0x0001, tulip_jumper_read, NULL, NULL, NULL, NULL, NULL, dev);
return dev;
}
const device_t tulip_jumper_device = {
.name = "Tulip Jumper Readout",
.internal_name = "tulip_jumper",
.flags = 0,
.local = 0,
.init = tulip_jumper_init,
.close = tulip_jumper_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

Some files were not shown because too many files have changed in this diff Show More