mirror of
https://github.com/86Box/86Box.git
synced 2026-02-22 01:25:33 -07:00
Merge branch 'master' into feature/global-config
This commit is contained in:
@@ -96,3 +96,4 @@ AppDir:
|
||||
AppImage:
|
||||
arch: !ENV '${arch_appimage}'
|
||||
file_name: !ENV '${appimage_path}'
|
||||
comp: gzip
|
||||
|
||||
43
.ci/build.sh
43
.ci/build.sh
@@ -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.
|
||||
|
||||
40
.github/workflows/cmake_linux.yml
vendored
40
.github/workflows/cmake_linux.yml
vendored
@@ -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/**
|
||||
|
||||
48
.github/workflows/cmake_macos.yml
vendored
48
.github/workflows/cmake_macos.yml
vendored
@@ -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
|
||||
|
||||
48
.github/workflows/cmake_windows_msys2.yml
vendored
48
.github/workflows/cmake_windows_msys2.yml
vendored
@@ -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
|
||||
|
||||
|
||||
45
.github/workflows/codeql_linux.yml
vendored
45
.github/workflows/codeql_linux.yml
vendored
@@ -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"
|
||||
|
||||
45
.github/workflows/codeql_macos.yml
vendored
45
.github/workflows/codeql_macos.yml
vendored
@@ -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"
|
||||
|
||||
73
.github/workflows/codeql_windows_msys2.yml
vendored
73
.github/workflows/codeql_windows_msys2.yml
vendored
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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!
|
||||
|
||||
[](https://kiwiirc.com/client/irc.ringoflightning.net/?nick=86box|?#86Box)
|
||||
|
||||
|
||||
225
src/86box.c
225
src/86box.c
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
16
src/acpi.c
16
src/acpi.c
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
1078
src/cdrom/cdrom_mke.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
346
src/chipset/acc2036.c
Normal 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
|
||||
};
|
||||
@@ -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
289
src/chipset/cs8220.c
Normal 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
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
131
src/chipset/isa486c.c
Normal 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
|
||||
};
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
360
src/chipset/opti498.c
Normal 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
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
362
src/chipset/sl82c461.c
Normal 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
|
||||
};
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)];
|
||||
|
||||
810
src/config.c
810
src/config.c
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
610
src/cpu/808x.c
610
src/cpu/808x.c
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -326,7 +326,6 @@ reset_common(int hard)
|
||||
resetreadlookup();
|
||||
makemod1table();
|
||||
cpu_set_edx();
|
||||
mmu_perm = 4;
|
||||
}
|
||||
x86seg_reset();
|
||||
#ifdef USE_DYNAREC
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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; \
|
||||
} \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)); \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
91
src/device.c
91
src/device.c
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -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
175
src/device/dell_jumper.c
Normal 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
|
||||
};
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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
706
src/device/isarom.c
Normal 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);
|
||||
}
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
1459
src/device/kbc_at.c
1459
src/device/kbc_at.c
File diff suppressed because it is too large
Load Diff
@@ -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
903
src/device/kbc_xt.c
Normal 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
|
||||
};
|
||||
@@ -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
@@ -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
945
src/device/lpt.c
Normal 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
|
||||
};
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
444
src/device/mouse_upc.c
Normal 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
|
||||
};
|
||||
@@ -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,
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
103
src/device/tulip_jumper.c
Normal 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
Reference in New Issue
Block a user